Merge "[Audiosharing] Test getInstance for states" into main
diff --git a/Android.bp b/Android.bp
index cb898be..0c6d8d1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -125,6 +125,9 @@
"telephony-common",
"ims-common",
],
+ flags_packages: [
+ "android.app.flags-aconfig",
+ ],
}
platform_compat_config {
@@ -155,6 +158,9 @@
optimize: {
proguard_flags_files: ["proguard.flags"],
},
+ flags_packages: [
+ "android.app.flags-aconfig",
+ ],
}
android_library_import {
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 90b42f4..8cfd9b5 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -140,7 +140,7 @@
<uses-permission android:name="android.permission.REMAP_MODIFIER_KEYS" />
<uses-permission android:name="android.permission.ACCESS_GPU_SERVICE" />
<uses-permission android:name="android.permission.MANAGE_GAME_MODE" />
- <uses-permission android:name="android.permission.RESTART_PHONE_PROCESS" />
+ <uses-permission android:name="android.permission.RESTART_TELEPHONY_PROCESS" />
<uses-permission android:name="android.permission.MANAGE_ENHANCED_CONFIRMATION_STATES" />
<uses-permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
@@ -1287,20 +1287,63 @@
</activity>
<activity
- android:name="Settings$ZenModeSettingsActivity"
+ android:name="Settings$ModesSettingsActivity"
android:label="@string/zen_mode_settings_title"
android:icon="@drawable/ic_homepage_notification"
android:exported="true">
- <intent-filter android:priority="1">
+ <intent-filter android:priority="1"
+ android:featureFlag="android.app.modes_ui">
<action android:name="android.settings.ZEN_MODE_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
- <intent-filter android:priority="1">
+ <intent-filter android:priority="1"
+ android:featureFlag="android.app.modes_ui">
<action android:name="android.settings.ZEN_MODE_PRIORITY_SETTINGS" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
- <intent-filter android:priority="41">
+ <intent-filter android:priority="41"
+ android:featureFlag="android.app.modes_ui">
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.settings.SHORTCUT" />
+ </intent-filter>
+ <intent-filter android:priority="10"
+ android:featureFlag="android.app.modes_ui">
+ <action android:name="android.settings.ZEN_MODE_AUTOMATION_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter android:priority="10"
+ android:featureFlag="android.app.modes_ui">
+ <action android:name="android.settings.ACTION_CONDITION_PROVIDER_SETTINGS" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="com.android.settings.notification.modes.ZenModesListFragment"/>
+ <meta-data android:name="com.android.settings.HIGHLIGHT_MENU_KEY"
+ android:value="@string/menu_key_notifications"/>
+ <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
+ android:value="true" />
+ </activity>
+
+ <activity
+ android:name="Settings$ZenModeSettingsActivity"
+ android:label="@string/zen_mode_settings_title"
+ android:icon="@drawable/ic_homepage_notification"
+ android:exported="true">
+ <intent-filter android:priority="1"
+ android:featureFlag="!android.app.modes_ui">
+ <action android:name="android.settings.ZEN_MODE_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter android:priority="1"
+ android:featureFlag="!android.app.modes_ui">
+ <action android:name="android.settings.ZEN_MODE_PRIORITY_SETTINGS" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter android:priority="41"
+ android:featureFlag="!android.app.modes_ui">
<action android:name="android.intent.action.MAIN" />
<category android:name="com.android.settings.SHORTCUT" />
</intent-filter>
@@ -1313,6 +1356,20 @@
</activity>
<activity
+ android:name="Settings$ModeSettingsActivity"
+ android:exported="true">
+ <intent-filter android:priority="1"
+ android:featureFlag="android.app.modes_ui">
+ <action android:name="android.settings.AUTOMATIC_ZEN_RULE_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="com.android.settings.notification.modes.ZenModeFragment"/>
+ <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
+ android:value="true" />
+ </activity>
+
+ <activity
android:name=".notification.zen.ZenSuggestionActivity"
android:label="@string/zen_mode_settings_title"
android:icon="@drawable/ic_suggestion_dnd"
@@ -1351,11 +1408,13 @@
android:label="@string/zen_mode_automation_settings_title"
android:icon="@drawable/ic_notifications"
android:exported="true">
- <intent-filter android:priority="1">
+ <intent-filter android:priority="10"
+ android:featureFlag="!android.app.modes_ui">
<action android:name="android.settings.ZEN_MODE_AUTOMATION_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
- <intent-filter android:priority="1">
+ <intent-filter android:priority="10"
+ android:featureFlag="!android.app.modes_ui">
<action android:name="android.settings.ACTION_CONDITION_PROVIDER_SETTINGS" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
@@ -2832,17 +2891,20 @@
<!-- Note this must not be exported since it returns the password in the intent -->
<activity android:name=".password.ConfirmLockPattern$InternalActivity"
android:exported="false"
+ android:enableOnBackInvokedCallback="false"
android:theme="@style/GlifTheme.Light"/>
<!-- Note this must not be exported since it returns the password in the intent -->
<activity android:name=".password.ConfirmLockPassword$InternalActivity"
android:exported="false"
android:windowSoftInputMode="adjustResize"
+ android:enableOnBackInvokedCallback="false"
android:theme="@style/GlifTheme.Light"/>
<activity android:name=".password.SetupChooseLockGeneric"
android:theme="@style/GlifTheme.Light"
android:exported="true"
+ android:enableOnBackInvokedCallback="false"
android:label="@string/lock_settings_picker_title">
<intent-filter android:priority="1">
<action android:name="com.android.settings.SETUP_LOCK_SCREEN" />
@@ -2852,16 +2914,19 @@
<activity android:name=".password.SetupChooseLockGeneric$InternalActivity"
android:exported="false"
+ android:enableOnBackInvokedCallback="false"
android:excludeFromRecents="true" />
<activity android:name=".password.ChooseLockGeneric"
android:label="@string/lockpassword_choose_lock_generic_header"
android:excludeFromRecents="true"
+ android:enableOnBackInvokedCallback="false"
android:exported="false" />
<activity android:name=".password.SetNewPasswordActivity"
android:theme="@android:style/Theme.NoDisplay"
android:exported="true"
+ android:enableOnBackInvokedCallback="false"
android:excludeFromRecents="true" >
<intent-filter android:priority="1">
<action android:name="android.app.action.SET_NEW_PASSWORD" />
@@ -2907,24 +2972,29 @@
<activity android:name=".password.ChooseLockGeneric$InternalActivity"
android:exported="false"
android:label="@string/lockpassword_choose_lock_generic_header"
+ android:enableOnBackInvokedCallback="false"
android:excludeFromRecents="true" />
<activity android:name=".password.SetupChooseLockPattern"
android:exported="false"
+ android:enableOnBackInvokedCallback="false"
android:theme="@style/GlifTheme.Light" />
<activity android:name=".password.ChooseLockPattern"
android:exported="false"
+ android:enableOnBackInvokedCallback="false"
android:theme="@style/GlifTheme.Light" />
<activity android:name=".password.SetupChooseLockPassword"
android:exported="false"
android:theme="@style/GlifTheme.Light"
+ android:enableOnBackInvokedCallback="false"
android:windowSoftInputMode="stateVisible|adjustResize" />
<activity android:name=".password.ChooseLockPassword"
android:exported="false"
android:theme="@style/GlifTheme.Light"
+ android:enableOnBackInvokedCallback="false"
android:windowSoftInputMode="stateVisible|adjustResize"/>
<activity
diff --git a/aconfig/settings_wifi_flag_declarations.aconfig b/aconfig/settings_wifi_flag_declarations.aconfig
new file mode 100644
index 0000000..cb8007f
--- /dev/null
+++ b/aconfig/settings_wifi_flag_declarations.aconfig
@@ -0,0 +1,12 @@
+package: "com.android.settings.flags"
+container: "system_ext"
+
+# NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors.
+
+flag {
+ name: "enable_wifi_sharing_runtime_fragment"
+ namespace: "prism_qr"
+ description: "Use WifiFeatureProvider to get the instance of WifiDppQrCodeGeneratorFragment."
+ bug: "329012096"
+}
+
diff --git a/res/drawable/ic_do_not_disturb_on_24dp.xml b/res/drawable/ic_do_not_disturb_on_24dp.xml
deleted file mode 100644
index cace8d4..0000000
--- a/res/drawable/ic_do_not_disturb_on_24dp.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"
- android:tint="?android:attr/colorControlNormal">
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8c0,-4.41 3.59,-8 8,-8c4.41,0 8,3.59 8,8C20,16.41 16.41,20 12,20z"/>
- <path
- android:fillColor="#FFFFFFFF"
- android:pathData="M7,11h10v2h-10z"/>
-</vector>
diff --git a/res/layout-land/request_manage_credentials.xml b/res/layout-land/request_manage_credentials.xml
index fbe0bd0..f6bfa0e 100644
--- a/res/layout-land/request_manage_credentials.xml
+++ b/res/layout-land/request_manage_credentials.xml
@@ -16,6 +16,7 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
diff --git a/res/layout-sw600dp/request_manage_credentials.xml b/res/layout-sw600dp/request_manage_credentials.xml
index 42facd3..529edf1 100644
--- a/res/layout-sw600dp/request_manage_credentials.xml
+++ b/res/layout-sw600dp/request_manage_credentials.xml
@@ -17,6 +17,7 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:fitsSystemWindows="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
diff --git a/res/layout/request_manage_credentials.xml b/res/layout/request_manage_credentials.xml
index ee697f7..4f6a5c4 100644
--- a/res/layout/request_manage_credentials.xml
+++ b/res/layout/request_manage_credentials.xml
@@ -19,6 +19,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:fitsSystemWindows="true"
android:clipChildren="true">
<RelativeLayout
diff --git a/res/layout/search_bar_unified_version.xml b/res/layout/search_bar_unified_version.xml
index a8ad6fc..dbcf266 100644
--- a/res/layout/search_bar_unified_version.xml
+++ b/res/layout/search_bar_unified_version.xml
@@ -45,6 +45,6 @@
android:layout_height="wrap_content"
android:paddingStart="8dp"
android:paddingEnd="8dp"
- android:text="@string/search_settings"/>
+ android:text="@string/homepage_search"/>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
diff --git a/res/layout/settings_homepage_container_v2.xml b/res/layout/settings_homepage_container_v2.xml
index 5ae5fbd..b244579 100644
--- a/res/layout/settings_homepage_container_v2.xml
+++ b/res/layout/settings_homepage_container_v2.xml
@@ -69,8 +69,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:paddingTop="8dp"
- android:paddingBottom="24dp"
+ android:paddingVertical="8dp"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
diff --git a/res/layout/zen_mode_type_item.xml b/res/layout/zen_mode_type_item.xml
new file mode 100644
index 0000000..841ca00
--- /dev/null
+++ b/res/layout/zen_mode_type_item.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/selectableItemBackground"
+ android:gravity="center_vertical"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_gravity="center" />
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:paddingStart="16dp"
+ android:layout_weight="1">
+
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:singleLine="true"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
+ android:textSize="16sp" />
+
+ <TextView
+ android:id="@+id/subtitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignStart="@id/title"
+ android:layout_below="@id/title"
+ android:maxLines="2"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="14sp" />
+
+ </RelativeLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f92fd2a..ed9341d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -7927,6 +7927,31 @@
<!-- Zen Modes: Summary for the Do not Disturb option and associated settings page. [CHAR LIMIT=240]-->
<string name="zen_mode_settings_summary">Only get notified by important people and apps</string>
+ <!-- Zen Modes: Option to add an automatic schedule for a mode. [CHAR_LIMIT=40] -->
+ <string name="zen_mode_select_schedule">Select activation type</string>
+
+ <!-- Priority Modes: Option to choose a time-based schedule for a mode. [CHAR_LIMIT=40] -->
+ <string name="zen_mode_select_schedule_time">Time</string>
+ <!-- Priority Modes: Example text for the option to choose a time-based schedule for a mode. [CHAR_LIMIT=60] -->
+ <string name="zen_mode_select_schedule_time_example">Ex. \"9:30 – 5:00 PM\"</string>
+
+ <!-- Priority Modes: Option to choose a calendar-events-based schedule for a mode. [CHAR_LIMIT=40] -->
+ <string name="zen_mode_select_schedule_calendar">Calendar</string>
+ <!-- Priority Modes: Example text for the option to choose a calendar-events-based schedule for a mode. [CHAR_LIMIT=60] -->
+ <string name="zen_mode_select_schedule_calendar_example">Ex. \"Personal calendar\"</string>
+
+ <!-- Priority Modes: Short text that indicates that a mode is currently on (active). [CHAR_LIMIT=10] -->
+ <string name="zen_mode_active_text">ON</string>
+
+ <!-- Priority Modes: Format string for the "current state + trigger description summary for rules in the list. [CHAR_LIMIT=10] -->
+ <string name="zen_mode_format_status_and_trigger" translatable="false"><xliff:g id="current_status" example="ON">%1$s</xliff:g> • <xliff:g id="trigger_description" example="Mon-Fri, 23:00-7:00">%2$s</xliff:g></string>
+
+ <!-- Priority Modes: Call to action for a mode that is disabled and needs to be configured. [CHAR_LIMIT=40] -->
+ <string name="zen_mode_disabled_tap_to_set_up">Tap to set up</string>
+
+ <!-- Priority Modes: Indicates that a mode is disabled by the user. [CHAR_LIMIT=40] -->
+ <string name="zen_mode_disabled_by_user">Paused</string>
+
<!-- Subtitle for the Do not Disturb slice. [CHAR LIMIT=50]-->
<string name="zen_mode_slice_subtitle">Limit interruptions</string>
@@ -7942,9 +7967,15 @@
<!-- Do not disturb: Title for dialog that allows users to delete DND rules/schedules[CHAR LIMIT=40] -->
<string name="zen_mode_delete_automatic_rules">Delete schedules</string>
- <!-- Do not disturb: Delete text button presented in a dialog to confirm the user would like to delete the selected DND rules. [CHAR LIMIT=30] -->
+ <!-- Do not disturb: Delete text button presented in a dialog to confirm the user would like to delete the selected DND rules. [CHAR LIMIT=30] -->
<string name="zen_mode_schedule_delete">Delete</string>
+ <!-- Do not disturb: Menu option for deleting a mode on its configuration page [CHAR LIMIT=40] -->
+ <string name="zen_mode_menu_delete_mode">Delete mode</string>
+
+ <!-- Do not disturb: Confirmation dialog asking the user whether they would like to delete the named mode [CHAR LIMIT: 40] -->
+ <string name="zen_mode_delete_mode_confirmation">Delete \"<xliff:g id="mode" example="My Schedule">%1$s</xliff:g>\" mode?</string>
+
<!-- Do not disturb: Edit label for button that allows user to edit the dnd schedule name. [CHAR LIMIT=30] -->
<string name="zen_mode_rule_name_edit">Edit</string>
@@ -8003,7 +8034,7 @@
<string name="zen_mode_visual_signals_settings_subtitle">Allow visual signals</string>
<!-- Do not disturb: mode page section title [CHAR LIMIT=80] -->
- <string name="mode_interruption_filter_title">Notifications that can reach you</string>
+ <string name="mode_interruption_filter_title">Stay focused</string>
<!-- Do not disturb: mode page section title [CHAR LIMIT=80] -->
<string name="mode_device_effects_title">Additional actions</string>
@@ -8047,7 +8078,10 @@
other {{effect_1}, {effect_2}, and # more}
}
</string>
-
+ <!-- Modes: setting for whether the mode should filter (silence/hide) notifications/volume streams -->
+ <string name="mode_notification_filter_title">Filter interruptions</string>
+ <!-- Modes: subtext when a mode is not filtering (silence/hide) notifications/volume streams -->
+ <string name="mode_no_notification_filter">No interruptions are filtered</string>
<!-- Do not disturb: restrict notifications settings title [CHAR LIMIT=80] -->
<string name="zen_mode_restrict_notifications_title">Display options for filtered
@@ -13588,4 +13622,7 @@
<!-- url for learning more about bluetooth audio sharing -->
<string name="help_url_audio_sharing" translatable="false"></string>
+
+ <!-- Text for Search bar of Settings home screen [CHAR LIMIT=34] -->
+ <string name="homepage_search">Search Settings</string>
</resources>
diff --git a/res/xml/mobile_network_settings.xml b/res/xml/mobile_network_settings.xml
index eb9f442..51cbbe6 100644
--- a/res/xml/mobile_network_settings.xml
+++ b/res/xml/mobile_network_settings.xml
@@ -85,13 +85,9 @@
android:summary="@string/auto_data_switch_summary"
settings:controller="com.android.settings.network.telephony.AutoDataSwitchPreferenceController"/>
- <com.android.settingslib.RestrictedSwitchPreference
+ <com.android.settings.spa.preference.ComposePreference
android:key="button_roaming_key"
android:title="@string/roaming"
- android:persistent="false"
- android:summaryOn="@string/roaming_enable"
- android:summaryOff="@string/roaming_disable"
- settings:userRestriction="no_data_roaming"
settings:controller="com.android.settings.network.telephony.RoamingPreferenceController"/>
<Preference
diff --git a/res/xml/modes_rule_settings.xml b/res/xml/modes_rule_settings.xml
index cf090be..0df9f80 100644
--- a/res/xml/modes_rule_settings.xml
+++ b/res/xml/modes_rule_settings.xml
@@ -35,13 +35,18 @@
<PreferenceCategory
android:title="@string/mode_interruption_filter_title"
android:key="modes_filters">
+
+ <SwitchPreferenceCompat
+ android:key="allow_filtering"
+ android:title="@string/mode_notification_filter_title"/>
+
<Preference
android:key="zen_mode_people"
android:title="@string/zen_category_people"/>
<Preference
android:key="zen_mode_apps"
- android:title="@string/zen_category_apps" />
+ android:title="@string/zen_category_apps"/>
<Preference
android:key="zen_other_settings"
diff --git a/src/com/android/settings/ResetNetworkRequest.java b/src/com/android/settings/ResetNetworkRequest.java
index 7632ea0..8df67e7 100644
--- a/src/com/android/settings/ResetNetworkRequest.java
+++ b/src/com/android/settings/ResetNetworkRequest.java
@@ -271,12 +271,12 @@
builder.resetIms(mSubscriptionIdToResetIms);
}
// Reset phone process and RILD may impact above components, keep them at the end
- if ((mResetOptions & RESET_PHONE_PROCESS) != 0) {
- builder.restartPhoneProcess();
- }
if ((mResetOptions & RESET_RILD) != 0) {
builder.restartRild();
}
+ if ((mResetOptions & RESET_PHONE_PROCESS) != 0) {
+ builder.restartPhoneProcess();
+ }
return builder;
}
}
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 3367bf1..e3bb1a1 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -18,6 +18,8 @@
import static android.provider.Settings.ACTION_PRIVACY_SETTINGS;
+import android.annotation.FlaggedApi;
+import android.app.Flags;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.os.Bundle;
@@ -317,11 +319,13 @@
public static class PrintSettingsActivity extends SettingsActivity { /* empty */ }
public static class PrintJobSettingsActivity extends SettingsActivity { /* empty */ }
public static class ZenModeSettingsActivity extends SettingsActivity { /* empty */ }
- public static class ZenModeBehaviorSettingsActivity extends SettingsActivity { /* empty */ }
- public static class ZenModeBlockedEffectsSettingsActivity extends SettingsActivity { /* empty */ }
public static class ZenModeAutomationSettingsActivity extends SettingsActivity { /* empty */ }
public static class ZenModeScheduleRuleSettingsActivity extends SettingsActivity { /* empty */ }
public static class ZenModeEventRuleSettingsActivity extends SettingsActivity { /* empty */ }
+ @FlaggedApi(Flags.FLAG_MODES_UI)
+ public static class ModeSettingsActivity extends SettingsActivity { /* empty */ }
+ @FlaggedApi(Flags.FLAG_MODES_UI)
+ public static class ModesSettingsActivity extends SettingsActivity { /* empty */ }
public static class SoundSettingsActivity extends SettingsActivity { /* empty */ }
public static class ConfigureNotificationSettingsActivity extends SettingsActivity { /* empty */ }
public static class ConversationListSettingsActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/accessibility/AccessibilityQuickSettingsPrimarySwitchPreferenceController.java b/src/com/android/settings/accessibility/AccessibilityQuickSettingsPrimarySwitchPreferenceController.java
index e82cd96..8a3f22d 100644
--- a/src/com/android/settings/accessibility/AccessibilityQuickSettingsPrimarySwitchPreferenceController.java
+++ b/src/com/android/settings/accessibility/AccessibilityQuickSettingsPrimarySwitchPreferenceController.java
@@ -21,6 +21,7 @@
import android.os.Bundle;
import android.os.Handler;
+import androidx.annotation.Nullable;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
@@ -42,6 +43,7 @@
private boolean mNeedsQSTooltipReshow = false;
/** Returns the accessibility tile component name. */
+ @Nullable
abstract ComponentName getTileComponentName();
/** Returns the accessibility tile tooltip content. */
diff --git a/src/com/android/settings/accessibility/ReduceBrightColorsPreferenceController.java b/src/com/android/settings/accessibility/ReduceBrightColorsPreferenceController.java
index 3ca089c..e7f59f4 100644
--- a/src/com/android/settings/accessibility/ReduceBrightColorsPreferenceController.java
+++ b/src/com/android/settings/accessibility/ReduceBrightColorsPreferenceController.java
@@ -29,6 +29,7 @@
import android.provider.Settings;
import android.text.TextUtils;
+import androidx.annotation.Nullable;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
@@ -125,9 +126,14 @@
mContext.getContentResolver().unregisterContentObserver(mSettingsContentObserver);
}
+ @Nullable
@Override
protected ComponentName getTileComponentName() {
- return REDUCE_BRIGHT_COLORS_TILE_SERVICE_COMPONENT_NAME;
+ // TODO: When clean up the feature flag, change the parent class from
+ // AccessibilityQuickSettingsPrimarySwitchPreferenceController to
+ // TogglePreferenceController
+ return android.view.accessibility.Flags.a11yQsShortcut()
+ ? null : REDUCE_BRIGHT_COLORS_TILE_SERVICE_COMPONENT_NAME;
}
@Override
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioController.java b/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioController.java
index 30e86fe..4ff7136 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioController.java
@@ -19,13 +19,16 @@
import static android.media.Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
import android.app.settings.SettingsEnums;
+import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
import android.media.Spatializer;
import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
@@ -37,9 +40,14 @@
import com.android.settings.R;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.LocalBluetoothProfile;
import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.flags.Flags;
import com.android.settingslib.utils.ThreadUtils;
+import com.google.common.collect.ImmutableSet;
+
+import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -53,22 +61,27 @@
private static final String KEY_SPATIAL_AUDIO = "spatial_audio";
private static final String KEY_HEAD_TRACKING = "head_tracking";
+ private final AudioManager mAudioManager;
private final Spatializer mSpatializer;
@VisibleForTesting
PreferenceCategory mProfilesContainer;
- @VisibleForTesting
- AudioDeviceAttributes mAudioDevice = null;
+ @VisibleForTesting @Nullable AudioDeviceAttributes mAudioDevice = null;
AtomicBoolean mHasHeadTracker = new AtomicBoolean(false);
AtomicBoolean mInitialRefresh = new AtomicBoolean(true);
+ public static final Set<Integer> SA_PROFILES =
+ ImmutableSet.of(
+ BluetoothProfile.A2DP, BluetoothProfile.LE_AUDIO, BluetoothProfile.HEARING_AID);
+
public BluetoothDetailsSpatialAudioController(
Context context,
PreferenceFragmentCompat fragment,
CachedBluetoothDevice device,
Lifecycle lifecycle) {
super(context, fragment, device, lifecycle);
+ mAudioManager = context.getSystemService(AudioManager.class);
mSpatializer = FeatureFactory.getFeatureFactory().getBluetoothFeatureProvider()
.getSpatializer(context);
}
@@ -142,8 +155,12 @@
@Override
protected void refresh() {
- if (mAudioDevice == null) {
- getAvailableDevice();
+ if (Flags.enableDeterminingSpatialAudioAttributesByProfile()) {
+ getAvailableDeviceByProfileState();
+ } else {
+ if (mAudioDevice == null) {
+ getAvailableDevice();
+ }
}
ThreadUtils.postOnBackgroundThread(
() -> {
@@ -274,6 +291,77 @@
+ ", type : " + (mAudioDevice == null ? "no type" : mAudioDevice.getType()));
}
+ private void getAvailableDeviceByProfileState() {
+ Log.i(
+ TAG,
+ "getAvailableDevice() mCachedDevice: "
+ + mCachedDevice
+ + " profiles: "
+ + mCachedDevice.getProfiles());
+
+ AudioDeviceAttributes saDevice = null;
+ for (LocalBluetoothProfile profile : mCachedDevice.getProfiles()) {
+ // pick first enabled profile that is compatible with spatial audio
+ if (SA_PROFILES.contains(profile.getProfileId())
+ && profile.isEnabled(mCachedDevice.getDevice())) {
+ switch (profile.getProfileId()) {
+ case BluetoothProfile.A2DP:
+ saDevice =
+ new AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
+ mCachedDevice.getAddress());
+ break;
+ case BluetoothProfile.LE_AUDIO:
+ if (mAudioManager.getBluetoothAudioDeviceCategory(
+ mCachedDevice.getAddress())
+ == AudioManager.AUDIO_DEVICE_CATEGORY_SPEAKER) {
+ saDevice =
+ new AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_BLE_SPEAKER,
+ mCachedDevice.getAddress());
+ } else {
+ saDevice =
+ new AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_BLE_HEADSET,
+ mCachedDevice.getAddress());
+ }
+
+ break;
+ case BluetoothProfile.HEARING_AID:
+ saDevice =
+ new AudioDeviceAttributes(
+ AudioDeviceAttributes.ROLE_OUTPUT,
+ AudioDeviceInfo.TYPE_HEARING_AID,
+ mCachedDevice.getAddress());
+ break;
+ default:
+ Log.i(
+ TAG,
+ "unrecognized profile for spatial audio: "
+ + profile.getProfileId());
+ break;
+ }
+ break;
+ }
+ }
+ mAudioDevice = null;
+ if (saDevice != null && mSpatializer.isAvailableForDevice(saDevice)) {
+ mAudioDevice = saDevice;
+ }
+
+ Log.d(
+ TAG,
+ "getAvailableDevice() device : "
+ + mCachedDevice.getDevice().getAnonymizedAddress()
+ + ", is available : "
+ + (mAudioDevice != null)
+ + ", type : "
+ + (mAudioDevice == null ? "no type" : mAudioDevice.getType()));
+ }
+
@VisibleForTesting
void setAvailableDevice(AudioDeviceAttributes audioDevice) {
mAudioDevice = audioDevice;
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 1c14712..11c05f3 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -162,6 +162,8 @@
import com.android.settings.notification.app.ChannelNotificationSettings;
import com.android.settings.notification.app.ConversationListSettings;
import com.android.settings.notification.history.NotificationStation;
+import com.android.settings.notification.modes.ZenModeFragment;
+import com.android.settings.notification.modes.ZenModesListFragment;
import com.android.settings.notification.zen.ZenAccessSettings;
import com.android.settings.notification.zen.ZenModeAutomationSettings;
import com.android.settings.notification.zen.ZenModeBlockedEffectsSettings;
@@ -396,6 +398,8 @@
CellularSecuritySettingsFragment.class.getName(),
AccessibilityHearingAidsFragment.class.getName(),
HearingDevicePairingFragment.class.getName(),
+ ZenModesListFragment.class.getName(),
+ ZenModeFragment.class.getName()
};
public static final String[] SETTINGS_FOR_RESTRICTED = {
diff --git a/src/com/android/settings/datausage/lib/BillingCycleRepository.kt b/src/com/android/settings/datausage/lib/BillingCycleRepository.kt
index d324c75..59c853d 100644
--- a/src/com/android/settings/datausage/lib/BillingCycleRepository.kt
+++ b/src/com/android/settings/datausage/lib/BillingCycleRepository.kt
@@ -21,7 +21,7 @@
import android.os.ServiceManager
import android.util.Log
import androidx.annotation.OpenForTesting
-import com.android.settings.network.telephony.TelephonyRepository
+import com.android.settings.network.telephony.MobileDataRepository
import com.android.settingslib.spaprivileged.framework.common.userManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
@@ -36,13 +36,13 @@
INetworkManagementService.Stub.asInterface(
ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)
),
- private val telephonyRepository: TelephonyRepository = TelephonyRepository(context),
+ private val mobileDataRepository: MobileDataRepository = MobileDataRepository(context),
) {
private val userManager = context.userManager
fun isModifiableFlow(subId: Int): Flow<Boolean> =
- telephonyRepository.isDataEnabledFlow(subId).map { isDataEnabled ->
- isDataEnabled && isBandwidthControlEnabled() && userManager.isAdminUser
+ mobileDataRepository.isMobileDataEnabledFlow(subId).map { mobileDataEnabled ->
+ mobileDataEnabled && isBandwidthControlEnabled() && userManager.isAdminUser
}.conflate().flowOn(Dispatchers.Default)
open fun isBandwidthControlEnabled(): Boolean = try {
diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogRepository.kt b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogRepository.kt
index 5ed6993..760f8b6 100644
--- a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogRepository.kt
+++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogRepository.kt
@@ -23,10 +23,10 @@
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
+import com.android.settings.network.telephony.CarrierConfigRepository
import com.android.settings.network.telephony.SimSlotRepository
import com.android.settings.network.telephony.ims.ImsMmTelRepository
import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl
-import com.android.settings.network.telephony.safeGetConfig
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
@@ -39,7 +39,9 @@
import kotlinx.coroutines.launch
@OptIn(ExperimentalCoroutinesApi::class)
-class SimStatusDialogRepository @JvmOverloads constructor(
+class SimStatusDialogRepository
+@JvmOverloads
+constructor(
private val context: Context,
private val simSlotRepository: SimSlotRepository = SimSlotRepository(context),
private val signalStrengthRepository: SignalStrengthRepository =
@@ -48,7 +50,7 @@
ImsMmTelRepositoryImpl(context, subId)
},
) {
- private val carrierConfigManager = context.getSystemService(CarrierConfigManager::class.java)!!
+ private val carrierConfigRepository = CarrierConfigRepository(context)
data class SimStatusDialogInfo(
val signalStrength: String? = null,
@@ -73,7 +75,8 @@
}
private fun simStatusDialogInfoBySlotFlow(simSlotIndex: Int): Flow<SimStatusDialogInfo> =
- simSlotRepository.subIdInSimSlotFlow(simSlotIndex)
+ simSlotRepository
+ .subIdInSimSlotFlow(simSlotIndex)
.flatMapLatest { subId ->
if (SubscriptionManager.isValidSubscriptionId(subId)) {
simStatusDialogInfoFlow(subId)
@@ -99,22 +102,16 @@
}
private fun showUpFlow(subId: Int) = flow {
- val config = carrierConfigManager.safeGetConfig(
- keys = listOf(
- CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL,
- CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL,
- ),
- subId = subId,
- )
- val visibility = SimStatusDialogVisibility(
- signalStrengthShowUp = config.getBoolean(
- CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL,
- true, // by default we show the signal strength in sim status
- ),
- imsRegisteredShowUp = config.getBoolean(
- CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL
- ),
- )
+ val visibility =
+ carrierConfigRepository.transformConfig(subId) {
+ SimStatusDialogVisibility(
+ signalStrengthShowUp =
+ getBoolean(
+ CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL),
+ imsRegisteredShowUp =
+ getBoolean(CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL),
+ )
+ }
emit(visibility)
}
}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index 0132273..e7b9a42 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -23,11 +23,13 @@
import android.util.ArrayMap;
import android.util.SparseIntArray;
+import com.android.settings.fuelgauge.batteryusage.BatteryDiffData;
import com.android.settings.fuelgauge.batteryusage.DetectRequestSourceType;
import com.android.settings.fuelgauge.batteryusage.PowerAnomalyEventList;
import com.android.settingslib.fuelgauge.Estimate;
import java.util.List;
+import java.util.Map;
import java.util.Set;
/** Feature Provider used in power usage */
@@ -157,4 +159,8 @@
/** Whether the device is under the battery defender mode */
boolean isBatteryDefend(BatteryInfo info);
+
+ /** Collect and process battery reattribute data if needed. */
+ boolean processBatteryReattributeData(
+ Context context, Map<Long, BatteryDiffData> batteryDiffDataMap);
}
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index 1675ce6..267c0a3 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -28,12 +28,14 @@
import android.util.SparseIntArray;
import com.android.internal.util.ArrayUtils;
+import com.android.settings.fuelgauge.batteryusage.BatteryDiffData;
import com.android.settings.fuelgauge.batteryusage.DetectRequestSourceType;
import com.android.settings.fuelgauge.batteryusage.PowerAnomalyEventList;
import com.android.settingslib.fuelgauge.Estimate;
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.Set;
/** Implementation of {@code PowerUsageFeatureProvider} */
@@ -245,4 +247,10 @@
public boolean isBatteryDefend(BatteryInfo info) {
return info.isBatteryDefender && !isExtraDefend();
}
+
+ @Override
+ public boolean processBatteryReattributeData(
+ Context context, Map<Long, BatteryDiffData> batteryDiffDataMap) {
+ return false;
+ }
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java
index 7ea7203..b5d5099 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffData.java
@@ -77,11 +77,13 @@
processAndSortEntries(mSystemEntries);
}
- long getStartTimestamp() {
+ /** Gets the start timestamp. */
+ public long getStartTimestamp() {
return mStartTimestamp;
}
- long getEndTimestamp() {
+ /** Gets the end timestamp. */
+ public long getEndTimestamp() {
return mEndTimestamp;
}
@@ -97,7 +99,8 @@
return mScreenOnTime;
}
- List<BatteryDiffEntry> getAppDiffEntryList() {
+ /** Gets the {@link BatteryDiffEntry} list for apps. */
+ public List<BatteryDiffEntry> getAppDiffEntryList() {
return mAppEntries;
}
@@ -296,8 +299,7 @@
* Sets total consume power, and adjusts the percentages to ensure the total round percentage
* could be 100%, and then sorts entries based on the sorting key.
*/
- @VisibleForTesting
- static void processAndSortEntries(final List<BatteryDiffEntry> batteryDiffEntries) {
+ public static void processAndSortEntries(final List<BatteryDiffEntry> batteryDiffEntries) {
if (batteryDiffEntries.isEmpty()) {
return;
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
index 0836912..7ef4615 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
@@ -128,6 +128,9 @@
final PowerUsageFeatureProvider featureProvider =
FeatureFactory.getFeatureFactory()
.getPowerUsageFeatureProvider();
+ // Collect and process battery reattribute data.
+ featureProvider.processBatteryReattributeData(
+ context, batteryDiffDataMap);
DatabaseUtils.sendBatteryUsageSlotData(
context,
ConvertUtils.convertToBatteryUsageSlotList(
diff --git a/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java b/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java
index baae109..7e759ee 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java
@@ -55,12 +55,12 @@
}
writer.println("dump BatteryUsage and AppUsage states:");
LogUtils.dumpAppOptimizationModeEventHist(context, writer);
+ LogUtils.dumpBatteryReattributeDatabaseHist(context, writer);
LogUtils.dumpBatteryUsageDatabaseHist(context, writer);
LogUtils.dumpAppUsageDatabaseHist(context, writer);
LogUtils.dumpBatteryUsageSlotDatabaseHist(context, writer);
LogUtils.dumpBatteryEventDatabaseHist(context, writer);
LogUtils.dumpBatteryStateDatabaseHist(context, writer);
- LogUtils.dumpBatteryReattributeDatabaseHist(context, writer);
}
@Override
diff --git a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryReattributeEntity.java b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryReattributeEntity.java
index 5367849..0ee2260 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryReattributeEntity.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryReattributeEntity.java
@@ -58,12 +58,16 @@
@NonNull
@Override
public String toString() {
+ final BatteryReattribute batteryReattribute =
+ ConvertUtils.decodeBatteryReattribute(reattributeData);
final StringBuilder builder = new StringBuilder()
.append("\nBatteryReattributeEntity{")
.append("\n\t" + utcToLocalTimeForLogging(timestampStart))
.append("\n\t" + utcToLocalTimeForLogging(timestampEnd))
- .append("\n\t" + ConvertUtils.decodeBatteryReattribute(reattributeData))
- .append("\n}");
- return builder.toString();
+ .append("\n\t" + batteryReattribute);
+ if (batteryReattribute != null) {
+ builder.append("\n\t" + batteryReattribute.getReattributeDataMap());
+ }
+ return builder.append("\n}").toString();
}
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDatabase.java b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDatabase.java
index 9a4f164..c3aea08 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDatabase.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/db/BatteryStateDatabase.java
@@ -33,10 +33,10 @@
BatteryUsageSlotEntity.class,
BatteryReattributeEntity.class
},
- version = 1)
+ version = 3)
public abstract class BatteryStateDatabase extends RoomDatabase {
private static final String TAG = "BatteryStateDatabase";
- private static final String DB_FILE_NAME = "battery-usage-db-v10";
+ private static final String DB_FILE_NAME = "battery-usage-db-v11";
private static BatteryStateDatabase sBatteryStateDatabase;
diff --git a/src/com/android/settings/homepage/contextualcards/conditional/DndConditionCardController.java b/src/com/android/settings/homepage/contextualcards/conditional/DndConditionCardController.java
index e69a336..6362068 100644
--- a/src/com/android/settings/homepage/contextualcards/conditional/DndConditionCardController.java
+++ b/src/com/android/settings/homepage/contextualcards/conditional/DndConditionCardController.java
@@ -105,7 +105,8 @@
+ mAppContext.getText(R.string.condition_zen_title))
.setTitleText(mAppContext.getText(R.string.condition_zen_title).toString())
.setSummaryText(getSummary())
- .setIconDrawable(mAppContext.getDrawable(R.drawable.ic_do_not_disturb_on_24dp))
+ .setIconDrawable(mAppContext.getDrawable(
+ com.android.settingslib.R.drawable.ic_do_not_disturb_on_24dp))
.setViewType(ConditionContextualCardRenderer.VIEW_TYPE_HALF_WIDTH)
.build();
}
diff --git a/src/com/android/settings/network/MobileDataEnabledFlow.kt b/src/com/android/settings/network/MobileDataEnabledFlow.kt
deleted file mode 100644
index 1f995a9..0000000
--- a/src/com/android/settings/network/MobileDataEnabledFlow.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.network
-
-import android.content.Context
-import android.provider.Settings
-import android.telephony.SubscriptionManager
-import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalChangeFlow
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.merge
-
-/**
- * Flow for mobile data enabled changed event.
- *
- * Note: This flow can only notify enabled status changes, cannot provide the latest status.
- */
-fun Context.mobileDataEnabledFlow(subId: Int, sendInitialValue: Boolean = true): Flow<Unit> {
- val flow = settingsGlobalChangeFlow(Settings.Global.MOBILE_DATA, sendInitialValue)
- return when (subId) {
- SubscriptionManager.INVALID_SUBSCRIPTION_ID -> flow
- else -> {
- val subIdFlow = settingsGlobalChangeFlow(
- name = Settings.Global.MOBILE_DATA + subId,
- sendInitialValue = false,
- )
- merge(flow, subIdFlow)
- }
- }
-}
diff --git a/src/com/android/settings/network/MobileNetworkRepository.java b/src/com/android/settings/network/MobileNetworkRepository.java
index 8ee5389..ce6f884 100644
--- a/src/com/android/settings/network/MobileNetworkRepository.java
+++ b/src/com/android/settings/network/MobileNetworkRepository.java
@@ -49,7 +49,6 @@
import com.android.settingslib.mobile.dataservice.MobileNetworkInfoEntity;
import com.android.settingslib.mobile.dataservice.SubscriptionInfoDao;
import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity;
-import com.android.settingslib.mobile.dataservice.UiccInfoDao;
import com.android.settingslib.mobile.dataservice.UiccInfoEntity;
import java.util.ArrayList;
@@ -81,12 +80,9 @@
private SubscriptionManager mSubscriptionManager;
private MobileNetworkDatabase mMobileNetworkDatabase;
private SubscriptionInfoDao mSubscriptionInfoDao;
- private UiccInfoDao mUiccInfoDao;
private MobileNetworkInfoDao mMobileNetworkInfoDao;
private List<SubscriptionInfoEntity> mAvailableSubInfoEntityList = new ArrayList<>();
private List<SubscriptionInfoEntity> mActiveSubInfoEntityList = new ArrayList<>();
- private List<UiccInfoEntity> mUiccInfoEntityList = new ArrayList<>();
- private List<MobileNetworkInfoEntity> mMobileNetworkInfoEntityList = new ArrayList<>();
private Context mContext;
private AirplaneModeObserver mAirplaneModeObserver;
private DataRoamingObserver mDataRoamingObserver;
@@ -124,7 +120,6 @@
mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_MOBILE_NETWORK_DB_CREATED);
mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
mSubscriptionInfoDao = mMobileNetworkDatabase.mSubscriptionInfoDao();
- mUiccInfoDao = mMobileNetworkDatabase.mUiccInfoDao();
mMobileNetworkInfoDao = mMobileNetworkDatabase.mMobileNetworkInfoDao();
mAirplaneModeObserver = new AirplaneModeObserver(new Handler(Looper.getMainLooper()));
mDataRoamingObserver = new DataRoamingObserver(new Handler(Looper.getMainLooper()));
@@ -338,22 +333,6 @@
lifecycleOwner, this::onAllMobileNetworkInfoChanged);
}
- public List<SubscriptionInfoEntity> getAvailableSubInfoEntityList() {
- return mAvailableSubInfoEntityList;
- }
-
- public List<SubscriptionInfoEntity> getActiveSubscriptionInfoList() {
- return mActiveSubInfoEntityList;
- }
-
- public List<UiccInfoEntity> getUiccInfoEntityList() {
- return mUiccInfoEntityList;
- }
-
- public List<MobileNetworkInfoEntity> getMobileNetworkInfoEntityList() {
- return mMobileNetworkInfoEntityList;
- }
-
public SubscriptionInfoEntity getSubInfoById(String subId) {
return mSubscriptionInfoDao.querySubInfoById(subId);
}
@@ -464,7 +443,6 @@
}
private void onAllUiccInfoChanged(List<UiccInfoEntity> uiccInfoEntityList) {
- mUiccInfoEntityList = new ArrayList<>(uiccInfoEntityList);
for (MobileNetworkCallback callback : sCallbacks) {
callback.onAllUiccInfoChanged(uiccInfoEntityList);
}
@@ -474,7 +452,6 @@
private void onAllMobileNetworkInfoChanged(
List<MobileNetworkInfoEntity> mobileNetworkInfoEntityList) {
- mMobileNetworkInfoEntityList = new ArrayList<>(mobileNetworkInfoEntityList);
for (MobileNetworkCallback callback : sCallbacks) {
callback.onAllMobileNetworkInfoChanged(mobileNetworkInfoEntityList);
}
@@ -515,8 +492,6 @@
mMobileNetworkDatabase.deleteSubInfoBySubId(subId);
mMobileNetworkDatabase.deleteUiccInfoBySubId(subId);
mMobileNetworkDatabase.deleteMobileNetworkInfoBySubId(subId);
- mUiccInfoEntityList.removeIf(info -> info.subId.equals(subId));
- mMobileNetworkInfoEntityList.removeIf(info -> info.subId.equals(subId));
int id = Integer.parseInt(subId);
removerRegisterBySubId(id);
mSubscriptionInfoMap.remove(id);
@@ -741,7 +716,6 @@
}
private class PhoneCallStateTelephonyCallback extends TelephonyCallback implements
- TelephonyCallback.CallStateListener,
TelephonyCallback.UserMobileDataStateListener {
private int mSubId;
@@ -751,13 +725,6 @@
}
@Override
- public void onCallStateChanged(int state) {
- for (MobileNetworkCallback callback : sCallbacks) {
- callback.onCallStateChanged(state);
- }
- }
-
- @Override
public void onUserMobileDataStateChanged(boolean enabled) {
Log.d(TAG, "onUserMobileDataStateChanged enabled " + enabled + " on SUB " + mSubId);
sExecutor.execute(() -> {
@@ -793,9 +760,6 @@
*/
default void onDataRoamingChanged(int subId, boolean enabled) {
}
-
- default void onCallStateChanged(int state) {
- }
}
public void dump(IndentingPrintWriter printwriter) {
@@ -803,8 +767,6 @@
printwriter.increaseIndent();
printwriter.println(" availableSubInfoEntityList= " + mAvailableSubInfoEntityList);
printwriter.println(" activeSubInfoEntityList=" + mActiveSubInfoEntityList);
- printwriter.println(" mobileNetworkInfoEntityList= " + mMobileNetworkInfoEntityList);
- printwriter.println(" uiccInfoEntityList= " + mUiccInfoEntityList);
printwriter.println(" CacheSubscriptionInfoEntityMap= " + sCacheSubscriptionInfoEntityMap);
printwriter.println(" SubscriptionInfoMap= " + mSubscriptionInfoMap);
printwriter.flush();
diff --git a/src/com/android/settings/network/ResetNetworkOperationBuilder.java b/src/com/android/settings/network/ResetNetworkOperationBuilder.java
index 6f36074..47c06d4 100644
--- a/src/com/android/settings/network/ResetNetworkOperationBuilder.java
+++ b/src/com/android/settings/network/ResetNetworkOperationBuilder.java
@@ -18,6 +18,7 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
+import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.net.ConnectivityManager;
@@ -28,11 +29,14 @@
import android.net.wifi.p2p.WifiP2pManager;
import android.os.Looper;
import android.os.RecoverySystem;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
+import androidx.annotation.Nullable;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.ResetNetworkRequest;
@@ -257,15 +261,15 @@
*/
public ResetNetworkOperationBuilder restartPhoneProcess() {
Runnable runnable = () -> {
- try {
- mContext.getContentResolver().call(
- getResetTelephonyContentProviderAuthority(),
- METHOD_RESTART_PHONE_PROCESS,
- /* arg= */ null,
- /* extras= */ null);
- Log.i(TAG, "Phone process was restarted.");
- } catch (IllegalArgumentException iae) {
- Log.w(TAG, "Fail to restart phone process: " + iae);
+ // Unstable content provider can avoid us getting killed together with phone process
+ try (ContentProviderClient client = getUnstableTelephonyContentProviderClient()) {
+ if (client != null) {
+ client.call(METHOD_RESTART_PHONE_PROCESS, /* arg= */ null, /* extra= */ null);
+ Log.i(TAG, "Phone process was restarted.");
+ }
+ } catch (RemoteException re) {
+ // It's normal to throw RE since phone process immediately dies
+ Log.i(TAG, "Phone process has been restarted: " + re);
}
};
mResetSequence.add(runnable);
@@ -279,15 +283,13 @@
*/
public ResetNetworkOperationBuilder restartRild() {
Runnable runnable = () -> {
- try {
- mContext.getContentResolver().call(
- getResetTelephonyContentProviderAuthority(),
- METHOD_RESTART_RILD,
- /* arg= */ null,
- /* extras= */ null);
- Log.i(TAG, "RILD was restarted.");
- } catch (IllegalArgumentException iae) {
- Log.w(TAG, "Fail to restart RILD: " + iae);
+ try (ContentProviderClient client = getUnstableTelephonyContentProviderClient()) {
+ if (client != null) {
+ client.call(METHOD_RESTART_RILD, /* arg= */ null, /* extra= */ null);
+ Log.i(TAG, "RILD was restarted.");
+ }
+ } catch (RemoteException re) {
+ Log.w(TAG, "Fail to restart RILD: " + re);
}
};
mResetSequence.add(runnable);
@@ -322,9 +324,18 @@
* @return the authority of the telephony content provider that support methods
* resetPhoneProcess and resetRild.
*/
- @VisibleForTesting
- String getResetTelephonyContentProviderAuthority() {
+ private String getResetTelephonyContentProviderAuthority() {
return mContext.getResources().getString(
R.string.reset_telephony_stack_content_provider_authority);
}
+
+ /**
+ * @return the unstable content provider to avoid us getting killed with phone process
+ */
+ @Nullable
+ @VisibleForTesting
+ public ContentProviderClient getUnstableTelephonyContentProviderClient() {
+ return mContext.getContentResolver().acquireUnstableContentProviderClient(
+ getResetTelephonyContentProviderAuthority());
+ }
}
diff --git a/src/com/android/settings/network/SimOnboardingService.kt b/src/com/android/settings/network/SimOnboardingService.kt
index f6c6065..ea0b5ac 100644
--- a/src/com/android/settings/network/SimOnboardingService.kt
+++ b/src/com/android/settings/network/SimOnboardingService.kt
@@ -27,9 +27,8 @@
import android.telephony.UiccSlotInfo
import android.util.Log
import com.android.settings.network.SimOnboardingActivity.Companion.CallbackType
-import com.android.settings.network.telephony.TelephonyRepository
+import com.android.settings.network.telephony.MobileDataRepository
import com.android.settings.sim.SimActivationNotifier
-import com.android.settings.spa.network.setAutomaticData
import com.android.settings.spa.network.setDefaultData
import com.android.settings.spa.network.setDefaultSms
import com.android.settings.spa.network.setDefaultVoice
@@ -366,7 +365,7 @@
wifiPickerTrackerHelper,
targetPrimarySimMobileData
)
- TelephonyRepository(context).setAutomaticData(
+ MobileDataRepository(context).setAutoDataSwitch(
targetNonDds,
targetPrimarySimAutoDataSwitch.value
)
diff --git a/src/com/android/settings/network/apn/ApnEditCarrierEnabled.kt b/src/com/android/settings/network/apn/ApnEditCarrierEnabled.kt
new file mode 100644
index 0000000..bd58da8
--- /dev/null
+++ b/src/com/android/settings/network/apn/ApnEditCarrierEnabled.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network.apn
+
+import android.provider.Telephony
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.res.booleanResource
+import androidx.compose.ui.res.stringResource
+import com.android.settings.R
+import com.android.settingslib.spa.widget.preference.SwitchPreference
+import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
+
+@Composable
+fun ApnEditCarrierEnabled(apnData: ApnData, onCarrierEnabledChanged: (Boolean) -> Unit) {
+ SwitchPreference(
+ object : SwitchPreferenceModel {
+ override val title = stringResource(R.string.carrier_enabled)
+ val allowEdit = booleanResource(R.bool.config_allow_edit_carrier_enabled)
+ override val changeable = {
+ allowEdit && apnData.isFieldEnabled(Telephony.Carriers.CARRIER_ENABLED)
+ }
+ override val checked = { apnData.carrierEnabled }
+ override val onCheckedChange = onCarrierEnabledChanged
+ }
+ )
+}
diff --git a/src/com/android/settings/network/apn/ApnEditPageProvider.kt b/src/com/android/settings/network/apn/ApnEditPageProvider.kt
index 099e2fa..5442082 100644
--- a/src/com/android/settings/network/apn/ApnEditPageProvider.kt
+++ b/src/com/android/settings/network/apn/ApnEditPageProvider.kt
@@ -235,19 +235,7 @@
enabled = apnData.isFieldEnabled(Telephony.Carriers.ROAMING_PROTOCOL),
) { apnData = apnData.copy(apnRoaming = it) }
ApnNetworkTypeCheckBox(apnData) { apnData = apnData.copy(networkType = it) }
- SwitchPreference(
- object : SwitchPreferenceModel {
- override val title = stringResource(R.string.carrier_enabled)
- override val changeable = {
- apnData.apnEnableEnabled &&
- apnData.isFieldEnabled(Telephony.Carriers.CARRIER_ENABLED)
- }
- override val checked = { apnData.apnEnable }
- override val onCheckedChange = { newChecked: Boolean ->
- apnData = apnData.copy(apnEnable = newChecked)
- }
- }
- )
+ ApnEditCarrierEnabled(apnData) { apnData = apnData.copy(carrierEnabled = it) }
}
}
}
\ No newline at end of file
diff --git a/src/com/android/settings/network/apn/ApnPreference.java b/src/com/android/settings/network/apn/ApnPreference.java
index 879fcb6..55258c1 100644
--- a/src/com/android/settings/network/apn/ApnPreference.java
+++ b/src/com/android/settings/network/apn/ApnPreference.java
@@ -85,10 +85,11 @@
final RelativeLayout textArea = (RelativeLayout) view.findViewById(R.id.text_layout);
textArea.setOnClickListener(this);
+ final View radioButtonFrame = view.itemView.requireViewById(R.id.apn_radio_button_frame);
final RadioButton rb = view.itemView.requireViewById(R.id.apn_radiobutton);
mRadioButton = rb;
if (mDefaultSelectable) {
- view.itemView.requireViewById(R.id.apn_radio_button_frame).setOnClickListener((v) -> {
+ radioButtonFrame.setOnClickListener((v) -> {
rb.performClick();
});
rb.setOnCheckedChangeListener(this);
@@ -96,9 +97,9 @@
mProtectFromCheckedChange = true;
rb.setChecked(mIsChecked);
mProtectFromCheckedChange = false;
- rb.setVisibility(View.VISIBLE);
+ radioButtonFrame.setVisibility(View.VISIBLE);
} else {
- rb.setVisibility(View.GONE);
+ radioButtonFrame.setVisibility(View.GONE);
}
}
diff --git a/src/com/android/settings/network/apn/ApnRepository.kt b/src/com/android/settings/network/apn/ApnRepository.kt
index 2d41976..8433715 100644
--- a/src/com/android/settings/network/apn/ApnRepository.kt
+++ b/src/com/android/settings/network/apn/ApnRepository.kt
@@ -90,7 +90,7 @@
apnRoaming = context.convertProtocol2Options(
cursor.getString(Telephony.Carriers.ROAMING_PROTOCOL)
),
- apnEnable = cursor.getInt(Telephony.Carriers.CARRIER_ENABLED) == 1,
+ carrierEnabled = cursor.getInt(Telephony.Carriers.CARRIER_ENABLED) == 1,
networkType = cursor.getLong(Telephony.Carriers.NETWORK_TYPE_BITMASK),
edited = cursor.getInt(Telephony.Carriers.EDITED_STATUS),
userEditable = cursor.getInt(Telephony.Carriers.USER_EDITABLE),
diff --git a/src/com/android/settings/network/apn/ApnStatus.kt b/src/com/android/settings/network/apn/ApnStatus.kt
index dc50452..6492d39 100644
--- a/src/com/android/settings/network/apn/ApnStatus.kt
+++ b/src/com/android/settings/network/apn/ApnStatus.kt
@@ -44,11 +44,10 @@
val apnType: String = "",
val apnProtocol: Int = -1,
val apnRoaming: Int = -1,
- val apnEnable: Boolean = true,
+ val carrierEnabled: Boolean = true,
val networkType: Long = 0,
val edited: Int = Telephony.Carriers.USER_EDITED,
val userEditable: Int = 1,
- val apnEnableEnabled: Boolean = true,
val newApn: Boolean = false,
val subId: Int = -1,
val validEnabled: Boolean = false,
@@ -72,7 +71,7 @@
Telephony.Carriers.NETWORK_TYPE_BITMASK to networkType,
// Copy network type into lingering network type.
Telephony.Carriers.LINGERING_NETWORK_TYPE_BITMASK to networkType,
- Telephony.Carriers.CARRIER_ENABLED to apnEnable,
+ Telephony.Carriers.CARRIER_ENABLED to carrierEnabled,
Telephony.Carriers.EDITED_STATUS to Telephony.Carriers.USER_EDITED,
)
@@ -134,10 +133,6 @@
)
}
- apnDataInit = apnDataInit.copy(
- apnEnableEnabled =
- context.resources.getBoolean(R.bool.config_allow_edit_carrier_enabled)
- )
// TODO: mIsCarrierIdApn
return disableInit(apnDataInit)
}
diff --git a/src/com/android/settings/network/telephony/CarrierConfigManagerExt.kt b/src/com/android/settings/network/telephony/CarrierConfigManagerExt.kt
index 05b4c07..5408ab0 100644
--- a/src/com/android/settings/network/telephony/CarrierConfigManagerExt.kt
+++ b/src/com/android/settings/network/telephony/CarrierConfigManagerExt.kt
@@ -24,6 +24,7 @@
/**
* Gets the configuration values of the specified config keys applied.
*/
+@Deprecated("Use CarrierConfigRepository instead")
fun CarrierConfigManager.safeGetConfig(
keys: List<String>,
subId: Int = SubscriptionManager.getDefaultSubscriptionId(),
diff --git a/src/com/android/settings/network/telephony/CarrierConfigRepository.kt b/src/com/android/settings/network/telephony/CarrierConfigRepository.kt
new file mode 100644
index 0000000..3ec529d
--- /dev/null
+++ b/src/com/android/settings/network/telephony/CarrierConfigRepository.kt
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network.telephony
+
+import android.content.Context
+import android.os.PersistableBundle
+import android.telephony.CarrierConfigManager
+import android.telephony.SubscriptionManager
+import android.util.Log
+import androidx.annotation.VisibleForTesting
+import java.util.concurrent.ConcurrentHashMap
+import kotlinx.atomicfu.atomic
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.asExecutor
+
+class CarrierConfigRepository(private val context: Context) {
+
+ private val carrierConfigManager: CarrierConfigManager? =
+ context.getSystemService(CarrierConfigManager::class.java)
+
+ private enum class KeyType {
+ BOOLEAN,
+ INT,
+ STRING
+ }
+
+ interface CarrierConfigAccessor {
+ fun getBoolean(key: String): Boolean
+
+ fun getInt(key: String): Int
+
+ fun getString(key: String): String?
+ }
+
+ private class Accessor(private val cache: ConfigCache) : CarrierConfigAccessor {
+ private val keysToRetrieve = mutableMapOf<String, KeyType>()
+
+ override fun getBoolean(key: String): Boolean {
+ check(key.endsWith("_bool")) { "Boolean key should ends with _bool" }
+ val value = cache[key]
+ return if (value == null) {
+ keysToRetrieve += key to KeyType.BOOLEAN
+ DefaultConfig.getBoolean(key)
+ } else {
+ check(value is BooleanConfigValue) { "Boolean value type wrong" }
+ value.value
+ }
+ }
+
+ override fun getInt(key: String): Int {
+ check(key.endsWith("_int")) { "Int key should ends with _int" }
+ val value = cache[key]
+ return if (value == null) {
+ keysToRetrieve += key to KeyType.INT
+ DefaultConfig.getInt(key)
+ } else {
+ check(value is IntConfigValue) { "Int value type wrong" }
+ value.value
+ }
+ }
+
+ override fun getString(key: String): String? {
+ check(key.endsWith("_string")) { "String key should ends with _string" }
+ val value = cache[key]
+ return if (value == null) {
+ keysToRetrieve += key to KeyType.STRING
+ DefaultConfig.getString(key)
+ } else {
+ check(value is StringConfigValue) { "String value type wrong" }
+ value.value
+ }
+ }
+
+ fun getKeysToRetrieve(): Map<String, KeyType> = keysToRetrieve
+ }
+
+ /**
+ * Gets the configuration values for the given [subId].
+ *
+ * Configuration values could be accessed in [block]. Note: [block] could be called multiple
+ * times, so it should be pure function without side effort.
+ */
+ fun <T> transformConfig(subId: Int, block: CarrierConfigAccessor.() -> T): T {
+ val perSubCache = getPerSubCache(subId)
+ val accessor = Accessor(perSubCache)
+ val result = accessor.block()
+ val keysToRetrieve = accessor.getKeysToRetrieve()
+ // If all keys found in the first pass, no need to collect again
+ if (keysToRetrieve.isEmpty()) return result
+
+ perSubCache.update(subId, keysToRetrieve)
+
+ return accessor.block()
+ }
+
+ /** Gets the configuration boolean for the given [subId] and [key]. */
+ fun getBoolean(subId: Int, key: String): Boolean = transformConfig(subId) { getBoolean(key) }
+
+ /** Gets the configuration int for the given [subId] and [key]. */
+ fun getInt(subId: Int, key: String): Int = transformConfig(subId) { getInt(key) }
+
+ /** Gets the configuration string for the given [subId] and [key]. */
+ fun getString(subId: Int, key: String): String? = transformConfig(subId) { getString(key) }
+
+ private fun ConfigCache.update(subId: Int, keysToRetrieve: Map<String, KeyType>) {
+ val config = safeGetConfig(subId, keysToRetrieve.keys) ?: return
+ for ((key, type) in keysToRetrieve) {
+ when (type) {
+ KeyType.BOOLEAN -> this[key] = BooleanConfigValue(config.getBoolean(key))
+ KeyType.INT -> this[key] = IntConfigValue(config.getInt(key))
+ KeyType.STRING -> this[key] = StringConfigValue(config.getString(key))
+ }
+ }
+ }
+
+ /** Gets the configuration values of the specified config keys applied. */
+ private fun safeGetConfig(subId: Int, keys: Collection<String>): PersistableBundle? {
+ if (carrierConfigManager == null || !SubscriptionManager.isValidSubscriptionId(subId)) {
+ return null
+ }
+ tryRegisterListener(context)
+ return try {
+ carrierConfigManager.getConfigForSubId(subId, *keys.toTypedArray())
+ } catch (e: Exception) {
+ Log.e(TAG, "safeGetConfig: exception", e)
+ // The CarrierConfigLoader (the service implemented the CarrierConfigManager) hasn't
+ // been initialized yet. This may occurs during very early phase of phone booting up
+ // or when Phone process has been restarted.
+ // Settings should not assume Carrier config loader (and any other system services
+ // as well) are always available. If not available, use default value instead.
+ null
+ }
+ }
+
+ companion object {
+ private const val TAG = "CarrierConfigRepository"
+
+ private val DefaultConfig = CarrierConfigManager.getDefaultConfig()
+
+ /** Cache of config values for each subscription. */
+ private val Cache = ConcurrentHashMap<Int, ConfigCache>()
+
+ private fun getPerSubCache(subId: Int) =
+ Cache.computeIfAbsent(subId) { ConcurrentHashMap() }
+
+ /** To make sure the registerCarrierConfigChangeListener is only called once. */
+ private val ListenerRegistered = atomic(false)
+
+ private fun tryRegisterListener(context: Context) {
+ if (ListenerRegistered.compareAndSet(expect = false, update = true)) {
+ val carrierConfigManager =
+ context.applicationContext.getSystemService(CarrierConfigManager::class.java)
+ if (carrierConfigManager != null) {
+ carrierConfigManager.registerCarrierConfigChangeListener()
+ } else {
+ ListenerRegistered.getAndSet(false)
+ }
+ }
+ }
+
+ private fun CarrierConfigManager.registerCarrierConfigChangeListener() {
+ val executor = Dispatchers.Default.asExecutor()
+ registerCarrierConfigChangeListener(executor) { _, subId, _, _ ->
+ Log.d(TAG, "[$subId] onCarrierConfigChanged")
+ Cache.remove(subId)
+ }
+ }
+
+ @VisibleForTesting
+ fun resetForTest() {
+ Cache.clear()
+ ListenerRegistered.getAndSet(false)
+ }
+
+ @VisibleForTesting
+ fun setBooleanForTest(subId: Int, key: String, value: Boolean) {
+ check(key.endsWith("_bool")) { "Boolean key should ends with _bool" }
+ getPerSubCache(subId)[key] = BooleanConfigValue(value)
+ }
+
+ @VisibleForTesting
+ fun setIntForTest(subId: Int, key: String, value: Int) {
+ check(key.endsWith("_int")) { "Int key should ends with _int" }
+ getPerSubCache(subId)[key] = IntConfigValue(value)
+ }
+
+ @VisibleForTesting
+ fun setStringForTest(subId: Int, key: String, value: String) {
+ check(key.endsWith("_string")) { "String key should ends with _string" }
+ getPerSubCache(subId)[key] = StringConfigValue(value)
+ }
+ }
+}
+
+private sealed interface ConfigValue
+
+private data class BooleanConfigValue(val value: Boolean) : ConfigValue
+
+private data class IntConfigValue(val value: Int) : ConfigValue
+
+private data class StringConfigValue(val value: String?) : ConfigValue
+
+private typealias ConfigCache = ConcurrentHashMap<String, ConfigValue>
diff --git a/src/com/android/settings/network/telephony/MmsMessagePreferenceController.kt b/src/com/android/settings/network/telephony/MmsMessagePreferenceController.kt
index e14d5f8..445597f 100644
--- a/src/com/android/settings/network/telephony/MmsMessagePreferenceController.kt
+++ b/src/com/android/settings/network/telephony/MmsMessagePreferenceController.kt
@@ -22,7 +22,6 @@
import android.telephony.data.ApnSetting
import androidx.lifecycle.LifecycleOwner
import androidx.preference.PreferenceScreen
-import com.android.settings.network.mobileDataEnabledFlow
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
import kotlinx.coroutines.flow.combine
@@ -71,7 +70,7 @@
override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
combine(
- mContext.mobileDataEnabledFlow(mSubId),
+ MobileDataRepository(mContext).mobileDataEnabledChangedFlow(mSubId),
mContext.subscriptionsChangedFlow(), // Capture isMobileDataPolicyEnabled() changes
) { _, _ -> }.collectLatestWithLifecycle(viewLifecycleOwner) {
preferenceScreen?.let { super.displayPreference(it) }
diff --git a/src/com/android/settings/network/telephony/MobileDataRepository.kt b/src/com/android/settings/network/telephony/MobileDataRepository.kt
new file mode 100644
index 0000000..5a0dff7
--- /dev/null
+++ b/src/com/android/settings/network/telephony/MobileDataRepository.kt
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network.telephony
+
+import android.content.Context
+import android.provider.Settings
+import android.telephony.SubscriptionManager
+import android.telephony.TelephonyManager
+import android.telephony.TelephonyManager.MobileDataPolicy
+import android.util.Log
+import com.android.settings.wifi.WifiPickerTrackerHelper
+import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalChangeFlow
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.catch
+import kotlinx.coroutines.flow.conflate
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.onEach
+
+class MobileDataRepository(
+ private val context: Context,
+ private val subscriptionsChangedFlow: Flow<Unit> = context.subscriptionsChangedFlow(),
+) {
+ fun isMobileDataPolicyEnabledFlow(subId: Int, @MobileDataPolicy policy: Int): Flow<Boolean> {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false)
+ val telephonyManager = context.telephonyManager(subId)
+ return subscriptionsChangedFlow
+ .map { telephonyManager.isMobileDataPolicyEnabled(policy) }
+ .distinctUntilChanged()
+ .conflate()
+ .onEach { Log.d(TAG, "[$subId] isMobileDataPolicyEnabled($policy): $it") }
+ .flowOn(Dispatchers.Default)
+ }
+
+ fun setMobileDataPolicyEnabled(subId: Int, @MobileDataPolicy policy: Int, enabled: Boolean) {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) return
+ Log.d(TAG, "[$subId] setMobileDataPolicyEnabled($policy): $enabled")
+ context.telephonyManager(subId).setMobileDataPolicyEnabled(policy, enabled)
+ }
+
+ fun setAutoDataSwitch(subId: Int, newEnabled: Boolean) {
+ setMobileDataPolicyEnabled(
+ subId = subId,
+ policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
+ enabled = newEnabled,
+ )
+ }
+
+ /**
+ * Flow for mobile data enabled changed event.
+ *
+ * Note: This flow can only notify enabled status changes, cannot provide the latest status.
+ */
+ fun mobileDataEnabledChangedFlow(subId: Int, sendInitialValue: Boolean = true): Flow<Unit> =
+ mobileSettingsGlobalChangedFlow(Settings.Global.MOBILE_DATA, subId, sendInitialValue)
+
+ private fun mobileSettingsGlobalChangedFlow(
+ name: String,
+ subId: Int,
+ sendInitialValue: Boolean = true,
+ ): Flow<Unit> {
+ val flow = context.settingsGlobalChangeFlow(name, sendInitialValue)
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) return flow
+ val subIdFlow =
+ context.settingsGlobalChangeFlow(name = name + subId, sendInitialValue = false)
+ return merge(flow, subIdFlow)
+ }
+
+ fun isMobileDataEnabledFlow(subId: Int): Flow<Boolean> {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false)
+ val telephonyManager = context.telephonyManager(subId)
+ return mobileDataEnabledChangedFlow(subId)
+ .map {
+ telephonyManager.isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
+ }
+ .catch { e ->
+ Log.w(TAG, "[$subId] isMobileDataEnabledFlow: exception", e)
+ emit(false)
+ }
+ .distinctUntilChanged()
+ .conflate()
+ .onEach { Log.d(TAG, "[$subId] isMobileDataEnabledFlow: $it") }
+ .flowOn(Dispatchers.Default)
+ }
+
+ fun setMobileDataEnabled(
+ subId: Int,
+ enabled: Boolean,
+ wifiPickerTrackerHelper: WifiPickerTrackerHelper? = null,
+ ) {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) return
+
+ Log.d(TAG, "setMobileDataEnabled: $enabled")
+ MobileNetworkUtils.setMobileDataEnabled(
+ context, subId, enabled, /* disableOtherSubscriptions= */ true)
+
+ if (wifiPickerTrackerHelper != null &&
+ !wifiPickerTrackerHelper.isCarrierNetworkProvisionEnabled(subId)) {
+ wifiPickerTrackerHelper.setCarrierNetworkEnabled(enabled)
+ }
+ }
+
+ /** Creates an instance of a cold Flow for whether data roaming is enabled of given [subId]. */
+ fun isDataRoamingEnabledFlow(subId: Int): Flow<Boolean> {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false)
+ val telephonyManager = context.telephonyManager(subId)
+ return mobileSettingsGlobalChangedFlow(Settings.Global.DATA_ROAMING, subId)
+ .map { telephonyManager.isDataRoamingEnabled }
+ .distinctUntilChanged()
+ .conflate()
+ .onEach { Log.d(TAG, "[$subId] isDataRoamingEnabledFlow: $it") }
+ .flowOn(Dispatchers.Default)
+ }
+
+ private companion object {
+ private const val TAG = "MobileDataRepository"
+ }
+}
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
index 8b927a9..d70ef25 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
@@ -20,11 +20,14 @@
import android.app.Activity;
import android.app.settings.SettingsEnums;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.os.Bundle;
import android.os.UserManager;
import android.provider.Settings;
+import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -79,7 +82,6 @@
@VisibleForTesting
static final String KEY_CLICKED_PREF = "key_clicked_pref";
- private static final String KEY_ROAMING_PREF = "button_roaming_key";
private static final String KEY_CALLS_PREF = "calls_preference";
private static final String KEY_SMS_PREF = "sms_preference";
private static final String KEY_MOBILE_DATA_PREF = "mobile_data_enable";
@@ -107,6 +109,15 @@
private SubscriptionInfoEntity mSubscriptionInfoEntity;
private MobileNetworkInfoEntity mMobileNetworkInfoEntity;
+ private BroadcastReceiver mBrocastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
+ redrawPreferenceControllers();
+ }
+ }
+ };
+
public MobileNetworkSettings() {
super(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
}
@@ -178,8 +189,6 @@
return Arrays.asList(
new DataUsageSummaryPreferenceController(context, mSubId),
- new RoamingPreferenceController(context, KEY_ROAMING_PREF, getSettingsLifecycle(),
- this, mSubId),
new CallsDefaultSubscriptionController(context, KEY_CALLS_PREF,
getSettingsLifecycle(), this),
new SmsDefaultSubscriptionController(context, KEY_SMS_PREF, getSettingsLifecycle(),
@@ -263,8 +272,7 @@
final RoamingPreferenceController roamingPreferenceController =
use(RoamingPreferenceController.class);
if (roamingPreferenceController != null) {
- roamingPreferenceController.init(getFragmentManager(), mSubId,
- mMobileNetworkInfoEntity);
+ roamingPreferenceController.init(getParentFragmentManager(), mSubId);
}
final SatelliteSettingPreferenceController satelliteSettingPreferenceController = use(
SatelliteSettingPreferenceController.class);
@@ -355,6 +363,10 @@
mMobileNetworkRepository.updateEntity();
// TODO: remove log after fixing b/182326102
Log.d(LOG_TAG, "onResume() subId=" + mSubId);
+
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+ getContext().registerReceiver(mBrocastReceiver, intentFilter, Context.RECEIVER_EXPORTED);
}
private void onSubscriptionDetailChanged() {
@@ -374,6 +386,7 @@
@Override
public void onPause() {
mMobileNetworkRepository.removeRegister(this);
+ getContext().unregisterReceiver(mBrocastReceiver);
super.onPause();
}
diff --git a/src/com/android/settings/network/telephony/RoamingPreferenceController.java b/src/com/android/settings/network/telephony/RoamingPreferenceController.java
deleted file mode 100644
index bf02308..0000000
--- a/src/com/android/settings/network/telephony/RoamingPreferenceController.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.network.telephony;
-
-import static androidx.lifecycle.Lifecycle.Event.ON_START;
-import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
-
-import android.content.Context;
-import android.os.PersistableBundle;
-import android.telephony.CarrierConfigManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.fragment.app.FragmentManager;
-import androidx.lifecycle.LifecycleObserver;
-import androidx.lifecycle.LifecycleOwner;
-import androidx.lifecycle.OnLifecycleEvent;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.network.MobileNetworkRepository;
-import com.android.settingslib.RestrictedSwitchPreference;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.mobile.dataservice.MobileNetworkInfoEntity;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Preference controller for "Roaming"
- */
-public class RoamingPreferenceController extends TelephonyTogglePreferenceController implements
- LifecycleObserver, MobileNetworkRepository.MobileNetworkCallback {
- private static final String TAG = "RoamingController";
- private static final String DIALOG_TAG = "MobileDataDialog";
-
- private RestrictedSwitchPreference mSwitchPreference;
- private TelephonyManager mTelephonyManager;
- private CarrierConfigManager mCarrierConfigManager;
- protected MobileNetworkRepository mMobileNetworkRepository;
- protected LifecycleOwner mLifecycleOwner;
- private List<MobileNetworkInfoEntity> mMobileNetworkInfoEntityList = new ArrayList<>();
-
- @VisibleForTesting
- FragmentManager mFragmentManager;
- MobileNetworkInfoEntity mMobileNetworkInfoEntity;
-
- public RoamingPreferenceController(Context context, String key, Lifecycle lifecycle,
- LifecycleOwner lifecycleOwner, int subId) {
- this(context, key);
- mSubId = subId;
- mLifecycleOwner = lifecycleOwner;
- if (lifecycle != null) {
- lifecycle.addObserver(this);
- }
- }
-
- public RoamingPreferenceController(Context context, String key) {
- super(context, key);
- mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
- mMobileNetworkRepository = MobileNetworkRepository.getInstance(context);
- }
-
- @Override
- public int getAvailabilityStatus() {
- final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(mSubId);
- if (carrierConfig != null && carrierConfig.getBoolean(
- CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL)) {
- return CONDITIONALLY_UNAVAILABLE;
- }
- return AVAILABLE;
- }
-
- @OnLifecycleEvent(ON_START)
- public void onStart() {
- mMobileNetworkRepository.addRegister(mLifecycleOwner, this, mSubId);
- mMobileNetworkRepository.updateEntity();
- }
-
- @OnLifecycleEvent(ON_STOP)
- public void onStop() {
- mMobileNetworkRepository.removeRegister(this);
- }
-
- @Override
- public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
- mSwitchPreference = screen.findPreference(getPreferenceKey());
- }
-
- @Override
- public int getAvailabilityStatus(int subId) {
- return mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID
- ? AVAILABLE
- : AVAILABLE_UNSEARCHABLE;
- }
-
- @Override
- public boolean setChecked(boolean isChecked) {
- if (isDialogNeeded()) {
- showDialog();
- } else {
- // Update data directly if we don't need dialog
- mTelephonyManager.setDataRoamingEnabled(isChecked);
- return true;
- }
-
- return false;
- }
-
- @Override
- public void updateState(Preference preference) {
- super.updateState(preference);
- mSwitchPreference = (RestrictedSwitchPreference) preference;
- update();
- }
-
- private void update() {
- if (mSwitchPreference == null) {
- return;
- }
- if (!mSwitchPreference.isDisabledByAdmin()) {
- mSwitchPreference.setEnabled(mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID);
- mSwitchPreference.setChecked(isChecked());
- }
- }
-
- @VisibleForTesting
- boolean isDialogNeeded() {
- final boolean isRoamingEnabled = mMobileNetworkInfoEntity == null ? false
- : mMobileNetworkInfoEntity.isDataRoamingEnabled;
- final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(
- mSubId);
- // Need dialog if we need to turn on roaming and the roaming charge indication is allowed
- if (!isRoamingEnabled && (carrierConfig == null || !carrierConfig.getBoolean(
- CarrierConfigManager.KEY_DISABLE_CHARGE_INDICATION_BOOL))) {
- return true;
- }
- return false;
- }
-
- @Override
- public boolean isChecked() {
- return mMobileNetworkInfoEntity == null ? false
- : mMobileNetworkInfoEntity.isDataRoamingEnabled;
- }
-
- public void init(FragmentManager fragmentManager, int subId, MobileNetworkInfoEntity entity) {
- mFragmentManager = fragmentManager;
- mSubId = subId;
- mMobileNetworkInfoEntity = entity;
- mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
- if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- return;
- }
- final TelephonyManager telephonyManager = mTelephonyManager
- .createForSubscriptionId(mSubId);
- if (telephonyManager == null) {
- Log.w(TAG, "fail to init in sub" + mSubId);
- mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- return;
- }
- mTelephonyManager = telephonyManager;
- }
-
- private void showDialog() {
- final RoamingDialogFragment dialogFragment = RoamingDialogFragment.newInstance(mSubId);
-
- dialogFragment.show(mFragmentManager, DIALOG_TAG);
- }
-
- @VisibleForTesting
- public void setMobileNetworkInfoEntity(MobileNetworkInfoEntity mobileNetworkInfoEntity) {
- mMobileNetworkInfoEntity = mobileNetworkInfoEntity;
- }
-
- @Override
- public void onAllMobileNetworkInfoChanged(
- List<MobileNetworkInfoEntity> mobileNetworkInfoEntityList) {
- mMobileNetworkInfoEntityList = mobileNetworkInfoEntityList;
- mMobileNetworkInfoEntityList.forEach(entity -> {
- if (Integer.parseInt(entity.subId) == mSubId) {
- mMobileNetworkInfoEntity = entity;
- update();
- refreshSummary(mSwitchPreference);
- return;
- }
- });
- }
-
- @Override
- public void onDataRoamingChanged(int subId, boolean enabled) {
- if (subId != mSubId) {
- Log.d(TAG, "onDataRoamingChanged - wrong subId : " + subId + " / " + enabled);
- return;
- }
- update();
- }
-}
diff --git a/src/com/android/settings/network/telephony/RoamingPreferenceController.kt b/src/com/android/settings/network/telephony/RoamingPreferenceController.kt
new file mode 100644
index 0000000..2529d41
--- /dev/null
+++ b/src/com/android/settings/network/telephony/RoamingPreferenceController.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network.telephony
+
+import android.content.Context
+import android.os.UserManager
+import android.telephony.CarrierConfigManager
+import android.telephony.SubscriptionManager
+import android.telephony.TelephonyManager
+import androidx.annotation.VisibleForTesting
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.ui.res.stringResource
+import androidx.fragment.app.FragmentManager
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.settings.R
+import com.android.settings.spa.preference.ComposePreferenceController
+import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
+import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
+import com.android.settingslib.spaprivileged.template.preference.RestrictedSwitchPreference
+
+/** Preference controller for "Roaming" */
+class RoamingPreferenceController
+@JvmOverloads
+constructor(
+ context: Context,
+ key: String,
+ private val mobileDataRepository: MobileDataRepository = MobileDataRepository(context),
+) : ComposePreferenceController(context, key) {
+ @VisibleForTesting var fragmentManager: FragmentManager? = null
+ private var subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID
+
+ private var telephonyManager = context.getSystemService(TelephonyManager::class.java)!!
+ private val carrierConfigRepository = CarrierConfigRepository(context)
+
+ fun init(fragmentManager: FragmentManager, subId: Int) {
+ this.fragmentManager = fragmentManager
+ this.subId = subId
+ telephonyManager = telephonyManager.createForSubscriptionId(subId)
+ }
+
+ override fun getAvailabilityStatus(): Int {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) return CONDITIONALLY_UNAVAILABLE
+ val isForceHomeNetwork =
+ carrierConfigRepository.getBoolean(
+ subId, CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL)
+
+ return if (isForceHomeNetwork) CONDITIONALLY_UNAVAILABLE else AVAILABLE
+ }
+
+ @Composable
+ override fun Content() {
+ val summary = stringResource(R.string.roaming_enable)
+ val isDataRoamingEnabled by
+ remember { mobileDataRepository.isDataRoamingEnabledFlow(subId) }
+ .collectAsStateWithLifecycle(null)
+ RestrictedSwitchPreference(
+ model =
+ object : SwitchPreferenceModel {
+ override val title = stringResource(R.string.roaming)
+ override val summary = { summary }
+ override val checked = { isDataRoamingEnabled }
+ override val onCheckedChange: (Boolean) -> Unit = { newChecked ->
+ if (newChecked && isDialogNeeded()) {
+ showDialog()
+ } else {
+ // Update data directly if we don't need dialog
+ telephonyManager.isDataRoamingEnabled = newChecked
+ }
+ }
+ },
+ restrictions = Restrictions(keys = listOf(UserManager.DISALLOW_DATA_ROAMING)),
+ )
+ }
+
+ @VisibleForTesting
+ fun isDialogNeeded(): Boolean {
+ // Need dialog if we need to turn on roaming and the roaming charge indication is allowed
+ return !carrierConfigRepository.getBoolean(
+ subId, CarrierConfigManager.KEY_DISABLE_CHARGE_INDICATION_BOOL)
+ }
+
+ private fun showDialog() {
+ fragmentManager?.let { RoamingDialogFragment.newInstance(subId).show(it, DIALOG_TAG) }
+ }
+
+ companion object {
+ private const val DIALOG_TAG = "MobileDataDialog"
+ }
+}
diff --git a/src/com/android/settings/network/telephony/TelephonyRepository.kt b/src/com/android/settings/network/telephony/TelephonyRepository.kt
index 7c334ee..3317c71 100644
--- a/src/com/android/settings/network/telephony/TelephonyRepository.kt
+++ b/src/com/android/settings/network/telephony/TelephonyRepository.kt
@@ -17,98 +17,16 @@
package com.android.settings.network.telephony
import android.content.Context
-import android.telephony.SubscriptionManager
import android.telephony.TelephonyCallback
import android.telephony.TelephonyManager
-import android.util.Log
-import com.android.settings.network.mobileDataEnabledFlow
-import com.android.settings.wifi.WifiPickerTrackerHelper
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.channels.ProducerScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
-import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.conflate
-import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOn
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.onEach
-
-class TelephonyRepository(
- private val context: Context,
- private val subscriptionsChangedFlow: Flow<Unit> = context.subscriptionsChangedFlow(),
-) {
- fun isMobileDataPolicyEnabledFlow(
- subId: Int,
- @TelephonyManager.MobileDataPolicy policy: Int,
- ): Flow<Boolean> {
- if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false)
-
- val telephonyManager = context.telephonyManager(subId)
-
- return subscriptionsChangedFlow.map {
- telephonyManager.isMobileDataPolicyEnabled(policy)
- .also { Log.d(TAG, "[$subId] isMobileDataPolicyEnabled($policy): $it") }
- }.conflate().flowOn(Dispatchers.Default)
- }
-
- fun setMobileDataPolicyEnabled(
- subId: Int,
- @TelephonyManager.MobileDataPolicy policy: Int,
- enabled: Boolean,
- ) {
- if (!SubscriptionManager.isValidSubscriptionId(subId)) return
-
- val telephonyManager = context.telephonyManager(subId)
- Log.d(TAG, "[$subId] setMobileDataPolicyEnabled($policy): $enabled")
- telephonyManager.setMobileDataPolicyEnabled(policy, enabled)
- }
-
- fun isDataEnabledFlow(subId: Int): Flow<Boolean> {
- if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false)
-
- return context.mobileDataEnabledFlow(subId)
- .map {
- val telephonyManager = context.telephonyManager(subId)
- telephonyManager.isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
- }
- .catch {
- Log.w(TAG, "[$subId] isDataEnabledFlow: exception", it)
- emit(false)
- }
- .onEach { Log.d(TAG, "[$subId] isDataEnabledFlow: isDataEnabled() = $it") }
- .conflate()
- .flowOn(Dispatchers.Default)
- }
-
- fun setMobileData(
- subId: Int,
- enabled: Boolean,
- wifiPickerTrackerHelper: WifiPickerTrackerHelper? = null
- ) {
- if (!SubscriptionManager.isValidSubscriptionId(subId)) return
-
- Log.d(TAG, "setMobileData: $enabled")
- MobileNetworkUtils.setMobileDataEnabled(
- context,
- subId,
- enabled /* enabled */,
- true /* disableOtherSubscriptions */
- )
-
- if (wifiPickerTrackerHelper != null
- && !wifiPickerTrackerHelper.isCarrierNetworkProvisionEnabled(subId)
- ) {
- wifiPickerTrackerHelper.setCarrierNetworkEnabled(enabled)
- }
- }
-
- private companion object {
- private const val TAG = "TelephonyRepository"
- }
-}
/** Creates an instance of a cold Flow for Telephony callback of given [subId]. */
fun <T> Context.telephonyCallbackFlow(
diff --git a/src/com/android/settings/network/telephony/wificalling/CrossSimCallingViewModel.kt b/src/com/android/settings/network/telephony/wificalling/CrossSimCallingViewModel.kt
index 5dcac1e..fb0bd82 100644
--- a/src/com/android/settings/network/telephony/wificalling/CrossSimCallingViewModel.kt
+++ b/src/com/android/settings/network/telephony/wificalling/CrossSimCallingViewModel.kt
@@ -24,7 +24,7 @@
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
import com.android.settings.R
-import com.android.settings.network.mobileDataEnabledFlow
+import com.android.settings.network.telephony.MobileDataRepository
import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl
import com.android.settings.network.telephony.requireSubscriptionManager
import com.android.settings.network.telephony.safeGetConfig
@@ -54,6 +54,7 @@
private val scope = viewModelScope + Dispatchers.Default
private val metricsFeatureProvider = featureFactory.metricsFeatureProvider
private val updateChannel = Channel<Unit>()
+ private val mobileDataRepository = MobileDataRepository(application)
init {
val resources = application.resources
@@ -81,7 +82,7 @@
}
private fun List<Int>.anyMobileDataEnableChangedFlow() = map { subId ->
- application.mobileDataEnabledFlow(subId = subId, sendInitialValue = false)
+ mobileDataRepository.mobileDataEnabledChangedFlow(subId = subId, sendInitialValue = false)
}.merge()
private suspend fun updateCrossSimCalling(activeSubIds: List<Int>, newEnabled: Boolean) {
diff --git a/src/com/android/settings/network/telephony/wificalling/WifiCallingRepository.kt b/src/com/android/settings/network/telephony/wificalling/WifiCallingRepository.kt
index a5d4ba8..b5cdeda 100644
--- a/src/com/android/settings/network/telephony/wificalling/WifiCallingRepository.kt
+++ b/src/com/android/settings/network/telephony/wificalling/WifiCallingRepository.kt
@@ -21,14 +21,16 @@
import android.telephony.CarrierConfigManager
import android.telephony.CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL
import android.telephony.SubscriptionManager
-import android.telephony.TelephonyManager
import android.telephony.ims.ImsMmTelManager.WiFiCallingMode
import android.telephony.ims.feature.MmTelFeature
import android.telephony.ims.stub.ImsRegistrationImplBase
+import androidx.lifecycle.LifecycleOwner
import com.android.settings.network.telephony.ims.ImsMmTelRepository
import com.android.settings.network.telephony.ims.ImsMmTelRepositoryImpl
import com.android.settings.network.telephony.ims.imsFeatureProvisionedFlow
import com.android.settings.network.telephony.subscriptionsChangedFlow
+import com.android.settings.network.telephony.telephonyManager
+import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
@@ -38,13 +40,19 @@
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext
-class WifiCallingRepository(
+interface IWifiCallingRepository {
+ /** TODO: Move this to UI layer, when UI layer migrated to Kotlin. */
+ fun collectIsWifiCallingReadyFlow(lifecycleOwner: LifecycleOwner, action: (Boolean) -> Unit)
+}
+
+class WifiCallingRepository
+@JvmOverloads
+constructor(
private val context: Context,
private val subId: Int,
private val imsMmTelRepository: ImsMmTelRepository = ImsMmTelRepositoryImpl(context, subId)
-) {
- private val telephonyManager = context.getSystemService(TelephonyManager::class.java)!!
- .createForSubscriptionId(subId)
+) : IWifiCallingRepository {
+ private val telephonyManager = context.telephonyManager(subId)
private val carrierConfigManager = context.getSystemService(CarrierConfigManager::class.java)!!
@@ -59,6 +67,14 @@
.getConfigForSubId(subId, KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL)
.getBoolean(KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL)
+ /** TODO: Move this to UI layer, when UI layer migrated to Kotlin. */
+ override fun collectIsWifiCallingReadyFlow(
+ lifecycleOwner: LifecycleOwner,
+ action: (Boolean) -> Unit,
+ ) {
+ wifiCallingReadyFlow().collectLatestWithLifecycle(lifecycleOwner, action = action)
+ }
+
@OptIn(ExperimentalCoroutinesApi::class)
fun wifiCallingReadyFlow(): Flow<Boolean> {
if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false)
diff --git a/src/com/android/settings/notification/modes/AbstractZenModePreferenceController.java b/src/com/android/settings/notification/modes/AbstractZenModePreferenceController.java
index aebc4eb..9f819d1 100644
--- a/src/com/android/settings/notification/modes/AbstractZenModePreferenceController.java
+++ b/src/com/android/settings/notification/modes/AbstractZenModePreferenceController.java
@@ -26,6 +26,8 @@
import androidx.preference.Preference;
import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import com.google.common.base.Preconditions;
diff --git a/src/com/android/settings/notification/modes/IconLoader.java b/src/com/android/settings/notification/modes/IconLoader.java
deleted file mode 100644
index c590285..0000000
--- a/src/com/android/settings/notification/modes/IconLoader.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.notification.modes;
-
-import static com.google.common.util.concurrent.Futures.immediateFuture;
-
-import static java.util.Objects.requireNonNull;
-
-import android.annotation.Nullable;
-import android.app.AutomaticZenRule;
-import android.content.Context;
-import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
-import android.service.notification.SystemZenRules;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.LruCache;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
-import androidx.appcompat.content.res.AppCompatResources;
-
-import com.google.common.util.concurrent.FluentFuture;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-class IconLoader {
-
- private static final String TAG = "ZenIconLoader";
-
- private static final Drawable MISSING = new ColorDrawable();
-
- @Nullable // Until first usage
- private static IconLoader sInstance;
-
- private final LruCache<String, Drawable> mCache;
- private final ListeningExecutorService mBackgroundExecutor;
-
- static IconLoader getInstance() {
- if (sInstance == null) {
- sInstance = new IconLoader();
- }
- return sInstance;
- }
-
- private IconLoader() {
- this(Executors.newFixedThreadPool(4));
- }
-
- @VisibleForTesting
- IconLoader(ExecutorService backgroundExecutor) {
- mCache = new LruCache<>(50);
- mBackgroundExecutor =
- MoreExecutors.listeningDecorator(backgroundExecutor);
- }
-
- @NonNull
- ListenableFuture<Drawable> getIcon(Context context, @NonNull AutomaticZenRule rule) {
- if (rule.getIconResId() == 0) {
- return Futures.immediateFuture(getFallbackIcon(context, rule.getType()));
- }
-
- return FluentFuture.from(loadIcon(context, rule.getPackageName(), rule.getIconResId()))
- .transform(icon ->
- icon != null ? icon : getFallbackIcon(context, rule.getType()),
- MoreExecutors.directExecutor());
- }
-
- @NonNull
- private ListenableFuture</* @Nullable */ Drawable> loadIcon(Context context, String pkg,
- int iconResId) {
- String cacheKey = pkg + ":" + iconResId;
- synchronized (mCache) {
- Drawable cachedValue = mCache.get(cacheKey);
- if (cachedValue != null) {
- return immediateFuture(cachedValue != MISSING ? cachedValue : null);
- }
- }
-
- return FluentFuture.from(mBackgroundExecutor.submit(() -> {
- if (TextUtils.isEmpty(pkg) || SystemZenRules.PACKAGE_ANDROID.equals(pkg)) {
- return context.getDrawable(iconResId);
- } else {
- Context appContext = context.createPackageContext(pkg, 0);
- Drawable appDrawable = AppCompatResources.getDrawable(appContext, iconResId);
- return getMonochromeIconIfPresent(appDrawable);
- }
- })).catching(Exception.class, ex -> {
- // If we cannot resolve the icon, then store MISSING in the cache below, so
- // we don't try again.
- Log.e(TAG, "Error while loading icon " + cacheKey, ex);
- return null;
- }, MoreExecutors.directExecutor()).transform(drawable -> {
- synchronized (mCache) {
- mCache.put(cacheKey, drawable != null ? drawable : MISSING);
- }
- return drawable;
- }, MoreExecutors.directExecutor());
- }
-
- private static Drawable getFallbackIcon(Context context, int ruleType) {
- int iconResIdFromType = switch (ruleType) {
- case AutomaticZenRule.TYPE_UNKNOWN ->
- com.android.internal.R.drawable.ic_zen_mode_type_unknown;
- case AutomaticZenRule.TYPE_OTHER ->
- com.android.internal.R.drawable.ic_zen_mode_type_other;
- case AutomaticZenRule.TYPE_SCHEDULE_TIME ->
- com.android.internal.R.drawable.ic_zen_mode_type_schedule_time;
- case AutomaticZenRule.TYPE_SCHEDULE_CALENDAR ->
- com.android.internal.R.drawable.ic_zen_mode_type_schedule_calendar;
- case AutomaticZenRule.TYPE_BEDTIME ->
- com.android.internal.R.drawable.ic_zen_mode_type_bedtime;
- case AutomaticZenRule.TYPE_DRIVING ->
- com.android.internal.R.drawable.ic_zen_mode_type_driving;
- case AutomaticZenRule.TYPE_IMMERSIVE ->
- com.android.internal.R.drawable.ic_zen_mode_type_immersive;
- case AutomaticZenRule.TYPE_THEATER ->
- com.android.internal.R.drawable.ic_zen_mode_type_theater;
- case AutomaticZenRule.TYPE_MANAGED ->
- com.android.internal.R.drawable.ic_zen_mode_type_managed;
- default ->
- com.android.internal.R.drawable.ic_zen_mode_type_unknown;
- };
- return requireNonNull(context.getDrawable(iconResIdFromType));
- }
-
- private static Drawable getMonochromeIconIfPresent(Drawable icon) {
- // For created rules, the app should've provided a monochrome Drawable. However, implicit
- // rules have the app's icon, which is not -- but might have a monochrome layer. Thus
- // we choose it, if present.
- if (icon instanceof AdaptiveIconDrawable adaptiveIcon) {
- if (adaptiveIcon.getMonochrome() != null) {
- // Wrap with negative inset => scale icon (inspired from BaseIconFactory)
- return new InsetDrawable(adaptiveIcon.getMonochrome(),
- -2.0f * AdaptiveIconDrawable.getExtraInsetFraction());
- }
- }
- return icon;
- }
-}
diff --git a/src/com/android/settings/notification/modes/IconUtil.java b/src/com/android/settings/notification/modes/IconUtil.java
index c6ecaa0..1e653bf 100644
--- a/src/com/android/settings/notification/modes/IconUtil.java
+++ b/src/com/android/settings/notification/modes/IconUtil.java
@@ -24,6 +24,7 @@
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
+import androidx.annotation.AttrRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
@@ -32,10 +33,18 @@
class IconUtil {
- static Drawable applyTint(@NonNull Context context, @NonNull Drawable icon) {
+ static Drawable applyNormalTint(@NonNull Context context, @NonNull Drawable icon) {
+ return applyTint(context, icon, android.R.attr.colorControlNormal);
+ }
+
+ static Drawable applyAccentTint(@NonNull Context context, @NonNull Drawable icon) {
+ return applyTint(context, icon, android.R.attr.colorAccent);
+ }
+
+ private static Drawable applyTint(@NonNull Context context, @NonNull Drawable icon,
+ @AttrRes int colorAttr) {
icon = icon.mutate();
- icon.setTintList(
- Utils.getColorAttr(context, android.R.attr.colorControlNormal));
+ icon.setTintList(Utils.getColorAttr(context, colorAttr));
return icon;
}
diff --git a/src/com/android/settings/notification/modes/InterruptionFilterPreferenceController.java b/src/com/android/settings/notification/modes/InterruptionFilterPreferenceController.java
new file mode 100644
index 0000000..8bdeea4
--- /dev/null
+++ b/src/com/android/settings/notification/modes/InterruptionFilterPreferenceController.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification.modes;
+
+import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL;
+import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+import androidx.preference.Preference;
+import androidx.preference.TwoStatePreference;
+
+import com.android.settings.R;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
+
+class InterruptionFilterPreferenceController extends AbstractZenModePreferenceController
+ implements Preference.OnPreferenceChangeListener {
+
+ public InterruptionFilterPreferenceController(Context context, String key,
+ ZenModesBackend backend) {
+ super(context, key, backend);
+ }
+
+ @Override
+ public boolean isAvailable(ZenMode zenMode) {
+ return !zenMode.isManualDnd();
+ }
+
+ @Override
+ public void updateState(Preference preference, @NonNull ZenMode zenMode) {
+ boolean filteringNotifications = zenMode.getRule().getInterruptionFilter()
+ != INTERRUPTION_FILTER_ALL;
+ ((TwoStatePreference) preference).setChecked(filteringNotifications);
+ preference.setSummary(filteringNotifications ? "" :
+ mContext.getResources().getString(R.string.mode_no_notification_filter));
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ final boolean filterNotifications = ((Boolean) newValue);
+ return saveMode(zenMode -> {
+ zenMode.getRule().setInterruptionFilter(filterNotifications
+ ? INTERRUPTION_FILTER_PRIORITY
+ : INTERRUPTION_FILTER_ALL);
+ return zenMode;
+ });
+ }
+}
diff --git a/src/com/android/settings/notification/modes/ZenMode.java b/src/com/android/settings/notification/modes/ZenMode.java
deleted file mode 100644
index cbe915b..0000000
--- a/src/com/android/settings/notification/modes/ZenMode.java
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.notification.modes;
-
-import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
-
-import static java.util.Objects.requireNonNull;
-
-import android.annotation.SuppressLint;
-import android.app.AutomaticZenRule;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.service.notification.ZenDeviceEffects;
-import android.service.notification.ZenPolicy;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.settings.R;
-
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-
-import java.util.Objects;
-
-/**
- * Represents either an {@link AutomaticZenRule} or the manual DND rule in a unified way.
- *
- * <p>It also adapts other rule features that we don't want to expose in the UI, such as
- * interruption filters other than {@code PRIORITY}, rules without specific icons, etc.
- */
-class ZenMode {
-
- private static final String TAG = "ZenMode";
-
- /**
- * Additional value for the {@code @ZenPolicy.ChannelType} enumeration that indicates that all
- * channels can bypass DND when this policy is active.
- *
- * <p>This value shouldn't be used on "real" ZenPolicy objects sent to or returned from
- * {@link android.app.NotificationManager}; it's a way of representing rules with interruption
- * filter = {@link NotificationManager#INTERRUPTION_FILTER_ALL} in the UI.
- */
- public static final int CHANNEL_POLICY_ALL = -1;
-
- static final String MANUAL_DND_MODE_ID = "manual_dnd";
-
- @SuppressLint("WrongConstant")
- private static final ZenPolicy POLICY_INTERRUPTION_FILTER_ALL =
- new ZenPolicy.Builder()
- .allowChannels(CHANNEL_POLICY_ALL)
- .allowAllSounds()
- .showAllVisualEffects()
- .build();
-
- // Must match com.android.server.notification.ZenModeHelper#applyCustomPolicy.
- private static final ZenPolicy POLICY_INTERRUPTION_FILTER_ALARMS =
- new ZenPolicy.Builder()
- .disallowAllSounds()
- .allowAlarms(true)
- .allowMedia(true)
- .allowPriorityChannels(false)
- .build();
-
- // Must match com.android.server.notification.ZenModeHelper#applyCustomPolicy.
- private static final ZenPolicy POLICY_INTERRUPTION_FILTER_NONE =
- new ZenPolicy.Builder()
- .disallowAllSounds()
- .hideAllVisualEffects()
- .allowPriorityChannels(false)
- .build();
-
- private final String mId;
- private AutomaticZenRule mRule;
- private final boolean mIsActive;
- private final boolean mIsManualDnd;
-
- ZenMode(String id, AutomaticZenRule rule, boolean isActive) {
- this(id, rule, isActive, false);
- }
-
- private ZenMode(String id, AutomaticZenRule rule, boolean isActive, boolean isManualDnd) {
- mId = id;
- mRule = rule;
- mIsActive = isActive;
- mIsManualDnd = isManualDnd;
- }
-
- static ZenMode manualDndMode(AutomaticZenRule manualRule, boolean isActive) {
- return new ZenMode(MANUAL_DND_MODE_ID, manualRule, isActive, true);
- }
-
- @NonNull
- public String getId() {
- return mId;
- }
-
- @NonNull
- public AutomaticZenRule getRule() {
- return mRule;
- }
-
- @NonNull
- public ListenableFuture<Drawable> getIcon(@NonNull Context context,
- @NonNull IconLoader iconLoader) {
- if (mIsManualDnd) {
- return Futures.immediateFuture(requireNonNull(
- context.getDrawable(R.drawable.ic_do_not_disturb_on_24dp)));
- }
-
- return iconLoader.getIcon(context, mRule);
- }
-
- @NonNull
- public ZenPolicy getPolicy() {
- switch (mRule.getInterruptionFilter()) {
- case INTERRUPTION_FILTER_PRIORITY:
- return requireNonNull(mRule.getZenPolicy());
-
- case NotificationManager.INTERRUPTION_FILTER_ALL:
- return POLICY_INTERRUPTION_FILTER_ALL;
-
- case NotificationManager.INTERRUPTION_FILTER_ALARMS:
- return POLICY_INTERRUPTION_FILTER_ALARMS;
-
- case NotificationManager.INTERRUPTION_FILTER_NONE:
- return POLICY_INTERRUPTION_FILTER_NONE;
-
- case NotificationManager.INTERRUPTION_FILTER_UNKNOWN:
- default:
- Log.wtf(TAG, "Rule " + mId + " with unexpected interruptionFilter "
- + mRule.getInterruptionFilter());
- return requireNonNull(mRule.getZenPolicy());
- }
- }
-
- /**
- * Updates the {@link ZenPolicy} of the associated {@link AutomaticZenRule} based on the
- * supplied policy. In some cases this involves conversions, so that the following call
- * to {@link #getPolicy} might return a different policy from the one supplied here.
- */
- @SuppressLint("WrongConstant")
- public void setPolicy(@NonNull ZenPolicy policy) {
- ZenPolicy currentPolicy = getPolicy();
- if (currentPolicy.equals(policy)) {
- return;
- }
-
- // A policy with CHANNEL_POLICY_ALL is only a UI representation of the
- // INTERRUPTION_FILTER_ALL filter. Thus, switching to or away to this value only updates
- // the filter, discarding the rest of the supplied policy.
- if (policy.getAllowedChannels() == CHANNEL_POLICY_ALL
- && currentPolicy.getAllowedChannels() != CHANNEL_POLICY_ALL) {
- if (mIsManualDnd) {
- throw new IllegalArgumentException("Manual DND cannot have CHANNEL_POLICY_ALL");
- }
- mRule.setInterruptionFilter(INTERRUPTION_FILTER_ALL);
- // Preserve the existing policy, e.g. if the user goes PRIORITY -> ALL -> PRIORITY that
- // shouldn't discard all other policy customizations. The existing policy will be a
- // synthetic one if the rule originally had filter NONE or ALARMS_ONLY and that's fine.
- if (mRule.getZenPolicy() == null) {
- mRule.setZenPolicy(currentPolicy);
- }
- return;
- } else if (policy.getAllowedChannels() != CHANNEL_POLICY_ALL
- && currentPolicy.getAllowedChannels() == CHANNEL_POLICY_ALL) {
- mRule.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY);
- // Go back to whatever policy the rule had before, unless the rule never had one, in
- // which case we use the supplied policy (which we know has a valid allowedChannels).
- if (mRule.getZenPolicy() == null) {
- mRule.setZenPolicy(policy);
- }
- return;
- }
-
- // If policy is customized from any of the "special" ones, make the rule PRIORITY.
- if (mRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) {
- mRule.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY);
- }
- mRule.setZenPolicy(policy);
- }
-
- @NonNull
- public ZenDeviceEffects getDeviceEffects() {
- return mRule.getDeviceEffects() != null
- ? mRule.getDeviceEffects()
- : new ZenDeviceEffects.Builder().build();
- }
-
- public boolean canEditName() {
- return !isManualDnd();
- }
-
- public boolean canEditIcon() {
- return !isManualDnd();
- }
-
- public boolean canBeDeleted() {
- return !mIsManualDnd;
- }
-
- public boolean isManualDnd() {
- return mIsManualDnd;
- }
-
- public boolean isActive() {
- return mIsActive;
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- return obj instanceof ZenMode other
- && mId.equals(other.mId)
- && mRule.equals(other.mRule)
- && mIsActive == other.mIsActive;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mId, mRule, mIsActive);
- }
-
- @Override
- public String toString() {
- return mId + "(" + (mIsActive ? "active" : "inactive") + ") -> " + mRule;
- }
-}
diff --git a/src/com/android/settings/notification/modes/ZenModeActionsPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeActionsPreferenceController.java
index 8585234..914683f 100644
--- a/src/com/android/settings/notification/modes/ZenModeActionsPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeActionsPreferenceController.java
@@ -16,7 +16,7 @@
package com.android.settings.notification.modes;
-import static com.android.settings.notification.modes.ZenModeFragmentBase.MODE_ID;
+import static android.provider.Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID;
import android.content.Context;
import android.os.Bundle;
@@ -27,6 +27,8 @@
import com.android.settings.R;
import com.android.settings.core.SubSettingLauncher;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.widget.ActionButtonsPreference;
class ZenModeActionsPreferenceController extends AbstractZenModePreferenceController {
@@ -50,7 +52,7 @@
buttonsPreference.setButton2Enabled(zenMode.canEditIcon());
buttonsPreference.setButton2OnClickListener(v -> {
Bundle bundle = new Bundle();
- bundle.putString(MODE_ID, zenMode.getId());
+ bundle.putString(EXTRA_AUTOMATIC_ZEN_RULE_ID, zenMode.getId());
new SubSettingLauncher(mContext)
.setDestination(ZenModeIconPickerFragment.class.getName())
// TODO: b/332937635 - Update metrics category
diff --git a/src/com/android/settings/notification/modes/ZenModeAppsFragment.java b/src/com/android/settings/notification/modes/ZenModeAppsFragment.java
index 73329a2..19035dd 100644
--- a/src/com/android/settings/notification/modes/ZenModeAppsFragment.java
+++ b/src/com/android/settings/notification/modes/ZenModeAppsFragment.java
@@ -37,10 +37,6 @@
context, ZenModeAppsPreferenceController.KEY_PRIORITY, mBackend));
controllers.add(new ZenModeAppsPreferenceController(
context, ZenModeAppsPreferenceController.KEY_NONE, mBackend));
- // TODO: b/308819928 - The manual DND mode cannot have the ALL type;
- // unify the controllers into one and only create a preference if isManualDnd is false.
- controllers.add(new ZenModeAppsPreferenceController(
- context, ZenModeAppsPreferenceController.KEY_ALL, mBackend));
return controllers;
}
diff --git a/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceController.java
index 691c92e..f62dfdd 100644
--- a/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceController.java
@@ -16,7 +16,8 @@
package com.android.settings.notification.modes;
-import static com.android.settings.notification.modes.ZenModeFragmentBase.MODE_ID;
+import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL;
+import static android.provider.Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID;
import android.content.Context;
import android.os.Bundle;
@@ -30,6 +31,8 @@
import com.android.settings.core.SubSettingLauncher;
import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import java.util.ArrayList;
import java.util.HashMap;
@@ -45,10 +48,12 @@
private static final String TAG = "ZenModeAppsLinkPreferenceController";
private final ZenModeSummaryHelper mSummaryHelper;
+ private final ApplicationsState mApplicationsState;
private ApplicationsState.Session mAppSession;
private final ZenHelperBackend mHelperBackend;
private ZenMode mZenMode;
private Preference mPreference;
+ private final Fragment mHost;
ZenModeAppsLinkPreferenceController(Context context, String key, Fragment host,
ApplicationsState applicationsState, ZenModesBackend backend,
@@ -56,15 +61,19 @@
super(context, key, backend);
mSummaryHelper = new ZenModeSummaryHelper(mContext, helperBackend);
mHelperBackend = helperBackend;
- if (applicationsState != null && host != null) {
- mAppSession = applicationsState.newSession(mAppSessionCallbacks, host.getLifecycle());
- }
+ mApplicationsState = applicationsState;
+ mHost = host;
+ }
+
+ @Override
+ public boolean isAvailable(ZenMode zenMode) {
+ return zenMode.getRule().getInterruptionFilter() != INTERRUPTION_FILTER_ALL;
}
@Override
public void updateState(Preference preference, @NonNull ZenMode zenMode) {
Bundle bundle = new Bundle();
- bundle.putString(MODE_ID, zenMode.getId());
+ bundle.putString(EXTRA_AUTOMATIC_ZEN_RULE_ID, zenMode.getId());
// TODO(b/332937635): Update metrics category
preference.setIntent(new SubSettingLauncher(mContext)
.setDestination(ZenModeAppsFragment.class.getName())
@@ -73,6 +82,9 @@
.toIntent());
mZenMode = zenMode;
mPreference = preference;
+ if (mApplicationsState != null && mHost != null) {
+ mAppSession = mApplicationsState.newSession(mAppSessionCallbacks, mHost.getLifecycle());
+ }
triggerUpdateAppsBypassingDndSummaryText();
}
@@ -118,11 +130,13 @@
return appsBypassingDnd;
}
- @VisibleForTesting final ApplicationsState.Callbacks mAppSessionCallbacks =
+ @VisibleForTesting
+ final ApplicationsState.Callbacks mAppSessionCallbacks =
new ApplicationsState.Callbacks() {
@Override
- public void onRunningStateChanged(boolean running) { }
+ public void onRunningStateChanged(boolean running) {
+ }
@Override
public void onPackageListChanged() {
@@ -135,16 +149,20 @@
}
@Override
- public void onPackageIconChanged() { }
+ public void onPackageIconChanged() {
+ }
@Override
- public void onPackageSizeChanged(String packageName) { }
+ public void onPackageSizeChanged(String packageName) {
+ }
@Override
- public void onAllSizesComputed() { }
+ public void onAllSizesComputed() {
+ }
@Override
- public void onLauncherInfoChanged() { }
+ public void onLauncherInfoChanged() {
+ }
@Override
public void onLoadEntriesCompleted() {
diff --git a/src/com/android/settings/notification/modes/ZenModeAppsPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeAppsPreferenceController.java
index 704bce0..1d807ed 100644
--- a/src/com/android/settings/notification/modes/ZenModeAppsPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeAppsPreferenceController.java
@@ -16,7 +16,7 @@
package com.android.settings.notification.modes;
-import static com.android.settings.notification.modes.ZenModeFragmentBase.MODE_ID;
+import static android.provider.Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID;
import android.app.settings.SettingsEnums;
import android.content.Context;
@@ -31,6 +31,8 @@
import androidx.preference.TwoStatePreference;
import com.android.settings.core.SubSettingLauncher;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.widget.SelectorWithWidgetPreference;
public class ZenModeAppsPreferenceController extends
@@ -38,11 +40,9 @@
static final String KEY_PRIORITY = "zen_mode_apps_priority";
static final String KEY_NONE = "zen_mode_apps_none";
- static final String KEY_ALL = "zen_mode_apps_all";
String mModeId;
-
public ZenModeAppsPreferenceController(@NonNull Context context,
@NonNull String key, @Nullable ZenModesBackend backend) {
super(context, key, backend);
@@ -79,13 +79,6 @@
== ZenPolicy.CHANNEL_POLICY_NONE;
pref.setChecked(policy_none);
break;
- case KEY_ALL:
- // A UI-only setting; the underlying policy never actually has this value,
- // but ZenMode acts as though it does for the sake of UI consistency.
- boolean policy_all = zenMode.getPolicy().getAllowedChannels()
- == ZenMode.CHANNEL_POLICY_ALL;
- pref.setChecked(policy_all);
- break;
}
}
@@ -96,8 +89,6 @@
return savePolicy(p -> p.allowChannels(ZenPolicy.CHANNEL_POLICY_PRIORITY));
case KEY_NONE:
return savePolicy(p -> p.allowChannels(ZenPolicy.CHANNEL_POLICY_NONE));
- case KEY_ALL:
- return savePolicy(p -> p.allowChannels(ZenMode.CHANNEL_POLICY_ALL));
}
return true;
}
@@ -114,7 +105,7 @@
private void launchPrioritySettings() {
Bundle bundle = new Bundle();
if (mModeId != null) {
- bundle.putString(MODE_ID, mModeId);
+ bundle.putString(EXTRA_AUTOMATIC_ZEN_RULE_ID, mModeId);
}
// TODO(b/332937635): Update metrics category
new SubSettingLauncher(mContext)
diff --git a/src/com/android/settings/notification/modes/ZenModeButtonPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeButtonPreferenceController.java
index 1846dfc..4a99b33 100644
--- a/src/com/android/settings/notification/modes/ZenModeButtonPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeButtonPreferenceController.java
@@ -23,9 +23,11 @@
import androidx.preference.Preference;
import com.android.settings.R;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.widget.LayoutPreference;
-public class ZenModeButtonPreferenceController extends AbstractZenModePreferenceController {
+class ZenModeButtonPreferenceController extends AbstractZenModePreferenceController {
private Button mZenButton;
diff --git a/src/com/android/settings/notification/modes/ZenModeCallsLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeCallsLinkPreferenceController.java
index 8d27d4c..e5c1e48 100644
--- a/src/com/android/settings/notification/modes/ZenModeCallsLinkPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeCallsLinkPreferenceController.java
@@ -16,7 +16,7 @@
package com.android.settings.notification.modes;
-import static com.android.settings.notification.modes.ZenModeFragmentBase.MODE_ID;
+import static android.provider.Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID;
import android.content.Context;
import android.os.Bundle;
@@ -25,6 +25,8 @@
import androidx.preference.Preference;
import com.android.settings.core.SubSettingLauncher;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
class ZenModeCallsLinkPreferenceController extends AbstractZenModePreferenceController {
@@ -39,7 +41,7 @@
@Override
public void updateState(Preference preference, @NonNull ZenMode zenMode) {
Bundle bundle = new Bundle();
- bundle.putString(MODE_ID, zenMode.getId());
+ bundle.putString(EXTRA_AUTOMATIC_ZEN_RULE_ID, zenMode.getId());
// TODO(b/332937635): Update metrics category
preference.setIntent(new SubSettingLauncher(mContext)
.setDestination(ZenModeCallsFragment.class.getName())
diff --git a/src/com/android/settings/notification/modes/ZenModeDisplayEffectPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeDisplayEffectPreferenceController.java
index bca7b55..b0d3952 100644
--- a/src/com/android/settings/notification/modes/ZenModeDisplayEffectPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeDisplayEffectPreferenceController.java
@@ -23,7 +23,10 @@
import androidx.preference.Preference;
import androidx.preference.TwoStatePreference;
-public class ZenModeDisplayEffectPreferenceController extends AbstractZenModePreferenceController
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
+
+class ZenModeDisplayEffectPreferenceController extends AbstractZenModePreferenceController
implements Preference.OnPreferenceChangeListener {
public ZenModeDisplayEffectPreferenceController(Context context, String key,
@@ -34,24 +37,20 @@
@Override
public void updateState(Preference preference, @NonNull ZenMode zenMode) {
TwoStatePreference pref = (TwoStatePreference) preference;
- ZenDeviceEffects effects = zenMode.getRule().getDeviceEffects();
- if (effects == null) {
- pref.setChecked(false);
- } else {
- switch (getPreferenceKey()) {
- case "effect_greyscale":
- pref.setChecked(effects.shouldDisplayGrayscale());
- break;
- case "effect_aod":
- pref.setChecked(effects.shouldSuppressAmbientDisplay());
- break;
- case "effect_wallpaper":
- pref.setChecked(effects.shouldDimWallpaper());
- break;
- case "effect_dark_theme":
- pref.setChecked(effects.shouldUseNightMode());
- break;
- }
+ ZenDeviceEffects effects = zenMode.getDeviceEffects();
+ switch (getPreferenceKey()) {
+ case "effect_greyscale":
+ pref.setChecked(effects.shouldDisplayGrayscale());
+ break;
+ case "effect_aod":
+ pref.setChecked(effects.shouldSuppressAmbientDisplay());
+ break;
+ case "effect_wallpaper":
+ pref.setChecked(effects.shouldDimWallpaper());
+ break;
+ case "effect_dark_theme":
+ pref.setChecked(effects.shouldUseNightMode());
+ break;
}
}
diff --git a/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceController.java
index 712c78a..d3559f1 100644
--- a/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceController.java
@@ -16,7 +16,7 @@
package com.android.settings.notification.modes;
-import static com.android.settings.notification.modes.ZenModeFragmentBase.MODE_ID;
+import static android.provider.Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID;
import android.content.Context;
import android.os.Bundle;
@@ -25,6 +25,8 @@
import androidx.preference.Preference;
import com.android.settings.core.SubSettingLauncher;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
class ZenModeDisplayLinkPreferenceController extends AbstractZenModePreferenceController {
@@ -39,7 +41,7 @@
@Override
void updateState(Preference preference, @NonNull ZenMode zenMode) {
Bundle bundle = new Bundle();
- bundle.putString(MODE_ID, zenMode.getId());
+ bundle.putString(EXTRA_AUTOMATIC_ZEN_RULE_ID, zenMode.getId());
// TODO(b/332937635): Update metrics category
preference.setIntent(new SubSettingLauncher(mContext)
.setDestination(ZenModeDisplayFragment.class.getName())
diff --git a/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceController.java
index 8517af1..326bc97 100644
--- a/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceController.java
@@ -23,6 +23,9 @@
import androidx.preference.Preference;
import androidx.preference.TwoStatePreference;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
+
/**
* Preference controller controlling whether a time schedule-based mode ends at the next alarm.
*/
diff --git a/src/com/android/settings/notification/modes/ZenModeFragment.java b/src/com/android/settings/notification/modes/ZenModeFragment.java
index 6bda5e1..5897c4d 100644
--- a/src/com/android/settings/notification/modes/ZenModeFragment.java
+++ b/src/com/android/settings/notification/modes/ZenModeFragment.java
@@ -16,20 +16,28 @@
package com.android.settings.notification.modes;
+import android.app.AlertDialog;
import android.app.Application;
import android.app.AutomaticZenRule;
import android.app.settings.SettingsEnums;
import android.content.Context;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
import com.android.settings.R;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.notification.modes.ZenMode;
import java.util.ArrayList;
import java.util.List;
public class ZenModeFragment extends ZenModeFragmentBase {
+ // for mode deletion menu
+ private static final int DELETE_MODE = 1;
+
@Override
protected int getPreferenceScreenResId() {
return R.xml.modes_rule_settings;
@@ -52,7 +60,9 @@
prefControllers.add(new ZenModeDisplayLinkPreferenceController(
context, "mode_display_settings", mBackend, mHelperBackend));
prefControllers.add(new ZenModeSetTriggerLinkPreferenceController(context,
- "zen_automatic_trigger_category", mBackend));
+ "zen_automatic_trigger_category", this, mBackend));
+ prefControllers.add(new InterruptionFilterPreferenceController(
+ context, "allow_filtering", mBackend));
return prefControllers;
}
@@ -74,4 +84,43 @@
// TODO: b/332937635 - make this the correct metrics category
return SettingsEnums.NOTIFICATION_ZEN_MODE_AUTOMATION;
}
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ menu.add(Menu.NONE, DELETE_MODE, Menu.NONE, R.string.zen_mode_menu_delete_mode);
+ super.onCreateOptionsMenu(menu, inflater);
+ }
+
+ @Override
+ protected boolean onOptionsItemSelected(MenuItem item, ZenMode zenMode) {
+ switch (item.getItemId()) {
+ case DELETE_MODE:
+ new AlertDialog.Builder(mContext)
+ .setTitle(mContext.getString(R.string.zen_mode_delete_mode_confirmation,
+ zenMode.getRule().getName()))
+ .setPositiveButton(R.string.zen_mode_schedule_delete,
+ (dialog, which) -> {
+ // start finishing before calling removeMode() so that we don't
+ // try to update this activity with a nonexistent mode when the
+ // zen mode config is updated
+ finish();
+ mBackend.removeMode(zenMode);
+ })
+ .setNegativeButton(R.string.cancel, null)
+ .show();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ @Override
+ protected void updateZenModeState() {
+ // Because this fragment may be asked to finish by the delete menu but not be done doing
+ // so yet, ignore any attempts to update info in that case.
+ if (getActivity() != null && getActivity().isFinishing()) {
+ return;
+ }
+ super.updateZenModeState();
+ }
}
diff --git a/src/com/android/settings/notification/modes/ZenModeFragmentBase.java b/src/com/android/settings/notification/modes/ZenModeFragmentBase.java
index e086524..d08f7ea 100644
--- a/src/com/android/settings/notification/modes/ZenModeFragmentBase.java
+++ b/src/com/android/settings/notification/modes/ZenModeFragmentBase.java
@@ -16,10 +16,13 @@
package com.android.settings.notification.modes;
+import static android.provider.Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID;
+
import android.app.AutomaticZenRule;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
+import android.view.MenuItem;
import android.widget.Toast;
import androidx.annotation.NonNull;
@@ -29,6 +32,7 @@
import com.android.settings.R;
import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.notification.modes.ZenMode;
import java.util.List;
@@ -37,7 +41,6 @@
*/
abstract class ZenModeFragmentBase extends ZenModesFragmentBase {
static final String TAG = "ZenModeSettings";
- static final String MODE_ID = "MODE_ID";
@Nullable // only until reloadMode() is called
private ZenMode mZenMode;
@@ -46,17 +49,21 @@
public void onAttach(@NonNull Context context) {
super.onAttach(context);
- // TODO: b/322373473 - Update if modes page ends up using a different method of passing id
+ String id = null;
+ if (getActivity() != null && getActivity().getIntent() != null) {
+ id = getActivity().getIntent().getStringExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID);
+ }
Bundle bundle = getArguments();
- if (bundle != null && bundle.containsKey(MODE_ID)) {
- String id = bundle.getString(MODE_ID);
- if (!reloadMode(id)) {
- Log.e(TAG, "Mode id " + id + " not found");
- toastAndFinish();
- return;
- }
- } else {
- Log.e(TAG, "Mode id required to set mode config settings");
+ if (id == null && bundle != null && bundle.containsKey(EXTRA_AUTOMATIC_ZEN_RULE_ID)) {
+ id = bundle.getString(EXTRA_AUTOMATIC_ZEN_RULE_ID);
+ }
+ if (id == null) {
+ Log.d(TAG, "No id provided");
+ toastAndFinish();
+ return;
+ }
+ if (!reloadMode(id)) {
+ Log.d(TAG, "Mode id " + id + " not found");
toastAndFinish();
return;
}
@@ -108,6 +115,18 @@
updateControllers();
}
+ @Override
+ public final boolean onOptionsItemSelected(MenuItem item) {
+ if (mZenMode != null) {
+ return onOptionsItemSelected(item, mZenMode);
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ protected boolean onOptionsItemSelected(MenuItem item, @NonNull ZenMode zenMode) {
+ return true;
+ }
+
private void updateControllers() {
if (getPreferenceControllers() == null || mZenMode == null) {
return;
@@ -120,10 +139,6 @@
}
for (List<AbstractPreferenceController> list : getPreferenceControllers()) {
for (AbstractPreferenceController controller : list) {
- if (!controller.isAvailable()) {
- continue;
- }
-
try {
// Find preference associated with controller
final String key = controller.getPreferenceKey();
@@ -137,6 +152,7 @@
String.format("Cannot find preference with key %s in Controller %s",
key, controller.getClass().getSimpleName()));
}
+ controller.displayPreference(screen);
} catch (ClassCastException e) {
// Skip any controllers that aren't AbstractZenModePreferenceController.
Log.d(TAG, "Could not cast: " + controller.getClass().getSimpleName());
diff --git a/src/com/android/settings/notification/modes/ZenModeHeaderController.java b/src/com/android/settings/notification/modes/ZenModeHeaderController.java
index d8f0a67..1845ee8 100644
--- a/src/com/android/settings/notification/modes/ZenModeHeaderController.java
+++ b/src/com/android/settings/notification/modes/ZenModeHeaderController.java
@@ -25,6 +25,9 @@
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.widget.EntityHeaderController;
+import com.android.settingslib.notification.modes.ZenIconLoader;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.widget.LayoutPreference;
class ZenModeHeaderController extends AbstractZenModePreferenceController {
@@ -62,8 +65,8 @@
}
FutureUtil.whenDone(
- zenMode.getIcon(mContext, IconLoader.getInstance()),
- icon -> mHeaderController.setIcon(IconUtil.applyTint(mContext, icon))
+ zenMode.getIcon(mContext, ZenIconLoader.getInstance()),
+ icon -> mHeaderController.setIcon(IconUtil.applyNormalTint(mContext, icon))
.done(/* rebindActions= */ false),
mContext.getMainExecutor());
}
diff --git a/src/com/android/settings/notification/modes/ZenModeIconPickerIconPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeIconPickerIconPreferenceController.java
index 9eaaa97..d1d53af 100644
--- a/src/com/android/settings/notification/modes/ZenModeIconPickerIconPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeIconPickerIconPreferenceController.java
@@ -25,6 +25,9 @@
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.widget.EntityHeaderController;
+import com.android.settingslib.notification.modes.ZenIconLoader;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.widget.LayoutPreference;
class ZenModeIconPickerIconPreferenceController extends AbstractZenModePreferenceController {
@@ -51,8 +54,8 @@
}
FutureUtil.whenDone(
- zenMode.getIcon(mContext, IconLoader.getInstance()),
- icon -> mHeaderController.setIcon(IconUtil.applyTint(mContext, icon))
+ zenMode.getIcon(mContext, ZenIconLoader.getInstance()),
+ icon -> mHeaderController.setIcon(IconUtil.applyNormalTint(mContext, icon))
.done(/* rebindActions= */ false),
mContext.getMainExecutor());
}
diff --git a/src/com/android/settings/notification/modes/ZenModeIconPickerListPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeIconPickerListPreferenceController.java
index fc991dc..85ceafe 100644
--- a/src/com/android/settings/notification/modes/ZenModeIconPickerListPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeIconPickerListPreferenceController.java
@@ -33,6 +33,8 @@
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.widget.LayoutPreference;
import com.google.common.collect.ImmutableList;
diff --git a/src/com/android/settings/notification/modes/ZenModeMessagesLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeMessagesLinkPreferenceController.java
index 6e563c4..9b7c8a1 100644
--- a/src/com/android/settings/notification/modes/ZenModeMessagesLinkPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeMessagesLinkPreferenceController.java
@@ -16,7 +16,7 @@
package com.android.settings.notification.modes;
-import static com.android.settings.notification.modes.ZenModeFragmentBase.MODE_ID;
+import static android.provider.Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID;
import android.content.Context;
import android.os.Bundle;
@@ -25,6 +25,8 @@
import androidx.preference.Preference;
import com.android.settings.core.SubSettingLauncher;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
class ZenModeMessagesLinkPreferenceController extends AbstractZenModePreferenceController {
private final ZenModeSummaryHelper mSummaryHelper;
@@ -38,7 +40,7 @@
@Override
public void updateState(Preference preference, @NonNull ZenMode zenMode) {
Bundle bundle = new Bundle();
- bundle.putString(MODE_ID, zenMode.getId());
+ bundle.putString(EXTRA_AUTOMATIC_ZEN_RULE_ID, zenMode.getId());
// TODO(b/332937635): Update metrics category
preference.setIntent(new SubSettingLauncher(mContext)
.setDestination(ZenModeMessagesFragment.class.getName())
diff --git a/src/com/android/settings/notification/modes/ZenModeNotifVisLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeNotifVisLinkPreferenceController.java
index 15da96e..a2d9411 100644
--- a/src/com/android/settings/notification/modes/ZenModeNotifVisLinkPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeNotifVisLinkPreferenceController.java
@@ -16,7 +16,8 @@
package com.android.settings.notification.modes;
-import static com.android.settings.notification.modes.ZenModeFragmentBase.MODE_ID;
+import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL;
+import static android.provider.Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID;
import android.content.Context;
import android.os.Bundle;
@@ -25,6 +26,8 @@
import androidx.preference.Preference;
import com.android.settings.core.SubSettingLauncher;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
class ZenModeNotifVisLinkPreferenceController extends AbstractZenModePreferenceController {
@@ -37,9 +40,14 @@
}
@Override
+ public boolean isAvailable(ZenMode zenMode) {
+ return zenMode.getRule().getInterruptionFilter() != INTERRUPTION_FILTER_ALL;
+ }
+
+ @Override
public void updateState(Preference preference, @NonNull ZenMode zenMode) {
Bundle bundle = new Bundle();
- bundle.putString(MODE_ID, zenMode.getId());
+ bundle.putString(EXTRA_AUTOMATIC_ZEN_RULE_ID, zenMode.getId());
// TODO(b/332937635): Update metrics category
preference.setIntent(new SubSettingLauncher(mContext)
.setDestination(ZenModeNotifVisFragment.class.getName())
diff --git a/src/com/android/settings/notification/modes/ZenModeNotifVisPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeNotifVisPreferenceController.java
index f918b25..3d9f713 100644
--- a/src/com/android/settings/notification/modes/ZenModeNotifVisPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeNotifVisPreferenceController.java
@@ -21,19 +21,21 @@
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
-import androidx.preference.CheckBoxPreference;
import androidx.preference.Preference;
import androidx.preference.TwoStatePreference;
-import com.android.settings.widget.DisabledCheckBoxPreference;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
public class ZenModeNotifVisPreferenceController extends AbstractZenModePreferenceController
implements Preference.OnPreferenceChangeListener {
- @VisibleForTesting protected @ZenPolicy.VisualEffect int mEffect;
+ @VisibleForTesting
+ protected @ZenPolicy.VisualEffect int mEffect;
// if any of these effects are suppressed, this effect must be too
- @VisibleForTesting protected @ZenPolicy.VisualEffect int[] mParentSuppressedEffects;
+ @VisibleForTesting
+ protected @ZenPolicy.VisualEffect int[] mParentSuppressedEffects;
public ZenModeNotifVisPreferenceController(Context context, String key,
@ZenPolicy.VisualEffect int visualEffect,
diff --git a/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceController.java
index 89b719e..99625eb 100644
--- a/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceController.java
@@ -16,7 +16,8 @@
package com.android.settings.notification.modes;
-import static com.android.settings.notification.modes.ZenModeFragmentBase.MODE_ID;
+import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL;
+import static android.provider.Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID;
import android.content.Context;
import android.os.Bundle;
@@ -25,6 +26,8 @@
import androidx.preference.Preference;
import com.android.settings.core.SubSettingLauncher;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
/**
* Preference with a link and summary about what other sounds can break through the mode
@@ -40,9 +43,14 @@
}
@Override
+ public boolean isAvailable(ZenMode zenMode) {
+ return zenMode.getRule().getInterruptionFilter() != INTERRUPTION_FILTER_ALL;
+ }
+
+ @Override
public void updateState(Preference preference, @NonNull ZenMode zenMode) {
Bundle bundle = new Bundle();
- bundle.putString(MODE_ID, zenMode.getId());
+ bundle.putString(EXTRA_AUTOMATIC_ZEN_RULE_ID, zenMode.getId());
preference.setIntent(new SubSettingLauncher(mContext)
.setDestination(ZenModeOtherFragment.class.getName())
.setSourceMetricsCategory(0)
diff --git a/src/com/android/settings/notification/modes/ZenModeOtherPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeOtherPreferenceController.java
index a770164e..ad5fa6a 100644
--- a/src/com/android/settings/notification/modes/ZenModeOtherPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeOtherPreferenceController.java
@@ -28,6 +28,9 @@
import androidx.preference.Preference;
import androidx.preference.TwoStatePreference;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
+
class ZenModeOtherPreferenceController extends AbstractZenModePreferenceController
implements Preference.OnPreferenceChangeListener {
diff --git a/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceController.java
index 271ca72..1613a01 100644
--- a/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceController.java
@@ -16,7 +16,8 @@
package com.android.settings.notification.modes;
-import static com.android.settings.notification.modes.ZenModeFragmentBase.MODE_ID;
+import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL;
+import static android.provider.Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID;
import android.content.Context;
import android.os.Bundle;
@@ -25,6 +26,8 @@
import androidx.preference.Preference;
import com.android.settings.core.SubSettingLauncher;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
/**
* Preference with a link and summary about what calls and messages can break through the mode
@@ -40,9 +43,14 @@
}
@Override
+ public boolean isAvailable(ZenMode zenMode) {
+ return zenMode.getRule().getInterruptionFilter() != INTERRUPTION_FILTER_ALL;
+ }
+
+ @Override
public void updateState(Preference preference, @NonNull ZenMode zenMode) {
Bundle bundle = new Bundle();
- bundle.putString(MODE_ID, zenMode.getId());
+ bundle.putString(EXTRA_AUTOMATIC_ZEN_RULE_ID, zenMode.getId());
// TODO(b/332937635): Update metrics category
preference.setIntent(new SubSettingLauncher(mContext)
.setDestination(ZenModePeopleFragment.class.getName())
diff --git a/src/com/android/settings/notification/modes/ZenModePrioritySendersPreferenceController.java b/src/com/android/settings/notification/modes/ZenModePrioritySendersPreferenceController.java
index 31a8a0d..0f9323d 100644
--- a/src/com/android/settings/notification/modes/ZenModePrioritySendersPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModePrioritySendersPreferenceController.java
@@ -46,6 +46,8 @@
import com.android.settings.R;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.notification.app.ConversationListSettings;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.widget.SelectorWithWidgetPreference;
import java.util.ArrayList;
diff --git a/src/com/android/settings/notification/modes/ZenModeRepeatCallersPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeRepeatCallersPreferenceController.java
index 7569051..ae62e35 100644
--- a/src/com/android/settings/notification/modes/ZenModeRepeatCallersPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeRepeatCallersPreferenceController.java
@@ -26,6 +26,8 @@
import androidx.preference.TwoStatePreference;
import com.android.settings.R;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
class ZenModeRepeatCallersPreferenceController extends AbstractZenModePreferenceController
implements Preference.OnPreferenceChangeListener {
diff --git a/src/com/android/settings/notification/modes/ZenModeScheduleChooserDialog.java b/src/com/android/settings/notification/modes/ZenModeScheduleChooserDialog.java
new file mode 100644
index 0000000..14264b7
--- /dev/null
+++ b/src/com/android/settings/notification/modes/ZenModeScheduleChooserDialog.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification.modes;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.service.notification.ZenModeConfig;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+import androidx.appcompat.app.AlertDialog;
+
+import com.android.settings.R;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.android.settings.dashboard.DashboardFragment;
+
+import com.google.common.collect.ImmutableList;
+
+public class ZenModeScheduleChooserDialog extends InstrumentedDialogFragment {
+
+ private static final String TAG = "ZenModeScheduleChooserDialog";
+
+ static final int OPTION_TIME = 0;
+ static final int OPTION_CALENDAR = 1;
+
+ private record ScheduleOption(@StringRes int nameResId, @StringRes int exampleResId,
+ @DrawableRes int iconResId) {}
+
+ private static final ImmutableList<ScheduleOption> SCHEDULE_OPTIONS = ImmutableList.of(
+ new ScheduleOption(R.string.zen_mode_select_schedule_time,
+ R.string.zen_mode_select_schedule_time_example,
+ com.android.internal.R.drawable.ic_zen_mode_type_schedule_time),
+ new ScheduleOption(R.string.zen_mode_select_schedule_calendar,
+ R.string.zen_mode_select_schedule_calendar_example,
+ com.android.internal.R.drawable.ic_zen_mode_type_schedule_calendar));
+
+ private OnScheduleOptionListener mOptionListener;
+
+ interface OnScheduleOptionListener {
+ void onScheduleSelected(Uri conditionId);
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ // TODO: b/332937635 - Update metrics category
+ return 0;
+ }
+
+ static void show(DashboardFragment parent, OnScheduleOptionListener optionListener) {
+ ZenModeScheduleChooserDialog dialog = new ZenModeScheduleChooserDialog();
+ dialog.mOptionListener = optionListener;
+ dialog.setTargetFragment(parent, 0);
+ dialog.show(parent.getParentFragmentManager(), TAG);
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+ checkState(getContext() != null);
+ return new AlertDialog.Builder(getContext())
+ .setTitle(R.string.zen_mode_choose_rule_type)
+ .setAdapter(new OptionsAdapter(getContext()),
+ (dialog, which) -> onScheduleTypeSelected(which))
+ .setNegativeButton(R.string.cancel, null)
+ .create();
+ }
+
+ private static class OptionsAdapter extends ArrayAdapter<ScheduleOption> {
+
+ private final LayoutInflater mInflater;
+
+ OptionsAdapter(@NonNull Context context) {
+ super(context, R.layout.zen_mode_type_item, SCHEDULE_OPTIONS);
+ mInflater = LayoutInflater.from(context);
+ }
+
+ @NonNull
+ @Override
+ public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
+ if (convertView == null) {
+ convertView = mInflater.inflate(R.layout.zen_mode_type_item, parent, false);
+ }
+ // No need for holder pattern since we have only 2 items.
+ ImageView imageView = checkNotNull(convertView.findViewById(R.id.icon));
+ TextView title = checkNotNull(convertView.findViewById(R.id.title));
+ TextView subtitle = checkNotNull(convertView.findViewById(R.id.subtitle));
+
+ ScheduleOption option = checkNotNull(getItem(position));
+ imageView.setImageResource(option.iconResId());
+ title.setText(option.nameResId());
+ subtitle.setText(option.exampleResId());
+
+ return convertView;
+ }
+ }
+
+ private void onScheduleTypeSelected(int whichOption) {
+ Uri conditionId = switch (whichOption) {
+ case OPTION_TIME -> getDefaultScheduleTimeCondition();
+ case OPTION_CALENDAR -> getDefaultScheduleCalendarCondition();
+ default -> ZenModeConfig.toCustomManualConditionId();
+ };
+
+ mOptionListener.onScheduleSelected(conditionId);
+ }
+
+ private static Uri getDefaultScheduleTimeCondition() {
+ ZenModeConfig.ScheduleInfo schedule = new ZenModeConfig.ScheduleInfo();
+ schedule.days = ZenModeConfig.ALL_DAYS;
+ schedule.startHour = 9;
+ schedule.startMinute = 30;
+ schedule.endHour = 17;
+ return ZenModeConfig.toScheduleConditionId(schedule);
+ }
+
+ private static Uri getDefaultScheduleCalendarCondition() {
+ ZenModeConfig.EventInfo eventInfo = new ZenModeConfig.EventInfo();
+ eventInfo.calendarId = null; // All calendars of the current user.
+ eventInfo.reply = ZenModeConfig.EventInfo.REPLY_ANY_EXCEPT_NO;
+ return ZenModeConfig.toEventConditionId(eventInfo);
+ }
+}
diff --git a/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceController.java
index 2841309..4f45c5c8 100644
--- a/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceController.java
@@ -16,14 +16,12 @@
package com.android.settings.notification.modes;
-import android.app.Flags;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.CalendarContract;
-import android.service.notification.SystemZenRules;
import android.service.notification.ZenModeConfig;
import androidx.annotation.NonNull;
@@ -33,6 +31,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import java.util.ArrayList;
import java.util.Arrays;
@@ -42,7 +42,7 @@
import java.util.Objects;
import java.util.function.Function;
-public class ZenModeSetCalendarPreferenceController extends AbstractZenModePreferenceController {
+class ZenModeSetCalendarPreferenceController extends AbstractZenModePreferenceController {
@VisibleForTesting
protected static final String KEY_CALENDAR = "calendar";
@VisibleForTesting
@@ -122,11 +122,7 @@
@VisibleForTesting
protected Function<ZenMode, ZenMode> updateEventMode(ZenModeConfig.EventInfo event) {
return (zenMode) -> {
- zenMode.getRule().setConditionId(ZenModeConfig.toEventConditionId(event));
- if (Flags.modesApi() && Flags.modesUi()) {
- zenMode.getRule().setTriggerDescription(
- SystemZenRules.getTriggerDescriptionForScheduleEvent(mContext, event));
- }
+ zenMode.setCustomModeConditionId(mContext, ZenModeConfig.toEventConditionId(event));
return zenMode;
};
}
diff --git a/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceController.java b/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceController.java
index a6008cc..878a508 100644
--- a/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceController.java
@@ -16,9 +16,7 @@
package com.android.settings.notification.modes;
-import android.app.Flags;
import android.content.Context;
-import android.service.notification.SystemZenRules;
import android.service.notification.ZenModeConfig;
import android.text.format.DateFormat;
import android.util.ArraySet;
@@ -33,6 +31,8 @@
import androidx.preference.Preference;
import com.android.settings.R;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.widget.LayoutPreference;
import java.text.SimpleDateFormat;
@@ -116,16 +116,13 @@
@VisibleForTesting
protected Function<ZenMode, ZenMode> updateScheduleMode(ZenModeConfig.ScheduleInfo schedule) {
return (zenMode) -> {
- zenMode.getRule().setConditionId(ZenModeConfig.toScheduleConditionId(schedule));
- if (Flags.modesApi() && Flags.modesUi()) {
- zenMode.getRule().setTriggerDescription(
- SystemZenRules.getTriggerDescriptionForScheduleTime(mContext, schedule));
- }
+ zenMode.setCustomModeConditionId(mContext,
+ ZenModeConfig.toScheduleConditionId(schedule));
return zenMode;
};
}
- private ZenModeTimePickerFragment.TimeSetter mStartSetter = (hour, minute) -> {
+ private final ZenModeTimePickerFragment.TimeSetter mStartSetter = (hour, minute) -> {
if (!isValidTime(hour, minute)) {
return;
}
@@ -137,7 +134,7 @@
saveMode(updateScheduleMode(mSchedule));
};
- private ZenModeTimePickerFragment.TimeSetter mEndSetter = (hour, minute) -> {
+ private final ZenModeTimePickerFragment.TimeSetter mEndSetter = (hour, minute) -> {
if (!isValidTime(hour, minute)) {
return;
}
diff --git a/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceController.java
index 14d5d59..1c96fee 100644
--- a/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceController.java
@@ -13,15 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.settings.notification.modes;
import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR;
import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
-import static com.android.settings.notification.modes.ZenModeFragmentBase.MODE_ID;
-
import android.content.Context;
-import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
@@ -29,8 +27,10 @@
import androidx.preference.PreferenceCategory;
import com.android.settings.R;
-import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.PrimarySwitchPreference;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
/**
* Preference controller for the link to an individual mode's configuration page.
@@ -39,9 +39,13 @@
@VisibleForTesting
protected static final String AUTOMATIC_TRIGGER_PREF_KEY = "zen_automatic_trigger_settings";
+ private final DashboardFragment mFragment;
+
ZenModeSetTriggerLinkPreferenceController(Context context, String key,
+ DashboardFragment fragment,
ZenModesBackend backend) {
super(context, key, backend);
+ mFragment = fragment;
}
@Override
@@ -54,47 +58,52 @@
// This controller is expected to govern a preference category so that it controls the
// availability of the entire preference category if the mode doesn't have a way to
// automatically trigger (such as manual DND).
- Preference switchPref = ((PreferenceCategory) preference).findPreference(
+ PrimarySwitchPreference switchPref = ((PreferenceCategory) preference).findPreference(
AUTOMATIC_TRIGGER_PREF_KEY);
if (switchPref == null) {
return;
}
- ((PrimarySwitchPreference) switchPref).setChecked(zenMode.getRule().isEnabled());
+ switchPref.setChecked(zenMode.getRule().isEnabled());
switchPref.setOnPreferenceChangeListener(mSwitchChangeListener);
+ switchPref.setSummary(zenMode.getRule().getTriggerDescription());
+ switchPref.setIcon(null);
+ switchPref.setOnPreferenceClickListener(null);
+ switchPref.setIntent(null);
- Bundle bundle = new Bundle();
- bundle.putString(MODE_ID, zenMode.getId());
-
- // TODO: b/341961712 - direct preference to app-owned intent if available
- switch (zenMode.getRule().getType()) {
- case TYPE_SCHEDULE_TIME:
- switchPref.setTitle(R.string.zen_mode_set_schedule_link);
- switchPref.setSummary(zenMode.getRule().getTriggerDescription());
- switchPref.setIntent(new SubSettingLauncher(mContext)
- .setDestination(ZenModeSetScheduleFragment.class.getName())
- // TODO: b/332937635 - set correct metrics category
- .setSourceMetricsCategory(0)
- .setArguments(bundle)
- .toIntent());
- break;
- case TYPE_SCHEDULE_CALENDAR:
- switchPref.setTitle(R.string.zen_mode_set_calendar_link);
- switchPref.setSummary(zenMode.getRule().getTriggerDescription());
- switchPref.setIntent(new SubSettingLauncher(mContext)
- .setDestination(ZenModeSetCalendarFragment.class.getName())
- // TODO: b/332937635 - set correct metrics category
- .setSourceMetricsCategory(0)
- .setArguments(bundle)
- .toIntent());
- break;
- default:
- // TODO: b/342156843 - change this to allow adding a trigger condition for system
- // rules that don't yet have a type selected
- switchPref.setTitle("not implemented");
+ if (zenMode.isSystemOwned() && zenMode.getType() == TYPE_SCHEDULE_TIME) {
+ switchPref.setTitle(R.string.zen_mode_set_schedule_link);
+ // TODO: b/332937635 - set correct metrics category
+ switchPref.setIntent(ZenSubSettingLauncher.forModeFragment(mContext,
+ ZenModeSetScheduleFragment.class, zenMode.getId(), 0).toIntent());
+ } else if (zenMode.isSystemOwned() && zenMode.getType() == TYPE_SCHEDULE_CALENDAR) {
+ switchPref.setTitle(R.string.zen_mode_set_calendar_link);
+ switchPref.setIcon(null);
+ // TODO: b/332937635 - set correct metrics category
+ switchPref.setIntent(ZenSubSettingLauncher.forModeFragment(mContext,
+ ZenModeSetCalendarFragment.class, zenMode.getId(), 0).toIntent());
+ } else if (zenMode.isSystemOwned()) {
+ switchPref.setTitle(R.string.zen_mode_select_schedule);
+ switchPref.setIcon(R.drawable.ic_add_24dp);
+ switchPref.setSummary("");
+ // TODO: b/342156843 - Hide the switch (needs support in SettingsLib).
+ switchPref.setOnPreferenceClickListener(clickedPreference -> {
+ ZenModeScheduleChooserDialog.show(mFragment, mOnScheduleOptionListener);
+ return true;
+ });
+ } else {
+ // TODO: b/341961712 - direct preference to app-owned intent if available
+ switchPref.setTitle("not implemented");
}
}
@VisibleForTesting
+ final ZenModeScheduleChooserDialog.OnScheduleOptionListener mOnScheduleOptionListener =
+ conditionId -> saveMode(mode -> {
+ mode.setCustomModeConditionId(mContext, conditionId);
+ return mode;
+ });
+
+ @VisibleForTesting
protected Preference.OnPreferenceChangeListener mSwitchChangeListener = (p, newValue) -> {
final boolean newEnabled = (Boolean) newValue;
return saveMode((zenMode) -> {
@@ -103,5 +112,6 @@
}
return zenMode;
});
+ // TODO: b/342156843 - Do we want to jump to the corresponding schedule editing screen?
};
}
diff --git a/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java b/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java
index bf0bac9..48a4c36 100644
--- a/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java
+++ b/src/com/android/settings/notification/modes/ZenModeSummaryHelper.java
@@ -15,6 +15,7 @@
*/
package com.android.settings.notification.modes;
+import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL;
import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_ANYONE;
import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_IMPORTANT;
import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_NONE;
@@ -47,6 +48,7 @@
import androidx.annotation.Nullable;
import com.android.settings.R;
+import com.android.settingslib.notification.modes.ZenMode;
import java.util.ArrayList;
import java.util.Arrays;
@@ -187,11 +189,12 @@
String getDisplayEffectsSummary(ZenMode zenMode) {
boolean isFirst = true;
List<String> enabledEffects = new ArrayList<>();
- if (!zenMode.getPolicy().shouldShowAllVisualEffects()) {
+ if (!zenMode.getPolicy().shouldShowAllVisualEffects()
+ && zenMode.getRule().getInterruptionFilter() != INTERRUPTION_FILTER_ALL) {
enabledEffects.add(getBlockedEffectsSummary(zenMode));
isFirst = false;
}
- ZenDeviceEffects currEffects = zenMode.getRule().getDeviceEffects();
+ ZenDeviceEffects currEffects = zenMode.getRule().getDeviceEffects();
if (currEffects != null) {
if (currEffects.shouldDisplayGrayscale()) {
if (isFirst) {
@@ -411,8 +414,6 @@
return formatAppsList(appsBypassing);
} else if (zenMode.getPolicy().getAllowedChannels() == ZenPolicy.CHANNEL_POLICY_NONE) {
return mContext.getResources().getString(R.string.zen_mode_apps_none_apps);
- } else if (zenMode.getPolicy().getAllowedChannels() == ZenMode.CHANNEL_POLICY_ALL) {
- return mContext.getResources().getString(R.string.zen_mode_apps_all_apps);
}
return "";
}
diff --git a/src/com/android/settings/notification/modes/ZenModesBackend.java b/src/com/android/settings/notification/modes/ZenModesBackend.java
deleted file mode 100644
index b58e310..0000000
--- a/src/com/android/settings/notification/modes/ZenModesBackend.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.notification.modes;
-
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.AutomaticZenRule;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.net.Uri;
-import android.provider.Settings;
-import android.service.notification.Condition;
-import android.service.notification.SystemZenRules;
-import android.service.notification.ZenModeConfig;
-import android.util.Log;
-
-import com.android.settings.R;
-
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Class used for Settings-NMS interactions related to Mode management.
- *
- * <p>This class converts {@link AutomaticZenRule} instances, as well as the manual zen mode,
- * into the unified {@link ZenMode} format.
- */
-class ZenModesBackend {
-
- private static final String TAG = "ZenModeBackend";
-
- @Nullable // Until first usage
- private static ZenModesBackend sInstance;
-
- private final NotificationManager mNotificationManager;
-
- private final Context mContext;
-
- static ZenModesBackend getInstance(Context context) {
- if (sInstance == null) {
- sInstance = new ZenModesBackend(context.getApplicationContext());
- }
- return sInstance;
- }
-
- ZenModesBackend(Context context) {
- mContext = context;
- mNotificationManager = context.getSystemService(NotificationManager.class);
- }
-
- List<ZenMode> getModes() {
- ArrayList<ZenMode> modes = new ArrayList<>();
- ZenModeConfig currentConfig = mNotificationManager.getZenModeConfig();
- modes.add(getManualDndMode(currentConfig));
-
- Map<String, AutomaticZenRule> zenRules = mNotificationManager.getAutomaticZenRules();
- for (Map.Entry<String, AutomaticZenRule> zenRuleEntry : zenRules.entrySet()) {
- String ruleId = zenRuleEntry.getKey();
- modes.add(new ZenMode(ruleId, zenRuleEntry.getValue(),
- isRuleActive(ruleId, currentConfig)));
- }
-
- modes.sort((l, r) -> {
- if (l.isManualDnd()) {
- return -1;
- } else if (r.isManualDnd()) {
- return 1;
- }
- return l.getRule().getName().compareTo(r.getRule().getName());
- });
-
- return modes;
- }
-
- @Nullable
- ZenMode getMode(String id) {
- ZenModeConfig currentConfig = mNotificationManager.getZenModeConfig();
- if (ZenMode.MANUAL_DND_MODE_ID.equals(id)) {
- return getManualDndMode(currentConfig);
- } else {
- AutomaticZenRule rule = mNotificationManager.getAutomaticZenRule(id);
- if (rule == null) {
- return null;
- }
- return new ZenMode(id, rule, isRuleActive(id, currentConfig));
- }
- }
-
- private ZenMode getManualDndMode(ZenModeConfig config) {
- ZenModeConfig.ZenRule manualRule = config.manualRule;
- // TODO: b/333682392 - Replace with final strings for name & trigger description
- AutomaticZenRule manualDndRule = new AutomaticZenRule.Builder(
- mContext.getString(R.string.zen_mode_settings_title), manualRule.conditionId)
- .setType(manualRule.type)
- .setZenPolicy(manualRule.zenPolicy)
- .setDeviceEffects(manualRule.zenDeviceEffects)
- .setManualInvocationAllowed(manualRule.allowManualInvocation)
- .setConfigurationActivity(null) // No further settings
- .setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY)
- .build();
-
- return ZenMode.manualDndMode(manualDndRule, config != null && config.isManualActive());
- }
-
- private static boolean isRuleActive(String id, ZenModeConfig config) {
- if (config == null) {
- // shouldn't happen if the config is coming from NM, but be safe
- return false;
- }
- ZenModeConfig.ZenRule configRule = config.automaticRules.get(id);
- return configRule != null && configRule.isAutomaticActive();
- }
-
- void updateMode(ZenMode mode) {
- if (mode.isManualDnd()) {
- try {
- NotificationManager.Policy dndPolicy =
- new ZenModeConfig().toNotificationPolicy(mode.getPolicy());
- mNotificationManager.setNotificationPolicy(dndPolicy, /* fromUser= */ true);
-
- mNotificationManager.setManualZenRuleDeviceEffects(
- mode.getRule().getDeviceEffects());
- } catch (Exception e) {
- Log.w(TAG, "Error updating manual mode", e);
- }
- } else {
- mNotificationManager.updateAutomaticZenRule(mode.getId(), mode.getRule(),
- /* fromUser= */ true);
- }
- }
-
- void activateMode(ZenMode mode, @Nullable Duration forDuration) {
- if (mode.isManualDnd()) {
- Uri durationConditionId = null;
- if (forDuration != null) {
- durationConditionId = ZenModeConfig.toTimeCondition(mContext,
- (int) forDuration.toMinutes(), ActivityManager.getCurrentUser(), true).id;
- }
- mNotificationManager.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
- durationConditionId, TAG, /* fromUser= */ true);
-
- } else {
- if (forDuration != null) {
- throw new IllegalArgumentException(
- "Only the manual DND mode can be activated for a specific duration");
- }
- mNotificationManager.setAutomaticZenRuleState(mode.getId(),
- new Condition(mode.getRule().getConditionId(), "", Condition.STATE_TRUE,
- Condition.SOURCE_USER_ACTION));
- }
- }
-
- void deactivateMode(ZenMode mode) {
- if (mode.isManualDnd()) {
- // When calling with fromUser=true this will not snooze other modes.
- mNotificationManager.setZenMode(Settings.Global.ZEN_MODE_OFF, null, TAG,
- /* fromUser= */ true);
- } else {
- // TODO: b/333527800 - This should (potentially) snooze the rule if it was active.
- mNotificationManager.setAutomaticZenRuleState(mode.getId(),
- new Condition(mode.getRule().getConditionId(), "", Condition.STATE_FALSE,
- Condition.SOURCE_USER_ACTION));
- }
- }
-
- void removeMode(ZenMode mode) {
- if (!mode.canBeDeleted()) {
- throw new IllegalArgumentException("Mode " + mode + " cannot be deleted!");
- }
- mNotificationManager.removeAutomaticZenRule(mode.getId(), /* fromUser= */ true);
- }
-
- /**
- * Creates a new custom mode with the provided {@code name}. The mode will be "manual" (i.e.
- * not have a schedule), this can be later updated by the user in the mode settings page.
- *
- * @return the created mode. Only {@code null} if creation failed due to an internal error
- */
- @Nullable
- ZenMode addCustomMode(String name) {
- ZenModeConfig.ScheduleInfo schedule = new ZenModeConfig.ScheduleInfo();
- schedule.days = ZenModeConfig.ALL_DAYS;
- schedule.startHour = 22;
- schedule.endHour = 7;
-
- // TODO: b/326442408 - Create as "manual" (i.e. no trigger) instead of schedule-time.
- AutomaticZenRule rule = new AutomaticZenRule.Builder(name,
- ZenModeConfig.toScheduleConditionId(schedule))
- .setPackage(ZenModeConfig.getScheduleConditionProvider().getPackageName())
- .setType(AutomaticZenRule.TYPE_SCHEDULE_CALENDAR)
- .setOwner(ZenModeConfig.getScheduleConditionProvider())
- .setTriggerDescription(SystemZenRules.getTriggerDescriptionForScheduleTime(
- mContext, schedule))
- .setManualInvocationAllowed(true)
- .build();
-
- String ruleId = mNotificationManager.addAutomaticZenRule(rule);
- return getMode(ruleId);
- }
-}
diff --git a/src/com/android/settings/notification/modes/ZenModesFragmentBase.java b/src/com/android/settings/notification/modes/ZenModesFragmentBase.java
index d99593a..e1156fe 100644
--- a/src/com/android/settings/notification/modes/ZenModesFragmentBase.java
+++ b/src/com/android/settings/notification/modes/ZenModesFragmentBase.java
@@ -27,6 +27,7 @@
import android.util.Log;
import com.android.settings.dashboard.RestrictedDashboardFragment;
+import com.android.settingslib.notification.modes.ZenModesBackend;
/**
* Base class for all Settings pages controlling Modes behavior.
diff --git a/src/com/android/settings/notification/modes/ZenModesListAddModePreferenceController.java b/src/com/android/settings/notification/modes/ZenModesListAddModePreferenceController.java
index c229fb1..ba74b93 100644
--- a/src/com/android/settings/notification/modes/ZenModesListAddModePreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModesListAddModePreferenceController.java
@@ -22,6 +22,8 @@
import com.android.settings.utils.ZenServiceListing;
import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import java.util.Random;
diff --git a/src/com/android/settings/notification/modes/ZenModesListFragment.java b/src/com/android/settings/notification/modes/ZenModesListFragment.java
index 80678f6..77107f8 100644
--- a/src/com/android/settings/notification/modes/ZenModesListFragment.java
+++ b/src/com/android/settings/notification/modes/ZenModesListFragment.java
@@ -29,6 +29,7 @@
import com.android.settings.utils.ManagedServiceSettings;
import com.android.settings.utils.ZenServiceListing;
import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.search.SearchIndexable;
import com.google.common.collect.ImmutableList;
diff --git a/src/com/android/settings/notification/modes/ZenModesListItemPreference.java b/src/com/android/settings/notification/modes/ZenModesListItemPreference.java
index 7ecfb3a..1bc6e55 100644
--- a/src/com/android/settings/notification/modes/ZenModesListItemPreference.java
+++ b/src/com/android/settings/notification/modes/ZenModesListItemPreference.java
@@ -16,16 +16,31 @@
package com.android.settings.notification.modes;
import android.content.Context;
+import android.widget.TextView;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settings.R;
import com.android.settingslib.RestrictedPreference;
+import com.android.settingslib.Utils;
+import com.android.settingslib.notification.modes.ZenIconLoader;
+import com.android.settingslib.notification.modes.ZenMode;
+
+import com.google.common.base.Strings;
/**
* Preference representing a single mode item on the modes aggregator page. Clicking on this
* preference leads to an individual mode's configuration page.
*/
class ZenModesListItemPreference extends RestrictedPreference {
- final Context mContext;
- ZenMode mZenMode;
+
+ private final Context mContext;
+ private ZenMode mZenMode;
+
+ private TextView mTitleView;
+ private TextView mSummaryView;
ZenModesListItemPreference(Context context, ZenMode zenMode) {
super(context);
@@ -35,19 +50,65 @@
}
@Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+ if (holder.findViewById(android.R.id.title) instanceof TextView titleView) {
+ mTitleView = titleView;
+ }
+ if (holder.findViewById(android.R.id.summary) instanceof TextView summaryView) {
+ mSummaryView = summaryView;
+ }
+ updateTextColor(mZenMode);
+ }
+
+ @Override
public void onClick() {
ZenSubSettingLauncher.forMode(mContext, mZenMode.getId()).launch();
}
public void setZenMode(ZenMode zenMode) {
mZenMode = zenMode;
- setTitle(mZenMode.getRule().getName());
- setSummary(mZenMode.getRule().getTriggerDescription());
- setIconSize(ICON_SIZE_SMALL);
+ setTitle(mZenMode.getName());
+ CharSequence statusText = switch (mZenMode.getStatus()) {
+ case ENABLED_AND_ACTIVE ->
+ Strings.isNullOrEmpty(mZenMode.getTriggerDescription())
+ ? mContext.getString(R.string.zen_mode_active_text)
+ : mContext.getString(
+ R.string.zen_mode_format_status_and_trigger,
+ mContext.getString(R.string.zen_mode_active_text),
+ mZenMode.getRule().getTriggerDescription());
+ case ENABLED -> mZenMode.getRule().getTriggerDescription();
+ case DISABLED_BY_USER -> mContext.getString(R.string.zen_mode_disabled_by_user);
+ case DISABLED_BY_OTHER -> mContext.getString(R.string.zen_mode_disabled_tap_to_set_up);
+ };
+ setSummary(statusText);
+ setIconSize(ICON_SIZE_SMALL);
FutureUtil.whenDone(
- mZenMode.getIcon(mContext, IconLoader.getInstance()),
- icon -> setIcon(IconUtil.applyTint(mContext, icon)),
+ mZenMode.getIcon(mContext, ZenIconLoader.getInstance()),
+ icon -> setIcon(
+ zenMode.isActive()
+ ? IconUtil.applyAccentTint(mContext, icon)
+ : IconUtil.applyNormalTint(mContext, icon)),
mContext.getMainExecutor());
+
+ updateTextColor(zenMode);
+ }
+
+ private void updateTextColor(@Nullable ZenMode zenMode) {
+ boolean isActive = zenMode != null && zenMode.isActive();
+ if (mTitleView != null) {
+ mTitleView.setTextColor(Utils.getColorAttr(mContext,
+ isActive ? android.R.attr.colorAccent : android.R.attr.textColorPrimary));
+ }
+ if (mSummaryView != null) {
+ mSummaryView.setTextColor(Utils.getColorAttr(mContext,
+ isActive ? android.R.attr.colorAccent : android.R.attr.textColorSecondary));
+ }
+ }
+
+ @VisibleForTesting(otherwise = VisibleForTesting.NONE)
+ ZenMode getZenMode() {
+ return mZenMode;
}
}
diff --git a/src/com/android/settings/notification/modes/ZenModesListPreferenceController.java b/src/com/android/settings/notification/modes/ZenModesListPreferenceController.java
index 5dcd9eb..fb07078 100644
--- a/src/com/android/settings/notification/modes/ZenModesListPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModesListPreferenceController.java
@@ -27,6 +27,8 @@
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.search.SearchIndexableRaw;
import java.util.HashMap;
diff --git a/src/com/android/settings/notification/modes/ZenSubSettingLauncher.java b/src/com/android/settings/notification/modes/ZenSubSettingLauncher.java
index 11f3492..529f7fa 100644
--- a/src/com/android/settings/notification/modes/ZenSubSettingLauncher.java
+++ b/src/com/android/settings/notification/modes/ZenSubSettingLauncher.java
@@ -16,6 +16,8 @@
package com.android.settings.notification.modes;
+import static android.provider.Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID;
+
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Bundle;
@@ -29,11 +31,11 @@
SettingsEnums.NOTIFICATION_ZEN_MODE_AUTOMATION);
}
- private static SubSettingLauncher forModeFragment(Context context,
+ static SubSettingLauncher forModeFragment(Context context,
Class<? extends ZenModeFragmentBase> fragmentClass, String modeId,
int sourceMetricsCategory) {
Bundle bundle = new Bundle();
- bundle.putString(ZenModeFragmentBase.MODE_ID, modeId);
+ bundle.putString(EXTRA_AUTOMATIC_ZEN_RULE_ID, modeId);
return new SubSettingLauncher(context)
.setDestination(fragmentClass.getName())
diff --git a/src/com/android/settings/notification/zen/ZenModeBackend.java b/src/com/android/settings/notification/zen/ZenModeBackend.java
index 426f52d..de641c5 100644
--- a/src/com/android/settings/notification/zen/ZenModeBackend.java
+++ b/src/com/android/settings/notification/zen/ZenModeBackend.java
@@ -116,7 +116,7 @@
ActivityManager.getCurrentUser(), true).id;
if (android.app.Flags.modesApi()) {
mNotificationManager.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
- conditionId, TAG, /* fromUser= */ true);
+ conditionId, TAG, /* fromUser= */ true);
} else {
mNotificationManager.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
conditionId, TAG);
@@ -241,12 +241,14 @@
}
savePolicy(getNewDefaultPriorityCategories(allowSenders, category),
- priorityCallSenders, priorityMessagesSenders, mPolicy.suppressedVisualEffects,
+ priorityCallSenders, priorityMessagesSenders, mPolicy.suppressedVisualEffects,
mPolicy.priorityConversationSenders);
- if (ZenModeSettingsBase.DEBUG) Log.d(TAG, "onPrefChange allow" +
- stringCategory + "=" + allowSenders + " allow" + stringCategory + "From="
- + ZenModeConfig.sourceToString(allowSendersFrom));
+ if (ZenModeSettingsBase.DEBUG) {
+ Log.d(TAG, "onPrefChange allow"
+ + stringCategory + "=" + allowSenders + " allow" + stringCategory + "From="
+ + ZenModeConfig.sourceToString(allowSendersFrom));
+ }
}
protected void saveConversationSenders(int val) {
@@ -280,7 +282,7 @@
switch (contactType) {
case ZenPolicy.PEOPLE_TYPE_ANYONE:
return ZEN_MODE_FROM_ANYONE;
- case ZenPolicy.PEOPLE_TYPE_CONTACTS:
+ case ZenPolicy.PEOPLE_TYPE_CONTACTS:
return ZEN_MODE_FROM_CONTACTS;
case ZenPolicy.PEOPLE_TYPE_STARRED:
return ZEN_MODE_FROM_STARRED;
@@ -308,7 +310,7 @@
switch (setting) {
case ZenPolicy.PEOPLE_TYPE_ANYONE:
return NotificationManager.Policy.PRIORITY_SENDERS_ANY;
- case ZenPolicy.PEOPLE_TYPE_CONTACTS:
+ case ZenPolicy.PEOPLE_TYPE_CONTACTS:
return NotificationManager.Policy.PRIORITY_SENDERS_CONTACTS;
case ZenPolicy.PEOPLE_TYPE_STARRED:
return NotificationManager.Policy.PRIORITY_SENDERS_STARRED;
@@ -321,7 +323,7 @@
protected int getAlarmsTotalSilencePeopleSummary(int category) {
if (category == NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES) {
return R.string.zen_mode_none_messages;
- } else if (category == NotificationManager.Policy.PRIORITY_CATEGORY_CALLS){
+ } else if (category == NotificationManager.Policy.PRIORITY_CATEGORY_CALLS) {
return R.string.zen_mode_none_calls;
} else if (category == NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS) {
return R.string.zen_mode_from_no_conversations;
@@ -470,8 +472,8 @@
if (cursor != null && cursor.moveToFirst()) {
do {
String contact = cursor.getString(0);
- starredContacts.add(contact != null ? contact :
- mContext.getString(R.string.zen_mode_starred_contacts_empty_name));
+ int emptyNameId = R.string.zen_mode_starred_contacts_empty_name;
+ starredContacts.add(contact != null ? contact : mContext.getString(emptyNameId));
} while (cursor.moveToNext());
}
diff --git a/src/com/android/settings/notification/zen/ZenModeSliceBuilder.java b/src/com/android/settings/notification/zen/ZenModeSliceBuilder.java
index 4f6f058..d16b1e4 100644
--- a/src/com/android/settings/notification/zen/ZenModeSliceBuilder.java
+++ b/src/com/android/settings/notification/zen/ZenModeSliceBuilder.java
@@ -132,8 +132,8 @@
final Uri contentUri = new Uri.Builder().appendPath(ZEN_MODE_SLICE_KEY).build();
final String screenTitle = context.getText(R.string.zen_mode_settings_title).toString();
return SliceBuilderUtils.buildSearchResultPageIntent(context,
- ZenModeSettings.class.getName(), ZEN_MODE_SLICE_KEY, screenTitle,
- SettingsEnums.NOTIFICATION_ZEN_MODE, R.string.menu_key_notifications)
+ ZenModeSettings.class.getName(), ZEN_MODE_SLICE_KEY, screenTitle,
+ SettingsEnums.NOTIFICATION_ZEN_MODE, R.string.menu_key_notifications)
.setClassName(context.getPackageName(), SubSettings.class.getName())
.setData(contentUri);
}
diff --git a/src/com/android/settings/print/PrintSettingsPageProvider.kt b/src/com/android/settings/print/PrintSettingsPageProvider.kt
index aac0a5d..f28f0bc 100644
--- a/src/com/android/settings/print/PrintSettingsPageProvider.kt
+++ b/src/com/android/settings/print/PrintSettingsPageProvider.kt
@@ -17,16 +17,32 @@
package com.android.settings.print
import android.app.settings.SettingsEnums
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
import android.os.Bundle
+import android.provider.Settings
import androidx.annotation.VisibleForTesting
import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Add
+import androidx.compose.material.icons.outlined.Print
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.unit.dp
import androidx.core.os.bundleOf
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.settings.R
@@ -36,13 +52,18 @@
import com.android.settings.print.PrintSettingsFragment.EXTRA_SERVICE_COMPONENT_NAME
import com.android.settings.print.PrintSettingsFragment.EXTRA_TITLE
import com.android.settingslib.spa.framework.common.SettingsPageProvider
+import com.android.settingslib.spa.framework.compose.rememberContext
import com.android.settingslib.spa.framework.compose.rememberDrawablePainter
import com.android.settingslib.spa.framework.theme.SettingsDimension
+import com.android.settingslib.spa.framework.theme.SettingsOpacity
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
import com.android.settingslib.spa.widget.ui.Category
+import com.android.settingslib.spa.widget.ui.SettingsIcon
+import com.android.settingslib.spaprivileged.settingsprovider.settingsSecureStringFlow
import com.android.settingslib.spaprivileged.template.common.UserProfilePager
+import kotlinx.coroutines.flow.Flow
object PrintSettingsPageProvider : SettingsPageProvider {
override val name = "PrintSettings"
@@ -52,51 +73,101 @@
RegularScaffold(title = stringResource(R.string.print_settings)) {
val context = LocalContext.current
val printRepository = remember(context) { PrintRepository(context) }
- UserProfilePager {
- PrintServices(printRepository)
- }
+ UserProfilePager { PrintServices(printRepository) }
}
}
@Composable
private fun PrintServices(printRepository: PrintRepository) {
- val printServiceDisplayInfos by remember {
- printRepository.printServiceDisplayInfosFlow()
- }.collectAsStateWithLifecycle(initialValue = emptyList())
- Category(title = stringResource(R.string.print_settings_title)) {
- for (printServiceDisplayInfo in printServiceDisplayInfos) {
- PrintService(printServiceDisplayInfo)
+ val printServiceDisplayInfos by
+ remember { printRepository.printServiceDisplayInfosFlow() }
+ .collectAsStateWithLifecycle(initialValue = emptyList())
+ if (printServiceDisplayInfos.isEmpty()) {
+ NoServicesInstalled()
+ } else {
+ Category(title = stringResource(R.string.print_settings_title)) {
+ for (printServiceDisplayInfo in printServiceDisplayInfos) {
+ PrintService(printServiceDisplayInfo)
+ }
}
}
+ AddPrintService()
+ }
+
+ @Composable
+ private fun NoServicesInstalled() {
+ Column(
+ modifier = Modifier.fillMaxSize().padding(SettingsDimension.itemPaddingAround),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ Icon(
+ imageVector = Icons.Outlined.Print,
+ contentDescription = null,
+ modifier =
+ Modifier.size(110.dp)
+ .padding(SettingsDimension.itemPaddingAround)
+ .alpha(SettingsOpacity.SurfaceTone),
+ )
+ Text(
+ text = stringResource(R.string.print_no_services_installed),
+ style = MaterialTheme.typography.titleLarge,
+ )
+ }
}
@VisibleForTesting
@Composable
fun PrintService(displayInfo: PrintServiceDisplayInfo) {
val context = LocalContext.current
- Preference(model = object : PreferenceModel {
- override val title = displayInfo.title
- override val summary = { displayInfo.summary }
- override val icon: @Composable () -> Unit = {
- Image(
- painter = rememberDrawablePainter(displayInfo.icon),
- contentDescription = null,
- modifier = Modifier.size(SettingsDimension.appIconItemSize),
- )
- }
- override val onClick = {
- SubSettingLauncher(context).apply {
- setDestination(PrintServiceSettingsFragment::class.qualifiedName)
- setArguments(
- bundleOf(
- EXTRA_CHECKED to displayInfo.isEnabled,
- EXTRA_TITLE to displayInfo.title,
- EXTRA_SERVICE_COMPONENT_NAME to displayInfo.componentName
- )
+ Preference(
+ object : PreferenceModel {
+ override val title = displayInfo.title
+ override val summary = { displayInfo.summary }
+ override val icon: @Composable () -> Unit = {
+ Image(
+ painter = rememberDrawablePainter(displayInfo.icon),
+ contentDescription = null,
+ modifier = Modifier.size(SettingsDimension.appIconItemSize),
)
- setSourceMetricsCategory(SettingsEnums.PRINT_SETTINGS)
- }.launch()
+ }
+ override val onClick = { launchPrintServiceSettings(context, displayInfo) }
}
- })
+ )
+ }
+
+ private fun launchPrintServiceSettings(context: Context, displayInfo: PrintServiceDisplayInfo) {
+ SubSettingLauncher(context)
+ .apply {
+ setDestination(PrintServiceSettingsFragment::class.qualifiedName)
+ setArguments(
+ bundleOf(
+ EXTRA_CHECKED to displayInfo.isEnabled,
+ EXTRA_TITLE to displayInfo.title,
+ EXTRA_SERVICE_COMPONENT_NAME to displayInfo.componentName
+ )
+ )
+ setSourceMetricsCategory(SettingsEnums.PRINT_SETTINGS)
+ }
+ .launch()
+ }
+
+ @Composable
+ fun AddPrintService(
+ searchUriFlow: Flow<String> = rememberContext { context ->
+ context.settingsSecureStringFlow(Settings.Secure.PRINT_SERVICE_SEARCH_URI)
+ },
+ ) {
+ val context = LocalContext.current
+ val searchUri by searchUriFlow.collectAsStateWithLifecycle("")
+ if (searchUri.isEmpty()) return
+ Preference(
+ object : PreferenceModel {
+ override val title = stringResource(R.string.print_menu_item_add_service)
+ override val icon = @Composable { SettingsIcon(imageVector = Icons.Outlined.Add) }
+ override val onClick = {
+ context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(searchUri)))
+ }
+ }
+ )
}
}
diff --git a/src/com/android/settings/spa/network/AutomaticDataSwitchingPreference.kt b/src/com/android/settings/spa/network/AutomaticDataSwitchingPreference.kt
index e79be4a..e7cc18f 100644
--- a/src/com/android/settings/spa/network/AutomaticDataSwitchingPreference.kt
+++ b/src/com/android/settings/spa/network/AutomaticDataSwitchingPreference.kt
@@ -16,13 +16,11 @@
package com.android.settings.spa.network
-import android.telephony.TelephonyManager
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.viewmodel.compose.viewModel
import com.android.settings.R
-import com.android.settings.network.telephony.TelephonyRepository
import com.android.settings.network.telephony.wificalling.CrossSimCallingViewModel
import com.android.settingslib.spa.widget.preference.SwitchPreference
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
@@ -51,11 +49,3 @@
}
)
}
-
-fun TelephonyRepository.setAutomaticData(subId: Int, newEnabled: Boolean) {
- setMobileDataPolicyEnabled(
- subId = subId,
- policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
- enabled = newEnabled,
- )
-}
diff --git a/src/com/android/settings/spa/network/MobileDataSwitchingPreference.kt b/src/com/android/settings/spa/network/MobileDataSwitchingPreference.kt
index 0d40bca..4b95d44 100644
--- a/src/com/android/settings/spa/network/MobileDataSwitchingPreference.kt
+++ b/src/com/android/settings/spa/network/MobileDataSwitchingPreference.kt
@@ -16,12 +16,10 @@
package com.android.settings.spa.network
-import android.telephony.TelephonyManager
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.res.stringResource
import com.android.settings.R
-import com.android.settings.network.telephony.TelephonyRepository
import com.android.settingslib.spa.widget.preference.SwitchPreference
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
import kotlinx.coroutines.Dispatchers
diff --git a/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt b/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt
index 4b9fcf4..05a8f6a 100644
--- a/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt
+++ b/src/com/android/settings/spa/network/NetworkCellularGroupProvider.kt
@@ -48,13 +48,14 @@
import com.android.settings.R
import com.android.settings.network.SubscriptionInfoListViewModel
import com.android.settings.network.telephony.DataSubscriptionRepository
-import com.android.settings.network.telephony.TelephonyRepository
+import com.android.settings.network.telephony.MobileDataRepository
import com.android.settings.spa.network.PrimarySimRepository.PrimarySimInfo
import com.android.settings.wifi.WifiPickerTrackerHelper
import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
import com.android.settingslib.spa.framework.common.SettingsPageProvider
import com.android.settingslib.spa.framework.common.createSettingsPage
import com.android.settingslib.spa.framework.compose.navigator
+import com.android.settingslib.spa.framework.compose.rememberContext
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
import com.android.settingslib.spa.widget.preference.Preference
import com.android.settingslib.spa.widget.preference.PreferenceModel
@@ -202,21 +203,18 @@
) {
val context = LocalContext.current
val localLifecycleOwner = LocalLifecycleOwner.current
- val wifiPickerTrackerHelper = getWifiPickerTrackerHelper(context, localLifecycleOwner)
-
- val subscriptionManager: SubscriptionManager? =
- context.getSystemService(SubscriptionManager::class.java)
+ val mobileDataRepository = rememberContext(::MobileDataRepository)
Category(title = stringResource(id = R.string.mobile_data_settings_title)) {
val isAutoDataEnabled by remember(nonDds.intValue) {
- TelephonyRepository(context).isMobileDataPolicyEnabledFlow(
+ mobileDataRepository.isMobileDataPolicyEnabledFlow(
subId = nonDds.intValue,
policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH
)
}.collectAsStateWithLifecycle(initialValue = null)
val mobileDataStateChanged by remember(mobileDataSelectedId.intValue) {
- TelephonyRepository(context).isDataEnabledFlow(mobileDataSelectedId.intValue)
+ mobileDataRepository.isMobileDataEnabledFlow(mobileDataSelectedId.intValue)
}.collectAsStateWithLifecycle(initialValue = false)
val coroutineScope = rememberCoroutineScope()
@@ -226,8 +224,8 @@
coroutineScope.launch {
setMobileData(
context,
- subscriptionManager,
- wifiPickerTrackerHelper,
+ context.getSystemService(SubscriptionManager::class.java),
+ getWifiPickerTrackerHelper(context, localLifecycleOwner),
mobileDataSelectedId.intValue,
newEnabled
)
@@ -238,7 +236,7 @@
AutomaticDataSwitchingPreference(
isAutoDataEnabled = { isAutoDataEnabled },
setAutoDataEnabled = { newEnabled ->
- TelephonyRepository(context).setAutomaticData(nonDds.intValue, newEnabled)
+ mobileDataRepository.setAutoDataSwitch(nonDds.intValue, newEnabled)
},
)
}
@@ -426,6 +424,6 @@
Log.d(NetworkCellularGroupProvider.fileName, "setDefaultData: [$targetSubId]")
subscriptionManager?.setDefaultDataSubId(targetSubId)
}
- TelephonyRepository(context)
- .setMobileData(targetSubId, enabled, wifiPickerTrackerHelper)
+ MobileDataRepository(context)
+ .setMobileDataEnabled(targetSubId, enabled, wifiPickerTrackerHelper)
}
\ No newline at end of file
diff --git a/src/com/android/settings/users/UserDetailsSettings.java b/src/com/android/settings/users/UserDetailsSettings.java
index b48c717..71dd43f 100644
--- a/src/com/android/settings/users/UserDetailsSettings.java
+++ b/src/com/android/settings/users/UserDetailsSettings.java
@@ -363,13 +363,12 @@
}
if (mUserInfo.isMain() || mUserInfo.isGuest() || !UserManager.isMultipleAdminEnabled()
|| mUserManager.hasUserRestrictionForUser(UserManager.DISALLOW_GRANT_ADMIN,
- mUserInfo.getUserHandle())) {
+ mUserInfo.getUserHandle()) || !mUserManager.isAdminUser()) {
removePreference(KEY_GRANT_ADMIN);
}
if (!mUserManager.isAdminUser()) { // non admin users can't remove users and allow calls
removePreference(KEY_ENABLE_TELEPHONY);
removePreference(KEY_REMOVE_USER);
- removePreference(KEY_GRANT_ADMIN);
removePreference(KEY_APP_AND_CONTENT_ACCESS);
removePreference(KEY_APP_COPYING);
} else {
diff --git a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
index 82537d4..e5581d3 100644
--- a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
+++ b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
@@ -33,7 +33,6 @@
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsManager;
import android.telephony.ims.ImsMmTelManager;
-import android.telephony.ims.ProvisioningManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
@@ -42,12 +41,14 @@
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
+import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import androidx.preference.Preference.OnPreferenceClickListener;
import androidx.preference.PreferenceScreen;
-import com.android.ims.ImsConfig;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.flags.Flags;
@@ -57,8 +58,12 @@
import com.android.settings.Utils;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.network.ims.WifiCallingQueryImsState;
+import com.android.settings.network.telephony.wificalling.IWifiCallingRepository;
+import com.android.settings.network.telephony.wificalling.WifiCallingRepository;
import com.android.settings.widget.SettingsMainSwitchPreference;
+import kotlin.Unit;
+
import java.util.List;
/**
@@ -103,7 +108,6 @@
private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private ImsMmTelManager mImsMmTelManager;
- private ProvisioningManager mProvisioningManager;
private TelephonyManager mTelephonyManager;
private PhoneTelephonyCallback mTelephonyCallback;
@@ -188,19 +192,6 @@
return true;
};
- private final ProvisioningManager.Callback mProvisioningCallback =
- new ProvisioningManager.Callback() {
- @Override
- public void onProvisioningIntChanged(int item, int value) {
- if (item == ImsConfig.ConfigConstants.VOICE_OVER_WIFI_SETTING_ENABLED
- || item == ImsConfig.ConfigConstants.VLT_SETTING_ENABLED) {
- // The provisioning policy might have changed. Update the body to make sure
- // this change takes effect if needed.
- updateBody();
- }
- }
- };
-
@VisibleForTesting
void showAlert(Intent intent) {
final Context context = getActivity();
@@ -264,14 +255,6 @@
}
@VisibleForTesting
- ProvisioningManager getImsProvisioningManager() {
- if (!SubscriptionManager.isValidSubscriptionId(mSubId)) {
- return null;
- }
- return ProvisioningManager.createForSubscriptionId(mSubId);
- }
-
- @VisibleForTesting
ImsMmTelManager getImsMmTelManager() {
if (!SubscriptionManager.isValidSubscriptionId(mSubId)) {
return null;
@@ -294,7 +277,6 @@
FRAGMENT_BUNDLE_SUBID, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
}
- mProvisioningManager = getImsProvisioningManager();
mImsMmTelManager = getImsMmTelManager();
mSwitchBar = (SettingsMainSwitchPreference) findPreference(SWITCH_BAR);
@@ -336,19 +318,33 @@
return view;
}
+ @Override
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ getWifiCallingRepository().collectIsWifiCallingReadyFlow(
+ getLifecycleOwner(), (isWifiWifiCallingReadyFlow) -> {
+ if (!isWifiWifiCallingReadyFlow) {
+ // This screen is not allowed to be shown due to provisioning policy and
+ // should therefore be closed.
+ finish();
+ }
+ return Unit.INSTANCE;
+ });
+ }
+
@VisibleForTesting
- boolean isWfcProvisionedOnDevice() {
- return queryImsState(mSubId).isWifiCallingProvisioned();
+ @NonNull
+ IWifiCallingRepository getWifiCallingRepository() {
+ return new WifiCallingRepository(requireContext(), mSubId);
+ }
+
+ @VisibleForTesting
+ @NonNull
+ LifecycleOwner getLifecycleOwner() {
+ return getViewLifecycleOwner();
}
private void updateBody() {
- if (!isWfcProvisionedOnDevice()) {
- // This screen is not allowed to be shown due to provisioning policy and should
- // therefore be closed.
- finish();
- return;
- }
-
final CarrierConfigManager configManager = (CarrierConfigManager)
getSystemService(Context.CARRIER_CONFIG_SERVICE);
boolean isWifiOnlySupported = true;
@@ -448,8 +444,6 @@
if (intent.getBooleanExtra(Phone.EXTRA_KEY_ALERT_SHOW, false)) {
showAlert(intent);
}
- // Register callback for provisioning changes.
- registerProvisioningChangedCallback();
}
@Override
@@ -462,8 +456,6 @@
mSwitchBar.removeOnSwitchChangeListener(this);
}
context.unregisterReceiver(mIntentReceiver);
- // Remove callback for provisioning changes.
- unregisterProvisioningChangedCallback();
}
/**
@@ -699,27 +691,6 @@
return SubscriptionManager.getResourcesForSubId(getContext(), mSubId);
}
- @VisibleForTesting
- void registerProvisioningChangedCallback() {
- if (mProvisioningManager == null) {
- return;
- }
- try {
- mProvisioningManager.registerProvisioningChangedCallback(getContext().getMainExecutor(),
- mProvisioningCallback);
- } catch (Exception ex) {
- Log.w(TAG, "onResume: Unable to register callback for provisioning changes.");
- }
- }
-
- @VisibleForTesting
- void unregisterProvisioningChangedCallback() {
- if (mProvisioningManager == null) {
- return;
- }
- mProvisioningManager.unregisterProvisioningChangedCallback(mProvisioningCallback);
- }
-
/**
* Determine whether to override roaming Wi-Fi calling preference when device is connected to
* non-terrestrial network.
diff --git a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
index a7527d7..c7ad9ca 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java
@@ -35,6 +35,8 @@
import androidx.fragment.app.FragmentTransaction;
import com.android.settings.R;
+import com.android.settings.flags.Flags;
+import com.android.settings.overlay.FeatureFactory;
import java.util.List;
@@ -236,7 +238,12 @@
WifiDppUtils.TAG_FRAGMENT_QR_CODE_GENERATOR);
if (fragment == null) {
- fragment = new WifiDppQrCodeGeneratorFragment();
+ if (Flags.enableWifiSharingRuntimeFragment()) {
+ fragment = FeatureFactory.getFeatureFactory().getWifiFeatureProvider()
+ .getWifiDppQrCodeGeneratorFragment();
+ } else {
+ fragment = new WifiDppQrCodeGeneratorFragment();
+ }
} else {
if (fragment.isVisible()) {
return;
diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java
index 3d437e2..1213b0d 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java
@@ -56,7 +56,7 @@
private static final String TAG = "WifiDppQrCodeGeneratorFragment";
private ImageView mQrCodeView;
- private String mQrCode;
+ protected String mQrCode;
private static final String CHIP_LABEL_METADATA_KEY = "android.service.chooser.chip_label";
private static final String CHIP_ICON_METADATA_KEY = "android.service.chooser.chip_icon";
@@ -258,7 +258,7 @@
return button;
}
- private void setQrCode() {
+ protected void setQrCode() {
try {
final int qrcodeSize = getContext().getResources().getDimensionPixelSize(
R.dimen.qrcode_size);
diff --git a/src/com/android/settings/wifi/factory/WifiFeatureProvider.java b/src/com/android/settings/wifi/factory/WifiFeatureProvider.java
index 5ab899a..e5bf81a 100644
--- a/src/com/android/settings/wifi/factory/WifiFeatureProvider.java
+++ b/src/com/android/settings/wifi/factory/WifiFeatureProvider.java
@@ -27,6 +27,7 @@
import androidx.lifecycle.ViewModelStoreOwner;
import com.android.settings.wifi.details.WifiNetworkDetailsViewModel;
+import com.android.settings.wifi.dpp.WifiDppQrCodeGeneratorFragment;
import com.android.settings.wifi.repository.SharedConnectivityRepository;
import com.android.settings.wifi.repository.WifiHotspotRepository;
import com.android.settings.wifi.tether.WifiHotspotSecurityViewModel;
@@ -147,6 +148,15 @@
}
/**
+ * Gets an instance of WifiDppQrCodeGeneratorFragment
+ */
+ public WifiDppQrCodeGeneratorFragment getWifiDppQrCodeGeneratorFragment() {
+ WifiDppQrCodeGeneratorFragment fragment = new WifiDppQrCodeGeneratorFragment();
+ verboseLog(TAG, "getWifiDppQrCodeGeneratorFragment():" + fragment);
+ return fragment;
+ }
+
+ /**
* Send a {@link Log#VERBOSE} log message.
*
* @param tag Used to identify the source of a log message. It usually identifies
diff --git a/tests/Enable16KbTests/Android.bp b/tests/Enable16KbTests/Android.bp
index 781ea8f..fa05d33 100644
--- a/tests/Enable16KbTests/Android.bp
+++ b/tests/Enable16KbTests/Android.bp
@@ -33,7 +33,6 @@
],
platform_apis: true,
certificate: "platform",
- test_suites: ["device-tests"],
libs: [
"android.test.runner",
"android.test.base",
@@ -57,6 +56,6 @@
data: [
":test_16kb_app",
],
- test_suites: ["device-tests"],
+ test_suites: ["general-tests"],
test_config: "AndroidTest.xml",
}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioControllerTest.java
index d9a917b..24528ae 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsSpatialAudioControllerTest.java
@@ -21,26 +21,35 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
import android.media.AudioDeviceAttributes;
import android.media.AudioDeviceInfo;
import android.media.AudioManager;
import android.media.Spatializer;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import androidx.preference.PreferenceCategory;
import androidx.preference.TwoStatePreference;
import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settingslib.bluetooth.A2dpProfile;
+import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.LeAudioProfile;
import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.flags.Flags;
import com.google.common.collect.ImmutableList;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -54,7 +63,8 @@
@RunWith(RobolectricTestRunner.class)
public class BluetoothDetailsSpatialAudioControllerTest extends BluetoothDetailsControllerTestBase {
-
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C";
private static final String KEY_SPATIAL_AUDIO = "spatial_audio";
private static final String KEY_HEAD_TRACKING = "head_tracking";
@@ -64,6 +74,9 @@
@Mock private Lifecycle mSpatialAudioLifecycle;
@Mock private PreferenceCategory mProfilesContainer;
@Mock private BluetoothDevice mBluetoothDevice;
+ @Mock private A2dpProfile mA2dpProfile;
+ @Mock private LeAudioProfile mLeAudioProfile;
+ @Mock private HearingAidProfile mHearingAidProfile;
private AudioDeviceAttributes mAvailableDevice;
@@ -83,6 +96,12 @@
when(mAudioManager.getSpatializer()).thenReturn(mSpatializer);
when(mCachedDevice.getAddress()).thenReturn(MAC_ADDRESS);
when(mCachedDevice.getDevice()).thenReturn(mBluetoothDevice);
+ when(mCachedDevice.getProfiles())
+ .thenReturn(List.of(mA2dpProfile, mLeAudioProfile, mHearingAidProfile));
+ when(mA2dpProfile.isEnabled(mBluetoothDevice)).thenReturn(true);
+ when(mA2dpProfile.getProfileId()).thenReturn(BluetoothProfile.A2DP);
+ when(mLeAudioProfile.getProfileId()).thenReturn(BluetoothProfile.LE_AUDIO);
+ when(mHearingAidProfile.getProfileId()).thenReturn(BluetoothProfile.HEARING_AID);
when(mBluetoothDevice.getAnonymizedAddress()).thenReturn(MAC_ADDRESS);
when(mFeatureFactory.getBluetoothFeatureProvider().getSpatializer(mContext))
.thenReturn(mSpatializer);
@@ -273,6 +292,52 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_DETERMINING_SPATIAL_AUDIO_ATTRIBUTES_BY_PROFILE)
+ public void refresh_leAudioProfileEnabledForHeadset_useLeAudioHeadsetAttributes() {
+ when(mLeAudioProfile.isEnabled(mBluetoothDevice)).thenReturn(true);
+ when(mA2dpProfile.isEnabled(mBluetoothDevice)).thenReturn(false);
+ when(mHearingAidProfile.isEnabled(mBluetoothDevice)).thenReturn(false);
+ when(mAudioManager.getBluetoothAudioDeviceCategory(MAC_ADDRESS))
+ .thenReturn(AudioManager.AUDIO_DEVICE_CATEGORY_HEADPHONES);
+ when(mSpatializer.isAvailableForDevice(any())).thenReturn(true);
+
+ mController.refresh();
+ ShadowLooper.idleMainLooper();
+
+ assertThat(mController.mAudioDevice.getType()).isEqualTo(AudioDeviceInfo.TYPE_BLE_HEADSET);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DETERMINING_SPATIAL_AUDIO_ATTRIBUTES_BY_PROFILE)
+ public void refresh_leAudioProfileEnabledForSpeaker_useLeAudioSpeakerAttributes() {
+ when(mLeAudioProfile.isEnabled(mBluetoothDevice)).thenReturn(true);
+ when(mA2dpProfile.isEnabled(mBluetoothDevice)).thenReturn(false);
+ when(mHearingAidProfile.isEnabled(mBluetoothDevice)).thenReturn(false);
+ when(mAudioManager.getBluetoothAudioDeviceCategory(MAC_ADDRESS))
+ .thenReturn(AudioManager.AUDIO_DEVICE_CATEGORY_SPEAKER);
+ when(mSpatializer.isAvailableForDevice(any())).thenReturn(true);
+
+ mController.refresh();
+ ShadowLooper.idleMainLooper();
+
+ assertThat(mController.mAudioDevice.getType()).isEqualTo(AudioDeviceInfo.TYPE_BLE_SPEAKER);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DETERMINING_SPATIAL_AUDIO_ATTRIBUTES_BY_PROFILE)
+ public void refresh_hearingAidProfileEnabled_useHearingAidAttributes() {
+ when(mLeAudioProfile.isEnabled(mBluetoothDevice)).thenReturn(false);
+ when(mA2dpProfile.isEnabled(mBluetoothDevice)).thenReturn(false);
+ when(mHearingAidProfile.isEnabled(mBluetoothDevice)).thenReturn(true);
+ when(mSpatializer.isAvailableForDevice(any())).thenReturn(true);
+
+ mController.refresh();
+ ShadowLooper.idleMainLooper();
+
+ assertThat(mController.mAudioDevice.getType()).isEqualTo(AudioDeviceInfo.TYPE_HEARING_AID);
+ }
+
+ @Test
public void turnedOnSpatialAudio_invokesAddCompatibleAudioDevice() {
mController.setAvailableDevice(mAvailableDevice);
mSpatialAudioPref.setChecked(true);
diff --git a/tests/robotests/src/com/android/settings/notification/modes/IconLoaderTest.java b/tests/robotests/src/com/android/settings/notification/modes/IconLoaderTest.java
deleted file mode 100644
index 7d4a367..0000000
--- a/tests/robotests/src/com/android/settings/notification/modes/IconLoaderTest.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.notification.modes;
-
-import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.AutomaticZenRule;
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.service.notification.ZenPolicy;
-
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.MoreExecutors;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-@RunWith(RobolectricTestRunner.class)
-public class IconLoaderTest {
-
- private Context mContext;
- private IconLoader mLoader;
-
- @Before
- public void setUp() {
- mContext = RuntimeEnvironment.application;
- mLoader = new IconLoader(MoreExecutors.newDirectExecutorService());
- }
-
- @Test
- public void getIcon_systemOwnedRuleWithIcon_loads() throws Exception {
- AutomaticZenRule systemRule = newRuleBuilder()
- .setPackage("android")
- .setIconResId(android.R.drawable.ic_media_play)
- .build();
-
- ListenableFuture<Drawable> loadFuture = mLoader.getIcon(mContext, systemRule);
- assertThat(loadFuture.isDone()).isTrue();
- assertThat(loadFuture.get()).isNotNull();
- }
-
- @Test
- public void getIcon_ruleWithoutSpecificIcon_loadsFallback() throws Exception {
- AutomaticZenRule rule = newRuleBuilder()
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setPackage("com.blah")
- .build();
-
- ListenableFuture<Drawable> loadFuture = mLoader.getIcon(mContext, rule);
- assertThat(loadFuture.isDone()).isTrue();
- assertThat(loadFuture.get()).isNotNull();
- }
-
- @Test
- public void getIcon_ruleWithAppIconWithLoadFailure_loadsFallback() throws Exception {
- AutomaticZenRule rule = newRuleBuilder()
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setPackage("com.blah")
- .setIconResId(-123456)
- .build();
-
- ListenableFuture<Drawable> loadFuture = mLoader.getIcon(mContext, rule);
- assertThat(loadFuture.get()).isNotNull();
- }
-
- private static AutomaticZenRule.Builder newRuleBuilder() {
- return new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().build());
- }
-}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java
new file mode 100644
index 0000000..ff25322
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification.modes;
+
+import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL;
+import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
+import static android.service.notification.ZenPolicy.STATE_DISALLOW;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.app.Flags;
+import android.content.Context;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.service.notification.ZenPolicy;
+
+import androidx.preference.TwoStatePreference;
+
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+@EnableFlags(Flags.FLAG_MODES_UI)
+public final class InterruptionFilterPreferenceControllerTest {
+
+ private InterruptionFilterPreferenceController mController;
+
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
+ private Context mContext;
+ @Mock private ZenModesBackend mBackend;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = RuntimeEnvironment.application;
+ mController = new InterruptionFilterPreferenceController(mContext, "something", mBackend);
+ }
+
+ @Test
+ public void testUpdateState_all() {
+ TwoStatePreference preference = mock(TwoStatePreference.class);
+ ZenMode zenMode = new TestModeBuilder()
+ .setInterruptionFilter(INTERRUPTION_FILTER_ALL)
+ .build();
+ mController.updateZenMode(preference, zenMode);
+
+ verify(preference).setChecked(false);
+ }
+
+ @Test
+ public void testOnPreferenceChange_fromAll() {
+ TwoStatePreference preference = mock(TwoStatePreference.class);
+ ZenMode zenMode = new TestModeBuilder()
+ .setInterruptionFilter(INTERRUPTION_FILTER_ALL)
+ .build();
+
+ mController.updateZenMode(preference, zenMode);
+
+ mController.onPreferenceChange(preference, true);
+
+ ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
+ verify(mBackend).updateMode(captor.capture());
+ assertThat(captor.getValue().getPolicy().getPriorityCategoryAlarms())
+ .isEqualTo(STATE_DISALLOW);
+ assertThat(captor.getValue().getRule().getInterruptionFilter())
+ .isEqualTo(INTERRUPTION_FILTER_PRIORITY);
+ }
+
+ @Test
+ public void testUpdateState_priority() {
+ TwoStatePreference preference = mock(TwoStatePreference.class);
+ ZenMode zenMode = new TestModeBuilder()
+ .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ .setZenPolicy(new ZenPolicy.Builder().allowAlarms(true).build())
+ .build();
+ mController.updateZenMode(preference, zenMode);
+
+ verify(preference).setChecked(true);
+ }
+
+ @Test
+ public void testOnPreferenceChange_fromPriority() {
+ TwoStatePreference preference = mock(TwoStatePreference.class);
+ ZenMode zenMode = new TestModeBuilder()
+ .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ .setZenPolicy(new ZenPolicy.Builder().allowAlarms(false).build())
+ .build();
+
+ mController.updateZenMode(preference, zenMode);
+
+ mController.onPreferenceChange(preference, false);
+
+ ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
+ verify(mBackend).updateMode(captor.capture());
+ assertThat(captor.getValue().getPolicy().getPriorityCategoryAlarms())
+ .isEqualTo(STATE_DISALLOW);
+ assertThat(captor.getValue().getRule().getInterruptionFilter())
+ .isEqualTo(INTERRUPTION_FILTER_ALL);
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/notification/modes/TestModeBuilder.java b/tests/robotests/src/com/android/settings/notification/modes/TestModeBuilder.java
new file mode 100644
index 0000000..fa12b30
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/modes/TestModeBuilder.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification.modes;
+
+import android.app.AutomaticZenRule;
+import android.app.NotificationManager;
+import android.net.Uri;
+import android.service.notification.Condition;
+import android.service.notification.ZenDeviceEffects;
+import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenPolicy;
+
+import androidx.annotation.Nullable;
+
+import com.android.settingslib.notification.modes.ZenMode;
+
+import java.util.Random;
+
+class TestModeBuilder {
+
+ private String mId;
+ private AutomaticZenRule mRule;
+ private ZenModeConfig.ZenRule mConfigZenRule;
+
+ public static final ZenMode EXAMPLE = new TestModeBuilder().build();
+
+ TestModeBuilder() {
+ // Reasonable defaults
+ int id = new Random().nextInt(1000);
+ mId = "rule_" + id;
+ mRule = new AutomaticZenRule.Builder("Test Rule #" + id, Uri.parse("rule://" + id))
+ .setPackage("some_package")
+ .setInterruptionFilter(NotificationManager.INTERRUPTION_FILTER_PRIORITY)
+ .setZenPolicy(new ZenPolicy.Builder().disallowAllSounds().build())
+ .build();
+ mConfigZenRule = new ZenModeConfig.ZenRule();
+ mConfigZenRule.enabled = true;
+ mConfigZenRule.pkg = "some_package";
+ }
+
+ TestModeBuilder setId(String id) {
+ mId = id;
+ return this;
+ }
+
+ TestModeBuilder setAzr(AutomaticZenRule rule) {
+ mRule = rule;
+ mConfigZenRule.pkg = rule.getPackageName();
+ mConfigZenRule.conditionId = rule.getConditionId();
+ mConfigZenRule.enabled = rule.isEnabled();
+ return this;
+ }
+
+ TestModeBuilder setConfigZenRule(ZenModeConfig.ZenRule configZenRule) {
+ mConfigZenRule = configZenRule;
+ return this;
+ }
+
+ public TestModeBuilder setName(String name) {
+ mRule.setName(name);
+ mConfigZenRule.name = name;
+ return this;
+ }
+
+ public TestModeBuilder setPackage(String pkg) {
+ mRule.setPackageName(pkg);
+ mConfigZenRule.pkg = pkg;
+ return this;
+ }
+
+ TestModeBuilder setConditionId(Uri conditionId) {
+ mRule.setConditionId(conditionId);
+ mConfigZenRule.conditionId = conditionId;
+ return this;
+ }
+
+ TestModeBuilder setType(@AutomaticZenRule.Type int type) {
+ mRule.setType(type);
+ mConfigZenRule.type = type;
+ return this;
+ }
+
+ TestModeBuilder setInterruptionFilter(
+ @NotificationManager.InterruptionFilter int interruptionFilter) {
+ mRule.setInterruptionFilter(interruptionFilter);
+ mConfigZenRule.zenMode = NotificationManager.zenModeFromInterruptionFilter(
+ interruptionFilter, NotificationManager.INTERRUPTION_FILTER_PRIORITY);
+ return this;
+ }
+
+ TestModeBuilder setZenPolicy(@Nullable ZenPolicy policy) {
+ mRule.setZenPolicy(policy);
+ mConfigZenRule.zenPolicy = policy;
+ return this;
+ }
+
+ TestModeBuilder setDeviceEffects(@Nullable ZenDeviceEffects deviceEffects) {
+ mRule.setDeviceEffects(deviceEffects);
+ mConfigZenRule.zenDeviceEffects = deviceEffects;
+ return this;
+ }
+
+ public TestModeBuilder setEnabled(boolean enabled) {
+ mRule.setEnabled(enabled);
+ mConfigZenRule.enabled = enabled;
+ return this;
+ }
+
+ TestModeBuilder setManualInvocationAllowed(boolean allowed) {
+ mRule.setManualInvocationAllowed(allowed);
+ mConfigZenRule.allowManualInvocation = allowed;
+ return this;
+ }
+
+ public TestModeBuilder setTriggerDescription(@Nullable String triggerDescription) {
+ mRule.setTriggerDescription(triggerDescription);
+ mConfigZenRule.triggerDescription = triggerDescription;
+ return this;
+ }
+
+ TestModeBuilder setActive(boolean active) {
+ if (active) {
+ mConfigZenRule.enabled = true;
+ mConfigZenRule.condition = new Condition(mRule.getConditionId(), "...",
+ Condition.STATE_TRUE);
+ } else {
+ mConfigZenRule.condition = null;
+ }
+ return this;
+ }
+
+ ZenMode build() {
+ return new ZenMode(mId, mRule, mConfigZenRule);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceControllerTest.java
index 8205f3a..83f8de0 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsLinkPreferenceControllerTest.java
@@ -17,23 +17,21 @@
package com.android.settings.notification.modes;
import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
-
-import static com.android.settings.notification.modes.ZenModeFragmentBase.MODE_ID;
+import static android.provider.Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.AutomaticZenRule;
import android.app.Flags;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
-import android.net.Uri;
import android.os.Bundle;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
@@ -45,6 +43,8 @@
import com.android.settings.SettingsActivity;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.widget.SelectorWithWidgetPreference;
import org.junit.Before;
@@ -101,14 +101,13 @@
}
private ZenMode createPriorityChannelsZenMode() {
- return new ZenMode("id", new AutomaticZenRule.Builder("Bedtime",
- Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
+ return new TestModeBuilder()
+ .setId("id")
.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
.setZenPolicy(new ZenPolicy.Builder()
.allowChannels(ZenPolicy.CHANNEL_POLICY_PRIORITY)
.build())
- .build(), true);
+ .build();
}
@Test
@@ -137,7 +136,7 @@
Bundle bundle = launcherIntent.getBundleExtra(
SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS);
assertThat(bundle).isNotNull();
- assertThat(bundle.getString(MODE_ID)).isEqualTo("id");
+ assertThat(bundle.getString(EXTRA_AUTOMATIC_ZEN_RULE_ID)).isEqualTo("id");
}
@Test
@@ -180,13 +179,30 @@
@Test
public void testOnPackageListChangedTriggersRebuild() {
- mController.mAppSessionCallbacks.onPackageListChanged();
+ SelectorWithWidgetPreference preference = mock(SelectorWithWidgetPreference.class);
+ // Create a zen mode that allows priority channels to breakthrough.
+ ZenMode zenMode = createPriorityChannelsZenMode();
+ mController.updateState(preference, zenMode);
verify(mSession).rebuild(any(), any(), eq(false));
+
+ mController.mAppSessionCallbacks.onPackageListChanged();
+ verify(mSession, times(2)).rebuild(any(), any(), eq(false));
}
@Test
public void testOnLoadEntriesCompletedTriggersRebuild() {
- mController.mAppSessionCallbacks.onLoadEntriesCompleted();
+ SelectorWithWidgetPreference preference = mock(SelectorWithWidgetPreference.class);
+ // Create a zen mode that allows priority channels to breakthrough.
+ ZenMode zenMode = createPriorityChannelsZenMode();
+ mController.updateState(preference, zenMode);
verify(mSession).rebuild(any(), any(), eq(false));
+
+ mController.mAppSessionCallbacks.onLoadEntriesCompleted();
+ verify(mSession, times(2)).rebuild(any(), any(), eq(false));
+ }
+
+ @Test
+ public void testNoCrashIfAppsReadyBeforeRuleAvailable() {
+ mController.mAppSessionCallbacks.onLoadEntriesCompleted();
}
}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsPreferenceControllerTest.java
index 750453d..c96dbb6 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsPreferenceControllerTest.java
@@ -16,11 +16,8 @@
package com.android.settings.notification.modes;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE;
import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
-import static com.android.settings.notification.modes.ZenModeAppsPreferenceController.KEY_ALL;
import static com.android.settings.notification.modes.ZenModeAppsPreferenceController.KEY_NONE;
import static com.android.settings.notification.modes.ZenModeAppsPreferenceController.KEY_PRIORITY;
@@ -29,10 +26,8 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import android.app.AutomaticZenRule;
import android.app.Flags;
import android.content.Context;
-import android.net.Uri;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.ZenPolicy;
@@ -42,6 +37,8 @@
import androidx.preference.PreferenceScreen;
import androidx.preference.TwoStatePreference;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.widget.SelectorWithWidgetPreference;
import org.junit.Before;
@@ -62,11 +59,9 @@
@Mock
private ZenModesBackend mBackend;
private ZenModeAppsPreferenceController mPriorityController;
- private ZenModeAppsPreferenceController mAllController;
private ZenModeAppsPreferenceController mNoneController;
private SelectorWithWidgetPreference mPriorityPref;
- private SelectorWithWidgetPreference mAllPref;
private SelectorWithWidgetPreference mNonePref;
private PreferenceCategory mPrefCategory;
private PreferenceScreen mPreferenceScreen;
@@ -81,10 +76,8 @@
mPriorityController = new ZenModeAppsPreferenceController(mContext, KEY_PRIORITY, mBackend);
mNoneController = new ZenModeAppsPreferenceController(mContext, KEY_NONE, mBackend);
- mAllController = new ZenModeAppsPreferenceController(mContext, KEY_ALL, mBackend);
mPriorityPref = makePreference(KEY_PRIORITY, mPriorityController);
- mAllPref = makePreference(KEY_ALL, mAllController);
mNonePref = makePreference(KEY_NONE, mNoneController);
mPrefCategory = new PreferenceCategory(mContext);
@@ -95,10 +88,8 @@
mPreferenceScreen.addPreference(mPrefCategory);
mPrefCategory.addPreference(mPriorityPref);
- mPrefCategory.addPreference(mAllPref);
mPrefCategory.addPreference(mNonePref);
- mAllController.displayPreference(mPreferenceScreen);
mPriorityController.displayPreference(mPreferenceScreen);
mNoneController.displayPreference(mPreferenceScreen);
}
@@ -112,45 +103,14 @@
}
@Test
- public void testUpdateState_All() {
- TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setZenPolicy(new ZenPolicy.Builder()
- .allowChannels(ZenMode.CHANNEL_POLICY_ALL)
- .build())
- .build(), true);
- mAllController.updateZenMode(preference, zenMode);
-
- verify(preference).setChecked(true);
- }
-
- @Test
- public void testUpdateState_All_Unchecked() {
- TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setZenPolicy(new ZenPolicy.Builder()
- .allowChannels(ZenPolicy.CHANNEL_POLICY_NONE)
- .build())
- .build(), true);
- mAllController.updateZenMode(preference, zenMode);
-
- verify(preference).setChecked(false);
- }
-
- @Test
public void testUpdateState_None() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setZenPolicy(new ZenPolicy.Builder()
- .allowChannels(ZenPolicy.CHANNEL_POLICY_NONE)
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder()
+ .allowChannels(ZenPolicy.CHANNEL_POLICY_NONE)
+ .build())
+ .build();
+
mNoneController.updateZenMode(preference, zenMode);
verify(preference).setChecked(true);
@@ -159,13 +119,12 @@
@Test
public void testUpdateState_None_Unchecked() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setZenPolicy(new ZenPolicy.Builder()
- .allowChannels(ZenMode.CHANNEL_POLICY_ALL)
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder()
+ .allowChannels(ZenPolicy.CHANNEL_POLICY_PRIORITY)
+ .build())
+ .build();
+
mNoneController.updateZenMode(preference, zenMode);
verify(preference).setChecked(false);
@@ -174,13 +133,12 @@
@Test
public void testUpdateState_Priority() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setZenPolicy(new ZenPolicy.Builder()
- .allowChannels(ZenPolicy.CHANNEL_POLICY_PRIORITY)
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder()
+ .allowChannels(ZenPolicy.CHANNEL_POLICY_PRIORITY)
+ .build())
+ .build();
+
mPriorityController.updateZenMode(preference, zenMode);
verify(preference).setChecked(true);
@@ -189,99 +147,32 @@
@Test
public void testUpdateState_Priority_Unchecked() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setZenPolicy(new ZenPolicy.Builder()
- .allowChannels(ZenPolicy.CHANNEL_POLICY_NONE)
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder()
+ .allowChannels(ZenPolicy.CHANNEL_POLICY_NONE)
+ .build())
+ .build();
+
mPriorityController.updateZenMode(preference, zenMode);
verify(preference).setChecked(false);
}
@Test
- public void testOnPreferenceChange_All() {
- TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_NONE)
- .setZenPolicy(new ZenPolicy.Builder()
- .allowChannels(ZenMode.CHANNEL_POLICY_ALL)
- .build())
- .build(), true);
-
- mAllController.updateZenMode(preference, zenMode);
- mAllController.onPreferenceChange(preference, true);
- ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
- verify(mBackend).updateMode(captor.capture());
-
- assertThat(captor.getValue().getPolicy().getAllowedChannels())
- .isEqualTo(ZenMode.CHANNEL_POLICY_ALL);
- }
-
- @Test
- public void testPreferenceClick_passesCorrectCheckedState_All() {
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setZenPolicy(new ZenPolicy.Builder()
- .allowChannels(ZenPolicy.CHANNEL_POLICY_NONE)
- .build())
- .build(), true);
-
-
- mAllController.updateZenMode(mAllPref, zenMode);
- mNoneController.updateZenMode(mNonePref, zenMode);
- mPriorityController.updateZenMode(mPriorityPref, zenMode);
-
- // MPME is checked; ALL and PRIORITY are unchecked.
- assertThat(((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_NONE))
- .isChecked());
- assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_ALL))
- .isChecked());
- assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_PRIORITY))
- .isChecked());
-
- mPrefCategory.findPreference(KEY_ALL).performClick();
-
- ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
- verify(mBackend).updateMode(captor.capture());
- // Checks the policy value for ALL is set.
- // The important part is that the interruption filter is propagated to the backend.
- assertThat(captor.getValue().getRule().getInterruptionFilter())
- .isEqualTo(INTERRUPTION_FILTER_ALL);
- // ALL is now checked; others are unchecked.
- assertThat(((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_ALL))
- .isChecked());
- assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_NONE))
- .isChecked());
- assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_PRIORITY))
- .isChecked());
- }
-
- @Test
public void testPreferenceClick_passesCorrectCheckedState_None() {
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setZenPolicy(new ZenPolicy.Builder()
- .allowChannels(ZenPolicy.CHANNEL_POLICY_PRIORITY)
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder()
+ .allowChannels(ZenPolicy.CHANNEL_POLICY_PRIORITY)
+ .build())
+ .build();
- mAllController.updateZenMode(mAllPref, zenMode);
mNoneController.updateZenMode(mNonePref, zenMode);
mPriorityController.updateZenMode(mPriorityPref, zenMode);
- assertThat(((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_ALL))
- .isChecked());
- assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_NONE))
- .isChecked());
- assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_PRIORITY))
- .isChecked());
+ assertThat(((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_NONE))
+ .isChecked()).isFalse();
+ assertThat(((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_PRIORITY))
+ .isChecked()).isTrue();
// Click on NONE
mPrefCategory.findPreference(KEY_NONE).performClick();
@@ -293,35 +184,31 @@
// See AbstractZenModePreferenceController.
assertThat(captor.getValue().getRule().getInterruptionFilter())
.isEqualTo(INTERRUPTION_FILTER_PRIORITY);
- // NONE is now checked; others are unchecked.
+
+ // After screen is refreshed, NONE is now checked; others are unchecked.
+ mNoneController.updateZenMode(mNonePref, captor.getValue());
+ mPriorityController.updateZenMode(mPriorityPref, captor.getValue());
assertThat(((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_NONE))
- .isChecked());
- assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_ALL))
- .isChecked());
- assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_PRIORITY))
- .isChecked());
+ .isChecked()).isTrue();
+ assertThat(((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_PRIORITY))
+ .isChecked()).isFalse();
}
@Test
public void testPreferenceClick_passesCorrectCheckedState_Priority() {
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setZenPolicy(new ZenPolicy.Builder()
- .allowChannels(ZenPolicy.CHANNEL_POLICY_NONE)
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder()
+ .allowChannels(ZenPolicy.CHANNEL_POLICY_NONE)
+ .build())
+ .build();
- mAllController.updateZenMode(mAllPref, zenMode);
mNoneController.updateZenMode(mNonePref, zenMode);
mPriorityController.updateZenMode(mPriorityPref, zenMode);
assertThat(((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_NONE))
- .isChecked());
- assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_ALL))
- .isChecked());
- assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_PRIORITY))
- .isChecked());
+ .isChecked()).isTrue();
+ assertThat(((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_PRIORITY))
+ .isChecked()).isFalse();
// Click on PRIORITY
mPrefCategory.findPreference(KEY_PRIORITY).performClick();
@@ -331,13 +218,13 @@
// Checks the policy value for PRIORITY is propagated to the backend.
assertThat(captor.getValue().getRule().getInterruptionFilter())
.isEqualTo(INTERRUPTION_FILTER_PRIORITY);
- // PRIORITY is now checked; others are unchecked.
- assertThat(((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_PRIORITY))
- .isChecked());
- assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_ALL))
- .isChecked());
- assertThat(!((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_NONE))
- .isChecked());
- }
+ // After screen is refreshed, PRIORITY is now checked; others are unchecked.
+ mNoneController.updateZenMode(mNonePref, captor.getValue());
+ mPriorityController.updateZenMode(mPriorityPref, captor.getValue());
+ assertThat(((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_PRIORITY))
+ .isChecked()).isTrue();
+ assertThat(((SelectorWithWidgetPreference) mPrefCategory.findPreference(KEY_NONE))
+ .isChecked()).isFalse();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeButtonPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeButtonPreferenceControllerTest.java
index bda3843..625f231 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeButtonPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeButtonPreferenceControllerTest.java
@@ -16,8 +16,6 @@
package com.android.settings.notification.modes;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
-
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -25,15 +23,14 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.AutomaticZenRule;
import android.app.Flags;
import android.content.Context;
-import android.net.Uri;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
-import android.service.notification.ZenPolicy;
import android.widget.Button;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.widget.LayoutPreference;
import org.junit.Before;
@@ -71,43 +68,34 @@
@Test
public void isAvailable_notIfAppOptsOut() {
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build())
+ ZenMode zenMode = new TestModeBuilder()
.setManualInvocationAllowed(false)
- .setEnabled(true)
- .build(), false);
+ .build();
mController.setZenMode(zenMode);
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void isAvailable_notIfModeDisabled() {
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build())
- .setManualInvocationAllowed(true)
- .setEnabled(false)
- .build(), false);
+ ZenMode zenMode = new TestModeBuilder()
+ .setManualInvocationAllowed(true)
+ .setEnabled(false)
+ .build();
+
mController.setZenMode(zenMode);
+
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void isAvailable_appOptedIn_modeEnabled() {
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build())
- .setManualInvocationAllowed(true)
- .setEnabled(true)
- .build(), false);
+ ZenMode zenMode = new TestModeBuilder()
+ .setManualInvocationAllowed(true)
+ .setEnabled(true)
+ .build();
+
mController.setZenMode(zenMode);
+
assertThat(mController.isAvailable()).isTrue();
}
@@ -116,15 +104,13 @@
Button button = new Button(mContext);
LayoutPreference pref = mock(LayoutPreference.class);
when(pref.findViewById(anyInt())).thenReturn(button);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build())
- .setManualInvocationAllowed(true)
- .setEnabled(true)
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setManualInvocationAllowed(true)
+ .setActive(true)
+ .build();
+
mController.updateZenMode(pref, zenMode);
+
assertThat(button.getText().toString()).contains("off");
assertThat(button.hasOnClickListeners()).isTrue();
}
@@ -134,15 +120,13 @@
Button button = new Button(mContext);
LayoutPreference pref = mock(LayoutPreference.class);
when(pref.findViewById(anyInt())).thenReturn(button);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build())
- .setManualInvocationAllowed(true)
- .setEnabled(true)
- .build(), false);
+ ZenMode zenMode = new TestModeBuilder()
+ .setManualInvocationAllowed(true)
+ .setActive(false)
+ .build();
+
mController.updateZenMode(pref, zenMode);
+
assertThat(button.getText().toString()).contains("on");
assertThat(button.hasOnClickListeners()).isTrue();
}
@@ -152,14 +136,11 @@
Button button = new Button(mContext);
LayoutPreference pref = mock(LayoutPreference.class);
when(pref.findViewById(anyInt())).thenReturn(button);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build())
- .setManualInvocationAllowed(true)
- .setEnabled(true)
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setManualInvocationAllowed(true)
+ .setActive(true)
+ .build();
+
mController.updateZenMode(pref, zenMode);
button.callOnClick();
@@ -171,14 +152,11 @@
Button button = new Button(mContext);
LayoutPreference pref = mock(LayoutPreference.class);
when(pref.findViewById(anyInt())).thenReturn(button);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build())
- .setManualInvocationAllowed(true)
- .setEnabled(true)
- .build(), false);
+ ZenMode zenMode = new TestModeBuilder()
+ .setManualInvocationAllowed(true)
+ .setActive(false)
+ .build();
+
mController.updateZenMode(pref, zenMode);
button.callOnClick();
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeCallsLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeCallsLinkPreferenceControllerTest.java
index 94c2d8a..058b2d7 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeCallsLinkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeCallsLinkPreferenceControllerTest.java
@@ -16,22 +16,19 @@
package com.android.settings.notification.modes;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
-
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import android.app.AutomaticZenRule;
import android.app.Flags;
import android.content.Context;
-import android.net.Uri;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
-import android.service.notification.ZenPolicy;
import androidx.preference.Preference;
+import com.android.settingslib.notification.modes.ZenModesBackend;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -67,13 +64,7 @@
@EnableFlags(Flags.FLAG_MODES_UI)
public void testHasSummary() {
Preference pref = mock(Preference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build())
- .build(), true);
- mController.updateZenMode(pref, zenMode);
+ mController.updateZenMode(pref, TestModeBuilder.EXAMPLE);
verify(pref).setSummary(any());
}
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayEffectPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayEffectPreferenceControllerTest.java
index 1a62b75..a735cd9 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayEffectPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayEffectPreferenceControllerTest.java
@@ -16,22 +16,22 @@
package com.android.settings.notification.modes;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
-import static android.service.notification.ZenPolicy.STATE_ALLOW;
-import static android.service.notification.ZenPolicy.STATE_UNSET;
import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import android.app.AutomaticZenRule;
import android.app.Flags;
import android.content.Context;
-import android.net.Uri;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.ZenDeviceEffects;
-import android.service.notification.ZenPolicy;
+
import androidx.preference.TwoStatePreference;
+
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -62,15 +62,11 @@
@Test
public void testUpdateState_grayscale() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAlarms(true).build())
- .setDeviceEffects(new ZenDeviceEffects.Builder()
- .setShouldDisplayGrayscale(true)
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setDeviceEffects(new ZenDeviceEffects.Builder()
+ .setShouldDisplayGrayscale(true)
+ .build())
+ .build();
ZenModeDisplayEffectPreferenceController controller =
new ZenModeDisplayEffectPreferenceController(
@@ -84,15 +80,11 @@
@Test
public void testOnPreferenceChange_grayscale() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAlarms(false).build())
- .setDeviceEffects(new ZenDeviceEffects.Builder()
- .setShouldDisplayGrayscale(true)
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setDeviceEffects(new ZenDeviceEffects.Builder()
+ .setShouldDisplayGrayscale(true)
+ .build())
+ .build();
ZenModeDisplayEffectPreferenceController controller =
new ZenModeDisplayEffectPreferenceController(mContext, "effect_greyscale", mBackend);
@@ -103,22 +95,18 @@
ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
verify(mBackend).updateMode(captor.capture());
- assertThat(captor.getValue().getRule().getDeviceEffects().shouldDisplayGrayscale())
+ assertThat(captor.getValue().getDeviceEffects().shouldDisplayGrayscale())
.isFalse();
}
@Test
public void testUpdateState_aod() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowMedia(true).build())
- .setDeviceEffects(new ZenDeviceEffects.Builder()
- .setShouldSuppressAmbientDisplay(true)
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setDeviceEffects(new ZenDeviceEffects.Builder()
+ .setShouldSuppressAmbientDisplay(true)
+ .build())
+ .build();
ZenModeDisplayEffectPreferenceController controller =
new ZenModeDisplayEffectPreferenceController(mContext, "effect_aod", mBackend);
@@ -131,15 +119,11 @@
@Test
public void testOnPreferenceChange_aod() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowMedia(false).build())
- .setDeviceEffects(new ZenDeviceEffects.Builder()
- .setShouldSuppressAmbientDisplay(true)
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setDeviceEffects(new ZenDeviceEffects.Builder()
+ .setShouldSuppressAmbientDisplay(true)
+ .build())
+ .build();
ZenModeDisplayEffectPreferenceController controller =
new ZenModeDisplayEffectPreferenceController(mContext, "effect_aod", mBackend);
@@ -150,22 +134,18 @@
ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
verify(mBackend).updateMode(captor.capture());
- assertThat(captor.getValue().getRule().getDeviceEffects().shouldSuppressAmbientDisplay())
+ assertThat(captor.getValue().getDeviceEffects().shouldSuppressAmbientDisplay())
.isFalse();
}
@Test
public void testUpdateState_wallpaper() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowSystem(true).build())
- .setDeviceEffects(new ZenDeviceEffects.Builder()
- .setShouldDimWallpaper(true)
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setDeviceEffects(new ZenDeviceEffects.Builder()
+ .setShouldDimWallpaper(true)
+ .build())
+ .build();
ZenModeDisplayEffectPreferenceController controller =
new ZenModeDisplayEffectPreferenceController(
@@ -179,15 +159,11 @@
@Test
public void testOnPreferenceChange_wallpaper() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowSystem(false).build())
- .setDeviceEffects(new ZenDeviceEffects.Builder()
- .setShouldDimWallpaper(true)
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setDeviceEffects(new ZenDeviceEffects.Builder()
+ .setShouldDimWallpaper(true)
+ .build())
+ .build();
ZenModeDisplayEffectPreferenceController controller =
new ZenModeDisplayEffectPreferenceController(
@@ -199,21 +175,17 @@
ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
verify(mBackend).updateMode(captor.capture());
- assertThat(captor.getValue().getRule().getDeviceEffects().shouldDimWallpaper()).isFalse();
+ assertThat(captor.getValue().getDeviceEffects().shouldDimWallpaper()).isFalse();
}
@Test
public void testUpdateState_darkTheme() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowReminders(true).build())
- .setDeviceEffects(new ZenDeviceEffects.Builder()
- .setShouldUseNightMode(true)
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setDeviceEffects(new ZenDeviceEffects.Builder()
+ .setShouldUseNightMode(true)
+ .build())
+ .build();
ZenModeDisplayEffectPreferenceController controller =
new ZenModeDisplayEffectPreferenceController(mContext, "effect_dark_theme",
@@ -227,15 +199,11 @@
@Test
public void testOnPreferenceChange_darkTheme() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowReminders(false).build())
- .setDeviceEffects(new ZenDeviceEffects.Builder()
- .setShouldUseNightMode(true)
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setDeviceEffects(new ZenDeviceEffects.Builder()
+ .setShouldUseNightMode(true)
+ .build())
+ .build();
ZenModeDisplayEffectPreferenceController controller =
new ZenModeDisplayEffectPreferenceController(mContext, "effect_dark_theme",
@@ -247,6 +215,6 @@
ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
verify(mBackend).updateMode(captor.capture());
- assertThat(captor.getValue().getRule().getDeviceEffects().shouldUseNightMode()).isFalse();
+ assertThat(captor.getValue().getDeviceEffects().shouldUseNightMode()).isFalse();
}
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceControllerTest.java
index 62aa046..3ccfb9f 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeDisplayLinkPreferenceControllerTest.java
@@ -16,22 +16,19 @@
package com.android.settings.notification.modes;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
-
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import android.app.AutomaticZenRule;
import android.app.Flags;
import android.content.Context;
-import android.net.Uri;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
-import android.service.notification.ZenPolicy;
import androidx.preference.Preference;
+import com.android.settingslib.notification.modes.ZenModesBackend;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -67,13 +64,7 @@
@EnableFlags(Flags.FLAG_MODES_UI)
public void testHasSummary() {
Preference pref = mock(Preference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build())
- .build(), true);
- mController.updateZenMode(pref, zenMode);
+ mController.updateZenMode(pref, TestModeBuilder.EXAMPLE);
verify(pref).setSummary(any());
}
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceControllerTest.java
index c1c4d61..03c75fb 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceControllerTest.java
@@ -21,13 +21,15 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import android.app.AutomaticZenRule;
import android.content.Context;
import android.service.notification.ZenModeConfig;
import androidx.preference.TwoStatePreference;
import androidx.test.core.app.ApplicationProvider;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -65,10 +67,9 @@
scheduleInfo.endHour = 2;
scheduleInfo.exitAtAlarm = false;
- ZenMode mode = new ZenMode("id",
- new AutomaticZenRule.Builder("name",
- ZenModeConfig.toScheduleConditionId(scheduleInfo)).build(),
- true); // is active
+ ZenMode mode = new TestModeBuilder()
+ .setConditionId(ZenModeConfig.toScheduleConditionId(scheduleInfo))
+ .build();
// need to call updateZenMode for the first call
mPrefController.updateZenMode(preference, mode);
@@ -94,10 +95,9 @@
scheduleInfo.endHour = 2;
scheduleInfo.exitAtAlarm = true;
- ZenMode mode = new ZenMode("id",
- new AutomaticZenRule.Builder("name",
- ZenModeConfig.toScheduleConditionId(scheduleInfo)).build(),
- true); // is active
+ ZenMode mode = new TestModeBuilder()
+ .setConditionId(ZenModeConfig.toScheduleConditionId(scheduleInfo))
+ .build();
mPrefController.updateZenMode(preference, mode);
// turn off exit at alarm
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeIconPickerListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeIconPickerListPreferenceControllerTest.java
index ba9a6b8..5db7e92 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeIconPickerListPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeIconPickerListPreferenceControllerTest.java
@@ -23,9 +23,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.AutomaticZenRule;
import android.content.Context;
-import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.preference.PreferenceScreen;
@@ -33,6 +31,8 @@
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.widget.LayoutPreference;
import com.google.common.collect.ImmutableList;
@@ -47,10 +47,7 @@
@RunWith(RobolectricTestRunner.class)
public class ZenModeIconPickerListPreferenceControllerTest {
- private static final ZenMode ZEN_MODE = new ZenMode(
- "mode_id",
- new AutomaticZenRule.Builder("mode name", Uri.parse("mode")).build(),
- /* isActive= */ false);
+ private static final ZenMode ZEN_MODE = TestModeBuilder.EXAMPLE;
private ZenModesBackend mBackend;
private ZenModeIconPickerListPreferenceController mController;
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeMessagesLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeMessagesLinkPreferenceControllerTest.java
index 9400f83..288359a 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeMessagesLinkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeMessagesLinkPreferenceControllerTest.java
@@ -16,22 +16,19 @@
package com.android.settings.notification.modes;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
-
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import android.app.AutomaticZenRule;
import android.app.Flags;
import android.content.Context;
-import android.net.Uri;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
-import android.service.notification.ZenPolicy;
import androidx.preference.Preference;
+import com.android.settingslib.notification.modes.ZenModesBackend;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -67,13 +64,7 @@
@EnableFlags(Flags.FLAG_MODES_UI)
public void testHasSummary() {
Preference pref = mock(Preference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build())
- .build(), true);
- mController.updateZenMode(pref, zenMode);
+ mController.updateZenMode(pref, TestModeBuilder.EXAMPLE);
verify(pref).setSummary(any());
}
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeNotifVisLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeNotifVisLinkPreferenceControllerTest.java
index 00a9fbe..ee7340b 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeNotifVisLinkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeNotifVisLinkPreferenceControllerTest.java
@@ -16,22 +16,19 @@
package com.android.settings.notification.modes;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
-
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import android.app.AutomaticZenRule;
import android.app.Flags;
import android.content.Context;
-import android.net.Uri;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
-import android.service.notification.ZenPolicy;
import androidx.preference.Preference;
+import com.android.settingslib.notification.modes.ZenModesBackend;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -67,13 +64,7 @@
@EnableFlags(Flags.FLAG_MODES_UI)
public void testHasSummary() {
Preference pref = mock(Preference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build())
- .build(), true);
- mController.updateZenMode(pref, zenMode);
+ mController.updateZenMode(pref, TestModeBuilder.EXAMPLE);
verify(pref).setSummary(any());
}
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeNotifVisPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeNotifVisPreferenceControllerTest.java
index 54edaf4..b23d946 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeNotifVisPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeNotifVisPreferenceControllerTest.java
@@ -16,7 +16,6 @@
package com.android.settings.notification.modes;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
import static android.service.notification.ZenPolicy.STATE_ALLOW;
import static android.service.notification.ZenPolicy.STATE_DISALLOW;
import static android.service.notification.ZenPolicy.VISUAL_EFFECT_LIGHTS;
@@ -32,17 +31,18 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.AutomaticZenRule;
import android.app.Flags;
import android.content.Context;
import android.content.res.Resources;
-import android.net.Uri;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.ZenPolicy;
import androidx.preference.TwoStatePreference;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -96,15 +96,12 @@
@Test
public void updateState_notChecked() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder()
- .allowAlarms(true)
- .showAllVisualEffects()
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder()
+ .allowAlarms(true)
+ .showAllVisualEffects()
+ .build())
+ .build();
mController.updateZenMode(preference, zenMode);
@@ -115,15 +112,12 @@
@Test
public void updateState_checked() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder()
- .allowAlarms(true)
- .showVisualEffect(VISUAL_EFFECT_PEEK, false)
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder()
+ .allowAlarms(true)
+ .showVisualEffect(VISUAL_EFFECT_PEEK, false)
+ .build())
+ .build();
mController.updateZenMode(preference, zenMode);
@@ -138,16 +132,13 @@
"zen_effect_status", VISUAL_EFFECT_STATUS_BAR,
new int[]{VISUAL_EFFECT_NOTIFICATION_LIST}, mBackend);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder()
- .allowAlarms(true)
- .showVisualEffect(VISUAL_EFFECT_NOTIFICATION_LIST, false)
- .showVisualEffect(VISUAL_EFFECT_STATUS_BAR, true)
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder()
+ .allowAlarms(true)
+ .showVisualEffect(VISUAL_EFFECT_NOTIFICATION_LIST, false)
+ .showVisualEffect(VISUAL_EFFECT_STATUS_BAR, true)
+ .build())
+ .build();
mController.updateZenMode(preference, zenMode);
@@ -168,15 +159,12 @@
"zen_effect_status", VISUAL_EFFECT_STATUS_BAR,
new int[]{VISUAL_EFFECT_NOTIFICATION_LIST}, mBackend);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder()
- .allowAlarms(true)
- .showAllVisualEffects()
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder()
+ .allowAlarms(true)
+ .showAllVisualEffects()
+ .build())
+ .build();
mController.updateZenMode(preference, zenMode);
@@ -188,15 +176,12 @@
@Test
public void onPreferenceChanged_checkedFalse() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder()
- .allowAlarms(true)
- .hideAllVisualEffects()
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder()
+ .allowAlarms(true)
+ .hideAllVisualEffects()
+ .build())
+ .build();
mController.updateZenMode(preference, zenMode);
@@ -213,15 +198,12 @@
@Test
public void onPreferenceChanged_checkedTrue() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder()
- .allowAlarms(true)
- .showAllVisualEffects()
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder()
+ .allowAlarms(true)
+ .showAllVisualEffects()
+ .build())
+ .build();
mController.updateZenMode(preference, zenMode);
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceControllerTest.java
index 699762e..c4d03fe 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeOtherLinkPreferenceControllerTest.java
@@ -16,22 +16,19 @@
package com.android.settings.notification.modes;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
-
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import android.app.AutomaticZenRule;
import android.app.Flags;
import android.content.Context;
-import android.net.Uri;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
-import android.service.notification.ZenPolicy;
import androidx.preference.Preference;
+import com.android.settingslib.notification.modes.ZenModesBackend;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -68,13 +65,7 @@
@EnableFlags(Flags.FLAG_MODES_UI)
public void testHasSummary() {
Preference pref = mock(Preference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build())
- .build(), true);
- mController.updateZenMode(pref, zenMode);
+ mController.updateZenMode(pref, TestModeBuilder.EXAMPLE);
verify(pref).setSummary(any());
}
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeOtherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeOtherPreferenceControllerTest.java
index 4a4a6e4..c69a8a0 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeOtherPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeOtherPreferenceControllerTest.java
@@ -16,7 +16,6 @@
package com.android.settings.notification.modes;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
import static android.service.notification.ZenPolicy.STATE_ALLOW;
import static android.service.notification.ZenPolicy.STATE_UNSET;
@@ -25,16 +24,17 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import android.app.AutomaticZenRule;
import android.app.Flags;
import android.content.Context;
-import android.net.Uri;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.ZenPolicy;
import androidx.preference.TwoStatePreference;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -65,12 +65,9 @@
@Test
public void testUpdateState_alarms() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAlarms(true).build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder().allowAlarms(true).build())
+ .build();
ZenModeOtherPreferenceController controller =
new ZenModeOtherPreferenceController(mContext, "modes_category_alarm", mBackend);
@@ -83,12 +80,9 @@
@Test
public void testOnPreferenceChange_alarms() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAlarms(false).build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder().allowAlarms(false).build())
+ .build();
ZenModeOtherPreferenceController controller =
new ZenModeOtherPreferenceController(mContext, "modes_category_alarm", mBackend);
@@ -108,12 +102,9 @@
@Test
public void testUpdateState_media() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowMedia(true).build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder().allowMedia(true).build())
+ .build();
ZenModeOtherPreferenceController controller =
new ZenModeOtherPreferenceController(mContext, "modes_category_media", mBackend);
@@ -126,12 +117,9 @@
@Test
public void testOnPreferenceChange_media() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowMedia(false).build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder().allowMedia(false).build())
+ .build();
ZenModeOtherPreferenceController controller =
new ZenModeOtherPreferenceController(mContext, "modes_category_media", mBackend);
@@ -151,12 +139,9 @@
@Test
public void testUpdateState_system() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowSystem(true).build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder().allowSystem(true).build())
+ .build();
ZenModeOtherPreferenceController controller =
new ZenModeOtherPreferenceController(mContext, "modes_category_system", mBackend);
@@ -169,12 +154,9 @@
@Test
public void testOnPreferenceChange_system() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowSystem(false).build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder().allowSystem(false).build())
+ .build();
ZenModeOtherPreferenceController controller =
new ZenModeOtherPreferenceController(mContext, "modes_category_system", mBackend);
@@ -194,12 +176,9 @@
@Test
public void testUpdateState_reminders() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowReminders(true).build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder().allowReminders(true).build())
+ .build();
ZenModeOtherPreferenceController controller =
new ZenModeOtherPreferenceController(mContext, "modes_category_reminders",
@@ -213,12 +192,9 @@
@Test
public void testOnPreferenceChange_reminders() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowReminders(false).build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder().allowReminders(false).build())
+ .build();
ZenModeOtherPreferenceController controller =
new ZenModeOtherPreferenceController(mContext, "modes_category_reminders",
@@ -239,12 +215,9 @@
@Test
public void testUpdateState_events() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowEvents(true).build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder().allowEvents(true).build())
+ .build();
ZenModeOtherPreferenceController controller =
new ZenModeOtherPreferenceController(mContext, "modes_category_events", mBackend);
@@ -257,12 +230,9 @@
@Test
public void testOnPreferenceChange_events() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowEvents(false).build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder().allowEvents(false).build())
+ .build();
ZenModeOtherPreferenceController controller =
new ZenModeOtherPreferenceController(mContext, "modes_category_events", mBackend);
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceControllerTest.java
index a331318..6591b72 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModePeopleLinkPreferenceControllerTest.java
@@ -16,22 +16,19 @@
package com.android.settings.notification.modes;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
-
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import android.app.AutomaticZenRule;
import android.app.Flags;
import android.content.Context;
-import android.net.Uri;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
-import android.service.notification.ZenPolicy;
import androidx.preference.Preference;
+import com.android.settingslib.notification.modes.ZenModesBackend;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -69,13 +66,7 @@
@EnableFlags(Flags.FLAG_MODES_UI)
public void testHasSummary() {
Preference pref = mock(Preference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build())
- .build(), true);
- mController.updateZenMode(pref, zenMode);
+ mController.updateZenMode(pref, TestModeBuilder.EXAMPLE);
verify(pref).setSummary(any());
}
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModePrioritySendersPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModePrioritySendersPreferenceControllerTest.java
index 709af43..04df27e 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModePrioritySendersPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModePrioritySendersPreferenceControllerTest.java
@@ -16,7 +16,6 @@
package com.android.settings.notification.modes;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_ANYONE;
import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_IMPORTANT;
import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_NONE;
@@ -40,11 +39,9 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.AutomaticZenRule;
import android.app.Flags;
import android.content.Context;
import android.database.Cursor;
-import android.net.Uri;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.ZenPolicy;
@@ -54,6 +51,8 @@
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.widget.SelectorWithWidgetPreference;
import org.junit.Before;
@@ -439,20 +438,17 @@
@Test
public void testPreferenceClick_passesCorrectCheckedState_startingUnchecked_messages() {
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder()
- .disallowAllSounds()
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder()
+ .disallowAllSounds()
+ .build())
+ .build();
mMessagesController.displayPreference(mPreferenceScreen);
mMessagesController.updateZenMode(mMessagesPrefCategory, zenMode);
assertThat(((SelectorWithWidgetPreference) mMessagesPrefCategory.findPreference(KEY_NONE))
- .isChecked());
+ .isChecked()).isTrue();
mMessagesPrefCategory.findPreference(KEY_STARRED).performClick();
@@ -464,14 +460,11 @@
@Test
public void testPreferenceClick_passesCorrectCheckedState_startingChecked_messages() {
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder()
- .allowAllSounds()
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder()
+ .allowAllSounds()
+ .build())
+ .build();
mMessagesController.displayPreference(mPreferenceScreen);
mMessagesController.updateZenMode(mMessagesPrefCategory, zenMode);
@@ -490,14 +483,11 @@
@Test
public void testPreferenceClick_passesCorrectCheckedState_startingUnchecked_calls() {
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder()
- .disallowAllSounds()
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder()
+ .disallowAllSounds()
+ .build())
+ .build();
mCallsController.displayPreference(mPreferenceScreen);
mCallsController.updateZenMode(mCallsPrefCategory, zenMode);
@@ -515,14 +505,11 @@
@Test
public void testPreferenceClick_passesCorrectCheckedState_startingChecked_calls() {
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder()
- .disallowAllSounds()
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder()
+ .disallowAllSounds()
+ .build())
+ .build();
mCallsController.displayPreference(mPreferenceScreen);
mCallsController.updateZenMode(mCallsPrefCategory, zenMode);
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeRepeatCallersPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeRepeatCallersPreferenceControllerTest.java
index 7bbb042..c1b99e5 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeRepeatCallersPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeRepeatCallersPreferenceControllerTest.java
@@ -16,24 +16,27 @@
package com.android.settings.notification.modes;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
import static android.service.notification.ZenPolicy.PEOPLE_TYPE_ANYONE;
import static android.service.notification.ZenPolicy.PEOPLE_TYPE_STARRED;
-import static android.service.notification.ZenPolicy.STATE_ALLOW;
import static android.service.notification.ZenPolicy.STATE_DISALLOW;
import static android.service.notification.ZenPolicy.STATE_UNSET;
+
import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import android.app.AutomaticZenRule;
import android.app.Flags;
import android.content.Context;
-import android.net.Uri;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.ZenPolicy;
+
import androidx.preference.TwoStatePreference;
+
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -64,14 +67,11 @@
@Test
public void testUpdateState_allCalls() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder()
- .allowCalls(PEOPLE_TYPE_ANYONE)
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder()
+ .allowCalls(PEOPLE_TYPE_ANYONE)
+ .build())
+ .build();
ZenModeRepeatCallersPreferenceController controller =
new ZenModeRepeatCallersPreferenceController(mContext, "repeat", mBackend, 1);
@@ -85,15 +85,12 @@
@Test
public void testUpdateState_someCalls() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder()
- .allowCalls(PEOPLE_TYPE_STARRED)
- .allowRepeatCallers(true)
- .build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder()
+ .allowCalls(PEOPLE_TYPE_STARRED)
+ .allowRepeatCallers(true)
+ .build())
+ .build();
ZenModeRepeatCallersPreferenceController controller =
new ZenModeRepeatCallersPreferenceController(mContext, "repeat", mBackend, 1);
@@ -107,12 +104,9 @@
@Test
public void testOnPreferenceChange() {
TwoStatePreference preference = mock(TwoStatePreference.class);
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowRepeatCallers(true).build())
- .build(), true);
+ ZenMode zenMode = new TestModeBuilder()
+ .setZenPolicy(new ZenPolicy.Builder().allowRepeatCallers(true).build())
+ .build();
ZenModeRepeatCallersPreferenceController controller =
new ZenModeRepeatCallersPreferenceController(mContext, "repeat", mBackend, 1);
@@ -130,4 +124,4 @@
assertThat(captor.getValue().getPolicy().getPriorityCallSenders())
.isEqualTo(STATE_UNSET);
}
-}
\ No newline at end of file
+}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceControllerTest.java
index 6b24fa2..cc6a497 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceControllerTest.java
@@ -28,18 +28,20 @@
import static org.mockito.Mockito.when;
-import android.app.AutomaticZenRule;
import android.app.Flags;
import android.content.Context;
-import android.net.Uri;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
+import android.service.notification.SystemZenRules;
import android.service.notification.ZenModeConfig;
import androidx.preference.DropDownPreference;
import androidx.preference.PreferenceCategory;
import androidx.test.core.app.ApplicationProvider;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -84,9 +86,9 @@
@Test
@EnableFlags({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI})
public void updateEventMode_updatesConditionAndTriggerDescription() {
- ZenMode mode = new ZenMode("id",
- new AutomaticZenRule.Builder("name", Uri.parse("condition")).build(),
- true); // is active
+ ZenMode mode = new TestModeBuilder()
+ .setPackage(SystemZenRules.PACKAGE_ANDROID)
+ .build();
// Explicitly update preference controller with mode info first, which will also call
// updateState()
@@ -99,6 +101,7 @@
// apply event mode updater to existing mode
ZenMode out = mPrefController.updateEventMode(eventInfo).apply(mode);
+ assertThat(out.getRule().getOwner()).isEqualTo(ZenModeConfig.getEventConditionProvider());
assertThat(out.getRule().getConditionId()).isEqualTo(
ZenModeConfig.toEventConditionId(eventInfo));
assertThat(out.getRule().getTriggerDescription()).isEqualTo("My events");
@@ -111,10 +114,9 @@
eventInfo.calName = "Definitely A Calendar";
eventInfo.reply = REPLY_YES;
- ZenMode mode = new ZenMode("id",
- new AutomaticZenRule.Builder("name",
- ZenModeConfig.toEventConditionId(eventInfo)).build(),
- true); // is active
+ ZenMode mode = new TestModeBuilder()
+ .setConditionId(ZenModeConfig.toEventConditionId(eventInfo))
+ .build();
mPrefController.updateZenMode(mPrefCategory, mode);
// We should see mCalendar, mReply have their values set
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceControllerTest.java
index 7cf327c..7dbc802 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceControllerTest.java
@@ -23,12 +23,11 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.AutomaticZenRule;
import android.app.Flags;
import android.content.Context;
-import android.net.Uri;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
+import android.service.notification.SystemZenRules;
import android.service.notification.ZenModeConfig;
import android.view.ViewGroup;
import android.widget.ToggleButton;
@@ -37,6 +36,8 @@
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import org.junit.Before;
import org.junit.Rule;
@@ -80,9 +81,9 @@
@Test
@EnableFlags({Flags.FLAG_MODES_API, Flags.FLAG_MODES_UI})
public void updateScheduleRule_updatesConditionAndTriggerDescription() {
- ZenMode mode = new ZenMode("id",
- new AutomaticZenRule.Builder("name", Uri.parse("condition")).build(),
- true); // is active
+ ZenMode mode = new TestModeBuilder()
+ .setPackage(SystemZenRules.PACKAGE_ANDROID)
+ .build();
ZenModeConfig.ScheduleInfo scheduleInfo = new ZenModeConfig.ScheduleInfo();
scheduleInfo.days = new int[] { Calendar.MONDAY };
@@ -93,6 +94,8 @@
assertThat(out.getRule().getConditionId())
.isEqualTo(ZenModeConfig.toScheduleConditionId(scheduleInfo));
assertThat(out.getRule().getTriggerDescription()).isNotEmpty();
+ assertThat(out.getRule().getOwner()).isEqualTo(
+ ZenModeConfig.getScheduleConditionProvider());
}
@Test
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceControllerTest.java
index 91de4ea..31959e5 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceControllerTest.java
@@ -16,6 +16,7 @@
package com.android.settings.notification.modes;
+import static android.app.AutomaticZenRule.TYPE_OTHER;
import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR;
import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
@@ -31,19 +32,21 @@
import android.app.AutomaticZenRule;
import android.app.Flags;
import android.content.Context;
-import android.content.Intent;
import android.net.Uri;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
+import android.service.notification.SystemZenRules;
import android.service.notification.ZenModeConfig;
-import android.service.notification.ZenPolicy;
import androidx.preference.PreferenceCategory;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
+import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.PrimarySwitchPreference;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import org.junit.Before;
import org.junit.Rule;
@@ -57,6 +60,7 @@
import java.util.Calendar;
@RunWith(RobolectricTestRunner.class)
+@EnableFlags(Flags.FLAG_MODES_UI)
public class ZenModeSetTriggerLinkPreferenceControllerTest {
@Rule
public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
@@ -65,10 +69,13 @@
private ZenModesBackend mBackend;
private Context mContext;
+ private PrimarySwitchPreference mPreference;
+
@Mock
private PreferenceCategory mPrefCategory;
@Mock
- private PrimarySwitchPreference mPreference;
+ private DashboardFragment mFragment;
+
private ZenModeSetTriggerLinkPreferenceController mPrefController;
@Before
@@ -77,12 +84,12 @@
mContext = ApplicationProvider.getApplicationContext();
mPrefController = new ZenModeSetTriggerLinkPreferenceController(mContext,
- "zen_automatic_trigger_category", mBackend);
+ "zen_automatic_trigger_category", mFragment, mBackend);
+ mPreference = new PrimarySwitchPreference(mContext);
when(mPrefCategory.findPreference(AUTOMATIC_TRIGGER_PREF_KEY)).thenReturn(mPreference);
}
@Test
- @EnableFlags(Flags.FLAG_MODES_UI)
public void testIsAvailable() {
// should not be available for manual DND
ZenMode manualMode = ZenMode.manualDndMode(new AutomaticZenRule.Builder("Do Not Disturb",
@@ -94,46 +101,27 @@
assertThat(mPrefController.isAvailable()).isFalse();
// should be available for other modes
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAlarms(true).build())
- .setEnabled(false)
- .build(), false);
- mPrefController.updateZenMode(mPrefCategory, zenMode);
+ mPrefController.updateZenMode(mPrefCategory, TestModeBuilder.EXAMPLE);
assertThat(mPrefController.isAvailable()).isTrue();
}
@Test
public void testUpdateState() {
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAlarms(true).build())
- .setEnabled(false)
- .build(), false);
+ ZenMode zenMode = new TestModeBuilder().setEnabled(false).build();
// Update preference controller with a zen mode that is not enabled
mPrefController.updateZenMode(mPrefCategory, zenMode);
- verify(mPreference).setChecked(false);
+ assertThat(mPreference.getCheckedState()).isFalse();
// Now with the rule enabled
zenMode.getRule().setEnabled(true);
mPrefController.updateZenMode(mPrefCategory, zenMode);
- verify(mPreference).setChecked(true);
+ assertThat(mPreference.getCheckedState()).isTrue();
}
@Test
public void testOnPreferenceChange() {
- ZenMode zenMode = new ZenMode("id",
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAlarms(true).build())
- .setEnabled(false)
- .build(), false);
+ ZenMode zenMode = new TestModeBuilder().setEnabled(false).build();
// start with disabled rule
mPrefController.updateZenMode(mPrefCategory, zenMode);
@@ -152,23 +140,25 @@
ZenModeConfig.EventInfo eventInfo = new ZenModeConfig.EventInfo();
eventInfo.calendarId = 1L;
eventInfo.calName = "My events";
- ZenMode mode = new ZenMode("id", new AutomaticZenRule.Builder("name",
- ZenModeConfig.toEventConditionId(eventInfo))
+ ZenMode mode = new TestModeBuilder()
+ .setPackage(SystemZenRules.PACKAGE_ANDROID)
+ .setConditionId(ZenModeConfig.toEventConditionId(eventInfo))
.setType(TYPE_SCHEDULE_CALENDAR)
.setTriggerDescription("My events")
- .build(),
- true); // is active
+ .build();
mPrefController.updateZenMode(mPrefCategory, mode);
- verify(mPreference).setTitle(R.string.zen_mode_set_calendar_link);
- verify(mPreference).setSummary(mode.getRule().getTriggerDescription());
+ assertThat(mPreference.getTitle()).isNotNull();
+ assertThat(mPreference.getTitle().toString()).isEqualTo(
+ mContext.getString(R.string.zen_mode_set_calendar_link));
+ assertThat(mPreference.getSummary()).isNotNull();
+ assertThat(mPreference.getSummary().toString()).isEqualTo(
+ mode.getRule().getTriggerDescription());
+ assertThat(mPreference.getIcon()).isNull();
- ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
- verify(mPreference).setIntent(captor.capture());
// Destination as written into the intent by SubSettingLauncher
- assertThat(
- captor.getValue().getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)).isEqualTo(
- ZenModeSetCalendarFragment.class.getName());
+ assertThat(mPreference.getIntent().getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
+ .isEqualTo(ZenModeSetCalendarFragment.class.getName());
}
@Test
@@ -177,22 +167,74 @@
scheduleInfo.days = new int[] { Calendar.MONDAY, Calendar.TUESDAY, Calendar.THURSDAY };
scheduleInfo.startHour = 1;
scheduleInfo.endHour = 15;
- ZenMode mode = new ZenMode("id", new AutomaticZenRule.Builder("name",
- ZenModeConfig.toScheduleConditionId(scheduleInfo))
+ ZenMode mode = new TestModeBuilder()
+ .setConditionId(ZenModeConfig.toScheduleConditionId(scheduleInfo))
+ .setPackage(SystemZenRules.PACKAGE_ANDROID)
.setType(TYPE_SCHEDULE_TIME)
.setTriggerDescription("some schedule")
- .build(),
- true); // is active
+ .build();
mPrefController.updateZenMode(mPrefCategory, mode);
- verify(mPreference).setTitle(R.string.zen_mode_set_schedule_link);
- verify(mPreference).setSummary(mode.getRule().getTriggerDescription());
+ assertThat(mPreference.getTitle()).isNotNull();
+ assertThat(mPreference.getTitle().toString()).isEqualTo(
+ mContext.getString(R.string.zen_mode_set_schedule_link));
+ assertThat(mPreference.getSummary()).isNotNull();
+ assertThat(mPreference.getSummary().toString()).isEqualTo(
+ mode.getRule().getTriggerDescription());
+ assertThat(mPreference.getIcon()).isNull();
- ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
- verify(mPreference).setIntent(captor.capture());
// Destination as written into the intent by SubSettingLauncher
- assertThat(
- captor.getValue().getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)).isEqualTo(
- ZenModeSetScheduleFragment.class.getName());
+ assertThat(mPreference.getIntent().getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
+ .isEqualTo(ZenModeSetScheduleFragment.class.getName());
+ }
+
+ @Test
+ public void testRuleLink_manual() {
+ ZenMode mode = new TestModeBuilder()
+ .setConditionId(ZenModeConfig.toCustomManualConditionId())
+ .setPackage(SystemZenRules.PACKAGE_ANDROID)
+ .setType(TYPE_OTHER)
+ .setTriggerDescription("Will not be shown")
+ .build();
+ mPrefController.updateZenMode(mPrefCategory, mode);
+
+ assertThat(mPreference.getTitle()).isNotNull();
+ assertThat(mPreference.getTitle().toString()).isEqualTo(
+ mContext.getString(R.string.zen_mode_select_schedule));
+ assertThat(mPreference.getIcon()).isNotNull();
+ assertThat(mPreference.getSummary()).isNotNull();
+ assertThat(mPreference.getSummary().toString()).isEqualTo("");
+
+ // Set up a click listener to open the dialog.
+ assertThat(mPreference.getOnPreferenceClickListener()).isNotNull();
+ }
+
+ @Test
+ public void onScheduleChosen_updatesMode() {
+ ZenMode originalMode = new TestModeBuilder()
+ .setConditionId(ZenModeConfig.toCustomManualConditionId())
+ .setPackage(SystemZenRules.PACKAGE_ANDROID)
+ .setType(TYPE_OTHER)
+ .setTriggerDescription("")
+ .build();
+ mPrefController.updateZenMode(mPrefCategory, originalMode);
+
+ ZenModeConfig.ScheduleInfo scheduleInfo = new ZenModeConfig.ScheduleInfo();
+ scheduleInfo.days = new int[] { Calendar.MONDAY };
+ scheduleInfo.startHour = 12;
+ scheduleInfo.endHour = 15;
+ Uri scheduleUri = ZenModeConfig.toScheduleConditionId(scheduleInfo);
+
+ mPrefController.mOnScheduleOptionListener.onScheduleSelected(scheduleUri);
+
+ // verify the backend got asked to update the mode to be schedule-based.
+ ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
+ verify(mBackend).updateMode(captor.capture());
+ ZenMode updatedMode = captor.getValue();
+ assertThat(updatedMode.getType()).isEqualTo(TYPE_SCHEDULE_TIME);
+ assertThat(updatedMode.getRule().getConditionId()).isEqualTo(scheduleUri);
+ assertThat(updatedMode.getRule().getTriggerDescription()).isNotEmpty();
+ assertThat(updatedMode.getRule().getOwner()).isEqualTo(
+ ZenModeConfig.getScheduleConditionProvider());
}
}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTest.java
deleted file mode 100644
index 0528621..0000000
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTest.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.notification.modes;
-
-import static android.app.NotificationManager.INTERRUPTION_FILTER_ALARMS;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_ALL;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_NONE;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.AutomaticZenRule;
-import android.net.Uri;
-import android.service.notification.ZenPolicy;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-@RunWith(RobolectricTestRunner.class)
-public class ZenModeTest {
-
- private static final ZenPolicy ZEN_POLICY = new ZenPolicy.Builder().allowAllSounds().build();
-
- private static final AutomaticZenRule ZEN_RULE =
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(ZEN_POLICY)
- .build();
-
- @Test
- public void testBasicMethods() {
- ZenMode zenMode = new ZenMode("id", ZEN_RULE, true);
-
- assertThat(zenMode.getId()).isEqualTo("id");
- assertThat(zenMode.getRule()).isEqualTo(ZEN_RULE);
- assertThat(zenMode.isManualDnd()).isFalse();
- assertThat(zenMode.canBeDeleted()).isTrue();
- assertThat(zenMode.isActive()).isTrue();
-
- ZenMode manualMode = ZenMode.manualDndMode(ZEN_RULE, false);
- assertThat(manualMode.getId()).isEqualTo(ZenMode.MANUAL_DND_MODE_ID);
- assertThat(manualMode.isManualDnd()).isTrue();
- assertThat(manualMode.canBeDeleted()).isFalse();
- assertThat(manualMode.isActive()).isFalse();
- }
-
- @Test
- public void getPolicy_interruptionFilterPriority_returnsZenPolicy() {
- ZenMode zenMode = new ZenMode("id", new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(ZEN_POLICY)
- .build(), false);
-
- assertThat(zenMode.getPolicy()).isEqualTo(ZEN_POLICY);
- }
-
- @Test
- public void getPolicy_interruptionFilterAll_returnsPolicyAllowingAll() {
- ZenMode zenMode = new ZenMode("id", new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
- .setInterruptionFilter(INTERRUPTION_FILTER_ALL)
- .setZenPolicy(ZEN_POLICY) // should be ignored
- .build(), false);
-
- assertThat(zenMode.getPolicy()).isEqualTo(
- new ZenPolicy.Builder().allowChannels(ZenMode.CHANNEL_POLICY_ALL)
- .allowAllSounds().showAllVisualEffects().build());
- }
-
- @Test
- public void getPolicy_interruptionFilterAlarms_returnsPolicyAllowingAlarms() {
- ZenMode zenMode = new ZenMode("id", new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
- .setInterruptionFilter(INTERRUPTION_FILTER_ALARMS)
- .setZenPolicy(ZEN_POLICY) // should be ignored
- .build(), false);
-
- assertThat(zenMode.getPolicy()).isEqualTo(
- new ZenPolicy.Builder()
- .disallowAllSounds()
- .allowAlarms(true)
- .allowMedia(true)
- .allowPriorityChannels(false)
- .build());
- }
-
- @Test
- public void getPolicy_interruptionFilterNone_returnsPolicyAllowingNothing() {
- ZenMode zenMode = new ZenMode("id", new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
- .setInterruptionFilter(INTERRUPTION_FILTER_NONE)
- .setZenPolicy(ZEN_POLICY) // should be ignored
- .build(), false);
-
- assertThat(zenMode.getPolicy()).isEqualTo(
- new ZenPolicy.Builder()
- .disallowAllSounds()
- .hideAllVisualEffects()
- .allowPriorityChannels(false)
- .build());
- }
-
- @Test
- public void setPolicy_setsInterruptionFilterPriority() {
- ZenMode zenMode = new ZenMode("id", new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
- .setInterruptionFilter(INTERRUPTION_FILTER_ALARMS)
- .build(), false);
-
- zenMode.setPolicy(ZEN_POLICY);
-
- assertThat(zenMode.getRule().getInterruptionFilter()).isEqualTo(
- INTERRUPTION_FILTER_PRIORITY);
- assertThat(zenMode.getPolicy()).isEqualTo(ZEN_POLICY);
- assertThat(zenMode.getRule().getZenPolicy()).isEqualTo(ZEN_POLICY);
- }
-
- @Test
- public void setPolicy_withAllChannelsAllowed_setsInterruptionFilterAll() {
- ZenMode zenMode = new ZenMode("id", new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
- .setInterruptionFilter(INTERRUPTION_FILTER_ALARMS)
- .setZenPolicy(ZEN_POLICY)
- .build(), false);
-
- zenMode.setPolicy(
- new ZenPolicy.Builder().allowChannels(ZenMode.CHANNEL_POLICY_ALL).build());
-
- assertThat(zenMode.getRule().getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_ALL);
- assertThat(zenMode.getPolicy()).isEqualTo(
- new ZenPolicy.Builder().allowChannels(ZenMode.CHANNEL_POLICY_ALL)
- .allowAllSounds().showAllVisualEffects().build());
- }
-
- @Test
- public void setPolicy_priorityToAllChannelsAndBack_restoresOldPolicy() {
- ZenMode zenMode = new ZenMode("id", new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(ZEN_POLICY)
- .build(), false);
-
- zenMode.setPolicy(
- new ZenPolicy.Builder().allowChannels(ZenMode.CHANNEL_POLICY_ALL).build());
- assertThat(zenMode.getRule().getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_ALL);
- assertThat(zenMode.getPolicy()).isEqualTo(
- new ZenPolicy.Builder().allowChannels(ZenMode.CHANNEL_POLICY_ALL)
- .allowAllSounds().showAllVisualEffects().build());
-
- zenMode.setPolicy(
- new ZenPolicy.Builder().allowChannels(ZenPolicy.CHANNEL_POLICY_PRIORITY).build());
-
- assertThat(zenMode.getRule().getInterruptionFilter()).isEqualTo(
- INTERRUPTION_FILTER_PRIORITY);
- assertThat(zenMode.getPolicy()).isEqualTo(ZEN_POLICY);
- assertThat(zenMode.getRule().getZenPolicy()).isEqualTo(ZEN_POLICY);
- }
-
- @Test
- public void setPolicy_alarmsOnlyToAllChannelsAndBack_restoresPolicySimilarToAlarmsOnly() {
- ZenMode zenMode = new ZenMode("id", new AutomaticZenRule.Builder("Rule", Uri.EMPTY)
- .setInterruptionFilter(INTERRUPTION_FILTER_ALARMS)
- .build(), false);
-
- zenMode.setPolicy(
- new ZenPolicy.Builder().allowChannels(ZenMode.CHANNEL_POLICY_ALL).build());
- assertThat(zenMode.getRule().getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_ALL);
- assertThat(zenMode.getPolicy()).isEqualTo(
- new ZenPolicy.Builder().allowChannels(ZenMode.CHANNEL_POLICY_ALL)
- .allowAllSounds().showAllVisualEffects().build());
-
- zenMode.setPolicy(
- new ZenPolicy.Builder().allowChannels(ZenPolicy.CHANNEL_POLICY_PRIORITY).build());
-
- // We don't go back to ALARMS, but the policy must be the one the user was seeing before.
- ZenPolicy alarmsOnlyLikePolicy = new ZenPolicy.Builder().disallowAllSounds()
- .allowAlarms(true).allowMedia(true).allowPriorityChannels(false)
- .build();
- assertThat(zenMode.getRule().getInterruptionFilter()).isEqualTo(
- INTERRUPTION_FILTER_PRIORITY);
- assertThat(zenMode.getPolicy()).isEqualTo(alarmsOnlyLikePolicy);
- assertThat(zenMode.getRule().getZenPolicy()).isEqualTo(alarmsOnlyLikePolicy);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModesBackendTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModesBackendTest.java
deleted file mode 100644
index 9483683..0000000
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModesBackendTest.java
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.notification.modes;
-
-import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
-import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
-import static android.provider.Settings.Global.ZEN_MODE_OFF;
-import static android.service.notification.Condition.SOURCE_UNKNOWN;
-import static android.service.notification.Condition.STATE_FALSE;
-import static android.service.notification.Condition.STATE_TRUE;
-import static android.service.notification.ZenPolicy.STATE_ALLOW;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.junit.Assert.assertThrows;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.AutomaticZenRule;
-import android.app.Flags;
-import android.app.NotificationManager;
-import android.app.NotificationManager.Policy;
-import android.content.Context;
-import android.net.Uri;
-import android.platform.test.annotations.EnableFlags;
-import android.platform.test.flag.junit.SetFlagsRule;
-import android.provider.Settings;
-import android.service.notification.Condition;
-import android.service.notification.ZenAdapters;
-import android.service.notification.ZenDeviceEffects;
-import android.service.notification.ZenModeConfig;
-import android.service.notification.ZenPolicy;
-
-import com.android.settings.R;
-
-import com.google.common.collect.ImmutableMap;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.shadows.ShadowApplication;
-
-import java.time.Duration;
-import java.util.List;
-
-@RunWith(RobolectricTestRunner.class)
-@EnableFlags(Flags.FLAG_MODES_UI)
-public class ZenModesBackendTest {
-
- private static final String ZEN_RULE_ID = "rule";
- private static final AutomaticZenRule ZEN_RULE =
- new AutomaticZenRule.Builder("Driving", Uri.parse("drive"))
- .setType(AutomaticZenRule.TYPE_DRIVING)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build())
- .build();
-
- private static final AutomaticZenRule MANUAL_DND_RULE =
- new AutomaticZenRule.Builder("Do Not Disturb", Uri.EMPTY)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build())
- .build();
-
- @Mock
- private NotificationManager mNm;
-
- private Context mContext;
- private ZenModesBackend mBackend;
-
- @Rule
- public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(
- SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT);
-
- // Helper methods to add active/inactive rule state to a config. Returns a copy.
- private ZenModeConfig configWithManualRule(ZenModeConfig base, boolean active) {
- ZenModeConfig out = base.copy();
-
- if (active) {
- out.manualRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- out.manualRule.condition =
- new Condition(out.manualRule.conditionId, "", STATE_TRUE, SOURCE_UNKNOWN);
- } else {
- out.manualRule.zenMode = ZEN_MODE_OFF;
- out.manualRule.condition =
- new Condition(out.manualRule.conditionId, "", STATE_FALSE, SOURCE_UNKNOWN);
- }
- return out;
- }
-
- private ZenModeConfig configWithRule(ZenModeConfig base, String ruleId, AutomaticZenRule rule,
- boolean active) {
- ZenModeConfig out = base.copy();
-
- // Note that there are many other fields of zenRule, but here we only set the ones
- // relevant to determining whether or not it is active.
- ZenModeConfig.ZenRule zenRule = new ZenModeConfig.ZenRule();
- zenRule.pkg = "package";
- zenRule.enabled = active;
- zenRule.snoozing = false;
- zenRule.condition = new Condition(rule.getConditionId(), "",
- active ? Condition.STATE_TRUE : Condition.STATE_FALSE,
- Condition.SOURCE_USER_ACTION);
- out.automaticRules.put(ruleId, zenRule);
-
- return out;
- }
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- ShadowApplication shadowApplication = ShadowApplication.getInstance();
- shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
-
- mContext = RuntimeEnvironment.application;
- mBackend = new ZenModesBackend(mContext);
-
- // Default catch-all case with no data. This isn't realistic, but tests below that rely
- // on the config to get data on rules active will create those individually.
- when(mNm.getZenModeConfig()).thenReturn(new ZenModeConfig());
- }
-
- @Test
- public void getModes_containsManualDndAndZenRules() {
- AutomaticZenRule rule2 = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().disallowAllSounds().build())
- .build();
- Policy dndPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS,
- Policy.PRIORITY_SENDERS_CONTACTS, Policy.PRIORITY_SENDERS_CONTACTS);
- when(mNm.getAutomaticZenRules()).thenReturn(
- ImmutableMap.of("rule1", ZEN_RULE, "rule2", rule2));
- ZenModeConfig config = new ZenModeConfig();
- config.applyNotificationPolicy(dndPolicy);
- assertThat(config.manualRule.zenPolicy.getPriorityCategoryAlarms()).isEqualTo(STATE_ALLOW);
- when(mNm.getZenModeConfig()).thenReturn(config);
-
- List<ZenMode> modes = mBackend.getModes();
-
- // all modes exist, but none of them are currently active
- assertThat(modes).containsExactly(
- ZenMode.manualDndMode(
- new AutomaticZenRule.Builder(
- mContext.getString(R.string.zen_mode_settings_title), Uri.EMPTY)
- .setType(AutomaticZenRule.TYPE_OTHER)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(ZenAdapters.notificationPolicyToZenPolicy(dndPolicy))
- .setManualInvocationAllowed(true)
- .build(),
- false),
- new ZenMode("rule2", rule2, false),
- new ZenMode("rule1", ZEN_RULE, false))
- .inOrder();
- }
-
- @Test
- public void getMode_manualDnd_returnsMode() {
- Policy dndPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS,
- Policy.PRIORITY_SENDERS_CONTACTS, Policy.PRIORITY_SENDERS_CONTACTS);
- ZenModeConfig config = new ZenModeConfig();
- config.applyNotificationPolicy(dndPolicy);
- when(mNm.getZenModeConfig()).thenReturn(config);
-
- ZenMode mode = mBackend.getMode(ZenMode.MANUAL_DND_MODE_ID);
-
- assertThat(mode).isEqualTo(
- ZenMode.manualDndMode(
- new AutomaticZenRule.Builder(
- mContext.getString(R.string.zen_mode_settings_title), Uri.EMPTY)
- .setType(AutomaticZenRule.TYPE_OTHER)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(ZenAdapters.notificationPolicyToZenPolicy(dndPolicy))
- .setManualInvocationAllowed(true)
- .build(), false));
- }
-
- @Test
- public void getMode_zenRule_returnsMode() {
- when(mNm.getAutomaticZenRule(eq(ZEN_RULE_ID))).thenReturn(ZEN_RULE);
-
- ZenMode mode = mBackend.getMode(ZEN_RULE_ID);
-
- assertThat(mode).isEqualTo(new ZenMode(ZEN_RULE_ID, ZEN_RULE, false));
- }
-
- @Test
- public void getMode_missingRule_returnsNull() {
- when(mNm.getAutomaticZenRule(any())).thenReturn(null);
-
- ZenMode mode = mBackend.getMode(ZEN_RULE_ID);
-
- assertThat(mode).isNull();
- verify(mNm).getAutomaticZenRule(eq(ZEN_RULE_ID));
- }
-
- @Test
- public void getMode_manualDnd_returnsCorrectActiveState() {
- // Set up a base config with an active rule to make sure we're looking at the correct info
- ZenModeConfig configWithActiveRule = configWithRule(new ZenModeConfig(), ZEN_RULE_ID,
- ZEN_RULE, true);
-
- // Equivalent to disallowAllSounds()
- Policy dndPolicy = new Policy(0, 0, 0);
- configWithActiveRule.applyNotificationPolicy(dndPolicy);
- when(mNm.getZenModeConfig()).thenReturn(configWithActiveRule);
-
- ZenMode mode = mBackend.getMode(ZenMode.MANUAL_DND_MODE_ID);
-
- // By default, manual rule is inactive
- assertThat(mode.isActive()).isFalse();
-
- // Now the returned config will represent the manual rule being active
- when(mNm.getZenModeConfig()).thenReturn(configWithManualRule(configWithActiveRule, true));
- ZenMode activeMode = mBackend.getMode(ZenMode.MANUAL_DND_MODE_ID);
- assertThat(activeMode.isActive()).isTrue();
- }
-
- @Test
- public void getMode_zenRule_returnsCorrectActiveState() {
- // Set up a base config that has an active manual rule and "rule2", to make sure we're
- // looking at the correct rule's info.
- ZenModeConfig configWithActiveRules = configWithRule(
- configWithManualRule(new ZenModeConfig(), true), // active manual rule
- "rule2", ZEN_RULE, true); // active rule 2
-
- when(mNm.getAutomaticZenRule(eq(ZEN_RULE_ID))).thenReturn(ZEN_RULE);
- when(mNm.getZenModeConfig()).thenReturn(
- configWithRule(configWithActiveRules, ZEN_RULE_ID, ZEN_RULE, false));
-
- // Round 1: the current config should indicate that the rule is not active
- ZenMode mode = mBackend.getMode(ZEN_RULE_ID);
- assertThat(mode.isActive()).isFalse();
-
- when(mNm.getZenModeConfig()).thenReturn(
- configWithRule(configWithActiveRules, ZEN_RULE_ID, ZEN_RULE, true));
- ZenMode activeMode = mBackend.getMode(ZEN_RULE_ID);
- assertThat(activeMode.isActive()).isTrue();
- }
-
- @Test
- public void updateMode_manualDnd_setsDeviceEffects() throws Exception {
- ZenMode manualDnd = ZenMode.manualDndMode(
- new AutomaticZenRule.Builder("DND", Uri.EMPTY)
- .setZenPolicy(new ZenPolicy())
- .setDeviceEffects(new ZenDeviceEffects.Builder()
- .setShouldDimWallpaper(true)
- .build())
- .build(), false);
-
- mBackend.updateMode(manualDnd);
-
- verify(mNm).setManualZenRuleDeviceEffects(new ZenDeviceEffects.Builder()
- .setShouldDimWallpaper(true)
- .build());
- }
-
- @Test
- public void updateMode_manualDnd_setsNotificationPolicy() {
- ZenMode manualDnd = ZenMode.manualDndMode(
- new AutomaticZenRule.Builder("DND", Uri.EMPTY)
- .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build())
- .build(), false);
-
- mBackend.updateMode(manualDnd);
-
- verify(mNm).setNotificationPolicy(eq(new ZenModeConfig().toNotificationPolicy(
- new ZenPolicy.Builder().allowAllSounds().build())), eq(true));
- }
-
- @Test
- public void updateMode_zenRule_updatesRule() {
- ZenMode ruleMode = new ZenMode("rule", ZEN_RULE, false);
-
- mBackend.updateMode(ruleMode);
-
- verify(mNm).updateAutomaticZenRule(eq("rule"), eq(ZEN_RULE), eq(true));
- }
-
- @Test
- public void activateMode_manualDnd_setsZenModeImportant() {
- mBackend.activateMode(ZenMode.manualDndMode(MANUAL_DND_RULE, false), null);
-
- verify(mNm).setZenMode(eq(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS), eq(null),
- any(), eq(true));
- }
-
- @Test
- public void activateMode_manualDndWithDuration_setsZenModeImportantWithCondition() {
- mBackend.activateMode(ZenMode.manualDndMode(MANUAL_DND_RULE, false),
- Duration.ofMinutes(30));
-
- verify(mNm).setZenMode(eq(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS),
- eq(ZenModeConfig.toTimeCondition(mContext, 30, 0, true).id),
- any(),
- eq(true));
- }
-
- @Test
- public void activateMode_zenRule_setsRuleStateActive() {
- mBackend.activateMode(new ZenMode(ZEN_RULE_ID, ZEN_RULE, false), null);
-
- verify(mNm).setAutomaticZenRuleState(eq(ZEN_RULE_ID),
- eq(new Condition(ZEN_RULE.getConditionId(), "", Condition.STATE_TRUE,
- Condition.SOURCE_USER_ACTION)));
- }
-
- @Test
- public void activateMode_zenRuleWithDuration_fails() {
- assertThrows(IllegalArgumentException.class,
- () -> mBackend.activateMode(new ZenMode(ZEN_RULE_ID, ZEN_RULE, false),
- Duration.ofMinutes(30)));
- }
-
- @Test
- public void deactivateMode_manualDnd_setsZenModeOff() {
- mBackend.deactivateMode(ZenMode.manualDndMode(MANUAL_DND_RULE, true));
-
- verify(mNm).setZenMode(eq(ZEN_MODE_OFF), eq(null), any(), eq(true));
- }
-
- @Test
- public void deactivateMode_zenRule_setsRuleStateInactive() {
- mBackend.deactivateMode(new ZenMode(ZEN_RULE_ID, ZEN_RULE, false));
-
- verify(mNm).setAutomaticZenRuleState(eq(ZEN_RULE_ID),
- eq(new Condition(ZEN_RULE.getConditionId(), "", Condition.STATE_FALSE,
- Condition.SOURCE_USER_ACTION)));
- }
-
- @Test
- public void removeMode_zenRule_deletesRule() {
- mBackend.removeMode(new ZenMode(ZEN_RULE_ID, ZEN_RULE, false));
-
- verify(mNm).removeAutomaticZenRule(ZEN_RULE_ID, true);
- }
-
- @Test
- public void removeMode_manualDnd_fails() {
- assertThrows(IllegalArgumentException.class,
- () -> mBackend.removeMode(ZenMode.manualDndMode(MANUAL_DND_RULE, false)));
- }
-}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModesListItemPreferenceTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModesListItemPreferenceTest.java
new file mode 100644
index 0000000..495a24c
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModesListItemPreferenceTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.notification.modes;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.service.notification.ZenModeConfig;
+
+import com.android.settingslib.notification.modes.ZenMode;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.shadows.ShadowLooper;
+
+@RunWith(RobolectricTestRunner.class)
+public class ZenModesListItemPreferenceTest {
+
+ private Context mContext;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ }
+
+ @Test
+ public void constructor_setsMode() {
+ ZenModesListItemPreference preference = new ZenModesListItemPreference(mContext,
+ TestModeBuilder.EXAMPLE);
+
+ assertThat(preference.getKey()).isEqualTo(TestModeBuilder.EXAMPLE.getId());
+ assertThat(preference.getZenMode()).isEqualTo(TestModeBuilder.EXAMPLE);
+ }
+
+ @Test
+ public void setZenMode_modeEnabled() {
+ ZenMode mode = new TestModeBuilder()
+ .setName("Enabled mode")
+ .setTriggerDescription("When the thrush knocks")
+ .setEnabled(true)
+ .build();
+
+ ZenModesListItemPreference preference = new ZenModesListItemPreference(mContext, mode);
+ ShadowLooper.idleMainLooper(); // To load icon.
+
+ assertThat(preference.getTitle()).isEqualTo("Enabled mode");
+ assertThat(preference.getSummary()).isEqualTo("When the thrush knocks");
+ assertThat(preference.getIcon()).isNotNull();
+ }
+
+ @Test
+ public void setZenMode_modeActive() {
+ ZenMode mode = new TestModeBuilder()
+ .setName("Active mode")
+ .setTriggerDescription("When Birnam forest comes to Dunsinane")
+ .setEnabled(true)
+ .setActive(true)
+ .build();
+
+ ZenModesListItemPreference preference = new ZenModesListItemPreference(mContext, mode);
+ ShadowLooper.idleMainLooper();
+
+ assertThat(preference.getTitle()).isEqualTo("Active mode");
+ assertThat(preference.getSummary()).isEqualTo("ON • When Birnam forest comes to Dunsinane");
+ assertThat(preference.getIcon()).isNotNull();
+ }
+
+ @Test
+ public void setZenMode_modeDisabledByApp() {
+ ZenModeConfig.ZenRule configRule = new ZenModeConfig.ZenRule();
+ configRule.enabled = false;
+ configRule.disabledOrigin = ZenModeConfig.UPDATE_ORIGIN_APP;
+ ZenMode mode = new TestModeBuilder()
+ .setName("Mode disabled by app")
+ .setTriggerDescription("When the cat's away")
+ .setEnabled(false)
+ .setConfigZenRule(configRule)
+ .build();
+
+ ZenModesListItemPreference preference = new ZenModesListItemPreference(mContext, mode);
+ ShadowLooper.idleMainLooper();
+
+ assertThat(preference.getTitle()).isEqualTo("Mode disabled by app");
+ assertThat(preference.getSummary()).isEqualTo("Tap to set up");
+ assertThat(preference.getIcon()).isNotNull();
+ }
+
+ @Test
+ public void setZenMode_modeDisabledByUser() {
+ ZenModeConfig.ZenRule configRule = new ZenModeConfig.ZenRule();
+ configRule.enabled = false;
+ configRule.disabledOrigin = ZenModeConfig.UPDATE_ORIGIN_USER;
+ ZenMode mode = new TestModeBuilder()
+ .setName("Mode disabled by user")
+ .setTriggerDescription("When the Levee Breaks")
+ .setEnabled(false)
+ .setConfigZenRule(configRule)
+ .build();
+
+ ZenModesListItemPreference preference = new ZenModesListItemPreference(mContext, mode);
+ ShadowLooper.idleMainLooper();
+
+ assertThat(preference.getTitle()).isEqualTo("Mode disabled by user");
+ assertThat(preference.getSummary()).isEqualTo("Paused");
+ assertThat(preference.getIcon()).isNotNull();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModesListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModesListPreferenceControllerTest.java
index 9a4de60..f2624ac 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModesListPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModesListPreferenceControllerTest.java
@@ -37,6 +37,8 @@
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
+import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.search.SearchIndexableRaw;
import com.google.common.collect.ImmutableList;
@@ -58,14 +60,15 @@
public class ZenModesListPreferenceControllerTest {
private static final String TEST_MODE_ID = "test_mode";
private static final String TEST_MODE_NAME = "Test Mode";
- private static final ZenMode TEST_MODE = new ZenMode(
- TEST_MODE_ID,
- new AutomaticZenRule.Builder(TEST_MODE_NAME, Uri.parse("test_uri"))
+
+ private static final ZenMode TEST_MODE = new TestModeBuilder()
+ .setId(TEST_MODE_ID)
+ .setAzr(new AutomaticZenRule.Builder(TEST_MODE_NAME, Uri.parse("test_uri"))
.setType(AutomaticZenRule.TYPE_BEDTIME)
.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
.setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build())
- .build(),
- false);
+ .build())
+ .build();
private static final ZenMode TEST_MANUAL_MODE = ZenMode.manualDndMode(
new AutomaticZenRule.Builder("Do Not Disturb", Uri.EMPTY)
@@ -110,14 +113,9 @@
assertThat(mPreference.getPreferenceCount()).isEqualTo(5);
List<ZenModesListItemPreference> itemPreferences = getModeListItems(mPreference);
- assertThat(itemPreferences.stream().map(pref -> pref.mZenMode).toList())
+ assertThat(itemPreferences.stream().map(ZenModesListItemPreference::getZenMode).toList())
.containsExactlyElementsIn(modes)
.inOrder();
-
- for (int i = 0; i < modes.size(); i++) {
- assertThat(((ZenModesListItemPreference) (mPreference.getPreference(i))).mZenMode)
- .isEqualTo(modes.get(i));
- }
}
@Test
@@ -138,7 +136,7 @@
mPrefController.updateState(mPreference);
List<ZenModesListItemPreference> newPreferences = getModeListItems(mPreference);
- assertThat(newPreferences.stream().map(pref -> pref.mZenMode).toList())
+ assertThat(newPreferences.stream().map(ZenModesListItemPreference::getZenMode).toList())
.containsExactlyElementsIn(updatedModes)
.inOrder();
@@ -194,7 +192,7 @@
assertThat(newData).hasSize(1);
SearchIndexableRaw newItem = newData.get(0);
- assertThat(newItem.key).isEqualTo(ZenMode.MANUAL_DND_MODE_ID);
+ assertThat(newItem.key).isEqualTo(TEST_MANUAL_MODE.getId());
assertThat(newItem.title).isEqualTo("Do Not Disturb"); // set above
}
@@ -209,7 +207,7 @@
// Should keep the order presented by getModes()
SearchIndexableRaw item0 = data.get(0);
- assertThat(item0.key).isEqualTo(ZenMode.MANUAL_DND_MODE_ID);
+ assertThat(item0.key).isEqualTo(TEST_MANUAL_MODE.getId());
assertThat(item0.title).isEqualTo("Do Not Disturb"); // set above
SearchIndexableRaw item1 = data.get(1);
@@ -218,13 +216,7 @@
}
private static ZenMode newMode(String id) {
- return new ZenMode(
- id,
- new AutomaticZenRule.Builder("Mode " + id, Uri.parse("test_uri"))
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder().allowAllSounds().build())
- .build(),
- false);
+ return new TestModeBuilder().setId(id).setName("Mode " + id).build();
}
/**
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModesSummaryHelperTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModesSummaryHelperTest.java
index 13ae4eb..62b5ee0 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModesSummaryHelperTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModesSummaryHelperTest.java
@@ -16,7 +16,6 @@
package com.android.settings.notification.modes;
-import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_ANYONE;
import static android.service.notification.ZenPolicy.PEOPLE_TYPE_ANYONE;
import static android.service.notification.ZenPolicy.PEOPLE_TYPE_CONTACTS;
@@ -25,12 +24,12 @@
import static com.google.common.truth.Truth.assertThat;
-import android.app.AutomaticZenRule;
import android.content.Context;
-import android.net.Uri;
import android.service.notification.ZenDeviceEffects;
import android.service.notification.ZenPolicy;
+import com.android.settingslib.notification.modes.ZenMode;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -40,7 +39,6 @@
import java.util.LinkedHashSet;
import java.util.Set;
-
@RunWith(RobolectricTestRunner.class)
public class ZenModesSummaryHelperTest {
private Context mContext;
@@ -58,50 +56,38 @@
@Test
public void getPeopleSummary_noOne() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ ZenMode zenMode = new TestModeBuilder()
.setZenPolicy(new ZenPolicy.Builder().disallowAllSounds().build())
.build();
- ZenMode zenMode = new ZenMode("id", rule, true);
assertThat(mSummaryHelper.getPeopleSummary(zenMode)).isEqualTo("No one can interrupt");
}
@Test
public void getPeopleSummary_some() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ ZenMode zenMode = new TestModeBuilder()
.setZenPolicy(new ZenPolicy.Builder().allowCalls(PEOPLE_TYPE_CONTACTS).build())
.build();
- ZenMode zenMode = new ZenMode("id", rule, true);
assertThat(mSummaryHelper.getPeopleSummary(zenMode)).isEqualTo("Some people can interrupt");
}
@Test
public void getPeopleSummary_all() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ ZenMode zenMode = new TestModeBuilder()
.setZenPolicy(new ZenPolicy.Builder().allowCalls(PEOPLE_TYPE_ANYONE).
allowConversations(CONVERSATION_SENDERS_ANYONE)
.allowMessages(PEOPLE_TYPE_ANYONE).build())
.build();
- ZenMode zenMode = new ZenMode("id", rule, true);
assertThat(mSummaryHelper.getPeopleSummary(zenMode)).isEqualTo("All people can interrupt");
}
@Test
public void getOtherSoundCategoriesSummary_single() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ ZenMode zenMode = new TestModeBuilder()
.setZenPolicy(new ZenPolicy.Builder().allowAlarms(true).build())
.build();
- ZenMode zenMode = new ZenMode("id", rule, true);
assertThat(mSummaryHelper.getOtherSoundCategoriesSummary(zenMode)).isEqualTo(
"Alarms can interrupt");
@@ -109,12 +95,9 @@
@Test
public void getOtherSoundCategoriesSummary_duo() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ ZenMode zenMode = new TestModeBuilder()
.setZenPolicy(new ZenPolicy.Builder().allowAlarms(true).allowMedia(true).build())
.build();
- ZenMode zenMode = new ZenMode("id", rule, true);
assertThat(mSummaryHelper.getOtherSoundCategoriesSummary(zenMode)).isEqualTo(
"Alarms and media can interrupt");
@@ -122,16 +105,13 @@
@Test
public void getOtherSoundCategoriesSummary_trio() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ ZenMode zenMode = new TestModeBuilder()
.setZenPolicy(new ZenPolicy.Builder()
.allowAlarms(true)
.allowMedia(true)
.allowSystem(true)
.build())
.build();
- ZenMode zenMode = new ZenMode("id", rule, true);
assertThat(mSummaryHelper.getOtherSoundCategoriesSummary(zenMode)).isEqualTo(
"Alarms, media, and touch sounds can interrupt");
@@ -139,9 +119,7 @@
@Test
public void getOtherSoundCategoriesSummary_quad() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ ZenMode zenMode = new TestModeBuilder()
.setZenPolicy(new ZenPolicy.Builder()
.allowAlarms(true)
.allowMedia(true)
@@ -149,7 +127,6 @@
.allowReminders(true)
.build())
.build();
- ZenMode zenMode = new ZenMode("id", rule, true);
assertThat(mSummaryHelper.getOtherSoundCategoriesSummary(zenMode)).isEqualTo(
"Alarms, media, and 2 more can interrupt");
@@ -157,9 +134,7 @@
@Test
public void getOtherSoundCategoriesSummary_all() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ ZenMode zenMode = new TestModeBuilder()
.setZenPolicy(new ZenPolicy.Builder()
.allowAlarms(true)
.allowMedia(true)
@@ -168,7 +143,6 @@
.allowEvents(true)
.build())
.build();
- ZenMode zenMode = new ZenMode("id", rule, true);
assertThat(mSummaryHelper.getOtherSoundCategoriesSummary(zenMode)).isEqualTo(
"Alarms, media, and 3 more can interrupt");
@@ -176,61 +150,52 @@
@Test
public void getBlockedEffectsSummary_none() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ ZenMode zenMode = new TestModeBuilder()
.setZenPolicy(new ZenPolicy.Builder()
.showAllVisualEffects()
.allowAlarms(true)
.build())
.build();
- ZenMode zenMode = new ZenMode("id", rule, true);
+
assertThat(mSummaryHelper.getBlockedEffectsSummary(zenMode))
.isEqualTo("Notifications shown");
}
@Test
public void getBlockedEffectsSummary_some() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ ZenMode zenMode = new TestModeBuilder()
.setZenPolicy(new ZenPolicy.Builder()
.allowAlarms(true)
.showAllVisualEffects()
.showVisualEffect(VISUAL_EFFECT_AMBIENT, false)
.build())
.build();
- ZenMode zenMode = new ZenMode("id", rule, true);
+
assertThat(mSummaryHelper.getBlockedEffectsSummary(zenMode))
.isEqualTo("Notifications partially hidden");
}
@Test
public void getBlockedEffectsSummary_all() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ ZenMode zenMode = new TestModeBuilder()
.setZenPolicy(new ZenPolicy.Builder()
.allowAlarms(true)
.hideAllVisualEffects()
.build())
.build();
- ZenMode zenMode = new ZenMode("id", rule, true);
+
assertThat(mSummaryHelper.getBlockedEffectsSummary(zenMode))
.isEqualTo("Notifications hidden");
}
@Test
public void getDisplayEffectsSummary_single_notifVis() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ ZenMode zenMode = new TestModeBuilder()
.setZenPolicy(new ZenPolicy.Builder()
.showAllVisualEffects()
.showVisualEffect(VISUAL_EFFECT_AMBIENT, false)
.build())
.build();
- ZenMode zenMode = new ZenMode("id", rule, true);
assertThat(mSummaryHelper.getDisplayEffectsSummary(zenMode)).isEqualTo(
"Notifications partially hidden");
@@ -238,15 +203,12 @@
@Test
public void getDisplayEffectsSummary_single_notifVis_unusedEffect() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ ZenMode zenMode = new TestModeBuilder()
.setZenPolicy(new ZenPolicy.Builder()
.showAllVisualEffects()
.showVisualEffect(VISUAL_EFFECT_LIGHTS, false)
.build())
.build();
- ZenMode zenMode = new ZenMode("id", rule, true);
assertThat(mSummaryHelper.getDisplayEffectsSummary(zenMode)).isEqualTo(
"Notifications shown");
@@ -254,15 +216,12 @@
@Test
public void getDisplayEffectsSummary_single_displayEffect() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ ZenMode zenMode = new TestModeBuilder()
.setZenPolicy(new ZenPolicy.Builder().showAllVisualEffects().build())
.setDeviceEffects(new ZenDeviceEffects.Builder()
.setShouldDimWallpaper(true)
.build())
.build();
- ZenMode zenMode = new ZenMode("id", rule, true);
assertThat(mSummaryHelper.getDisplayEffectsSummary(zenMode)).isEqualTo(
"Dim the wallpaper");
@@ -270,16 +229,13 @@
@Test
public void getDisplayEffectsSummary_duo() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ ZenMode zenMode = new TestModeBuilder()
.setZenPolicy(new ZenPolicy.Builder().showAllVisualEffects().build())
.setDeviceEffects(new ZenDeviceEffects.Builder()
.setShouldDimWallpaper(true)
.setShouldDisplayGrayscale(true)
.build())
.build();
- ZenMode zenMode = new ZenMode("id", rule, true);
assertThat(mSummaryHelper.getDisplayEffectsSummary(zenMode)).isEqualTo(
"Grayscale and dim the wallpaper");
@@ -287,9 +243,7 @@
@Test
public void getDisplayEffectsSummary_trio() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ ZenMode zenMode = new TestModeBuilder()
.setZenPolicy(new ZenPolicy.Builder()
.hideAllVisualEffects()
.allowAlarms(true)
@@ -301,7 +255,6 @@
.setShouldDimWallpaper(true)
.build())
.build();
- ZenMode zenMode = new ZenMode("id", rule, true);
assertThat(mSummaryHelper.getDisplayEffectsSummary(zenMode)).isEqualTo(
"Notifications hidden, grayscale, and dim the wallpaper");
@@ -309,9 +262,7 @@
@Test
public void getDisplayEffectsSummary_quad() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ ZenMode zenMode = new TestModeBuilder()
.setZenPolicy(new ZenPolicy.Builder()
.showAllVisualEffects()
.showVisualEffect(VISUAL_EFFECT_AMBIENT, false)
@@ -325,50 +276,29 @@
.setShouldUseNightMode(true)
.build())
.build();
- ZenMode zenMode = new ZenMode("id", rule, true);
assertThat(mSummaryHelper.getDisplayEffectsSummary(zenMode)).isEqualTo(
"Notifications partially hidden, grayscale, and 2 more");
}
@Test
- public void getAppsSummary_all() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
- .setZenPolicy(new ZenPolicy.Builder()
- .allowChannels(ZenMode.CHANNEL_POLICY_ALL)
- .build())
- .build();
- ZenMode zenMode = new ZenMode("id", rule, true);
-
- assertThat(mSummaryHelper.getAppsSummary(zenMode, new LinkedHashSet<>())).isEqualTo("All");
- }
-
- @Test
public void getAppsSummary_none() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ ZenMode zenMode = new TestModeBuilder()
.setZenPolicy(new ZenPolicy.Builder()
.allowChannels(ZenPolicy.CHANNEL_POLICY_NONE)
.build())
.build();
- ZenMode zenMode = new ZenMode("id", rule, true);
assertThat(mSummaryHelper.getAppsSummary(zenMode, new LinkedHashSet<>())).isEqualTo("None");
}
@Test
public void getAppsSummary_priorityAppsNoList() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ ZenMode zenMode = new TestModeBuilder()
.setZenPolicy(new ZenPolicy.Builder()
.allowChannels(ZenPolicy.CHANNEL_POLICY_PRIORITY)
.build())
.build();
- ZenMode zenMode = new ZenMode("id", rule, true);
assertThat(mSummaryHelper.getAppsSummary(zenMode, null)).isEqualTo("Selected apps");
}
@@ -410,19 +340,15 @@
@Test
public void getAppsSummary_priorityApps() {
- AutomaticZenRule rule = new AutomaticZenRule.Builder("Bedtime", Uri.parse("bed"))
- .setType(AutomaticZenRule.TYPE_BEDTIME)
- .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ ZenMode zenMode = new TestModeBuilder()
.setZenPolicy(new ZenPolicy.Builder()
.allowChannels(ZenPolicy.CHANNEL_POLICY_PRIORITY)
.build())
.build();
- ZenMode zenMode = new ZenMode("id", rule, true);
Set<String> apps = Set.of("My App", "SecondApp", "ThirdApp", "FourthApp",
"FifthApp", "SixthApp");
assertThat(mSummaryHelper.getAppsSummary(zenMode, apps)).isEqualTo("FifthApp, FourthApp, "
+ "and 4 more can interrupt");
}
-
}
diff --git a/tests/robotests/src/com/android/settings/users/TimeoutToDockUserPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/users/TimeoutToDockUserPreferenceControllerTest.java
index 7bc66c8..fe88148 100644
--- a/tests/robotests/src/com/android/settings/users/TimeoutToDockUserPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/users/TimeoutToDockUserPreferenceControllerTest.java
@@ -39,7 +39,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -126,7 +125,6 @@
BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
}
- @Ignore("b/313530297")
@Test
public void getAvailabilityStatus_isCurrentlyMainUser_returnDisabledForUser() {
when(mUserManager.getMainUser()).thenReturn(UserHandle.CURRENT);
@@ -136,7 +134,6 @@
BasePreferenceController.DISABLED_FOR_USER);
}
- @Ignore("b/313530297")
@Test
public void getAvailabilityStatus_featureAndMultiUserEnabledAndNonMainUser_returnAvailable() {
when(mUserManager.isUserForeground()).thenReturn(true);
diff --git a/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java b/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java
index 7f27324..44e1cc6 100644
--- a/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/users/UserDetailsSettingsTest.java
@@ -22,7 +22,7 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
@@ -63,7 +63,6 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -222,8 +221,8 @@
}
@Test
- @Ignore("b/313530297")
public void onResume_canSwitch_shouldEnableSwitchPref() {
+ setupSelectedUser();
mUserManager.setSwitchabilityStatus(SWITCHABILITY_STATUS_OK);
mFragment.mSwitchUserPref = mSwitchUserPref;
mFragment.onAttach(mContext);
@@ -234,8 +233,8 @@
}
@Test
- @Ignore("b/313530297")
public void onResume_userInCall_shouldDisableSwitchPref() {
+ setupSelectedUser();
mUserManager.setSwitchabilityStatus(SWITCHABILITY_STATUS_USER_IN_CALL);
mFragment.mSwitchUserPref = mSwitchUserPref;
mFragment.onAttach(mContext);
@@ -246,8 +245,8 @@
}
@Test
- @Ignore("b/313530297")
public void onResume_switchDisallowed_shouldDisableSwitchPref() {
+ setupSelectedUser();
mUserManager.setSwitchabilityStatus(SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED);
mFragment.mSwitchUserPref = mSwitchUserPref;
mFragment.onAttach(mContext);
@@ -258,8 +257,8 @@
}
@Test
- @Ignore("b/313530297")
public void onResume_systemUserLocked_shouldDisableSwitchPref() {
+ setupSelectedUser();
mUserManager.setSwitchabilityStatus(UserManager.SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED);
mFragment.mSwitchUserPref = mSwitchUserPref;
mFragment.onAttach(mContext);
@@ -269,7 +268,6 @@
verify(mSwitchUserPref).setEnabled(false);
}
- @Ignore("b/313530297")
@Test
public void initialize_adminWithTelephony_shouldShowPhonePreference() {
setupSelectedUser();
@@ -315,7 +313,6 @@
verify(mFragment).removePreference(KEY_APP_AND_CONTENT_ACCESS);
}
- @Ignore("b/313530297")
@Test
public void initialize_adminSelectsSecondaryUser_shouldShowRemovePreference() {
setupSelectedUser();
@@ -328,7 +325,6 @@
verify(mFragment, never()).removePreference(KEY_REMOVE_USER);
}
- @Ignore("b/313530297")
@Test
public void initialize_adminSelectsNewRestrictedUser_shouldOpenAppContentScreen() {
setupSelectedRestrictedUser();
@@ -351,7 +347,6 @@
.isEqualTo(true);
}
- @Ignore("b/313530297")
@Test
public void initialize_adminSelectsRestrictedUser_shouldSetupPreferences() {
setupSelectedRestrictedUser();
@@ -381,7 +376,6 @@
verify(mActivity, never()).startActivity(any(Intent.class));
}
- @Ignore("b/313530297")
@Test
public void initialize_adminSelectsGuest_shouldShowRemovePreference() {
setupSelectedGuest();
@@ -425,7 +419,6 @@
verify(mFragment).removePreference(KEY_REMOVE_USER);
}
- @Ignore("b/313530297")
@Test
public void initialize_userHasCallRestriction_shouldSetPhoneSwitchUnChecked() {
setupSelectedUser();
@@ -438,7 +431,6 @@
verify(mPhonePref).setChecked(false);
}
- @Ignore("b/313530297")
@Test
public void initialize_noCallRestriction_shouldSetPhoneSwitchChecked() {
setupSelectedUser();
@@ -537,7 +529,6 @@
verify(mFragment, never()).switchUser();
}
- @Ignore("b/313530297")
@Test
public void onPreferenceClick_removeGuestClicked_canDelete_shouldShowDialog() {
setupSelectedGuest();
@@ -555,7 +546,6 @@
verify(mFragment).showDialog(DIALOG_CONFIRM_RESET_GUEST);
}
- @Ignore("b/313530297")
@Test
public void onPreferenceClick_removeRestrictedClicked_canDelete_shouldShowDialog() {
setupSelectedRestrictedUser();
@@ -574,7 +564,6 @@
verify(mFragment).showDialog(DIALOG_CONFIRM_REMOVE);
}
- @Ignore("b/313530297")
@Test
public void onPreferenceClick_removeClicked_canDelete_shouldShowDialog() {
setupSelectedUser();
@@ -666,7 +655,6 @@
assertThat(result).isFalse();
}
- @Ignore("b/313530297")
@Test
public void canDeleteUser_adminSelectsUser_noRestrictions_shouldReturnTrue() {
setupSelectedUser();
@@ -700,17 +688,16 @@
assertThat(result).isFalse();
}
- @Ignore("b/313530297")
@Test
public void initialize_userSelected_shouldShowGrantAdminPref_MultipleAdminEnabled() {
+ assumeTrue(UserManager.isHeadlessSystemUserMode());
setupSelectedUser();
+ mUserManager.setIsAdminUser(true);
ShadowUserManager.setIsMultipleAdminEnabled(true);
mFragment.initialize(mActivity, mArguments);
- assertTrue(UserManager.isMultipleAdminEnabled());
verify(mFragment, never()).removePreference(KEY_GRANT_ADMIN);
}
- @Ignore("b/313530297")
@Test
public void initialize_userSelected_shouldNotShowGrantAdminPref() {
setupSelectedUser();
@@ -718,7 +705,6 @@
verify(mFragment).removePreference(KEY_GRANT_ADMIN);
}
- @Ignore("b/313530297")
@Test
public void initialize_restrictUserSelected_shouldNotShowGrantAdminPref_MultipleAdminEnabled() {
setupSelectedUser();
@@ -729,7 +715,6 @@
verify(mFragment).removePreference(KEY_GRANT_ADMIN);
}
- @Ignore("b/313530297")
@Test
public void initialize_mainUserSelected_shouldShowGrantAdminPref_MultipleAdminEnabled() {
setupSelectedMainUser();
@@ -738,7 +723,6 @@
verify(mFragment).removePreference(KEY_GRANT_ADMIN);
}
- @Ignore("b/313530297")
@Test
public void initialize_guestSelected_shouldNotShowGrantAdminPref_MultipleAdminEnabled() {
setupSelectedGuest();
@@ -778,7 +762,7 @@
mUserInfo = new UserInfo(1, "Tom", null,
UserInfo.FLAG_FULL | UserInfo.FLAG_INITIALIZED,
UserManager.USER_TYPE_FULL_SECONDARY);
-
+ mFragment.mUserInfo = mUserInfo;
mUserManager.addProfile(mUserInfo);
}
@@ -787,7 +771,7 @@
mUserInfo = new UserInfo(11, "Jerry", null,
UserInfo.FLAG_FULL | UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_MAIN,
UserManager.USER_TYPE_FULL_SECONDARY);
-
+ mFragment.mUserInfo = mUserInfo;
mUserManager.addProfile(mUserInfo);
}
@@ -796,7 +780,7 @@
mUserInfo = new UserInfo(12, "Andy", null,
UserInfo.FLAG_FULL | UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_ADMIN,
UserManager.USER_TYPE_FULL_SECONDARY);
-
+ mFragment.mUserInfo = mUserInfo;
mUserManager.addProfile(mUserInfo);
}
@@ -805,7 +789,7 @@
mUserInfo = new UserInfo(23, "Guest", null,
UserInfo.FLAG_FULL | UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_GUEST,
UserManager.USER_TYPE_FULL_GUEST);
-
+ mFragment.mUserInfo = mUserInfo;
mUserManager.addProfile(mUserInfo);
}
@@ -814,7 +798,7 @@
mUserInfo = new UserInfo(21, "Bob", null,
UserInfo.FLAG_FULL | UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_RESTRICTED,
UserManager.USER_TYPE_FULL_RESTRICTED);
-
+ mFragment.mUserInfo = mUserInfo;
mUserManager.addProfile(mUserInfo);
}
}
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
index 4497a0a..4440bc9 100644
--- a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
@@ -48,6 +48,8 @@
import android.telephony.ims.ImsMmTelManager;
import android.view.View;
+import androidx.annotation.NonNull;
+import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
@@ -56,10 +58,14 @@
import com.android.settings.SettingsActivity;
import com.android.settings.network.ims.MockWifiCallingQueryImsState;
import com.android.settings.network.ims.WifiCallingQueryImsState;
+import com.android.settings.network.telephony.wificalling.IWifiCallingRepository;
import com.android.settings.testutils.shadow.ShadowFragment;
import com.android.settings.widget.SettingsMainSwitchBar;
import com.android.settings.widget.SettingsMainSwitchPreference;
+import kotlin.Unit;
+import kotlin.jvm.functions.Function1;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -183,36 +189,25 @@
}
@Test
- public void onResume_provisioningAllowed_shouldNotFinish() {
- // Call onResume while provisioning is allowed.
- mFragment.onResume();
+ public void onViewCreated_provisioningAllowed_shouldNotFinish() {
+ // Call onViewCreated while provisioning is allowed.
+ mFragment.onViewCreated(mView, null);
// Verify that finish() is not called.
verify(mFragment, never()).finish();
}
@Test
- public void onResume_provisioningDisallowed_shouldFinish() {
- // Call onResume while provisioning is disallowed.
- mQueryImsState.setIsProvisionedOnDevice(false);
- mFragment.onResume();
+ public void onViewCreated_provisioningDisallowed_shouldFinish() {
+ // Call onViewCreated while provisioning is disallowed.
+ mFragment.mIsWifiCallingReady = false;
+ mFragment.onViewCreated(mView, null);
// Verify that finish() is called
verify(mFragment).finish();
}
@Test
- public void onResumeOnPause_provisioningCallbackRegistration() throws Exception {
- // Verify that provisioning callback is registered after call to onResume().
- mFragment.onResume();
- verify(mFragment).registerProvisioningChangedCallback();
-
- // Verify that provisioning callback is unregistered after call to onPause.
- mFragment.onPause();
- verify(mFragment).unregisterProvisioningChangedCallback();
- }
-
- @Test
public void onResume_useWfcHomeModeConfigFalseAndEditable_shouldShowWfcRoaming() {
// Call onResume to update the WFC roaming preference.
mFragment.onResume();
@@ -377,6 +372,7 @@
protected class TestFragment extends WifiCallingSettingsForSub {
private SettingsMainSwitchPreference mSwitchPref;
+ protected boolean mIsWifiCallingReady = true;
protected void setSwitchBar(SettingsMainSwitchPreference switchPref) {
mSwitchPref = switchPref;
@@ -422,6 +418,25 @@
}
@Override
+ @NonNull
+ IWifiCallingRepository getWifiCallingRepository() {
+ return new IWifiCallingRepository() {
+ @Override
+ public void collectIsWifiCallingReadyFlow(
+ @NonNull LifecycleOwner lifecycleOwner,
+ @NonNull Function1<? super Boolean, Unit> action) {
+ action.invoke(mIsWifiCallingReady);
+ }
+ };
+ }
+
+ @NonNull
+ @Override
+ LifecycleOwner getLifecycleOwner() {
+ return this;
+ }
+
+ @Override
void showAlert(Intent intent) {
}
}
diff --git a/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowUserManager.java b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowUserManager.java
index 417b102..02ed03c 100644
--- a/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowUserManager.java
+++ b/tests/robotests/testutils/com/android/settings/testutils/shadow/ShadowUserManager.java
@@ -363,6 +363,10 @@
}
@Implementation
+ protected boolean isAdminUser() {
+ return getUserInfo(UserHandle.myUserId()).isAdmin();
+ }
+ @Implementation
protected boolean isGuestUser() {
return mIsGuestUser;
}
diff --git a/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogRepositoryTest.kt
index 01f32bf..1c1d9df 100644
--- a/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogRepositoryTest.kt
+++ b/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogRepositoryTest.kt
@@ -17,65 +17,65 @@
package com.android.settings.deviceinfo.simstatus
import android.content.Context
-import android.os.PersistableBundle
import android.telephony.CarrierConfigManager
import androidx.lifecycle.testing.TestLifecycleOwner
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.deviceinfo.simstatus.SimStatusDialogRepository.SimStatusDialogInfo
+import com.android.settings.network.telephony.CarrierConfigRepository
import com.android.settings.network.telephony.SimSlotRepository
import com.android.settings.network.telephony.ims.ImsMmTelRepository
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking
+import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.kotlin.anyVararg
import org.mockito.kotlin.doReturn
-import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
-import org.mockito.kotlin.spy
@RunWith(AndroidJUnit4::class)
class SimStatusDialogRepositoryTest {
- private val carrierConfig = PersistableBundle().apply {
- putBoolean(CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, true)
- }
+ private val context: Context = ApplicationProvider.getApplicationContext()
- private val mockCarrierConfigManager = mock<CarrierConfigManager> {
- on { getConfigForSubId(eq(SUB_ID), anyVararg()) } doReturn carrierConfig
- }
+ private val mockSimSlotRepository =
+ mock<SimSlotRepository> {
+ on { subIdInSimSlotFlow(SIM_SLOT_INDEX) } doReturn flowOf(SUB_ID)
+ }
- private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
- on { getSystemService(CarrierConfigManager::class.java) } doReturn mockCarrierConfigManager
- }
+ private val mockSignalStrengthRepository =
+ mock<SignalStrengthRepository> {
+ on { signalStrengthDisplayFlow(SUB_ID) } doReturn flowOf(SIGNAL_STRENGTH)
+ }
- private val mockSimSlotRepository = mock<SimSlotRepository> {
- on { subIdInSimSlotFlow(SIM_SLOT_INDEX) } doReturn flowOf(SUB_ID)
- }
+ private val mockImsMmTelRepository =
+ mock<ImsMmTelRepository> { on { imsRegisteredFlow() } doReturn flowOf(true) }
- private val mockSignalStrengthRepository = mock<SignalStrengthRepository> {
- on { signalStrengthDisplayFlow(SUB_ID) } doReturn flowOf(SIGNAL_STRENGTH)
- }
+ private val controller =
+ SimStatusDialogRepository(
+ context = context,
+ simSlotRepository = mockSimSlotRepository,
+ signalStrengthRepository = mockSignalStrengthRepository,
+ imsMmTelRepositoryFactory = { subId ->
+ assertThat(subId).isEqualTo(SUB_ID)
+ mockImsMmTelRepository
+ },
+ )
- private val mockImsMmTelRepository = mock<ImsMmTelRepository> {
- on { imsRegisteredFlow() } doReturn flowOf(true)
+ @Before
+ fun setUp() {
+ CarrierConfigRepository.resetForTest()
}
- private val controller = SimStatusDialogRepository(
- context = context,
- simSlotRepository = mockSimSlotRepository,
- signalStrengthRepository = mockSignalStrengthRepository,
- imsMmTelRepositoryFactory = { subId ->
- assertThat(subId).isEqualTo(SUB_ID)
- mockImsMmTelRepository
- },
- )
-
@Test
fun collectSimStatusDialogInfo() = runBlocking {
+ CarrierConfigRepository.setBooleanForTest(
+ subId = SUB_ID,
+ key = CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL,
+ value = true,
+ )
var simStatusDialogInfo = SimStatusDialogInfo()
controller.collectSimStatusDialogInfo(TestLifecycleOwner(), SIM_SLOT_INDEX) {
@@ -83,19 +83,20 @@
}
delay(100)
- assertThat(simStatusDialogInfo).isEqualTo(
- SimStatusDialogInfo(
- signalStrength = SIGNAL_STRENGTH,
- imsRegistered = true,
- )
- )
+ assertThat(simStatusDialogInfo)
+ .isEqualTo(
+ SimStatusDialogInfo(
+ signalStrength = SIGNAL_STRENGTH,
+ imsRegistered = true,
+ ))
}
@Test
fun collectSimStatusDialogInfo_doNotShowSignalStrength() = runBlocking {
- carrierConfig.putBoolean(
- CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL,
- false
+ CarrierConfigRepository.setBooleanForTest(
+ subId = SUB_ID,
+ key = CarrierConfigManager.KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL,
+ value = false,
)
var simStatusDialogInfo = SimStatusDialogInfo()
@@ -109,7 +110,11 @@
@Test
fun collectSimStatusDialogInfo_doNotShowImsRegistration() = runBlocking {
- carrierConfig.putBoolean(CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, false)
+ CarrierConfigRepository.setBooleanForTest(
+ subId = SUB_ID,
+ key = CarrierConfigManager.KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL,
+ value = false,
+ )
var simStatusDialogInfo = SimStatusDialogInfo()
controller.collectSimStatusDialogInfo(TestLifecycleOwner(), SIM_SLOT_INDEX) {
diff --git a/tests/spa_unit/src/com/android/settings/network/MobileDataEnabledFlowTest.kt b/tests/spa_unit/src/com/android/settings/network/MobileDataEnabledFlowTest.kt
deleted file mode 100644
index c4611ac..0000000
--- a/tests/spa_unit/src/com/android/settings/network/MobileDataEnabledFlowTest.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.network
-
-import android.content.Context
-import android.provider.Settings
-import android.telephony.SubscriptionManager
-import androidx.test.core.app.ApplicationProvider
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
-import com.android.settingslib.spa.testutils.toListWithTimeout
-import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalBoolean
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.async
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.runBlocking
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-class MobileDataEnabledFlowTest {
- private val context: Context = ApplicationProvider.getApplicationContext()
-
- @Test
- fun mobileDataEnabledFlow_notified(): Unit = runBlocking {
- val flow = context.mobileDataEnabledFlow(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
-
- assertThat(flow.firstWithTimeoutOrNull()).isNotNull()
- }
-
- @Test
- fun mobileDataEnabledFlow_changed_notified(): Unit = runBlocking {
- var mobileDataEnabled by context.settingsGlobalBoolean(Settings.Global.MOBILE_DATA)
- mobileDataEnabled = false
-
- val flow = context.mobileDataEnabledFlow(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
- mobileDataEnabled = true
-
- assertThat(flow.firstWithTimeoutOrNull()).isNotNull()
- }
-
- @Test
- fun mobileDataEnabledFlow_forSubIdNotChanged(): Unit = runBlocking {
- var mobileDataEnabled by context.settingsGlobalBoolean(Settings.Global.MOBILE_DATA)
- mobileDataEnabled = false
- var mobileDataEnabledForSubId
- by context.settingsGlobalBoolean(Settings.Global.MOBILE_DATA + SUB_ID)
- mobileDataEnabledForSubId = false
-
- val listDeferred = async {
- context.mobileDataEnabledFlow(SUB_ID).toListWithTimeout()
- }
-
- assertThat(listDeferred.await()).hasSize(1)
- }
-
- @Test
- fun mobileDataEnabledFlow_forSubIdChanged(): Unit = runBlocking {
- var mobileDataEnabled by context.settingsGlobalBoolean(Settings.Global.MOBILE_DATA)
- mobileDataEnabled = false
- var mobileDataEnabledForSubId
- by context.settingsGlobalBoolean(Settings.Global.MOBILE_DATA + SUB_ID)
- mobileDataEnabledForSubId = false
-
- val listDeferred = async {
- context.mobileDataEnabledFlow(SUB_ID).toListWithTimeout()
- }
- delay(100)
- mobileDataEnabledForSubId = true
-
- assertThat(listDeferred.await().size).isAtLeast(2)
- }
-
- private companion object {
- const val SUB_ID = 123
- }
-}
diff --git a/tests/spa_unit/src/com/android/settings/network/apn/ApnEditCarrierEnabledTest.kt b/tests/spa_unit/src/com/android/settings/network/apn/ApnEditCarrierEnabledTest.kt
new file mode 100644
index 0000000..bd97482
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/network/apn/ApnEditCarrierEnabledTest.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network.apn
+
+import android.content.Context
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsEnabled
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.assertIsOff
+import androidx.compose.ui.test.assertIsOn
+import androidx.compose.ui.test.junit4.ComposeTestRule
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.R
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.stub
+
+@RunWith(AndroidJUnit4::class)
+class ApnEditCarrierEnabledTest {
+
+ @get:Rule val composeTestRule = createComposeRule()
+
+ private val context: Context = spy(ApplicationProvider.getApplicationContext()) {}
+
+ private val resources = spy(context.resources) {}
+
+ @Before
+ fun setUp() {
+ context.stub { on { resources } doReturn resources }
+ }
+
+ @Test
+ fun carrierEnabled_displayed() {
+ composeTestRule.setContent { ApnEditCarrierEnabled(ApnData()) {} }
+
+ composeTestRule.onCarrierEnabled().assertIsDisplayed()
+ }
+
+ @Test
+ fun carrierEnabled_isChecked() {
+ val apnData = ApnData(carrierEnabled = true)
+
+ composeTestRule.setContent { ApnEditCarrierEnabled(apnData) {} }
+
+ composeTestRule.onCarrierEnabled().assertIsOn()
+ }
+
+ @Test
+ fun carrierEnabled_allowEdit_checkChanged() {
+ resources.stub { on { getBoolean(R.bool.config_allow_edit_carrier_enabled) } doReturn true }
+ var apnData by mutableStateOf(ApnData(carrierEnabled = true))
+ composeTestRule.setContent {
+ CompositionLocalProvider(LocalContext provides context) {
+ ApnEditCarrierEnabled(apnData) { apnData = apnData.copy(carrierEnabled = it) }
+ }
+ }
+
+ composeTestRule.onCarrierEnabled().performClick()
+
+ composeTestRule.onCarrierEnabled().assertIsEnabled().assertIsOff()
+ }
+
+ @Test
+ fun carrierEnabled_notAllowEdit_checkNotChanged() {
+ resources.stub {
+ on { getBoolean(R.bool.config_allow_edit_carrier_enabled) } doReturn false
+ }
+ var apnData by mutableStateOf(ApnData(carrierEnabled = true))
+ composeTestRule.setContent {
+ CompositionLocalProvider(LocalContext provides context) {
+ ApnEditCarrierEnabled(apnData) { apnData = apnData.copy(carrierEnabled = it) }
+ }
+ }
+
+ composeTestRule.onCarrierEnabled().performClick()
+
+ composeTestRule.onCarrierEnabled().assertIsNotEnabled().assertIsOn()
+ }
+
+ private fun ComposeTestRule.onCarrierEnabled() =
+ onNodeWithText(context.getString(R.string.carrier_enabled))
+}
diff --git a/tests/spa_unit/src/com/android/settings/network/apn/ApnEditPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/network/apn/ApnEditPageProviderTest.kt
index 3621948..d310604 100644
--- a/tests/spa_unit/src/com/android/settings/network/apn/ApnEditPageProviderTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/apn/ApnEditPageProviderTest.kt
@@ -21,24 +21,17 @@
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.test.assertIsDisplayed
-import androidx.compose.ui.test.assertIsOff
-import androidx.compose.ui.test.assertIsOn
import androidx.compose.ui.test.hasText
-import androidx.compose.ui.test.isFocused
import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.test.onAllNodesWithText
import androidx.compose.ui.test.onChild
import androidx.compose.ui.test.onChildAt
-import androidx.compose.ui.test.onLast
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.onRoot
-import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performScrollToNode
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
import com.google.common.truth.Truth
-import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -55,7 +48,6 @@
private val port = "port"
private val apnType = context.resources.getString(R.string.apn_type)
private val apnRoaming = "IPv4"
- private val apnEnable = context.resources.getString(R.string.carrier_enabled)
private val apnProtocolOptions =
context.resources.getStringArray(R.array.apn_protocol_entries).toList()
private val passwordTitle = context.resources.getString(R.string.apn_password)
@@ -65,7 +57,6 @@
port = port,
apnType = apnType,
apnRoaming = apnProtocolOptions.indexOf(apnRoaming),
- apnEnable = true
)
private val apnData = mutableStateOf(
apnInit
@@ -133,39 +124,6 @@
composeTestRule.onNodeWithText(apnRoaming, true).assertIsDisplayed()
}
- @Ignore("b/342374681")
- @Test
- fun carrier_enabled_displayed() {
- composeTestRule.setContent {
- ApnPage(apnInit, remember { apnData }, uri)
- }
- composeTestRule.onRoot().onChild().onChildAt(0)
- .performScrollToNode(hasText(apnEnable, true))
- composeTestRule.onNodeWithText(apnEnable, true).assertIsDisplayed()
- }
-
- @Test
- fun carrier_enabled_isChecked() {
- composeTestRule.setContent {
- ApnPage(apnInit, remember { apnData }, uri)
- }
- composeTestRule.onRoot().onChild().onChildAt(0)
- .performScrollToNode(hasText(apnEnable, true))
- composeTestRule.onNodeWithText(apnEnable, true).assertIsOn()
- }
-
- @Ignore("b/342374681")
- @Test
- fun carrier_enabled_checkChanged() {
- composeTestRule.setContent {
- ApnPage(apnInit, remember { apnData }, uri)
- }
- composeTestRule.onRoot().onChild().onChildAt(0)
- .performScrollToNode(hasText(apnEnable, true))
- composeTestRule.onNodeWithText(apnEnable, true).performClick()
- composeTestRule.onNodeWithText(apnEnable, true).assertIsOff()
- }
-
@Test
fun password_displayed() {
composeTestRule.setContent {
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/CarrierConfigRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/CarrierConfigRepositoryTest.kt
new file mode 100644
index 0000000..8c54751
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/CarrierConfigRepositoryTest.kt
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network.telephony
+
+import android.content.Context
+import android.telephony.CarrierConfigManager
+import androidx.core.os.persistableBundleOf
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.anyVararg
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.doThrow
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.stub
+import org.mockito.kotlin.times
+import org.mockito.kotlin.verify
+
+@RunWith(AndroidJUnit4::class)
+class CarrierConfigRepositoryTest {
+
+ private val mockCarrierConfigManager = mock<CarrierConfigManager>()
+
+ private val context =
+ mock<Context> {
+ on { applicationContext } doReturn mock
+ on { getSystemService(CarrierConfigManager::class.java) } doReturn
+ mockCarrierConfigManager
+ }
+
+ private val repository = CarrierConfigRepository(context)
+
+ @Before
+ fun setUp() {
+ CarrierConfigRepository.resetForTest()
+ }
+
+ @Test
+ fun getBoolean_returnValue() {
+ val key = CarrierConfigManager.KEY_CARRIER_CONFIG_APPLIED_BOOL
+ mockCarrierConfigManager.stub {
+ on { getConfigForSubId(any(), eq(key)) } doReturn persistableBundleOf(key to true)
+ }
+
+ val value = repository.getBoolean(SUB_ID, key)
+
+ assertThat(value).isTrue()
+ }
+
+ @Test
+ fun getInt_returnValue() {
+ val key = CarrierConfigManager.KEY_GBA_MODE_INT
+ mockCarrierConfigManager.stub {
+ on { getConfigForSubId(any(), eq(key)) } doReturn persistableBundleOf(key to 99)
+ }
+
+ val value = repository.getInt(SUB_ID, key)
+
+ assertThat(value).isEqualTo(99)
+ }
+
+ @Test
+ fun getString_returnValue() {
+ val key = CarrierConfigManager.KEY_CARRIER_NAME_STRING
+ mockCarrierConfigManager.stub {
+ on { getConfigForSubId(any(), eq(key)) } doReturn
+ persistableBundleOf(key to STRING_VALUE)
+ }
+
+ val value = repository.getString(SUB_ID, key)
+
+ assertThat(value).isEqualTo(STRING_VALUE)
+ }
+
+ @Test
+ fun transformConfig_managerThrowIllegalStateException_returnDefaultValue() {
+ mockCarrierConfigManager.stub {
+ on { getConfigForSubId(any(), anyVararg()) } doThrow IllegalStateException()
+ }
+
+ val carrierName =
+ repository.transformConfig(SUB_ID) {
+ getInt(CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT)
+ }
+
+ assertThat(carrierName)
+ .isEqualTo(
+ CarrierConfigManager.getDefaultConfig()
+ .getInt(CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT))
+ }
+
+ @Test
+ fun transformConfig_getValueTwice_cached() {
+ val key = CarrierConfigManager.KEY_CARRIER_NAME_STRING
+ mockCarrierConfigManager.stub {
+ on { getConfigForSubId(any(), eq(key)) } doReturn
+ persistableBundleOf(key to STRING_VALUE)
+ }
+
+ repository.transformConfig(SUB_ID) { getString(key) }
+ repository.transformConfig(SUB_ID) { getString(key) }
+
+ verify(mockCarrierConfigManager, times(1)).getConfigForSubId(any(), anyVararg())
+ }
+
+ @Test
+ fun transformConfig_registerCarrierConfigChangeListener() {
+ val key = CarrierConfigManager.KEY_CARRIER_NAME_STRING
+
+ repository.transformConfig(SUB_ID) { getString(key) }
+ repository.transformConfig(SUB_ID) { getString(key) }
+
+ verify(mockCarrierConfigManager, times(1)).registerCarrierConfigChangeListener(any(), any())
+ }
+
+ private companion object {
+ const val SUB_ID = 123
+ const val STRING_VALUE = "value"
+ }
+}
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/MobileDataRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/MobileDataRepositoryTest.kt
new file mode 100644
index 0000000..fc762fa
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/MobileDataRepositoryTest.kt
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network.telephony
+
+import android.content.Context
+import android.provider.Settings
+import android.telephony.SubscriptionManager
+import android.telephony.TelephonyManager
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
+import com.android.settingslib.spa.testutils.toListWithTimeout
+import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalBoolean
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.async
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.runBlocking
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.stub
+import org.mockito.kotlin.verify
+
+@RunWith(AndroidJUnit4::class)
+class MobileDataRepositoryTest {
+ private val mockTelephonyManager =
+ mock<TelephonyManager> { on { createForSubscriptionId(SUB_ID) } doReturn mock }
+
+ private val context: Context =
+ spy(ApplicationProvider.getApplicationContext()) {
+ on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
+ }
+
+ private val repository = MobileDataRepository(context, flowOf(Unit))
+
+ @Test
+ fun isMobileDataPolicyEnabledFlow_invalidSub_returnFalse() = runBlocking {
+ val flow =
+ repository.isMobileDataPolicyEnabledFlow(
+ subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+ policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
+ )
+
+ assertThat(flow.firstWithTimeoutOrNull()).isFalse()
+ }
+
+ @Test
+ fun isMobileDataPolicyEnabledFlow_validSub_returnPolicyState() = runBlocking {
+ mockTelephonyManager.stub {
+ on {
+ isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)
+ } doReturn true
+ }
+
+ val flow =
+ repository.isMobileDataPolicyEnabledFlow(
+ subId = SUB_ID,
+ policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
+ )
+
+ assertThat(flow.firstWithTimeoutOrNull()).isTrue()
+ }
+
+ @Test
+ fun setMobileDataPolicyEnabled() = runBlocking {
+ repository.setMobileDataPolicyEnabled(
+ subId = SUB_ID,
+ policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
+ enabled = true)
+
+ verify(mockTelephonyManager)
+ .setMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH, true)
+ }
+
+ @Test
+ fun mobileDataEnabledChangedFlow_notified(): Unit = runBlocking {
+ val flow =
+ repository.mobileDataEnabledChangedFlow(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+
+ assertThat(flow.firstWithTimeoutOrNull()).isNotNull()
+ }
+
+ @Test
+ fun mobileDataEnabledChangedFlow_changed_notified(): Unit = runBlocking {
+ var mobileDataEnabled by context.settingsGlobalBoolean(Settings.Global.MOBILE_DATA)
+ mobileDataEnabled = false
+
+ val flow =
+ repository.mobileDataEnabledChangedFlow(SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+ mobileDataEnabled = true
+
+ assertThat(flow.firstWithTimeoutOrNull()).isNotNull()
+ }
+
+ @Test
+ fun mobileDataEnabledChangedFlow_forSubIdNotChanged(): Unit = runBlocking {
+ var mobileDataEnabled by context.settingsGlobalBoolean(Settings.Global.MOBILE_DATA)
+ mobileDataEnabled = false
+ var mobileDataEnabledForSubId by
+ context.settingsGlobalBoolean(Settings.Global.MOBILE_DATA + SUB_ID)
+ mobileDataEnabledForSubId = false
+
+ val listDeferred = async {
+ repository.mobileDataEnabledChangedFlow(SUB_ID).toListWithTimeout()
+ }
+
+ assertThat(listDeferred.await()).hasSize(1)
+ }
+
+ @Test
+ fun mobileDataEnabledChangedFlow_forSubIdChanged(): Unit = runBlocking {
+ var mobileDataEnabled by context.settingsGlobalBoolean(Settings.Global.MOBILE_DATA)
+ mobileDataEnabled = false
+ var mobileDataEnabledForSubId by
+ context.settingsGlobalBoolean(Settings.Global.MOBILE_DATA + SUB_ID)
+ mobileDataEnabledForSubId = false
+
+ val listDeferred = async {
+ repository.mobileDataEnabledChangedFlow(SUB_ID).toListWithTimeout()
+ }
+ delay(100)
+ mobileDataEnabledForSubId = true
+
+ assertThat(listDeferred.await().size).isAtLeast(2)
+ }
+
+ @Test
+ fun isMobileDataEnabledFlow_invalidSub_returnFalse() = runBlocking {
+ val state =
+ repository.isMobileDataEnabledFlow(
+ subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+ )
+
+ assertThat(state.firstWithTimeoutOrNull()).isFalse()
+ }
+
+ @Test
+ fun isMobileDataEnabledFlow_validSub_returnPolicyState() = runBlocking {
+ mockTelephonyManager.stub {
+ on { isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER) } doReturn true
+ }
+
+ val state = repository.isMobileDataEnabledFlow(subId = SUB_ID)
+
+ assertThat(state.firstWithTimeoutOrNull()).isTrue()
+ }
+
+ @Test
+ fun isDataRoamingEnabledFlow_invalidSub_returnFalse() = runBlocking {
+ val isDataRoamingEnabled =
+ repository
+ .isDataRoamingEnabledFlow(subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+ .firstWithTimeoutOrNull()
+
+ assertThat(isDataRoamingEnabled).isFalse()
+ }
+
+ @Test
+ fun isDataRoamingEnabledFlow_validSub_returnCurrentValue() = runBlocking {
+ mockTelephonyManager.stub { on { isDataRoamingEnabled } doReturn true }
+
+ val isDataRoamingEnabled =
+ repository.isDataRoamingEnabledFlow(subId = SUB_ID).firstWithTimeoutOrNull()
+
+ assertThat(isDataRoamingEnabled).isTrue()
+ }
+
+ private companion object {
+ const val SUB_ID = 123
+ }
+}
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/RoamingPreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/RoamingPreferenceControllerTest.kt
new file mode 100644
index 0000000..ee4cff6
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/RoamingPreferenceControllerTest.kt
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.network.telephony
+
+import android.content.Context
+import android.telephony.CarrierConfigManager
+import android.telephony.SubscriptionManager
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsOff
+import androidx.compose.ui.test.assertIsOn
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.fragment.app.FragmentManager
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.R
+import com.android.settings.core.BasePreferenceController.AVAILABLE
+import com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.flowOf
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.stub
+
+@RunWith(AndroidJUnit4::class)
+class RoamingPreferenceControllerTest {
+ @get:Rule val composeTestRule = createComposeRule()
+
+ private val context: Context = ApplicationProvider.getApplicationContext()
+
+ private val mockMobileDataRepository =
+ mock<MobileDataRepository> {
+ on { isDataRoamingEnabledFlow(SUB_ID) } doReturn flowOf(false)
+ }
+
+ private val controller =
+ RoamingPreferenceController(context, TEST_KEY, mockMobileDataRepository)
+
+ @Before
+ fun setUp() {
+ CarrierConfigRepository.resetForTest()
+ }
+
+ @Test
+ fun getAvailabilityStatus_validSubId_returnAvailable() {
+ controller.init(mock<FragmentManager>(), SUB_ID)
+
+ val availabilityStatus = controller.getAvailabilityStatus()
+
+ assertThat(availabilityStatus).isEqualTo(AVAILABLE)
+ }
+
+ @Test
+ fun getAvailabilityStatus_invalidSubId_returnConditionallyUnavailable() {
+ controller.init(mock<FragmentManager>(), SubscriptionManager.INVALID_SUBSCRIPTION_ID)
+
+ val availabilityStatus = controller.getAvailabilityStatus()
+
+ assertThat(availabilityStatus).isEqualTo(CONDITIONALLY_UNAVAILABLE)
+ }
+
+ @Test
+ fun getAvailabilityStatus_forceHomeNetworkIsTrue_returnConditionallyUnavailable() {
+ CarrierConfigRepository.setBooleanForTest(
+ subId = SUB_ID,
+ key = CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL,
+ value = true,
+ )
+ controller.init(mock<FragmentManager>(), SUB_ID)
+
+ val availabilityStatus = controller.getAvailabilityStatus()
+
+ assertThat(availabilityStatus).isEqualTo(CONDITIONALLY_UNAVAILABLE)
+ }
+
+ @Test
+ fun getAvailabilityStatus_forceHomeNetworkIsFalse_returnAvailable() {
+ CarrierConfigRepository.setBooleanForTest(
+ subId = SUB_ID,
+ key = CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL,
+ value = false,
+ )
+ controller.init(mock<FragmentManager>(), SUB_ID)
+
+ val availabilityStatus = controller.getAvailabilityStatus()
+
+ assertThat(availabilityStatus).isEqualTo(AVAILABLE)
+ }
+
+ @Test
+ fun title_displayed() {
+ controller.init(mock<FragmentManager>(), SUB_ID)
+
+ composeTestRule.setContent {
+ CompositionLocalProvider(LocalContext provides context) { controller.Content() }
+ }
+
+ composeTestRule.onNodeWithText(context.getString(R.string.roaming)).assertIsDisplayed()
+ }
+
+ @Test
+ fun summary_displayed() {
+ controller.init(mock<FragmentManager>(), SUB_ID)
+
+ composeTestRule.setContent {
+ CompositionLocalProvider(LocalContext provides context) { controller.Content() }
+ }
+
+ composeTestRule
+ .onNodeWithText(context.getString(R.string.roaming_enable))
+ .assertIsDisplayed()
+ }
+
+ @Test
+ fun isDialogNeeded_enableChargeIndication_returnTrue() {
+ CarrierConfigRepository.setBooleanForTest(
+ subId = SUB_ID,
+ key = CarrierConfigManager.KEY_DISABLE_CHARGE_INDICATION_BOOL,
+ value = false,
+ )
+ controller.init(mock<FragmentManager>(), SUB_ID)
+
+ val isDialogNeeded = controller.isDialogNeeded()
+
+ assertThat(isDialogNeeded).isTrue()
+ }
+
+ @Test
+ fun isDialogNeeded_disableChargeIndication_returnFalse() {
+ CarrierConfigRepository.setBooleanForTest(
+ subId = SUB_ID,
+ key = CarrierConfigManager.KEY_DISABLE_CHARGE_INDICATION_BOOL,
+ value = true,
+ )
+ controller.init(mock<FragmentManager>(), SUB_ID)
+
+ val isDialogNeeded = controller.isDialogNeeded()
+
+ assertThat(isDialogNeeded).isFalse()
+ }
+
+ @Test
+ fun checked_roamingEnabled_isOn() {
+ mockMobileDataRepository.stub {
+ on { isDataRoamingEnabledFlow(SUB_ID) } doReturn flowOf(true)
+ }
+ controller.init(mock<FragmentManager>(), SUB_ID)
+
+ composeTestRule.setContent {
+ CompositionLocalProvider(LocalContext provides context) { controller.Content() }
+ }
+
+ composeTestRule.onNodeWithText(context.getString(R.string.roaming)).assertIsOn()
+ }
+
+ @Test
+ fun checked_roamingDisabled_isOff() {
+ mockMobileDataRepository.stub {
+ on { isDataRoamingEnabledFlow(SUB_ID) } doReturn flowOf(false)
+ }
+ controller.init(mock<FragmentManager>(), SUB_ID)
+
+ composeTestRule.setContent {
+ CompositionLocalProvider(LocalContext provides context) { controller.Content() }
+ }
+
+ composeTestRule.onNodeWithText(context.getString(R.string.roaming)).assertIsOff()
+ }
+
+ private companion object {
+ const val TEST_KEY = "test_key"
+ const val SUB_ID = 2
+ }
+}
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/TelephonyRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/TelephonyRepositoryTest.kt
index 65e8c47..12791b8 100644
--- a/tests/spa_unit/src/com/android/settings/network/telephony/TelephonyRepositoryTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/TelephonyRepositoryTest.kt
@@ -17,14 +17,12 @@
package com.android.settings.network.telephony
import android.content.Context
-import android.telephony.SubscriptionManager
import android.telephony.TelephonyCallback
import android.telephony.TelephonyManager
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking
import org.junit.Test
import org.junit.runner.RunWith
@@ -33,91 +31,29 @@
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
-import org.mockito.kotlin.stub
import org.mockito.kotlin.verify
@RunWith(AndroidJUnit4::class)
class TelephonyRepositoryTest {
private var telephonyCallback: TelephonyCallback? = null
- private val mockTelephonyManager = mock<TelephonyManager> {
- on { createForSubscriptionId(SUB_ID) } doReturn mock
- on { registerTelephonyCallback(any(), any()) } doAnswer {
- telephonyCallback = it.arguments[1] as TelephonyCallback
- }
- }
-
- private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
- on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
- }
-
- private val repository = TelephonyRepository(context, flowOf(Unit))
-
- @Test
- fun isMobileDataPolicyEnabledFlow_invalidSub_returnFalse() = runBlocking {
- val flow = repository.isMobileDataPolicyEnabledFlow(
- subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
- policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
- )
-
- assertThat(flow.firstWithTimeoutOrNull()).isFalse()
- }
-
- @Test
- fun isMobileDataPolicyEnabledFlow_validSub_returnPolicyState() = runBlocking {
- mockTelephonyManager.stub {
- on {
- isMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH)
- } doReturn true
+ private val mockTelephonyManager =
+ mock<TelephonyManager> {
+ on { createForSubscriptionId(SUB_ID) } doReturn mock
+ on { registerTelephonyCallback(any(), any()) } doAnswer
+ {
+ telephonyCallback = it.arguments[1] as TelephonyCallback
+ }
}
- val flow = repository.isMobileDataPolicyEnabledFlow(
- subId = SUB_ID,
- policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
- )
-
- assertThat(flow.firstWithTimeoutOrNull()).isTrue()
- }
-
- @Test
- fun setMobileDataPolicyEnabled() = runBlocking {
- repository.setMobileDataPolicyEnabled(
- subId = SUB_ID,
- policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH,
- enabled = true
- )
-
- verify(mockTelephonyManager)
- .setMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH, true)
- }
-
- @Test
- fun isDataEnabled_invalidSub_returnFalse() = runBlocking {
- val state = repository.isDataEnabledFlow(
- subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
- )
-
- assertThat(state.firstWithTimeoutOrNull()).isFalse()
- }
-
- @Test
- fun isDataEnabled_validSub_returnPolicyState() = runBlocking {
- mockTelephonyManager.stub {
- on {
- isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
- } doReturn true
+ private val context: Context =
+ spy(ApplicationProvider.getApplicationContext()) {
+ on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
}
- val state = repository.isDataEnabledFlow(subId = SUB_ID)
-
- assertThat(state.firstWithTimeoutOrNull()).isTrue()
- }
-
@Test
fun telephonyCallbackFlow_callbackRegistered() = runBlocking {
- val flow = context.telephonyCallbackFlow<Unit>(SUB_ID) {
- object : TelephonyCallback() {}
- }
+ val flow = context.telephonyCallbackFlow<Unit>(SUB_ID) { object : TelephonyCallback() {} }
flow.firstWithTimeoutOrNull()
@@ -126,9 +62,7 @@
@Test
fun telephonyCallbackFlow_callbackUnregistered() = runBlocking {
- val flow = context.telephonyCallbackFlow<Unit>(SUB_ID) {
- object : TelephonyCallback() {}
- }
+ val flow = context.telephonyCallbackFlow<Unit>(SUB_ID) { object : TelephonyCallback() {} }
flow.firstWithTimeoutOrNull()
diff --git a/tests/spa_unit/src/com/android/settings/print/PrintSettingsPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/print/PrintSettingsPageProviderTest.kt
index 746816b..2571406 100644
--- a/tests/spa_unit/src/com/android/settings/print/PrintSettingsPageProviderTest.kt
+++ b/tests/spa_unit/src/com/android/settings/print/PrintSettingsPageProviderTest.kt
@@ -17,6 +17,7 @@
package com.android.settings.print
import android.content.Context
+import android.net.Uri
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.isDisplayed
@@ -31,7 +32,9 @@
import com.android.settings.print.PrintSettingsFragment.EXTRA_CHECKED
import com.android.settings.print.PrintSettingsFragment.EXTRA_SERVICE_COMPONENT_NAME
import com.android.settings.print.PrintSettingsFragment.EXTRA_TITLE
+import com.android.settings.print.PrintSettingsPageProvider.AddPrintService
import com.android.settings.print.PrintSettingsPageProvider.PrintService
+import kotlinx.coroutines.flow.flowOf
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -44,35 +47,32 @@
@RunWith(AndroidJUnit4::class)
class PrintSettingsPageProviderTest {
- @get:Rule
- val composeTestRule = createComposeRule()
+ @get:Rule val composeTestRule = createComposeRule()
- private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
- doNothing().whenever(mock).startActivity(any())
- }
+ private val context: Context =
+ spy(ApplicationProvider.getApplicationContext()) {
+ doNothing().whenever(mock).startActivity(any())
+ }
- private val displayInfo = PrintServiceDisplayInfo(
- title = TITLE,
- isEnabled = true,
- summary = SUMMARY,
- icon = context.getDrawable(R.drawable.ic_settings_print)!!,
- componentName = "ComponentName",
- )
+ private val displayInfo =
+ PrintServiceDisplayInfo(
+ title = TITLE,
+ isEnabled = true,
+ summary = SUMMARY,
+ icon = context.getDrawable(R.drawable.ic_settings_print)!!,
+ componentName = "ComponentName",
+ )
@Test
fun printService_titleDisplayed() {
- composeTestRule.setContent {
- PrintService(displayInfo)
- }
+ composeTestRule.setContent { PrintService(displayInfo) }
composeTestRule.onNodeWithText(TITLE).isDisplayed()
}
@Test
fun printService_summaryDisplayed() {
- composeTestRule.setContent {
- PrintService(displayInfo)
- }
+ composeTestRule.setContent { PrintService(displayInfo) }
composeTestRule.onNodeWithText(SUMMARY).isDisplayed()
}
@@ -80,25 +80,43 @@
@Test
fun printService_onClick() {
composeTestRule.setContent {
- CompositionLocalProvider(LocalContext provides context) {
- PrintService(displayInfo)
- }
+ CompositionLocalProvider(LocalContext provides context) { PrintService(displayInfo) }
}
composeTestRule.onNodeWithText(TITLE).performClick()
- verify(context).startActivity(argThat {
- val fragment = getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)
- val arguments = getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS)!!
- fragment == PrintServiceSettingsFragment::class.qualifiedName &&
- arguments.getBoolean(EXTRA_CHECKED) == displayInfo.isEnabled &&
- arguments.getString(EXTRA_TITLE) == displayInfo.title &&
- arguments.getString(EXTRA_SERVICE_COMPONENT_NAME) == displayInfo.componentName
- })
+ verify(context)
+ .startActivity(
+ argThat {
+ val fragment = getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)
+ val arguments = getBundleExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS)!!
+ fragment == PrintServiceSettingsFragment::class.qualifiedName &&
+ arguments.getBoolean(EXTRA_CHECKED) == displayInfo.isEnabled &&
+ arguments.getString(EXTRA_TITLE) == displayInfo.title &&
+ arguments.getString(EXTRA_SERVICE_COMPONENT_NAME) ==
+ displayInfo.componentName
+ }
+ )
+ }
+
+ @Test
+ fun addPrintService_onClick() {
+ composeTestRule.setContent {
+ CompositionLocalProvider(LocalContext provides context) {
+ AddPrintService(flowOf(SEARCH_URI))
+ }
+ }
+
+ composeTestRule
+ .onNodeWithText(context.getString(R.string.print_menu_item_add_service))
+ .performClick()
+
+ verify(context).startActivity(argThat { data == Uri.parse(SEARCH_URI) })
}
private companion object {
const val TITLE = "Title"
const val SUMMARY = "Summary"
+ const val SEARCH_URI = "search.uri"
}
}
diff --git a/tests/unit/src/com/android/settings/accessibility/ReduceBrightColorsPreferenceControllerTest.java b/tests/unit/src/com/android/settings/accessibility/ReduceBrightColorsPreferenceControllerTest.java
index e1c0277..7229996 100644
--- a/tests/unit/src/com/android/settings/accessibility/ReduceBrightColorsPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/accessibility/ReduceBrightColorsPreferenceControllerTest.java
@@ -16,6 +16,8 @@
package com.android.settings.accessibility;
+import static com.android.internal.accessibility.AccessibilityShortcutController.REDUCE_BRIGHT_COLORS_TILE_SERVICE_COMPONENT_NAME;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
@@ -24,7 +26,12 @@
import android.content.Context;
import android.content.res.Resources;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.provider.Settings;
+import android.view.accessibility.Flags;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -33,6 +40,7 @@
import org.junit.Before;
import org.junit.Ignore;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -40,6 +48,8 @@
public class ReduceBrightColorsPreferenceControllerTest {
private static final String PREF_KEY = "rbc_preference";
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
private Context mContext;
private Resources mResources;;
private ReduceBrightColorsPreferenceController mController;
@@ -88,6 +98,20 @@
assertThat(mController.isAvailable()).isFalse();
}
+
+ @Test
+ @RequiresFlagsDisabled(Flags.FLAG_A11Y_QS_SHORTCUT)
+ public void getTileComponentName_a11yQsFlagOff_returnComponentName() {
+ assertThat(mController.getTileComponentName())
+ .isEqualTo(REDUCE_BRIGHT_COLORS_TILE_SERVICE_COMPONENT_NAME);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_A11Y_QS_SHORTCUT)
+ public void getTileComponentName_a11yQsFlagOff_returnNull() {
+ assertThat(mController.getTileComponentName()).isNull();
+ }
+
private int resourceId(String type, String name) {
return mContext.getResources().getIdentifier(name, type, mContext.getPackageName());
}
diff --git a/tests/unit/src/com/android/settings/network/ResetNetworkOperationBuilderTest.java b/tests/unit/src/com/android/settings/network/ResetNetworkOperationBuilderTest.java
index 5f54406..7f1c475 100644
--- a/tests/unit/src/com/android/settings/network/ResetNetworkOperationBuilderTest.java
+++ b/tests/unit/src/com/android/settings/network/ResetNetworkOperationBuilderTest.java
@@ -16,20 +16,16 @@
package com.android.settings.network;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import android.content.ContentProvider;
-import android.content.ContentResolver;
+import android.content.ContentProviderClient;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkPolicyManager;
@@ -67,7 +63,7 @@
@Mock
private NetworkPolicyManager mNetworkPolicyManager;
@Mock
- private ContentProvider mContentProvider;;
+ private ContentProviderClient mContentProviderClient;
private Context mContext;
@@ -77,9 +73,8 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
- doReturn(ContentResolver.wrap(mContentProvider)).when(mContext).getContentResolver();
-
mBuilder = spy(new ResetNetworkOperationBuilder(mContext));
+ doReturn(mContentProviderClient).when(mBuilder).getUnstableTelephonyContentProviderClient();
}
@Test
@@ -184,38 +179,38 @@
}
@Test
- public void restartPhoneProcess_withoutTelephonyContentProvider_shouldNotCrash() {
- doThrow(new IllegalArgumentException()).when(mContentProvider).call(
- anyString(), anyString(), anyString(), any());
+ public void restartPhoneProcess_withoutTelephonyContentProvider_shouldNotCrash()
+ throws Exception {
+ doReturn(null).when(mBuilder).getUnstableTelephonyContentProviderClient();
mBuilder.restartPhoneProcess().build().run();
}
@Test
- public void restartRild_withoutTelephonyContentProvider_shouldNotCrash() {
- doThrow(new IllegalArgumentException()).when(mContentProvider).call(
- anyString(), anyString(), anyString(), any());
+ public void restartRild_withoutTelephonyContentProvider_shouldNotCrash()
+ throws Exception {
+ doReturn(null).when(mBuilder).getUnstableTelephonyContentProviderClient();
mBuilder.restartRild().build().run();
}
@Test
- public void restartPhoneProcess_withTelephonyContentProvider_shouldCallRestartPhoneProcess() {
+ public void restartPhoneProcess_withTelephonyContentProvider_shouldCallRestartPhoneProcess()
+ throws Exception {
mBuilder.restartPhoneProcess().build().run();
- verify(mContentProvider).call(
- eq(mBuilder.getResetTelephonyContentProviderAuthority()),
+ verify(mContentProviderClient).call(
eq(ResetNetworkOperationBuilder.METHOD_RESTART_PHONE_PROCESS),
isNull(),
isNull());
}
@Test
- public void restartRild_withTelephonyContentProvider_shouldCallRestartRild() {
+ public void restartRild_withTelephonyContentProvider_shouldCallRestartRild()
+ throws Exception {
mBuilder.restartRild().build().run();
- verify(mContentProvider).call(
- eq(mBuilder.getResetTelephonyContentProviderAuthority()),
+ verify(mContentProviderClient).call(
eq(ResetNetworkOperationBuilder.METHOD_RESTART_RILD),
isNull(),
isNull());
diff --git a/tests/unit/src/com/android/settings/network/telephony/RoamingPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/RoamingPreferenceControllerTest.java
deleted file mode 100644
index d221280..0000000
--- a/tests/unit/src/com/android/settings/network/telephony/RoamingPreferenceControllerTest.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.network.telephony;
-
-import static com.android.settings.core.BasePreferenceController.AVAILABLE;
-import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.os.Looper;
-import android.os.PersistableBundle;
-import android.telephony.CarrierConfigManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-
-import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.FragmentTransaction;
-import androidx.lifecycle.LifecycleOwner;
-import androidx.lifecycle.LifecycleRegistry;
-import androidx.test.annotation.UiThreadTest;
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import com.android.settings.core.BasePreferenceController;
-import com.android.settingslib.RestrictedSwitchPreference;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.mobile.dataservice.MobileNetworkInfoEntity;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-public class RoamingPreferenceControllerTest {
- private static final int SUB_ID = 2;
-
- @Mock
- private FragmentManager mFragmentManager;
- @Mock
- private TelephonyManager mTelephonyManager;
- @Mock
- private TelephonyManager mInvalidTelephonyManager;
- @Mock
- private SubscriptionManager mSubscriptionManager;
- @Mock
- private FragmentTransaction mFragmentTransaction;
- @Mock
- private CarrierConfigManager mCarrierConfigManager;
- @Mock
- private Lifecycle mLifecycle;
- @Mock
- private LifecycleOwner mLifecycleOwner;
-
- private LifecycleRegistry mLifecycleRegistry;
- private RoamingPreferenceController mController;
- private RestrictedSwitchPreference mPreference;
- private Context mContext;
- private MobileNetworkInfoEntity mMobileNetworkInfoEntity;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
-
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
-
- mContext = spy(ApplicationProvider.getApplicationContext());
- doReturn(mTelephonyManager).when(mContext).getSystemService(Context.TELEPHONY_SERVICE);
- doReturn(mSubscriptionManager).when(mContext).getSystemService(
- Context.TELEPHONY_SUBSCRIPTION_SERVICE);
-
- doReturn(mCarrierConfigManager).when(mContext).getSystemService(
- Context.CARRIER_CONFIG_SERVICE);
- doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(SUB_ID);
- doReturn(mInvalidTelephonyManager).when(mTelephonyManager).createForSubscriptionId(
- SubscriptionManager.INVALID_SUBSCRIPTION_ID);
- doReturn(mFragmentTransaction).when(mFragmentManager).beginTransaction();
-
- mPreference = spy(new RestrictedSwitchPreference(mContext));
- mController = spy(
- new RoamingPreferenceController(mContext, "roaming", mLifecycle, mLifecycleOwner,
- SUB_ID));
- mLifecycleRegistry = new LifecycleRegistry(mLifecycleOwner);
- when(mLifecycleOwner.getLifecycle()).thenReturn(mLifecycleRegistry);
- mController.init(mFragmentManager, SUB_ID, mMobileNetworkInfoEntity);
- mPreference.setKey(mController.getPreferenceKey());
- }
-
- private MobileNetworkInfoEntity setupMobileNetworkInfoEntity(String subId,
- boolean isDataRoaming) {
- return new MobileNetworkInfoEntity(subId, false, false, true, false, false, false, false,
- false, false, false, isDataRoaming);
- }
-
- @Test
- public void getAvailabilityStatus_validSubId_returnAvailable() {
- assertThat(mController.getAvailabilityStatus()).isEqualTo(
- AVAILABLE);
- }
-
- @Test
- public void getAvailabilityStatus_invalidSubId_returnUnsearchable() {
- mController.init(mFragmentManager, SubscriptionManager.INVALID_SUBSCRIPTION_ID,
- mMobileNetworkInfoEntity);
-
- assertThat(mController.getAvailabilityStatus(
- SubscriptionManager.INVALID_SUBSCRIPTION_ID)).isEqualTo(
- BasePreferenceController.AVAILABLE_UNSEARCHABLE);
- }
-
- @Test
- public void isDialogNeeded_roamingDisabledWithoutFlag_returnTrue() {
- final PersistableBundle bundle = new PersistableBundle();
- bundle.putBoolean(CarrierConfigManager.KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
- doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(SUB_ID);
- mMobileNetworkInfoEntity = setupMobileNetworkInfoEntity(String.valueOf(SUB_ID), false);
- mController.setMobileNetworkInfoEntity(mMobileNetworkInfoEntity);
-
- assertThat(mController.isDialogNeeded()).isTrue();
- }
-
- @Test
- public void isDialogNeeded_roamingEnabled_returnFalse() {
- mMobileNetworkInfoEntity = setupMobileNetworkInfoEntity(String.valueOf(SUB_ID), true);
- mController.setMobileNetworkInfoEntity(mMobileNetworkInfoEntity);
-
- assertThat(mController.isDialogNeeded()).isFalse();
- }
-
- @Test
- @UiThreadTest
- public void setChecked_needDialog_showDialog() {
- mMobileNetworkInfoEntity = setupMobileNetworkInfoEntity(String.valueOf(SUB_ID), false);
- mController.setMobileNetworkInfoEntity(mMobileNetworkInfoEntity);
- doReturn(null).when(mCarrierConfigManager).getConfigForSubId(SUB_ID);
-
- mController.setChecked(true);
-
- verify(mFragmentManager).beginTransaction();
- }
-
- @Test
- public void updateState_invalidSubId_disabled() {
- mMobileNetworkInfoEntity = setupMobileNetworkInfoEntity(
- String.valueOf(SubscriptionManager.INVALID_SUBSCRIPTION_ID), false);
- mController.setMobileNetworkInfoEntity(mMobileNetworkInfoEntity);
- mController.init(mFragmentManager, SubscriptionManager.INVALID_SUBSCRIPTION_ID,
- mMobileNetworkInfoEntity);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isEnabled()).isFalse();
- }
-
- @Test
- public void updateState_validSubId_enabled() {
- mMobileNetworkInfoEntity = setupMobileNetworkInfoEntity(String.valueOf(SUB_ID), true);
- mController.setMobileNetworkInfoEntity(mMobileNetworkInfoEntity);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isEnabled()).isTrue();
- assertThat(mPreference.isChecked()).isTrue();
- }
-
- @Test
- public void updateState_isNotDisabledByAdmin_shouldInvokeSetEnabled() {
- when(mPreference.isDisabledByAdmin()).thenReturn(false);
-
- mController.updateState(mPreference);
-
- verify(mPreference).setEnabled(anyBoolean());
- }
-
- @Test
- public void updateState_isDisabledByAdmin_shouldNotInvokeSetEnabled() {
- when(mPreference.isDisabledByAdmin()).thenReturn(true);
-
- mController.updateState(mPreference);
-
- verify(mPreference, never()).setEnabled(anyBoolean());
- }
-
- @Test
- public void getAvailabilityStatus_carrierConfigIsNull_shouldReturnAvailable() {
- doReturn(null).when(mCarrierConfigManager).getConfigForSubId(SUB_ID);
-
- assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
- }
-
- @Test
- public void getAvailabilityStatus_forceHomeNetworkIsFalse_shouldReturnAvailable() {
- final PersistableBundle bundle = new PersistableBundle();
- bundle.putBoolean(CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL, false);
- doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(SUB_ID);
-
- assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
- }
-
- @Test
- public void getAvailabilityStatus_forceHomeNetworkIsTrue_shouldReturnConditionallyAvailable() {
- final PersistableBundle bundle = new PersistableBundle();
- bundle.putBoolean(CarrierConfigManager.KEY_FORCE_HOME_NETWORK_BOOL, true);
- doReturn(bundle).when(mCarrierConfigManager).getConfigForSubId(SUB_ID);
-
- assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
- }
-}