Merge "Import translations. DO NOT MERGE ANYWHERE" into main
diff --git a/res/layout/preference_battery_header_text.xml b/res/layout/preference_battery_header_text.xml
index 72bdbf6..616984e 100644
--- a/res/layout/preference_battery_header_text.xml
+++ b/res/layout/preference_battery_header_text.xml
@@ -18,8 +18,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:layout_marginStart="?android:attr/listPreferredItemPaddingStart"
- android:layout_marginEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:layout_marginTop="-6dp"
android:paddingBottom="16dp">
<TextView
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6ba2853..ea505da 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2007,6 +2007,8 @@
<string name="external_display_off">Off</string>
<!-- External Display settings. The title of the screen. [CHAR LIMIT=40] -->
<string name="external_display_settings_title">External Display</string>
+ <!-- Built-in display settings category. Appears in External displays and Connected Displays fragments. -->
+ <string name="builtin_display_settings_category">Built-in display</string>
<!-- External Display use. The title of the use preference. [CHAR LIMIT=40] -->
<string name="external_display_use_title">Use external display</string>
<!-- External Display resolution settings. The title of the screen. [CHAR LIMIT=40] -->
@@ -2871,9 +2873,9 @@
<!-- Display settings screen, screen resolution option for high resolution [CHAR LIMIT=45] -->
<string name="screen_resolution_option_high">High resolution</string>
<!-- Display settings screen, screen resolution option for full resolution [CHAR LIMIT=45] -->
- <string name="screen_resolution_option_full">Full resolution</string>
+ <string name="screen_resolution_option_full">Max resolution</string>
<!-- The footer message for switch screen resolution [CHAR LIMIT=NONE] -->
- <string name="screen_resolution_footer">Full resolution uses more of your battery. Switching your resolution may cause some apps to restart.</string>
+ <string name="screen_resolution_footer">Max resolution uses more of your battery. Switching your resolution may cause some apps to restart.</string>
<!-- Message announced to a11y users when they selected one resolution [CHAR LIMIT=NONE] -->
<string name="screen_resolution_selected_a11y">Selected</string>
@@ -4681,6 +4683,9 @@
<string name="pointer_stroke_style_name_none">None</string>
<!-- Title for the button to trigger the 'touch gesture' education. [CHAR LIMIT=35] -->
<string name="trackpad_touch_gesture">Learn touchpad gestures</string>
+ <!-- TODO(b/353947750): finalize this string and mark it translatable. -->
+ <!-- Notice displayed at the end of the touchpad settings page when the user has disabled system navigation gestures. "Pointer & touchpad accessibility" and "Use touchpad gestures" refer to other labels in Settings, and should be translated in exactly the same way. -->
+ <string name="trackpad_gestures_disabled_footer_text" translatable="false">Some settings are unavailable as touchpad gestures have been turned off. You can turn them on via Pointer & touchpad accessibility > Use touchpad gestures</string>
<!-- Search keywords for "touchpad" -->
<string name="keywords_touchpad">trackpad, track pad, mouse, cursor, scroll, swipe, right click, click, pointer</string>
<!-- Search keywords for 'Bottom-right tap', the name of the touchpad setting that allows the user to click the bottom right corner of the touchpad for more options. -->
@@ -4963,6 +4968,15 @@
<string name="accessibility_pointer_and_touchpad_summary">Pointer color, pointer size & more</string>
<!-- Title for the accessibility pointer color customization page. [CHAR LIMIT=50] -->
<string name="accessibility_pointer_color_customization_title">Pointer color customization</string>
+ <!-- TODO(b/353947750): finalize the four strings below and mark them translatable. -->
+ <!-- Title for the touchpad section of the accessibility pointer and touchpad page. -->
+ <string name="accessibility_touchpad_title" translatable="false">Touchpad</string>
+ <!-- Title for a settings toggle that allows the user to enable or disable system gestures (3- or 4-finger swipes for going home, back, to the overview screen, or between apps) being made on a touchpad. -->
+ <string name="accessibility_touchpad_system_gestures_enable_title" translatable="false">Use system gestures</string>
+ <!-- Description text for a settings toggle that allows the user to enable or disable system gestures (3- or 4-finger swipes for going home, back, to the overview screen, or between apps) being made on a touchpad. -->
+ <string name="accessibility_touchpad_system_gestures_enable_summary" translatable="false">When turned off, 3- or 4-finger gestures are ignored</string>
+ <!-- List of synonyms used in the settings search bar to find the "Use system gestures" touchpad setting, which allows the user to enable or disable system gestures (3- or 4-finger swipes for going home, back, to the overview screen, or between apps) being made on a touchpad. -->
+ <string name="keywords_accessibility_touchpad_system_gestures_enable" translatable="false">touchpad, trackpad, swipe</string>
<!-- Title for the accessibility color contrast page. [CHAR LIMIT=50] -->
<string name="accessibility_color_contrast_title">Color contrast</string>
<!-- Intro for the accessibility color contrast page. [CHAR LIMIT=NONE] -->
@@ -12273,15 +12287,15 @@
<!-- Summary for _satellite_setting_preference_layout. [CHAR LIMIT=NONE]-->
<string name="satellite_setting_disabled_summary">Send and receive text messages by satellite. Not included with your account.</string>
<!-- Search keywords for "_satellite_setting_preference_layout" [CHAR_LIMIT=NONE] -->
- <string name="keywords_satellite_setting">Satellite messaging</string>
+ <string name="keywords_satellite_setting">Satellite messaging, satellite connectivity</string>
<!-- Category name "About satellite messaging" [CHAR_LIMIT=NONE] -->
- <string name="category_name_about_satellite_messaging">About satellite messaging</string>
+ <string name="category_name_about_satellite_messaging">About <xliff:g id="subject" example="satellite messaging">%1$s</xliff:g></string>
<!-- Summary for category "About satellite messaging" [CHAR_LIMIT=NONE] -->
<string name="title_about_satellite_setting">You can send and receive text messages by satellite as part of an eligible <xliff:g id="carrier_name" example="T-Mobile">%1$s</xliff:g> account</string>
<!-- Category title "Your mobile plan" [CHAR_LIMIT=NONE] -->
<string name="category_title_your_satellite_plan">Your <xliff:g id="carrier_name" example="T-Mobile">%1$s</xliff:g> plan</string>
<!-- Title for category "Your mobile plan when satellite is included in plan" [CHAR_LIMIT=NONE] -->
- <string name="title_have_satellite_plan">Satellite messaging is included with your account</string>
+ <string name="title_have_satellite_plan">Messaging is included with your account</string>
<!-- Title for category "Your mobile plan when satellite is not included in plan" [CHAR_LIMIT=NONE] -->
<string name="title_no_satellite_plan">Satellite messaging isn\u2019t included with your account</string>
<!-- text view "Learn more" [CHAR_LIMIT=NONE] -->
@@ -12297,9 +12311,9 @@
<!-- Summary for satellite supported service [CHAR_LIMIT=NONE] -->
<string name="summary_supported_service">You can text anyone, including emergency services. Your phone will reconnect to a mobile network when available.</string>
<!-- learn more text - more about satellite messaging [CHAR_LIMIT=NONE] -->
- <string name="satellite_setting_summary_more_information">Satellite messaging may take longer and is available only in some areas. Weather and certain structures may affect your satellite connection. Calling by satellite isn\u2019t available. Emergency calls may still connect.\n\nIt may take some time for account changes to show in Settings. Contact your carrier for details.</string>
+ <string name="satellite_setting_summary_more_information"><xliff:g id="subject" example="satellite messaging">%1$s</xliff:g> may take longer and is available only in some areas. Weather and certain structures may affect your satellite connection. Calling by satellite isn\u2019t available. Emergency calls may still connect.\n\nIt may take some time for account changes to show in Settings. Contact <xliff:g id="carrier_name" example="T-Mobile">%1$s</xliff:g> for details.</string>
<!-- more about satellite messaging [CHAR_LIMIT=NONE] -->
- <string name="more_about_satellite_messaging">More about satellite messaging</string>
+ <string name="more_about_satellite_messaging">More about <xliff:g id="subject" example="satellite messaging">%1$s</xliff:g></string>
<!-- Title for satellite warning dialog to avoid user using wifi/bluetooth/airplane mode [CHAR_LIMIT=NONE] -->
<string name="satellite_warning_dialog_title">Can’t turn on <xliff:g id="function" example="bluetooth">%1$s</xliff:g></string>
<!-- Content for satellite warning dialog to avoid user using wifi/bluetooth/airplane mode [CHAR_LIMIT=NONE] -->
@@ -12307,7 +12321,20 @@
<!-- Category title for satellite functions with data transmission in mobile network settings [CHAR LIMIT=60] -->
<string name="category_title_satellite_connectivity">Satellite connectivity</string>
<!-- Title for satellite functions with data transmission in mobile network settings [CHAR LIMIT=60] -->
- <string name="satellite_setting_connectivity">Satellite connectivity</string>
+ <string name="title_satellite_setting_connectivity">Satellite connectivity</string>
+ <!-- Description of satellite function with data transmission [CHAR LIMIT=60] -->
+ <string name="description_satellite_setting_connectivity">satellite connectivity</string>
+ <!-- Description of satellite function [CHAR LIMIT=60] -->
+ <string name="description_satellite_setting_messaging">satellite messaging</string>
+ <!-- Title for notifying user's account be able to use data transmission of Satellite" [CHAR_LIMIT=NONE] -->
+ <string name="title_have_satellite_data_plan">Use of data is included with your account</string>
+ <!-- Title for the entry of Satellite SOS [CHAR_LIMIT=NONE] -->
+ <string name="title_for_satellite_sos_entry">Satellite SOS</string>
+ <!-- Summary for the entry of Satellite SOS [CHAR_LIMIT=NONE] -->
+ <string name="summary_for_satellite_sos_entry">Message with emergency services when you can\u2019t connect to a mobile or Wi\u2011Fi network</string>
+ <!-- Keywords for the entry of Satellite SOS [CHAR_LIMIT=NONE] -->
+ <string name="keywords_satellite_sos">satellite sos, sos</string>
+
<!-- Title for Apn settings in mobile network settings [CHAR LIMIT=60] -->
diff --git a/res/xml/accessibility_pointer_and_touchpad.xml b/res/xml/accessibility_pointer_and_touchpad.xml
index 8da4177..a46c857 100644
--- a/res/xml/accessibility_pointer_and_touchpad.xml
+++ b/res/xml/accessibility_pointer_and_touchpad.xml
@@ -46,4 +46,17 @@
settings:keywords="@string/keywords_auto_click"
settings:controller="com.android.settings.accessibility.AutoclickPreferenceController"/>
+ <PreferenceCategory
+ android:key="touchpad_category"
+ android:persistent="false"
+ android:title="@string/accessibility_touchpad_title">
+
+ <SwitchPreferenceCompat
+ android:key="touchpad_system_gestures_enable"
+ android:title="@string/accessibility_touchpad_system_gestures_enable_title"
+ android:summary="@string/accessibility_touchpad_system_gestures_enable_summary"
+ settings:keywords="@string/keywords_accessibility_touchpad_system_gestures_enable"/>
+
+ </PreferenceCategory>
+
</PreferenceScreen>
diff --git a/res/xml/accessibility_vibration_intensity_settings.xml b/res/xml/accessibility_vibration_intensity_settings.xml
index f9a5578..ba1bd83 100644
--- a/res/xml/accessibility_vibration_intensity_settings.xml
+++ b/res/xml/accessibility_vibration_intensity_settings.xml
@@ -20,7 +20,7 @@
android:title="@string/accessibility_vibration_settings_title">
<com.android.settingslib.widget.MainSwitchPreference
- android:key="vibration_intensity_switch_main"
+ android:key="vibrate_on"
android:title="@string/accessibility_vibration_primary_switch_title"
app:keywords="@string/keywords_accessibility_vibration_primary_switch"
app:controller="com.android.settings.accessibility.VibrationMainSwitchPreferenceController"/>
diff --git a/res/xml/accessibility_vibration_settings.xml b/res/xml/accessibility_vibration_settings.xml
index 3ce92a6..be45659 100644
--- a/res/xml/accessibility_vibration_settings.xml
+++ b/res/xml/accessibility_vibration_settings.xml
@@ -20,7 +20,7 @@
android:title="@string/accessibility_vibration_settings_title">
<com.android.settingslib.widget.MainSwitchPreference
- android:key="vibration_switch_main"
+ android:key="vibrate_on"
android:title="@string/accessibility_vibration_primary_switch_title"
app:keywords="@string/keywords_accessibility_vibration_primary_switch"
app:controller="com.android.settings.accessibility.VibrationMainSwitchPreferenceController"/>
diff --git a/res/xml/mobile_network_settings.xml b/res/xml/mobile_network_settings.xml
index 3c1317d..72acbe0 100644
--- a/res/xml/mobile_network_settings.xml
+++ b/res/xml/mobile_network_settings.xml
@@ -217,6 +217,16 @@
settings:controller=
"com.android.settings.network.telephony.SatelliteSettingPreferenceController"/>
+ <com.android.settingslib.RestrictedPreference
+ android:key="telephony_satellite_setting_sos_key"
+ android:persistent="false"
+ android:title="@string/title_for_satellite_sos_entry"
+ android:summary="@string/summary_for_satellite_sos_entry"
+ settings:keywords="@string/keywords_satellite_setting"
+ settings:fragment="com.android.settings.network.telephony.SatelliteSettingsSosFragment"
+ settings:controller=
+ "com.android.settings.network.telephony.SatelliteSettingSosPreferenceController"/>
+
</PreferenceCategory>
<PreferenceCategory
diff --git a/res/xml/power_usage_summary.xml b/res/xml/power_usage_summary.xml
index c7cf873..21a836d 100644
--- a/res/xml/power_usage_summary.xml
+++ b/res/xml/power_usage_summary.xml
@@ -26,7 +26,6 @@
android:title="@string/summary_placeholder"
android:selectable="false"
android:paddingBottom="0px"
- android:persistent="false"
settings:controller="com.android.settings.fuelgauge.BatteryHeaderPreferenceController" />
<com.android.settings.fuelgauge.BatteryHeaderTextPreference
diff --git a/res/xml/satellite_setting.xml b/res/xml/satellite_setting.xml
index 09fbbd6..60fe5bf 100644
--- a/res/xml/satellite_setting.xml
+++ b/res/xml/satellite_setting.xml
@@ -22,7 +22,7 @@
settings:keywords="@string/keywords_satellite_setting">
<PreferenceCategory
- android:title="@string/category_name_about_satellite_messaging">
+ android:key="key_category_about_satellite">
<com.android.settingslib.widget.TopIntroPreference
android:key="key_about_satellite_messaging"/>
@@ -35,6 +35,12 @@
<Preference
android:key="key_your_satellite_plan"
android:icon="?android:attr/textColorPrimary"/>
+
+ <Preference
+ android:key="key_your_satellite_data_plan"
+ android:icon="?android:attr/textColorPrimary"
+ settings:isPreferenceVisible="false"/>
+
</PreferenceCategory>
<PreferenceCategory
diff --git a/res/xml/touchpad_and_mouse_settings.xml b/res/xml/touchpad_and_mouse_settings.xml
index cdfd398..b82b3a6 100644
--- a/res/xml/touchpad_and_mouse_settings.xml
+++ b/res/xml/touchpad_and_mouse_settings.xml
@@ -96,4 +96,10 @@
android:key="trackpad_touch_gesture"
android:title="@string/trackpad_touch_gesture"
settings:controller="com.android.settings.inputmethod.TouchGesturesButtonPreferenceController"/>
+
+ <com.android.settingslib.widget.FooterPreference
+ android:key="trackpad_gestures_disabled_footer"
+ android:title="@string/trackpad_gestures_disabled_footer_text"
+ settings:searchable="false"
+ settings:controller="com.android.settings.inputmethod.TrackpadGesturesDisabledFooterPreferenceController"/>
</PreferenceScreen>
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index 34badfc..39ce081 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -43,7 +43,6 @@
import com.android.settings.R;
import com.android.settings.accessibility.AccessibilityUtil.AccessibilityServiceFragmentType;
import com.android.settings.dashboard.DashboardFragment;
-import com.android.settings.development.Enable16kUtils;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.RestrictedPreference;
@@ -96,8 +95,6 @@
static final String EXTRA_TIME_FOR_LOGGING = "start_time_to_log_a11y_tool";
static final String EXTRA_METRICS_CATEGORY = "metrics_category";
- public static final String VOICE_ACCESS_SERVICE = "android.apps.accessibility.voiceaccess";
-
// Timeout before we update the services if packages are added/removed
// since the AccessibilityManagerService has to do that processing first
// to generate the AccessibilityServiceInfo we need for proper
@@ -503,11 +500,6 @@
String[] services = getResources().getStringArray(key);
PreferenceCategory category = mCategoryToPrefCategoryMap.get(categoryKey);
for (int i = 0; i < services.length; i++) {
- // TODO(b/335443194) Voice access is not available in 16kB mode.
- if (services[i].contains(VOICE_ACCESS_SERVICE)
- && Enable16kUtils.isPageAgnosticModeOn(getContext())) {
- continue;
- }
ComponentName component = ComponentName.unflattenFromString(services[i]);
mPreBundledServiceComponentToCategoryMap.put(component, category);
}
diff --git a/src/com/android/settings/accessibility/RemoveAnimationsPreference.kt b/src/com/android/settings/accessibility/RemoveAnimationsPreference.kt
index 5b732bc..65519e9 100644
--- a/src/com/android/settings/accessibility/RemoveAnimationsPreference.kt
+++ b/src/com/android/settings/accessibility/RemoveAnimationsPreference.kt
@@ -28,6 +28,7 @@
import com.android.settingslib.metadata.PreferenceLifecycleContext
import com.android.settingslib.metadata.PreferenceLifecycleProvider
import com.android.settingslib.metadata.ReadWritePermit
+import com.android.settingslib.metadata.SensitivityLevel
import com.android.settingslib.metadata.SwitchPreference
class RemoveAnimationsPreference :
@@ -70,6 +71,9 @@
override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) =
ReadWritePermit.ALLOW
+ override val sensitivityLevel
+ get() = SensitivityLevel.NO_SENSITIVITY
+
@Suppress("UNCHECKED_CAST")
private class RemoveAnimationsStorage(private val context: Context) :
NoOpKeyedObservable<String>(), KeyValueStore {
diff --git a/src/com/android/settings/accessibility/RestrictedPreferenceHelper.java b/src/com/android/settings/accessibility/RestrictedPreferenceHelper.java
index 82aa098..d97895a 100644
--- a/src/com/android/settings/accessibility/RestrictedPreferenceHelper.java
+++ b/src/com/android/settings/accessibility/RestrictedPreferenceHelper.java
@@ -16,8 +16,6 @@
package com.android.settings.accessibility;
-import static com.android.settings.accessibility.AccessibilitySettings.VOICE_ACCESS_SERVICE;
-
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accessibilityservice.AccessibilityShortcutInfo;
import android.app.AppOpsManager;
@@ -31,7 +29,6 @@
import android.text.TextUtils;
import com.android.settings.R;
-import com.android.settings.development.Enable16kUtils;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.RestrictedPreference;
@@ -81,12 +78,6 @@
final AccessibilityServiceInfo info = installedServices.get(i);
final ResolveInfo resolveInfo = info.getResolveInfo();
final String packageName = resolveInfo.serviceInfo.packageName;
- // TODO(b/335443194) Voice access is not available in 16kB mode.
- if (packageName.contains(VOICE_ACCESS_SERVICE)
- && Enable16kUtils.isPageAgnosticModeOn(mContext)) {
- continue;
- }
-
final ComponentName componentName = new ComponentName(packageName,
resolveInfo.serviceInfo.name);
final boolean serviceEnabled = enabledServices.contains(componentName);
diff --git a/src/com/android/settings/accessibility/VibrationIntensityScreen.kt b/src/com/android/settings/accessibility/VibrationIntensityScreen.kt
index 5d7d4fb..0a37230 100644
--- a/src/com/android/settings/accessibility/VibrationIntensityScreen.kt
+++ b/src/com/android/settings/accessibility/VibrationIntensityScreen.kt
@@ -19,18 +19,32 @@
import androidx.fragment.app.Fragment
import com.android.settings.R
import com.android.settings.flags.Flags
+import com.android.settingslib.metadata.PreferenceAvailabilityProvider
import com.android.settingslib.metadata.ProvidePreferenceScreen
import com.android.settingslib.metadata.preferenceHierarchy
import com.android.settingslib.preference.PreferenceScreenCreator
+/**
+ * Accessibility settings for vibration intensities.
+ */
+// TODO(b/368360218): investigate if we still need this screen once we finish the migration.
+// We might be able to consolidate this into VibrationScreen with PreferenceHierarchy choosing
+// between toggle or slider preferences based on device config, depending on how overlays are done.
+// LINT.IfChange
@ProvidePreferenceScreen
-class VibrationIntensityScreen : PreferenceScreenCreator {
+class VibrationIntensityScreen : PreferenceScreenCreator, PreferenceAvailabilityProvider {
override val key: String
get() = KEY
override val title: Int
get() = R.string.accessibility_vibration_settings_title
+ override val keywords: Int
+ get() = R.string.keywords_vibration
+
+ override fun isAvailable(context: Context) =
+ context.isVibratorAvailable() && context.getSupportedVibrationIntensityLevels() > 1
+
override fun isFlagEnabled(context: Context): Boolean = Flags.catalystVibrationIntensityScreen()
override fun hasCompleteHierarchy() = false
@@ -38,9 +52,12 @@
override fun fragmentClass(): Class<out Fragment>? =
VibrationIntensitySettingsFragment::class.java
- override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {}
+ override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {
+ +VibrationMainSwitchPreference()
+ }
companion object {
const val KEY = "vibration_intensity_screen"
}
}
+// LINT.ThenChange(VibrationPreferenceController.java)
diff --git a/src/com/android/settings/accessibility/VibrationMainSwitchPreference.kt b/src/com/android/settings/accessibility/VibrationMainSwitchPreference.kt
new file mode 100644
index 0000000..70a0033
--- /dev/null
+++ b/src/com/android/settings/accessibility/VibrationMainSwitchPreference.kt
@@ -0,0 +1,100 @@
+/*
+ * 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.accessibility
+
+import android.content.Context
+import android.os.VibrationAttributes
+import android.os.Vibrator
+import android.provider.Settings
+import android.widget.CompoundButton
+import android.widget.CompoundButton.OnCheckedChangeListener
+import com.android.settings.R
+import com.android.settingslib.datastore.KeyValueStore
+import com.android.settingslib.datastore.KeyedObservableDelegate
+import com.android.settingslib.datastore.SettingsStore
+import com.android.settingslib.datastore.SettingsSystemStore
+import com.android.settingslib.metadata.MainSwitchPreference
+import com.android.settingslib.metadata.PreferenceLifecycleContext
+import com.android.settingslib.metadata.PreferenceLifecycleProvider
+import com.android.settingslib.metadata.ReadWritePermit
+import com.android.settingslib.preference.MainSwitchPreferenceBinding
+
+/**
+ * Accessibility settings for vibration.
+ */
+// LINT.IfChange
+class VibrationMainSwitchPreference : MainSwitchPreference(
+ key = Settings.System.VIBRATE_ON,
+ title = R.string.accessibility_vibration_primary_switch_title,
+), PreferenceLifecycleProvider, OnCheckedChangeListener {
+ override val keywords: Int
+ get() = R.string.keywords_accessibility_vibration_primary_switch
+
+ lateinit var vibrator: Vibrator
+
+ override fun storage(context: Context): KeyValueStore =
+ VibrationMainSwitchToggleStorage(SettingsSystemStore.get(context))
+
+ override fun getReadPermit(context: Context, myUid: Int, callingUid: Int) =
+ ReadWritePermit.ALLOW
+
+ override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) =
+ ReadWritePermit.ALLOW
+
+ override fun onResume(context: PreferenceLifecycleContext) {
+ vibrator = context.getSystemService(Vibrator::class.java)
+ context.findPreference<com.android.settingslib.widget.MainSwitchPreference>(key)
+ ?.addOnSwitchChangeListener(this)
+ }
+
+ override fun onPause(context: PreferenceLifecycleContext) {
+ context.findPreference<com.android.settingslib.widget.MainSwitchPreference>(key)
+ ?.removeOnSwitchChangeListener(this)
+ }
+
+ override fun onCheckedChanged(button: CompoundButton, isChecked: Boolean) {
+ if (isChecked) {
+ // Play a haptic as preview for the main toggle only when touch feedback is enabled.
+ VibrationPreferenceConfig.playVibrationPreview(
+ vibrator, VibrationAttributes.USAGE_TOUCH
+ )
+ }
+ }
+
+ /** Provides SettingsStore for vibration main switch with custom default value. */
+ @Suppress("UNCHECKED_CAST")
+ private class VibrationMainSwitchToggleStorage(
+ private val settingsStore: SettingsStore,
+ ) : KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
+
+ override fun contains(key: String) = settingsStore.contains(key)
+
+ override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) =
+ DEFAULT_VALUE as T
+
+ override fun <T : Any> getValue(key: String, valueType: Class<T>) =
+ (settingsStore.getBoolean(key) ?: DEFAULT_VALUE) as T
+
+ override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
+ settingsStore.setBoolean(key, value as Boolean?)
+ }
+ }
+
+ companion object {
+ const val DEFAULT_VALUE = true
+ }
+}
+// LINT.ThenChange(VibrationMainSwitchPreferenceController.java)
diff --git a/src/com/android/settings/accessibility/VibrationMainSwitchPreferenceController.java b/src/com/android/settings/accessibility/VibrationMainSwitchPreferenceController.java
index 5b553e3..0f2fb77 100644
--- a/src/com/android/settings/accessibility/VibrationMainSwitchPreferenceController.java
+++ b/src/com/android/settings/accessibility/VibrationMainSwitchPreferenceController.java
@@ -41,6 +41,7 @@
* will disable the entire settings screen once the settings is turned OFF. All device haptics will
* be disabled by this setting, except the flagged alerts and accessibility touch feedback.
*/
+// LINT.IfChange
public class VibrationMainSwitchPreferenceController extends SettingsMainSwitchPreferenceController
implements LifecycleObserver, OnStart, OnStop {
@@ -106,3 +107,4 @@
return R.string.menu_key_accessibility;
}
}
+// LINT.ThenChange(VibrationMainSwitchPreference.kt)
diff --git a/src/com/android/settings/accessibility/VibrationPreferenceController.java b/src/com/android/settings/accessibility/VibrationPreferenceController.java
index 092ff69..e84543d 100644
--- a/src/com/android/settings/accessibility/VibrationPreferenceController.java
+++ b/src/com/android/settings/accessibility/VibrationPreferenceController.java
@@ -31,6 +31,7 @@
import com.android.settings.core.SubSettingLauncher;
/** Controller for "Vibration & haptics" settings page. */
+// LINT.IfChange
public class VibrationPreferenceController extends BasePreferenceController {
private final boolean mHasVibrator;
@@ -79,3 +80,7 @@
}
+// LINT.ThenChange(
+// VibrationIntensityScreenTest.kt,
+// VibrationScreenTest.kt,
+// )
diff --git a/src/com/android/settings/accessibility/VibrationScreen.kt b/src/com/android/settings/accessibility/VibrationScreen.kt
new file mode 100644
index 0000000..63a7c44
--- /dev/null
+++ b/src/com/android/settings/accessibility/VibrationScreen.kt
@@ -0,0 +1,69 @@
+/*
+ * 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.accessibility
+
+import android.content.Context
+import android.os.Vibrator
+import androidx.fragment.app.Fragment
+import com.android.settings.R
+import com.android.settings.flags.Flags
+import com.android.settingslib.metadata.PreferenceAvailabilityProvider
+import com.android.settingslib.metadata.ProvidePreferenceScreen
+import com.android.settingslib.metadata.preferenceHierarchy
+import com.android.settingslib.preference.PreferenceScreenCreator
+
+/**
+ * Accessibility settings for vibration.
+ */
+// LINT.IfChange
+@ProvidePreferenceScreen
+class VibrationScreen : PreferenceScreenCreator, PreferenceAvailabilityProvider {
+ override val key: String
+ get() = KEY
+
+ override val title: Int
+ get() = R.string.accessibility_vibration_settings_title
+
+ override val keywords: Int
+ get() = R.string.keywords_vibration
+
+ override fun isAvailable(context: Context) =
+ context.isVibratorAvailable() && context.getSupportedVibrationIntensityLevels() == 1
+
+ override fun isFlagEnabled(context: Context): Boolean = Flags.catalystVibrationIntensityScreen()
+
+ override fun hasCompleteHierarchy() = false
+
+ override fun fragmentClass(): Class<out Fragment>? = VibrationSettings::class.java
+
+ override fun getPreferenceHierarchy(context: Context) = preferenceHierarchy(this) {
+ +VibrationMainSwitchPreference()
+ }
+
+ companion object {
+ const val KEY = "vibration_screen"
+ }
+}
+
+/** Returns true if the device has a system vibrator, false otherwise. */
+fun Context.isVibratorAvailable(): Boolean =
+ getSystemService(Vibrator::class.java).hasVibrator()
+
+/** Returns the number of vibration intensity levels supported by this device. */
+fun Context.getSupportedVibrationIntensityLevels(): Int =
+ resources.getInteger(R.integer.config_vibration_supported_intensity_levels)
+
+// LINT.ThenChange(VibrationPreferenceController.java)
diff --git a/src/com/android/settings/accessibility/VibrationSettings.java b/src/com/android/settings/accessibility/VibrationSettings.java
index 48393d9..11e1ddd 100644
--- a/src/com/android/settings/accessibility/VibrationSettings.java
+++ b/src/com/android/settings/accessibility/VibrationSettings.java
@@ -20,6 +20,8 @@
import android.content.Context;
import android.os.Vibrator;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.settings.R;
@@ -36,6 +38,11 @@
private static final String TAG = "VibrationSettings";
@Override
+ public @Nullable String getPreferenceScreenBindingKey(@NonNull Context context) {
+ return VibrationScreen.KEY;
+ }
+
+ @Override
public int getMetricsCategory() {
return SettingsEnums.ACCESSIBILITY_VIBRATION;
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
index 924ba2c..f782c6b 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
@@ -27,7 +27,6 @@
import android.text.TextUtils;
import android.util.Log;
-import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
@@ -109,28 +108,34 @@
PreferenceFragmentCompat fragment,
LocalBluetoothManager manager,
CachedBluetoothDevice device,
- Lifecycle lifecycle,
- @Nullable List<String> invisibleProfiles,
- boolean hasExtraSpace) {
+ Lifecycle lifecycle) {
super(context, fragment, device, lifecycle);
mManager = manager;
mProfileManager = mManager.getProfileManager();
mCachedDevice = device;
mCachedDeviceGroup = Utils.findAllCachedBluetoothDevicesByGroupId(mManager, mCachedDevice);
+ }
+
+ /** Sets the profiles to be hidden. */
+ public void setInvisibleProfiles(List<String> invisibleProfiles) {
if (invisibleProfiles != null) {
mInvisibleProfiles = Set.copyOf(invisibleProfiles);
}
- mHasExtraSpace = hasExtraSpace;
}
- @Override
- protected void init(PreferenceScreen screen) {
- mProfilesContainer = (PreferenceCategory)screen.findPreference(getPreferenceKey());
- if (mHasExtraSpace) {
+ /** Sets whether it should show an extra padding on top of the preference. */
+ public void setHasExtraSpace(boolean hasExtraSpace) {
+ if (hasExtraSpace) {
mProfilesContainer.setLayoutResource(R.layout.preference_bluetooth_profile_category);
} else {
mProfilesContainer.setLayoutResource(R.layout.preference_category_bluetooth_no_padding);
}
+ }
+
+ @Override
+ protected void init(PreferenceScreen screen) {
+ mProfilesContainer = (PreferenceCategory) screen.findPreference(getPreferenceKey());
+ mProfilesContainer.setLayoutResource(R.layout.preference_bluetooth_profile_category);
// Call refresh here even though it will get called later in onResume, to avoid the
// list of switches appearing to "pop" into the page.
refresh();
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index 633b44f..403a824 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -61,7 +61,6 @@
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
import java.util.ArrayList;
import java.util.List;
@@ -289,9 +288,12 @@
getController(
SlicePreferenceController.class,
controller -> {
- controller.setSliceUri(finalControlUri);
- controller.onStart();
- controller.displayPreference(getPreferenceScreen());
+ if (getPreferenceScreen().findPreference(controller.getPreferenceKey())
+ != null) {
+ controller.setSliceUri(finalControlUri);
+ controller.onStart();
+ controller.displayPreference(getPreferenceScreen());
+ }
});
// Temporarily fix the issue that the page will be automatically scrolled to a wrong
@@ -352,9 +354,23 @@
}
@Override
- public void onCreatePreferences(@NonNull Bundle savedInstanceState, @NonNull String rootKey) {
- super.onCreatePreferences(savedInstanceState, rootKey);
+ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
if (Flags.enableBluetoothDeviceDetailsPolish()) {
+ if (mFormatter == null) {
+ List<AbstractPreferenceController> controllers = getPreferenceControllers().stream()
+ .flatMap(List::stream)
+ .toList();
+ mFormatter =
+ FeatureFactory.getFeatureFactory()
+ .getBluetoothFeatureProvider()
+ .getDeviceDetailsFragmentFormatter(
+ requireContext(),
+ this,
+ mBluetoothAdapter,
+ mCachedDevice,
+ controllers);
+ }
mFormatter.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment.INSTANCE);
}
}
@@ -410,37 +426,7 @@
}
@Override
- protected void addPreferenceController(AbstractPreferenceController controller) {
- if (Flags.enableBluetoothDeviceDetailsPolish()) {
- List<String> keys =
- mFormatter.getVisiblePreferenceKeys(
- FragmentTypeModel.DeviceDetailsMainFragment.INSTANCE);
- Lifecycle lifecycle = getSettingsLifecycle();
- if (keys == null || keys.contains(controller.getPreferenceKey())) {
- super.addPreferenceController(controller);
- } else if (controller instanceof LifecycleObserver) {
- lifecycle.removeObserver((LifecycleObserver) controller);
- }
- } else {
- super.addPreferenceController(controller);
- }
- }
-
- @Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
- List<String> invisibleProfiles = List.of();
- if (Flags.enableBluetoothDeviceDetailsPolish()) {
- if (mFormatter == null) {
- mFormatter =
- FeatureFactory.getFeatureFactory()
- .getBluetoothFeatureProvider()
- .getDeviceDetailsFragmentFormatter(
- requireContext(), this, mBluetoothAdapter, mCachedDevice);
- }
- invisibleProfiles =
- mFormatter.getInvisibleBluetoothProfiles(
- FragmentTypeModel.DeviceDetailsMainFragment.INSTANCE);
- }
ArrayList<AbstractPreferenceController> controllers = new ArrayList<>();
if (mCachedDevice != null) {
@@ -459,7 +445,7 @@
controllers.add(new BluetoothDetailsSpatialAudioController(context, this, mCachedDevice,
lifecycle));
controllers.add(new BluetoothDetailsProfilesController(context, this, mManager,
- mCachedDevice, lifecycle, invisibleProfiles, invisibleProfiles == null));
+ mCachedDevice, lifecycle));
controllers.add(new BluetoothDetailsMacAddressController(context, this, mCachedDevice,
lifecycle));
controllers.add(new StylusDevicesController(context, mInputDevice, mCachedDevice,
diff --git a/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java b/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java
index d87e609..dae7bb0 100644
--- a/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java
+++ b/src/com/android/settings/bluetooth/BluetoothFeatureProvider.java
@@ -26,10 +26,11 @@
import androidx.annotation.NonNull;
import androidx.preference.Preference;
-import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.bluetooth.ui.view.DeviceDetailsFragmentFormatter;
+import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.devicesettings.data.repository.DeviceSettingRepository;
+import com.android.settingslib.core.AbstractPreferenceController;
import kotlinx.coroutines.CoroutineScope;
@@ -100,7 +101,8 @@
@NonNull
DeviceDetailsFragmentFormatter getDeviceDetailsFragmentFormatter(
@NonNull Context context,
- @NonNull SettingsPreferenceFragment fragment,
+ @NonNull DashboardFragment fragment,
@NonNull BluetoothAdapter bluetoothAdapter,
- @NonNull CachedBluetoothDevice cachedDevice);
+ @NonNull CachedBluetoothDevice cachedDevice,
+ @NonNull List<AbstractPreferenceController> controllers);
}
diff --git a/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.kt b/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.kt
index 082c693..4807899 100644
--- a/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.kt
+++ b/src/com/android/settings/bluetooth/BluetoothFeatureProviderImpl.kt
@@ -23,13 +23,14 @@
import android.media.Spatializer
import android.net.Uri
import androidx.preference.Preference
-import com.android.settings.SettingsPreferenceFragment
import com.android.settings.bluetooth.ui.view.DeviceDetailsFragmentFormatter
import com.android.settings.bluetooth.ui.view.DeviceDetailsFragmentFormatterImpl
+import com.android.settings.dashboard.DashboardFragment
import com.android.settingslib.bluetooth.BluetoothUtils
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.devicesettings.data.repository.DeviceSettingRepository
import com.android.settingslib.bluetooth.devicesettings.data.repository.DeviceSettingRepositoryImpl
+import com.android.settingslib.core.AbstractPreferenceController
import com.google.common.collect.ImmutableList
import com.google.common.collect.ImmutableSet
import kotlinx.coroutines.CoroutineScope
@@ -78,13 +79,15 @@
override fun getDeviceDetailsFragmentFormatter(
context: Context,
- fragment: SettingsPreferenceFragment,
+ fragment: DashboardFragment,
bluetoothAdapter: BluetoothAdapter,
- cachedDevice: CachedBluetoothDevice
+ cachedDevice: CachedBluetoothDevice,
+ controllers: List<AbstractPreferenceController>,
): DeviceDetailsFragmentFormatter {
return DeviceDetailsFragmentFormatterImpl(
context,
fragment,
+ controllers,
bluetoothAdapter,
cachedDevice,
Dispatchers.IO
diff --git a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
index caa41ef..b093d9c 100644
--- a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
+++ b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
@@ -45,7 +45,8 @@
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
import com.android.settings.R
-import com.android.settings.SettingsPreferenceFragment
+import com.android.settings.bluetooth.BlockingPrefWithSliceController
+import com.android.settings.bluetooth.BluetoothDetailsProfilesController
import com.android.settings.bluetooth.ui.composable.Icon
import com.android.settings.bluetooth.ui.composable.MultiTogglePreference
import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout
@@ -54,12 +55,18 @@
import com.android.settings.bluetooth.ui.view.DeviceDetailsMoreSettingsFragment.Companion.KEY_DEVICE_ADDRESS
import com.android.settings.bluetooth.ui.viewmodel.BluetoothDeviceDetailsViewModel
import com.android.settings.core.SubSettingLauncher
+import com.android.settings.dashboard.DashboardFragment
import com.android.settings.overlay.FeatureFactory
import com.android.settings.spa.preference.ComposePreference
import com.android.settingslib.bluetooth.CachedBluetoothDevice
+import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingActionModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon
+import com.android.settingslib.core.AbstractPreferenceController
+import com.android.settingslib.core.lifecycle.LifecycleObserver
+import com.android.settingslib.core.lifecycle.events.OnPause
+import com.android.settingslib.core.lifecycle.events.OnStop
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.widget.preference.Preference as SpaPreference
import com.android.settingslib.spa.widget.preference.PreferenceModel
@@ -81,16 +88,10 @@
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.launch
/** Handles device details fragment layout according to config. */
interface DeviceDetailsFragmentFormatter {
- /** Gets keys of visible preferences in built-in preference in xml. */
- fun getVisiblePreferenceKeys(fragmentType: FragmentTypeModel): List<String>?
-
- /** Updates device details fragment layout. */
- fun getInvisibleBluetoothProfiles(fragmentType: FragmentTypeModel): List<String>?
-
/** Updates device details fragment layout. */
fun updateLayout(fragmentType: FragmentTypeModel)
@@ -104,7 +105,8 @@
@OptIn(ExperimentalCoroutinesApi::class)
class DeviceDetailsFragmentFormatterImpl(
private val context: Context,
- private val fragment: SettingsPreferenceFragment,
+ private val fragment: DashboardFragment,
+ controllers: List<AbstractPreferenceController>,
private val bluetoothAdapter: BluetoothAdapter,
private val cachedDevice: CachedBluetoothDevice,
private val backgroundCoroutineContext: CoroutineContext,
@@ -112,40 +114,32 @@
private val metricsFeatureProvider = FeatureFactory.featureFactory.metricsFeatureProvider
private val prefVisibility = mutableMapOf<String, MutableStateFlow<Boolean>>()
private val prefVisibilityJobs = mutableListOf<Job>()
+ private var isLoading = false
+ private var prefKeyToController: Map<String, AbstractPreferenceController> =
+ controllers.associateBy { it.preferenceKey }
private val viewModel: BluetoothDeviceDetailsViewModel =
ViewModelProvider(
- fragment,
- BluetoothDeviceDetailsViewModel.Factory(
- fragment.requireActivity().application,
- bluetoothAdapter,
- cachedDevice,
- backgroundCoroutineContext,
- ),
- )
+ fragment,
+ BluetoothDeviceDetailsViewModel.Factory(
+ fragment.requireActivity().application,
+ bluetoothAdapter,
+ cachedDevice,
+ backgroundCoroutineContext,
+ ),
+ )
.get(BluetoothDeviceDetailsViewModel::class.java)
- override fun getVisiblePreferenceKeys(fragmentType: FragmentTypeModel): List<String>? =
- runBlocking {
- viewModel
- .getItems(fragmentType)
- ?.filterIsInstance<DeviceSettingConfigItemModel.BuiltinItem>()
- ?.map { it.preferenceKey }
- }
-
- override fun getInvisibleBluetoothProfiles(fragmentType: FragmentTypeModel): List<String>? =
- runBlocking {
- viewModel
- .getItems(fragmentType)
- ?.filterIsInstance<DeviceSettingConfigItemModel.BuiltinItem.BluetoothProfilesItem>()
- ?.firstOrNull()
- ?.invisibleProfiles
- }
-
/** Updates bluetooth device details fragment layout. */
- override fun updateLayout(fragmentType: FragmentTypeModel) = runBlocking {
- val items = viewModel.getItems(fragmentType) ?: return@runBlocking
- val layout = viewModel.getLayout(fragmentType) ?: return@runBlocking
+ override fun updateLayout(fragmentType: FragmentTypeModel) {
+ fragment.setLoading(true, false)
+ isLoading = true
+ fragment.lifecycleScope.launch { updateLayoutInternal(fragmentType) }
+ }
+
+ private suspend fun updateLayoutInternal(fragmentType: FragmentTypeModel) {
+ val items = viewModel.getItems(fragmentType) ?: return
+ val layout = viewModel.getLayout(fragmentType) ?: return
val prefKeyToSettingId =
items
@@ -156,21 +150,21 @@
for (i in 0 until fragment.preferenceScreen.preferenceCount) {
val pref = fragment.preferenceScreen.getPreference(i)
prefKeyToSettingId[pref.key]?.let { id -> settingIdToXmlPreferences[id] = pref }
+ if (pref.key !in prefKeyToSettingId) {
+ getController(pref.key)?.let { disableController(it) }
+ }
}
fragment.preferenceScreen.removeAll()
for (job in prefVisibilityJobs) {
job.cancel()
}
prefVisibilityJobs.clear()
-
for (row in items.indices) {
- val settingId = items[row].settingId
+ val settingItem = items[row]
+ val settingId = settingItem.settingId
if (settingIdToXmlPreferences.containsKey(settingId)) {
- fragment.preferenceScreen.addPreference(
- settingIdToXmlPreferences[settingId]!!
- .apply { order = row }
- .also { logItemShown(it.key, it.isVisible) }
- )
+ val pref = settingIdToXmlPreferences[settingId]!!.apply { order = row }
+ fragment.preferenceScreen.addPreference(pref)
} else {
val prefKey = getPreferenceKey(settingId)
prefVisibilityJobs.add(
@@ -195,6 +189,29 @@
isSelectable = false
setContent { Spacer(modifier = Modifier.height(1.dp)) }
})
+
+ for (row in items.indices) {
+ val settingItem = items[row]
+ val settingId = settingItem.settingId
+ if (settingIdToXmlPreferences.containsKey(settingId)) {
+ val pref = fragment.preferenceScreen.getPreference(row)
+ if (settingId == DeviceSettingId.DEVICE_SETTING_ID_BLUETOOTH_PROFILES) {
+ (getController(pref.key) as? BluetoothDetailsProfilesController)?.run {
+ if (settingItem is DeviceSettingConfigItemModel.BuiltinItem.BluetoothProfilesItem) {
+ setInvisibleProfiles(settingItem.invisibleProfiles)
+ setHasExtraSpace(false)
+ }
+ }
+ }
+ getController(pref.key)?.displayPreference(fragment.preferenceScreen)
+ logItemShown(pref.key, pref.isVisible)
+ }
+ }
+
+ if (isLoading) {
+ fragment.setLoading(false, false)
+ isLoading = false
+ }
}
override fun getMenuItem(
@@ -232,14 +249,14 @@
@Composable
private fun buildPreference(layout: DeviceSettingLayout, row: Int, prefKey: String) {
val contents by
- remember(row) { getDevicesSettingForRow(layout, row) }
- .collectAsStateWithLifecycle(initialValue = listOf())
+ remember(row) { getDevicesSettingForRow(layout, row) }
+ .collectAsStateWithLifecycle(initialValue = listOf())
val highlighted by
- remember(row) {
- layout.rows[row].columns.map { columns -> columns.any { it.highlighted } }
- }
- .collectAsStateWithLifecycle(initialValue = false)
+ remember(row) {
+ layout.rows[row].columns.map { columns -> columns.any { it.highlighted } }
+ }
+ .collectAsStateWithLifecycle(initialValue = false)
val settings = contents
AnimatedVisibility(visible = settings.isNotEmpty(), enter = fadeIn(), exit = fadeOut()) {
@@ -454,6 +471,29 @@
}
}
+ private fun getController(key: String): AbstractPreferenceController? {
+ return prefKeyToController[key]
+ }
+
+ private fun disableController(controller: AbstractPreferenceController) {
+ if (controller is LifecycleObserver) {
+ fragment.settingsLifecycle.removeObserver(controller as LifecycleObserver)
+ }
+
+ if (controller is BlockingPrefWithSliceController) {
+ // Make UiBlockListener finished, otherwise UI will flicker.
+ controller.onChanged(null)
+ }
+
+ if (controller is OnPause) {
+ (controller as OnPause).onPause()
+ }
+
+ if (controller is OnStop) {
+ (controller as OnStop).onStop()
+ }
+ }
+
private fun getPreferenceKey(settingId: Int) = "DEVICE_SETTING_${settingId}"
private companion object {
diff --git a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt
index 47fda74..cc0fe7b 100644
--- a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt
+++ b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsMoreSettingsFragment.kt
@@ -25,6 +25,7 @@
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
+import android.view.View
import androidx.lifecycle.lifecycleScope
import com.android.settings.R
import com.android.settings.bluetooth.BluetoothDetailsAudioDeviceTypeController
@@ -33,12 +34,12 @@
import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel
import com.android.settings.bluetooth.ui.model.FragmentTypeModel
import com.android.settings.dashboard.DashboardFragment
+import com.android.settings.flags.Flags
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon
import com.android.settingslib.core.AbstractPreferenceController
-import com.android.settingslib.core.lifecycle.LifecycleObserver
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.filterNotNull
@@ -88,17 +89,29 @@
return R.xml.bluetooth_device_more_settings_fragment
}
- override fun addPreferenceController(controller: AbstractPreferenceController) {
- val keys: List<String>? =
- formatter.getVisiblePreferenceKeys(FragmentTypeModel.DeviceDetailsMoreSettingsFragment)
- val lifecycle = settingsLifecycle
- if (keys == null || keys.contains(controller.preferenceKey)) {
- super.addPreferenceController(controller)
- } else if (controller is LifecycleObserver) {
- lifecycle.removeObserver((controller as LifecycleObserver))
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ if (!this::formatter.isInitialized) {
+ val controllers = preferenceControllers.stream()
+ .flatMap { obj: List<AbstractPreferenceController?> -> obj.stream() }
+ .toList()
+ val bluetoothManager = requireContext().getSystemService(BluetoothManager::class.java)
+ formatter =
+ featureFactory
+ .bluetoothFeatureProvider
+ .getDeviceDetailsFragmentFormatter(
+ requireContext(), this, bluetoothManager.adapter, cachedDevice, controllers
+ )
}
+ formatter.updateLayout(FragmentTypeModel.DeviceDetailsMoreSettingsFragment)
+ helpItem =
+ formatter
+ .getMenuItem(FragmentTypeModel.DeviceDetailsMoreSettingsFragment)
+ .stateIn(lifecycleScope, SharingStarted.WhileSubscribed(), initialValue = null)
}
+
+
private fun getCachedDevice(): CachedBluetoothDevice? {
val bluetoothAddress = arguments?.getString(KEY_DEVICE_ADDRESS) ?: return null
localBluetoothManager = Utils.getLocalBtManager(context) ?: return null
@@ -107,32 +120,13 @@
return Utils.getLocalBtManager(context).cachedDeviceManager.findDevice(remoteDevice)
}
- override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
- super.onCreatePreferences(savedInstanceState, rootKey)
- formatter.updateLayout(FragmentTypeModel.DeviceDetailsMoreSettingsFragment)
- }
-
override fun createPreferenceControllers(context: Context): List<AbstractPreferenceController> {
- val bluetoothManager = context.getSystemService(BluetoothManager::class.java)
cachedDevice =
getCachedDevice()
?: run {
finish()
return emptyList()
}
- if (!this::formatter.isInitialized) {
- formatter =
- featureFactory.bluetoothFeatureProvider.getDeviceDetailsFragmentFormatter(
- requireContext(),
- this,
- bluetoothManager.adapter,
- cachedDevice,
- )
- }
- helpItem =
- formatter
- .getMenuItem(FragmentTypeModel.DeviceDetailsMoreSettingsFragment)
- .stateIn(lifecycleScope, SharingStarted.WhileSubscribed(), initialValue = null)
return listOf(
BluetoothDetailsProfilesController(
context,
@@ -140,10 +134,6 @@
localBluetoothManager,
cachedDevice,
settingsLifecycle,
- formatter.getInvisibleBluetoothProfiles(
- FragmentTypeModel.DeviceDetailsMoreSettingsFragment
- ),
- false,
),
BluetoothDetailsAudioDeviceTypeController(
context,
diff --git a/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragment.java b/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragment.java
index 047ffd4..de1363d 100644
--- a/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragment.java
+++ b/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragment.java
@@ -16,7 +16,6 @@
package com.android.settings.connecteddevice.display;
-
import static android.view.Display.INVALID_DISPLAY;
import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.EXTERNAL_DISPLAY_HELP_URL;
@@ -46,6 +45,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragmentBase;
+import com.android.settings.accessibility.TextReadingPreferenceFragment;
import com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.DisplayListener;
import com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.Injector;
import com.android.settings.core.SubSettingLauncher;
@@ -64,6 +64,7 @@
public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmentBase {
static final int EXTERNAL_DISPLAY_SETTINGS_RESOURCE = R.xml.external_display_settings;
static final String DISPLAYS_LIST_PREFERENCE_KEY = "displays_list_preference";
+ static final String BUILTIN_DISPLAY_LIST_PREFERENCE_KEY = "builtin_display_list_preference";
static final String EXTERNAL_DISPLAY_USE_PREFERENCE_KEY = "external_display_use_preference";
static final String EXTERNAL_DISPLAY_ROTATION_KEY = "external_display_rotation";
static final String EXTERNAL_DISPLAY_RESOLUTION_PREFERENCE_KEY = "external_display_resolution";
@@ -83,6 +84,8 @@
R.string.external_display_rotation;
static final int EXTERNAL_DISPLAY_RESOLUTION_TITLE_RESOURCE =
R.string.external_display_resolution_settings_title;
+ static final int BUILTIN_DISPLAY_SETTINGS_CATEGORY_RESOURCE =
+ R.string.builtin_display_settings_category;
@VisibleForTesting
static final String PREVIOUSLY_SHOWN_LIST_KEY = "mPreviouslyShownListOfDisplays";
private boolean mStarted;
@@ -101,6 +104,8 @@
@Nullable
private PreferenceCategory mDisplaysPreference;
@Nullable
+ private PreferenceCategory mBuiltinDisplayPreference;
+ @Nullable
private Injector mInjector;
@Nullable
private String[] mRotationEntries;
@@ -200,7 +205,7 @@
}
@VisibleForTesting
- protected void launchDisplaySettings(final int displayId) {
+ protected void launchExternalDisplaySettings(final int displayId) {
final Bundle args = new Bundle();
var context = getPrefContext();
args.putInt(DISPLAY_ID_ARG, displayId);
@@ -210,6 +215,16 @@
.setSourceMetricsCategory(getMetricsCategory()).launch();
}
+ @VisibleForTesting
+ protected void launchBuiltinDisplaySettings() {
+ final Bundle args = new Bundle();
+ var context = getPrefContext();
+ new SubSettingLauncher(context)
+ .setDestination(TextReadingPreferenceFragment.class.getName())
+ .setArguments(args)
+ .setSourceMetricsCategory(getMetricsCategory()).launch();
+ }
+
/**
* Returns the preference for the footer.
*/
@@ -281,6 +296,15 @@
return mDisplaysPreference;
}
+ @NonNull
+ private PreferenceCategory getBuiltinDisplayListPreference(@NonNull Context context) {
+ if (mBuiltinDisplayPreference == null) {
+ mBuiltinDisplayPreference = new PreferenceCategory(context);
+ mBuiltinDisplayPreference.setPersistent(false);
+ }
+ return mBuiltinDisplayPreference;
+ }
+
@NonNull Preference getDisplayTopologyPreference(@NonNull Context context) {
if (mDisplayTopologyPreference == null) {
mDisplayTopologyPreference = new DisplayTopologyPreference(context);
@@ -310,7 +334,7 @@
@NonNull final PreferenceScreen screen, @NonNull Context context) {
final boolean forceShowList = displayId == INVALID_DISPLAY
&& mInjector != null && forceShowDisplayList(mInjector.getFlags());
- final var displaysToShow = getDisplaysToShow(displayId);
+ final var displaysToShow = externalDisplaysToShow(displayId);
if (!forceShowList && displaysToShow.isEmpty() && displayId == INVALID_DISPLAY) {
showTextWhenNoDisplaysToShow(screen, context);
@@ -373,9 +397,18 @@
private void showDisplaysList(@NonNull List<Display> displaysToShow,
@NonNull PreferenceScreen screen, @NonNull Context context) {
- if (mInjector != null
- && mInjector.getFlags().displayTopologyPaneInDisplayList()) {
+ if (mInjector != null && mInjector.getFlags().displayTopologyPaneInDisplayList()) {
screen.addPreference(getDisplayTopologyPreference(context));
+
+ // If topology is shown, we also show a preference for the built-in display for
+ // consistency with the topology.
+ var builtinCategory = getBuiltinDisplayListPreference(context);
+ builtinCategory.setKey(BUILTIN_DISPLAY_LIST_PREFERENCE_KEY);
+ builtinCategory.setTitle(BUILTIN_DISPLAY_SETTINGS_CATEGORY_RESOURCE);
+ builtinCategory.removeAll();
+ screen.addPreference(builtinCategory);
+
+ builtinCategory.addPreference(new BuiltinDisplaySizeAndTextPreference(context));
}
var pref = getDisplaysListPreference(context);
@@ -389,7 +422,7 @@
}
}
- private List<Display> getDisplaysToShow(int displayIdToShow) {
+ private List<Display> externalDisplaysToShow(int displayIdToShow) {
if (mInjector == null) {
return List.of();
}
@@ -530,6 +563,24 @@
mInjector.getHandler().removeCallbacks(mUpdateRunnable);
}
+ private class BuiltinDisplaySizeAndTextPreference extends Preference
+ implements Preference.OnPreferenceClickListener {
+ BuiltinDisplaySizeAndTextPreference(@NonNull final Context context) {
+ super(context);
+
+ setPersistent(false);
+ setKey("builtin_display_size_and_text");
+ setTitle(R.string.accessibility_text_reading_options_title);
+ setOnPreferenceClickListener(this);
+ }
+
+ @Override
+ public boolean onPreferenceClick(@NonNull Preference preference) {
+ launchBuiltinDisplaySettings();
+ return true;
+ }
+ }
+
@VisibleForTesting
class DisplayPreference extends TwoTargetPreference
implements Preference.OnPreferenceClickListener {
@@ -538,6 +589,7 @@
DisplayPreference(@NonNull final Context context, @NonNull final Display display) {
super(context);
mDisplayId = display.getDisplayId();
+
setPersistent(false);
setKey("display_id_" + mDisplayId);
setTitle(display.getName());
@@ -548,7 +600,7 @@
@Override
public boolean onPreferenceClick(@NonNull Preference preference) {
- launchDisplaySettings(mDisplayId);
+ launchExternalDisplaySettings(mDisplayId);
writePreferenceClickMetric(preference);
return true;
}
diff --git a/src/com/android/settings/datausage/DataSaverMainSwitchPreference.kt b/src/com/android/settings/datausage/DataSaverMainSwitchPreference.kt
index de128e6..e4e38d4 100644
--- a/src/com/android/settings/datausage/DataSaverMainSwitchPreference.kt
+++ b/src/com/android/settings/datausage/DataSaverMainSwitchPreference.kt
@@ -24,6 +24,7 @@
import com.android.settingslib.metadata.PreferenceLifecycleContext
import com.android.settingslib.metadata.PreferenceLifecycleProvider
import com.android.settingslib.metadata.ReadWritePermit
+import com.android.settingslib.metadata.SensitivityLevel
class DataSaverMainSwitchPreference(context: Context) :
MainSwitchBarMetadata, PreferenceLifecycleProvider {
@@ -45,6 +46,9 @@
override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) =
ReadWritePermit.ALLOW
+ override val sensitivityLevel
+ get() = SensitivityLevel.NO_SENSITIVITY
+
override fun onStart(context: PreferenceLifecycleContext) {
val listener = DataSaverBackend.Listener { context.notifyPreferenceChange(KEY) }
dataSaverBackendListener = listener
diff --git a/src/com/android/settings/display/AdaptiveSleepPreference.kt b/src/com/android/settings/display/AdaptiveSleepPreference.kt
index 71d7749..a160001 100644
--- a/src/com/android/settings/display/AdaptiveSleepPreference.kt
+++ b/src/com/android/settings/display/AdaptiveSleepPreference.kt
@@ -37,6 +37,7 @@
import com.android.settingslib.metadata.PreferenceLifecycleContext
import com.android.settingslib.metadata.PreferenceLifecycleProvider
import com.android.settingslib.metadata.ReadWritePermit
+import com.android.settingslib.metadata.SensitivityLevel
import com.android.settingslib.metadata.TwoStatePreference
import com.android.settingslib.preference.PreferenceBindingPlaceholder
import com.android.settingslib.preference.SwitchPreferenceBinding
@@ -82,6 +83,9 @@
override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) =
ReadWritePermit.ALLOW
+ override val sensitivityLevel
+ get() = SensitivityLevel.NO_SENSITIVITY
+
@Suppress("UNCHECKED_CAST")
private class Storage(
private val context: Context,
diff --git a/src/com/android/settings/display/AmbientDisplayAlwaysOnPreference.kt b/src/com/android/settings/display/AmbientDisplayAlwaysOnPreference.kt
index 0537e62..e50b00b 100644
--- a/src/com/android/settings/display/AmbientDisplayAlwaysOnPreference.kt
+++ b/src/com/android/settings/display/AmbientDisplayAlwaysOnPreference.kt
@@ -36,6 +36,7 @@
import com.android.settingslib.metadata.PreferenceLifecycleProvider
import com.android.settingslib.metadata.PreferenceSummaryProvider
import com.android.settingslib.metadata.ReadWritePermit
+import com.android.settingslib.metadata.SensitivityLevel
import com.android.settingslib.metadata.SwitchPreference
// LINT.IfChange
@@ -76,6 +77,9 @@
override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) =
ReadWritePermit.ALLOW
+ override val sensitivityLevel
+ get() = SensitivityLevel.NO_SENSITIVITY
+
override fun onCreate(context: PreferenceLifecycleContext) {
val storage = SettingsSecureStore.get(context)
keyMappingObserver =
diff --git a/src/com/android/settings/display/AutoBrightnessScreen.kt b/src/com/android/settings/display/AutoBrightnessScreen.kt
index 385fe20..32d70ad 100644
--- a/src/com/android/settings/display/AutoBrightnessScreen.kt
+++ b/src/com/android/settings/display/AutoBrightnessScreen.kt
@@ -35,6 +35,7 @@
import com.android.settingslib.metadata.PreferenceMetadata
import com.android.settingslib.metadata.ProvidePreferenceScreen
import com.android.settingslib.metadata.ReadWritePermit
+import com.android.settingslib.metadata.SensitivityLevel
import com.android.settingslib.metadata.preferenceHierarchy
import com.android.settingslib.preference.PreferenceScreenBinding
import com.android.settingslib.preference.PreferenceScreenCreator
@@ -70,6 +71,9 @@
override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) =
ReadWritePermit.ALLOW
+ override val sensitivityLevel
+ get() = SensitivityLevel.NO_SENSITIVITY
+
override fun isAvailable(context: Context) =
context.resources.getBoolean(
com.android.internal.R.bool.config_automatic_brightness_available
diff --git a/src/com/android/settings/display/BatteryPercentageSwitchPreference.kt b/src/com/android/settings/display/BatteryPercentageSwitchPreference.kt
index fd7b037..25623b3 100644
--- a/src/com/android/settings/display/BatteryPercentageSwitchPreference.kt
+++ b/src/com/android/settings/display/BatteryPercentageSwitchPreference.kt
@@ -29,6 +29,7 @@
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
import com.android.settingslib.metadata.PreferenceMetadata
import com.android.settingslib.metadata.ReadWritePermit
+import com.android.settingslib.metadata.SensitivityLevel
import com.android.settingslib.metadata.SwitchPreference
import com.android.settingslib.preference.SwitchPreferenceBinding
@@ -54,6 +55,9 @@
override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) =
ReadWritePermit.ALLOW
+ override val sensitivityLevel
+ get() = SensitivityLevel.NO_SENSITIVITY
+
override fun bind(preference: Preference, metadata: PreferenceMetadata) {
super.bind(preference, metadata)
preference.onPreferenceChangeListener = this
diff --git a/src/com/android/settings/display/PeakRefreshRateSwitchPreference.kt b/src/com/android/settings/display/PeakRefreshRateSwitchPreference.kt
index 6dc09f6..3240616 100644
--- a/src/com/android/settings/display/PeakRefreshRateSwitchPreference.kt
+++ b/src/com/android/settings/display/PeakRefreshRateSwitchPreference.kt
@@ -34,6 +34,7 @@
import com.android.settingslib.metadata.PreferenceLifecycleProvider
import com.android.settingslib.metadata.PreferenceSummaryProvider
import com.android.settingslib.metadata.ReadWritePermit
+import com.android.settingslib.metadata.SensitivityLevel
import com.android.settingslib.metadata.SwitchPreference
import kotlin.math.roundToInt
@@ -55,6 +56,9 @@
override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) =
ReadWritePermit.ALLOW
+ override val sensitivityLevel
+ get() = SensitivityLevel.NO_SENSITIVITY
+
override fun isAvailable(context: Context) =
context.resources.getBoolean(R.bool.config_show_smooth_display) &&
context.peakRefreshRate > DEFAULT_REFRESH_RATE
diff --git a/src/com/android/settings/display/darkmode/DarkModeScreen.kt b/src/com/android/settings/display/darkmode/DarkModeScreen.kt
index 9166705..7f8087a 100644
--- a/src/com/android/settings/display/darkmode/DarkModeScreen.kt
+++ b/src/com/android/settings/display/darkmode/DarkModeScreen.kt
@@ -37,6 +37,7 @@
import com.android.settingslib.metadata.PreferenceSummaryProvider
import com.android.settingslib.metadata.ProvidePreferenceScreen
import com.android.settingslib.metadata.ReadWritePermit
+import com.android.settingslib.metadata.SensitivityLevel
import com.android.settingslib.metadata.preferenceHierarchy
import com.android.settingslib.preference.PreferenceScreenBinding
import com.android.settingslib.preference.PreferenceScreenCreator
@@ -76,6 +77,9 @@
override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) =
ReadWritePermit.ALLOW
+ override val sensitivityLevel
+ get() = SensitivityLevel.NO_SENSITIVITY
+
override fun isFlagEnabled(context: Context) = Flags.catalystDarkUiMode()
override fun fragmentClass() = DarkModeSettingsFragment::class.java
diff --git a/src/com/android/settings/fuelgauge/BatteryHeaderPreference.kt b/src/com/android/settings/fuelgauge/BatteryHeaderPreference.kt
index 2a9b0e8..95d73dd 100644
--- a/src/com/android/settings/fuelgauge/BatteryHeaderPreference.kt
+++ b/src/com/android/settings/fuelgauge/BatteryHeaderPreference.kt
@@ -22,21 +22,27 @@
import com.android.settings.R
import com.android.settings.fuelgauge.BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_NOT_PRESENT
import com.android.settingslib.Utils
+import com.android.settingslib.datastore.KeyValueStore
+import com.android.settingslib.datastore.NoOpKeyedObservable
import com.android.settingslib.fuelgauge.BatteryUtils
+import com.android.settingslib.metadata.PersistentPreference
import com.android.settingslib.metadata.PreferenceLifecycleContext
import com.android.settingslib.metadata.PreferenceLifecycleProvider
import com.android.settingslib.metadata.PreferenceMetadata
+import com.android.settingslib.metadata.RangeValue
+import com.android.settingslib.metadata.ReadWritePermit
import com.android.settingslib.preference.PreferenceBinding
import com.android.settingslib.widget.UsageProgressBarPreference
// LINT.IfChange
class BatteryHeaderPreference :
+ PersistentPreference<Int>,
PreferenceMetadata,
PreferenceBinding,
- PreferenceLifecycleProvider {
+ PreferenceLifecycleProvider,
+ RangeValue {
- @VisibleForTesting
- var batteryBroadcastReceiver: BatteryBroadcastReceiver? = null
+ @VisibleForTesting var batteryBroadcastReceiver: BatteryBroadcastReceiver? = null
override val key: String
get() = KEY
@@ -58,25 +64,50 @@
override fun onCreate(context: PreferenceLifecycleContext) {
super.onCreate(context)
- batteryBroadcastReceiver = BatteryBroadcastReceiver(context).apply {
- setBatteryChangedListener {
- if (it != BATTERY_NOT_PRESENT) {
- context.notifyPreferenceChange(KEY)
+ batteryBroadcastReceiver =
+ BatteryBroadcastReceiver(context).apply {
+ setBatteryChangedListener {
+ if (it != BATTERY_NOT_PRESENT) {
+ context.notifyPreferenceChange(KEY)
+ }
}
}
- }
}
override fun onStart(context: PreferenceLifecycleContext) {
super.onStart(context)
- batteryBroadcastReceiver?.register();
+ batteryBroadcastReceiver?.register()
}
override fun onStop(context: PreferenceLifecycleContext) {
super.onStop(context)
- batteryBroadcastReceiver?.unRegister();
+ batteryBroadcastReceiver?.unRegister()
}
+ override fun storage(context: Context): KeyValueStore =
+ object : NoOpKeyedObservable<String>(), KeyValueStore {
+ override fun contains(key: String) = BatteryUtils.getBatteryIntent(context) != null
+
+ @Suppress("UNCHECKED_CAST")
+ override fun <T : Any> getValue(key: String, valueType: Class<T>): T? {
+ val batteryIntent = BatteryUtils.getBatteryIntent(context) ?: return null
+ return Utils.getBatteryLevel(batteryIntent) as T
+ }
+
+ override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) =
+ throw UnsupportedOperationException()
+ }
+
+ override fun getMinValue(context: Context): Int = 0
+
+ override fun getMaxValue(context: Context): Int = 100
+
+ override fun getReadPermit(context: Context, myUid: Int, callingUid: Int) =
+ ReadWritePermit.ALLOW
+
+ override fun getWritePermit(context: Context, value: Int?, myUid: Int, callingUid: Int) =
+ ReadWritePermit.DISALLOW
+
companion object {
private const val KEY = "battery_header"
private const val BATTERY_MAX_LEVEL: Long = 100L
diff --git a/src/com/android/settings/fuelgauge/BatteryHeaderTextPreference.java b/src/com/android/settings/fuelgauge/BatteryHeaderTextPreference.java
index 5c81277..516cc71 100644
--- a/src/com/android/settings/fuelgauge/BatteryHeaderTextPreference.java
+++ b/src/com/android/settings/fuelgauge/BatteryHeaderTextPreference.java
@@ -26,9 +26,10 @@
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
+import com.android.settingslib.widget.GroupSectionDividerMixin;
/** A preference for battery header text. */
-public class BatteryHeaderTextPreference extends Preference {
+public class BatteryHeaderTextPreference extends Preference implements GroupSectionDividerMixin {
private static final String TAG = "BatteryHeaderTextPreference";
@Nullable private CharSequence mText;
diff --git a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverPreference.kt b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverPreference.kt
index da401c5..84bba00 100644
--- a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverPreference.kt
+++ b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverPreference.kt
@@ -32,6 +32,7 @@
import com.android.settingslib.metadata.PreferenceLifecycleContext
import com.android.settingslib.metadata.PreferenceLifecycleProvider
import com.android.settingslib.metadata.ReadWritePermit
+import com.android.settingslib.metadata.SensitivityLevel
// LINT.IfChange
class BatterySaverPreference :
@@ -49,6 +50,9 @@
override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) =
ReadWritePermit.ALLOW
+ override val sensitivityLevel
+ get() = SensitivityLevel.NO_SENSITIVITY
+
override fun isEnabled(context: Context) =
!BatteryStatus(BatteryUtils.getBatteryIntent(context)).isPluggedIn
diff --git a/src/com/android/settings/inputmethod/PointerTouchpadFragment.java b/src/com/android/settings/inputmethod/PointerTouchpadFragment.java
index 890d9b6..441bddd 100644
--- a/src/com/android/settings/inputmethod/PointerTouchpadFragment.java
+++ b/src/com/android/settings/inputmethod/PointerTouchpadFragment.java
@@ -25,8 +25,12 @@
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.widget.PreferenceCategoryController;
+import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.search.SearchIndexable;
+import java.util.List;
+
/** Accessibility settings for pointer and touchpad. */
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class PointerTouchpadFragment extends DashboardFragment {
@@ -34,6 +38,21 @@
private static final String TAG = "PointerTouchpadFragment";
@Override
+ protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
+ return buildPreferenceControllers(context);
+ }
+
+ private static List<AbstractPreferenceController> buildPreferenceControllers(Context context) {
+ TouchpadSystemGesturesPreferenceController systemGesturesController =
+ new TouchpadSystemGesturesPreferenceController(
+ context, "touchpad_system_gestures_enable");
+ return List.of(
+ systemGesturesController,
+ new PreferenceCategoryController(context, "touchpad_category")
+ .setChildren(List.of(systemGesturesController)));
+ }
+
+ @Override
public int getMetricsCategory() {
return SettingsEnums.ACCESSIBILITY_POINTER_TOUCHPAD;
}
@@ -54,5 +73,11 @@
protected boolean isPageSearchEnabled(Context context) {
return isTouchpad() || isMouse();
}
+
+ @Override
+ public List<AbstractPreferenceController> createPreferenceControllers(
+ Context context) {
+ return buildPreferenceControllers(context);
+ }
};
}
diff --git a/src/com/android/settings/inputmethod/TouchGesturesButtonPreferenceController.java b/src/com/android/settings/inputmethod/TouchGesturesButtonPreferenceController.java
index 5154623..8b0ae4c 100644
--- a/src/com/android/settings/inputmethod/TouchGesturesButtonPreferenceController.java
+++ b/src/com/android/settings/inputmethod/TouchGesturesButtonPreferenceController.java
@@ -21,6 +21,7 @@
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
+import android.hardware.input.InputSettings;
import android.os.UserHandle;
import android.util.FeatureFlagUtils;
@@ -75,7 +76,14 @@
@Override
public int getAvailabilityStatus() {
boolean isTouchpad = InputPeripheralsSettingsUtils.isTouchpad();
- return isTouchpad ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ if (isTouchpad) {
+ // If the user's disabled touchpad system gestures in the accessibility settings, the
+ // tutorial won't work or be relevant, so disable the button.
+ return InputSettings.useTouchpadSystemGestures(mContext) ? AVAILABLE
+ : DISABLED_DEPENDENT_SETTING;
+ } else {
+ return CONDITIONALLY_UNAVAILABLE;
+ }
}
private void showTouchpadGestureEducation() {
diff --git a/src/com/android/settings/inputmethod/TouchpadSystemGesturesPreferenceController.java b/src/com/android/settings/inputmethod/TouchpadSystemGesturesPreferenceController.java
new file mode 100644
index 0000000..9f0acb1
--- /dev/null
+++ b/src/com/android/settings/inputmethod/TouchpadSystemGesturesPreferenceController.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 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.inputmethod;
+
+import android.content.Context;
+import android.hardware.input.InputSettings;
+
+import com.android.settings.R;
+import com.android.settings.core.TogglePreferenceController;
+
+public class TouchpadSystemGesturesPreferenceController extends TogglePreferenceController {
+
+ public TouchpadSystemGesturesPreferenceController(Context context, String key) {
+ super(context, key);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return InputSettings.isTouchpadSystemGestureDisableFeatureFlagEnabled()
+ && InputPeripheralsSettingsUtils.isTouchpad() ? AVAILABLE
+ : CONDITIONALLY_UNAVAILABLE;
+ }
+
+ @Override
+ public boolean isChecked() {
+ return InputSettings.useTouchpadSystemGestures(mContext);
+ }
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ InputSettings.setTouchpadSystemGesturesEnabled(mContext, isChecked);
+ // TODO(b/353947750): add a metric for when the setting changes.
+ return true;
+ }
+
+ @Override
+ public int getSliceHighlightMenuRes() {
+ return R.string.menu_key_accessibility;
+ }
+}
diff --git a/src/com/android/settings/inputmethod/TrackpadGesturesDisabledFooterPreferenceController.java b/src/com/android/settings/inputmethod/TrackpadGesturesDisabledFooterPreferenceController.java
new file mode 100644
index 0000000..1fed57e
--- /dev/null
+++ b/src/com/android/settings/inputmethod/TrackpadGesturesDisabledFooterPreferenceController.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 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.inputmethod;
+
+import android.content.Context;
+import android.hardware.input.InputSettings;
+
+import com.android.settings.core.BasePreferenceController;
+
+public class TrackpadGesturesDisabledFooterPreferenceController extends BasePreferenceController {
+
+ public TrackpadGesturesDisabledFooterPreferenceController(Context context, String key) {
+ super(context, key);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return InputSettings.useTouchpadSystemGestures(mContext) ? CONDITIONALLY_UNAVAILABLE
+ : AVAILABLE;
+ }
+}
diff --git a/src/com/android/settings/network/AdaptiveConnectivityTogglePreference.kt b/src/com/android/settings/network/AdaptiveConnectivityTogglePreference.kt
index 159ec0f..c29ec6e 100644
--- a/src/com/android/settings/network/AdaptiveConnectivityTogglePreference.kt
+++ b/src/com/android/settings/network/AdaptiveConnectivityTogglePreference.kt
@@ -26,6 +26,7 @@
import com.android.settingslib.datastore.SettingsStore
import com.android.settingslib.metadata.MainSwitchPreference
import com.android.settingslib.metadata.ReadWritePermit
+import com.android.settingslib.metadata.SensitivityLevel
// LINT.IfChange
class AdaptiveConnectivityTogglePreference :
@@ -40,6 +41,9 @@
override fun getWritePermit(context: Context, value: Boolean?, myUid: Int, callingUid: Int) =
ReadWritePermit.ALLOW
+ override val sensitivityLevel
+ get() = SensitivityLevel.NO_SENSITIVITY
+
@Suppress("UNCHECKED_CAST")
private class AdaptiveConnectivityToggleStorage(
private val context: Context,
diff --git a/src/com/android/settings/network/AirplaneModePreference.kt b/src/com/android/settings/network/AirplaneModePreference.kt
index 2d9fbe9..d9d1bd8 100644
--- a/src/com/android/settings/network/AirplaneModePreference.kt
+++ b/src/com/android/settings/network/AirplaneModePreference.kt
@@ -23,6 +23,7 @@
import com.android.settings.R
import com.android.settingslib.datastore.SettingsGlobalStore
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
+import com.android.settingslib.metadata.SensitivityLevel
import com.android.settingslib.metadata.SwitchPreference
// LINT.IfChange
@@ -35,6 +36,9 @@
override fun storage(context: Context) = SettingsGlobalStore.get(context)
+ override val sensitivityLevel
+ get() = SensitivityLevel.HIGH_SENSITIVITY
+
override fun isAvailable(context: Context) =
(context.resources.getBoolean(R.bool.config_show_toggle_airplane)
&& !context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK))
diff --git a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java
index 1b1eb9e..8051711 100644
--- a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java
+++ b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java
@@ -16,9 +16,6 @@
package com.android.settings.network.telephony;
-import static androidx.lifecycle.Lifecycle.Event.ON_START;
-import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
-
import static com.android.settings.network.telephony.EnabledNetworkModePreferenceControllerHelperKt.getNetworkModePreferenceType;
import static com.android.settings.network.telephony.EnabledNetworkModePreferenceControllerHelperKt.setAllowedNetworkTypes;
import static com.android.settings.network.telephony.mode.NetworkModes.addNrToLteNetworkMode;
@@ -33,15 +30,17 @@
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
+import android.telephony.satellite.SatelliteManager;
+import android.telephony.satellite.SatelliteModemStateCallback;
+import android.telephony.satellite.SelectedNbIotSatelliteSubscriptionCallback;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
-import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
-import androidx.lifecycle.OnLifecycleEvent;
import androidx.preference.ListPreference;
import androidx.preference.ListPreferenceDialogFragmentCompat;
import androidx.preference.Preference;
@@ -67,7 +66,7 @@
*/
public class EnabledNetworkModePreferenceController extends
BasePreferenceController implements
- ListPreference.OnPreferenceChangeListener, LifecycleObserver,
+ ListPreference.OnPreferenceChangeListener, DefaultLifecycleObserver,
SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
private static final String LOG_TAG = "EnabledNetworkMode";
@@ -83,6 +82,43 @@
private PhoneCallStateTelephonyCallback mTelephonyCallback;
private FragmentManager mFragmentManager;
private LifecycleOwner mViewLifecycleOwner;
+ private SatelliteManager mSatelliteManager;
+ private boolean mIsSatelliteSessionStarted = false;
+ private boolean mIsCurrentSubscriptionForSatellite = false;
+
+ @VisibleForTesting
+ final SelectedNbIotSatelliteSubscriptionCallback mSelectedNbIotSatelliteSubscriptionCallback =
+ new SelectedNbIotSatelliteSubscriptionCallback() {
+ @Override
+ public void onSelectedNbIotSatelliteSubscriptionChanged(int selectedSubId) {
+ mIsCurrentSubscriptionForSatellite = selectedSubId == mSubId;
+ updatePreference();
+ }
+ };
+
+ @VisibleForTesting
+ final SatelliteModemStateCallback mSatelliteModemStateCallback =
+ new SatelliteModemStateCallback() {
+ @Override
+ public void onSatelliteModemStateChanged(int state) {
+ switch (state) {
+ case SatelliteManager.SATELLITE_MODEM_STATE_OFF:
+ case SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE:
+ case SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN:
+ if (mIsSatelliteSessionStarted) {
+ mIsSatelliteSessionStarted = false;
+ updatePreference();
+ }
+ break;
+ default:
+ if (!mIsSatelliteSessionStarted) {
+ mIsSatelliteSessionStarted = true;
+ updatePreference();
+ }
+ break;
+ }
+ }
+ };
public EnabledNetworkModePreferenceController(Context context, String key) {
super(context, key);
@@ -90,6 +126,7 @@
if (mTelephonyCallback == null) {
mTelephonyCallback = new PhoneCallStateTelephonyCallback();
}
+ mSatelliteManager = context.getSystemService(SatelliteManager.class);
}
@Override
@@ -103,8 +140,22 @@
return mCallState == TelephonyManager.CALL_STATE_IDLE;
}
- @OnLifecycleEvent(ON_START)
- public void onStart() {
+ @Override
+ public void onStart(@NonNull LifecycleOwner owner) {
+ if (com.android.settings.flags.Flags.satelliteOemSettingsUxMigration()) {
+ if (mSatelliteManager != null) {
+ try {
+ mSatelliteManager.registerForModemStateChanged(
+ mContext.getMainExecutor(), mSatelliteModemStateCallback);
+ mSatelliteManager.registerForSelectedNbIotSatelliteSubscriptionChanged(
+ mContext.getMainExecutor(),
+ mSelectedNbIotSatelliteSubscriptionCallback);
+ } catch (IllegalStateException e) {
+ Log.w(LOG_TAG, "IllegalStateException : " + e);
+ }
+ }
+ }
+
mSubscriptionsListener.start();
if (mAllowedNetworkTypesListener == null || mTelephonyCallback == null) {
return;
@@ -113,9 +164,21 @@
mTelephonyCallback.register(mTelephonyManager, mSubId);
}
- @OnLifecycleEvent(ON_STOP)
- public void onStop() {
+ @Override
+ public void onStop(@NonNull LifecycleOwner owner) {
mSubscriptionsListener.stop();
+ if (com.android.settings.flags.Flags.satelliteOemSettingsUxMigration()) {
+ if (mSatelliteManager != null) {
+ try {
+ mSatelliteManager.unregisterForModemStateChanged(mSatelliteModemStateCallback);
+ mSatelliteManager.unregisterForSelectedNbIotSatelliteSubscriptionChanged(
+ mSelectedNbIotSatelliteSubscriptionCallback);
+ } catch (IllegalStateException e) {
+ Log.w(LOG_TAG, "IllegalStateException : " + e);
+ }
+ }
+ }
+
if (mAllowedNetworkTypesListener == null || mTelephonyCallback == null) {
return;
}
@@ -147,7 +210,7 @@
listPreference.setEntryValues(mBuilder.getEntryValues());
listPreference.setValue(Integer.toString(mBuilder.getSelectedEntryValue()));
listPreference.setSummary(mBuilder.getSummary());
- boolean listPreferenceEnabled = isCallStateIdle();
+ boolean listPreferenceEnabled = isPreferenceShallEnabled();
listPreference.setEnabled(listPreferenceEnabled);
if (!listPreferenceEnabled) {
// If dialog is already opened when ListPreference disabled, dismiss them.
@@ -203,6 +266,14 @@
}
}
+ private boolean isPreferenceShallEnabled() {
+ Log.d(LOG_TAG, "isPreferenceShallEnabled, mIsSatelliteSessionStarted : "
+ + mIsSatelliteSessionStarted + " / mIsCurrentSubscriptionForSatellite : "
+ + mIsCurrentSubscriptionForSatellite);
+ return isCallStateIdle()
+ && !(mIsSatelliteSessionStarted && mIsCurrentSubscriptionForSatellite);
+ }
+
private final class PreferenceEntriesBuilder {
private CarrierConfigCache mCarrierConfigCache;
private Context mContext;
@@ -254,7 +325,7 @@
if (flagHidePrefer3gItem) {
mDisplay3gOptions = carrierConfig.getBoolean(
- CarrierConfigManager.KEY_PREFER_3G_VISIBILITY_BOOL);
+ CarrierConfigManager.KEY_PREFER_3G_VISIBILITY_BOOL);
} else {
mDisplay3gOptions = getResourcesForSubId().getBoolean(
R.bool.config_display_network_mode_3g_option);
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
index baf16c7..1c4b262 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
@@ -288,6 +288,11 @@
if (satelliteSettingPreferenceController != null) {
satelliteSettingPreferenceController.init(mSubId);
}
+ final SatelliteSettingSosPreferenceController satelliteSettingSosPreferenceController = use(
+ SatelliteSettingSosPreferenceController.class);
+ if (satelliteSettingSosPreferenceController != null) {
+ satelliteSettingSosPreferenceController.init(mSubId);
+ }
use(ApnPreferenceController.class).init(mSubId);
use(CarrierPreferenceController.class).init(mSubId);
use(DataUsagePreferenceController.class).init(mSubId);
diff --git a/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java b/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java
index d855069..4409188 100644
--- a/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java
+++ b/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java
@@ -24,10 +24,18 @@
import android.telephony.RadioAccessFamily;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.telephony.satellite.SatelliteManager;
+import android.telephony.satellite.SatelliteModemStateCallback;
+import android.telephony.satellite.SelectedNbIotSatelliteSubscriptionCallback;
import android.util.Log;
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
@@ -38,17 +46,56 @@
* Preference controller for "Preferred network mode"
*/
public class PreferredNetworkModePreferenceController extends BasePreferenceController
- implements ListPreference.OnPreferenceChangeListener {
+ implements ListPreference.OnPreferenceChangeListener, DefaultLifecycleObserver {
private static final String TAG = "PrefNetworkModeCtrl";
private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private CarrierConfigCache mCarrierConfigCache;
private TelephonyManager mTelephonyManager;
private boolean mIsGlobalCdma;
+ private SatelliteManager mSatelliteManager;
+ private Preference mPreference;
+ private boolean mIsSatelliteSessionStarted = false;
+ private boolean mIsCurrentSubscriptionForSatellite = false;
+
+ @VisibleForTesting
+ final SelectedNbIotSatelliteSubscriptionCallback mSelectedNbIotSatelliteSubscriptionCallback =
+ new SelectedNbIotSatelliteSubscriptionCallback() {
+ @Override
+ public void onSelectedNbIotSatelliteSubscriptionChanged(int selectedSubId) {
+ mIsCurrentSubscriptionForSatellite = selectedSubId == mSubId;
+ updateState(mPreference);
+ }
+ };
+
+ @VisibleForTesting
+ final SatelliteModemStateCallback mSatelliteModemStateCallback =
+ new SatelliteModemStateCallback() {
+ @Override
+ public void onSatelliteModemStateChanged(int state) {
+ switch (state) {
+ case SatelliteManager.SATELLITE_MODEM_STATE_OFF:
+ case SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE:
+ case SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN:
+ if (mIsSatelliteSessionStarted) {
+ mIsSatelliteSessionStarted = false;
+ updateState(mPreference);
+ }
+ break;
+ default:
+ if (!mIsSatelliteSessionStarted) {
+ mIsSatelliteSessionStarted = true;
+ updateState(mPreference);
+ }
+ break;
+ }
+ }
+ };
public PreferredNetworkModePreferenceController(Context context, String key) {
super(context, key);
mCarrierConfigCache = CarrierConfigCache.getInstance(context);
+ mSatelliteManager = context.getSystemService(SatelliteManager.class);
}
@Override
@@ -59,8 +106,18 @@
}
@Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ }
+
+ @Override
public void updateState(Preference preference) {
+ if (preference == null) {
+ return;
+ }
super.updateState(preference);
+ preference.setEnabled(!(mIsCurrentSubscriptionForSatellite && mIsSatelliteSessionStarted));
final ListPreference listPreference = (ListPreference) preference;
final int networkMode = getPreferredNetworkMode();
listPreference.setValue(Integer.toString(networkMode));
@@ -75,9 +132,9 @@
TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER,
RadioAccessFamily.getRafFromNetworkType(newPreferredNetworkMode));
- final ListPreference listPreference = (ListPreference) preference;
- listPreference.setSummary(getPreferredNetworkModeSummaryResId(newPreferredNetworkMode));
- return true;
+ final ListPreference listPreference = (ListPreference) preference;
+ listPreference.setSummary(getPreferredNetworkModeSummaryResId(newPreferredNetworkMode));
+ return true;
}
public void init(int subId) {
@@ -90,6 +147,38 @@
&& carrierConfig.getBoolean(CarrierConfigManager.KEY_SHOW_CDMA_CHOICES_BOOL);
}
+ @Override
+ public void onStart(@NonNull LifecycleOwner owner) {
+ if (com.android.settings.flags.Flags.satelliteOemSettingsUxMigration()) {
+ if (mSatelliteManager != null) {
+ try {
+ mSatelliteManager.registerForModemStateChanged(
+ mContext.getMainExecutor(), mSatelliteModemStateCallback);
+ mSatelliteManager.registerForSelectedNbIotSatelliteSubscriptionChanged(
+ mContext.getMainExecutor(),
+ mSelectedNbIotSatelliteSubscriptionCallback);
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "IllegalStateException : " + e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onStop(@NonNull LifecycleOwner owner) {
+ if (com.android.settings.flags.Flags.satelliteOemSettingsUxMigration()) {
+ if (mSatelliteManager != null) {
+ try {
+ mSatelliteManager.unregisterForModemStateChanged(mSatelliteModemStateCallback);
+ mSatelliteManager.unregisterForSelectedNbIotSatelliteSubscriptionChanged(
+ mSelectedNbIotSatelliteSubscriptionCallback);
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "IllegalStateException : " + e);
+ }
+ }
+ }
+ }
+
private int getPreferredNetworkMode() {
if (mTelephonyManager == null) {
Log.w(TAG, "TelephonyManager is null");
diff --git a/src/com/android/settings/network/telephony/SatelliteSetting.java b/src/com/android/settings/network/telephony/SatelliteSetting.java
index 16c56f0..a6e2f82 100644
--- a/src/com/android/settings/network/telephony/SatelliteSetting.java
+++ b/src/com/android/settings/network/telephony/SatelliteSetting.java
@@ -56,20 +56,26 @@
/** Handle Satellite Setting Preference Layout. */
public class SatelliteSetting extends RestrictedDashboardFragment {
private static final String TAG = "SatelliteSetting";
- public static final String PREF_KEY_ABOUT_SATELLITE_MESSAGING = "key_about_satellite_messaging";
- public static final String PREF_KEY_CATEGORY_YOUR_SATELLITE_PLAN =
+ private static final String PREF_KEY_ABOUT_SATELLITE_MESSAGING =
+ "key_about_satellite_messaging";
+ private static final String PREF_KEY_CATEGORY_YOUR_SATELLITE_PLAN =
"key_category_your_satellite_plan";
- public static final String PREF_KEY_YOUR_SATELLITE_PLAN = "key_your_satellite_plan";
- public static final String PREF_KEY_CATEGORY_HOW_IT_WORKS = "key_category_how_it_works";
+ private static final String PREF_KEY_YOUR_SATELLITE_PLAN = "key_your_satellite_plan";
+ private static final String PREF_KEY_CATEGORY_HOW_IT_WORKS = "key_category_how_it_works";
+ private static final String PREF_KEY_YOUR_SATELLITE_DATA_PLAN = "key_your_satellite_data_plan";
+ private static final String PREF_KEY_CATEGORY_ABOUT_SATELLITE = "key_category_about_satellite";
private static final String KEY_FOOTER_PREFERENCE = "satellite_setting_extra_info_footer_pref";
- public static final String SUB_ID = "sub_id";
+
+ static final String SUB_ID = "sub_id";
+ static final String EXTRA_IS_SERVICE_DATA_TYPE = "is_service_data_type";
private Activity mActivity;
- private TelephonyManager mTelephonymanager;
private CarrierConfigManager mCarrierConfigManager;
private SatelliteManager mSatelliteManager;
private PersistableBundle mConfigBundle;
- private int mSubId;
+ private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ private String mSimOperatorName = "";
+ private boolean mIsServiceDataType = false;
public SatelliteSetting() {
super(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
@@ -111,13 +117,19 @@
return;
}
- mTelephonymanager = mActivity.getSystemService(TelephonyManager.class);
+ mIsServiceDataType = getIntent().getBooleanExtra(EXTRA_IS_SERVICE_DATA_TYPE, false);
+ mSimOperatorName = getSystemService(TelephonyManager.class).getSimOperatorName(mSubId);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- updateDynamicPreferenceViews();
+ boolean isSatelliteEligible = isSatelliteEligible();
+ updateTitle();
+ updateAboutSatelliteContent();
+ updateMobilePlan(isSatelliteEligible);
+ updateHowItWorksContent(isSatelliteEligible);
+ updateFooterContent();
}
@Override
@@ -130,31 +142,45 @@
return R.xml.satellite_setting;
}
- private void updateDynamicPreferenceViews() {
- String operatorName = mTelephonymanager.getSimOperatorName(mSubId);
- boolean isSatelliteEligible = isSatelliteEligible();
+ private void updateTitle() {
+ getActivity().setTitle(getSubjectString());
+ }
- // About satellite messaging
+ // About satellite content
+ private void updateAboutSatelliteContent() {
+ Preference categoryTitle = findPreference(PREF_KEY_CATEGORY_ABOUT_SATELLITE);
+ categoryTitle.setTitle(
+ getString(R.string.category_name_about_satellite_messaging,
+ getDescriptionString()));
+
Preference preference = findPreference(PREF_KEY_ABOUT_SATELLITE_MESSAGING);
preference.setTitle(
- getResources().getString(R.string.title_about_satellite_setting, operatorName));
+ getResources().getString(R.string.title_about_satellite_setting, mSimOperatorName));
+ }
+ private void updateMobilePlan(boolean isSatelliteEligible) {
// Your mobile plan
PreferenceCategory prefCategory = findPreference(PREF_KEY_CATEGORY_YOUR_SATELLITE_PLAN);
prefCategory.setTitle(getResources().getString(R.string.category_title_your_satellite_plan,
- operatorName));
+ mSimOperatorName));
+ Preference messagingPreference = findPreference(PREF_KEY_YOUR_SATELLITE_PLAN);
- preference = findPreference(PREF_KEY_YOUR_SATELLITE_PLAN);
- Drawable icon;
+ Drawable icon = getContext().getDrawable(R.drawable.ic_check_circle_24px);
if (isSatelliteEligible) {
/* In case satellite is allowed by carrier's entitlement server, the page will show
the check icon with guidance that satellite is included in user's mobile plan */
- preference.setTitle(R.string.title_have_satellite_plan);
- icon = getContext().getDrawable(R.drawable.ic_check_circle_24px);
+ messagingPreference.setTitle(R.string.title_have_satellite_plan);
+ if (com.android.settings.flags.Flags.satelliteOemSettingsUxMigration()) {
+ Preference connectivityPreference = findPreference(
+ PREF_KEY_YOUR_SATELLITE_DATA_PLAN);
+ connectivityPreference.setTitle(R.string.title_have_satellite_data_plan);
+ connectivityPreference.setIcon(icon);
+ connectivityPreference.setVisible(true);
+ }
} else {
/* Or, it will show the blocked icon with the guidance that satellite is not included
in user's mobile plan */
- preference.setTitle(R.string.title_no_satellite_plan);
+ messagingPreference.setTitle(R.string.title_no_satellite_plan);
/* And, the link url provides more information via web page will be shown */
SpannableString spannable = new SpannableString(
getResources().getString(R.string.summary_add_satellite_setting));
@@ -162,9 +188,9 @@
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
spannable.setSpan(new StyleSpan(Typeface.BOLD), 0, spannable.length(),
Spanned.SPAN_INCLUSIVE_INCLUSIVE);
- preference.setSummary(spannable);
+ messagingPreference.setSummary(spannable);
/* The link will lead users to a guide page */
- preference.setOnPreferenceClickListener(pref -> {
+ messagingPreference.setOnPreferenceClickListener(pref -> {
String url = readSatelliteMoreInfoString(mSubId);
if (!url.isEmpty()) {
Uri uri = Uri.parse(url);
@@ -173,11 +199,13 @@
}
return true;
});
- icon = getResources().getDrawable(R.drawable.ic_block_24px);
+ icon = getResources().getDrawable(R.drawable.ic_block_24px, null);
}
icon.setTintList(Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary));
- preference.setIcon(icon);
+ messagingPreference.setIcon(icon);
+ }
+ private void updateHowItWorksContent(boolean isSatelliteEligible) {
/* Composes "How it works" section, which guides how users can use satellite messaging, when
satellite messaging is included in user's mobile plan, or it'll will be grey out. */
if (!isSatelliteEligible) {
@@ -185,13 +213,15 @@
category.setEnabled(false);
category.setShouldDisableView(true);
}
+ }
+ private void updateFooterContent() {
// More about satellite messaging
FooterPreference footerPreference = findPreference(KEY_FOOTER_PREFERENCE);
if (footerPreference != null) {
footerPreference.setSummary(
getResources().getString(R.string.satellite_setting_summary_more_information,
- operatorName));
+ getSubjectString(), mSimOperatorName));
final String[] link = new String[1];
link[0] = readSatelliteMoreInfoString(mSubId);
@@ -205,8 +235,9 @@
}
}
});
+
footerPreference.setLearnMoreText(
- getResources().getString(R.string.more_about_satellite_messaging));
+ getString(R.string.more_about_satellite_messaging, getDescriptionString()));
}
}
}
@@ -245,6 +276,32 @@
return bundle.getBoolean(KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, false);
}
+ // This is for a word which first letter is uppercase. e.g. Satellite messaging.
+ private String getSubjectString() {
+ int result;
+ if (com.android.settings.flags.Flags.satelliteOemSettingsUxMigration()) {
+ result = mIsServiceDataType
+ ? R.string.title_satellite_setting_connectivity
+ : R.string.satellite_setting_title;
+ } else {
+ result = R.string.satellite_setting_title;
+ }
+ return getString(result);
+ }
+
+ // This is for a word without uppercase letter. e.g. satellite messaging.
+ private String getDescriptionString() {
+ int result;
+ if (com.android.settings.flags.Flags.satelliteOemSettingsUxMigration()) {
+ result = mIsServiceDataType
+ ? R.string.description_satellite_setting_connectivity
+ : R.string.description_satellite_setting_messaging;
+ } else {
+ result = R.string.satellite_setting_title;
+ }
+ return getString(result);
+ }
+
private static void loge(String message) {
Log.e(TAG, message);
}
diff --git a/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java b/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java
index efdd9cb..017d478 100644
--- a/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java
+++ b/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java
@@ -16,16 +16,25 @@
package com.android.settings.network.telephony;
+import static android.telephony.NetworkRegistrationInfo.SERVICE_TYPE_DATA;
+import static android.telephony.NetworkRegistrationInfo.SERVICE_TYPE_SMS;
+
import android.content.Context;
import android.content.Intent;
import android.os.PersistableBundle;
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
+import android.telephony.TelephonyCallback;
+import android.telephony.TelephonyManager;
+import android.telephony.satellite.NtnSignalStrength;
import android.telephony.satellite.SatelliteManager;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
@@ -33,28 +42,34 @@
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.network.CarrierConfigCache;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnStart;
-import com.android.settingslib.core.lifecycle.events.OnStop;
+import java.util.Arrays;
+import java.util.List;
import java.util.Set;
/**
* Preference controller for "Satellite Setting"
*/
public class SatelliteSettingPreferenceController extends
- TelephonyBasePreferenceController implements LifecycleObserver, OnStart, OnStop {
-
+ TelephonyBasePreferenceController implements DefaultLifecycleObserver {
private static final String TAG = "SatelliteSettingPreferenceController";
CarrierConfigCache mCarrierConfigCache;
SatelliteManager mSatelliteManager;
- @Nullable private Boolean mIsSatelliteEligible = null;
+ private TelephonyManager mTelephonyManager = null;
+ @VisibleForTesting
+ final CarrierRoamingNtnModeCallback mCarrierRoamingNtnModeCallback =
+ new CarrierRoamingNtnModeCallback();
+
+ @Nullable
+ private Boolean mIsSatelliteEligible = null;
+ private boolean mIsServiceDataType = false;
public SatelliteSettingPreferenceController(@NonNull Context context, @NonNull String key) {
super(context, key);
mCarrierConfigCache = CarrierConfigCache.getInstance(context);
mSatelliteManager = context.getSystemService(SatelliteManager.class);
+ mTelephonyManager = context.getSystemService(TelephonyManager.class);
}
@Override
@@ -76,11 +91,18 @@
}
@Override
- public void onStart() {
+ public void onResume(@NonNull LifecycleOwner owner) {
+ if (com.android.settings.flags.Flags.satelliteOemSettingsUxMigration()) {
+ mTelephonyManager.registerTelephonyCallback(mContext.getMainExecutor(),
+ mCarrierRoamingNtnModeCallback);
+ }
}
@Override
- public void onStop() {
+ public void onPause(@NonNull LifecycleOwner owner) {
+ if (com.android.settings.flags.Flags.satelliteOemSettingsUxMigration()) {
+ mTelephonyManager.unregisterTelephonyCallback(mCarrierRoamingNtnModeCallback);
+ }
}
@Override
@@ -93,6 +115,7 @@
public void updateState(@Nullable Preference preference) {
super.updateState(preference);
if (preference != null) {
+ mCarrierRoamingNtnModeCallback.mPref = preference;
updateSummary(preference);
}
}
@@ -106,6 +129,7 @@
// This will setup the Home and Search affordance
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_AS_SUBSETTING, true);
intent.putExtra(SatelliteSetting.SUB_ID, mSubId);
+ intent.putExtra(SatelliteSetting.EXTRA_IS_SERVICE_DATA_TYPE, mIsServiceDataType);
mContext.startActivity(intent);
return true;
}
@@ -115,14 +139,20 @@
/**
* Set subId for Satellite Settings page.
+ *
* @param subId subscription ID.
*/
public void init(int subId) {
logd("init(), subId=" + subId);
mSubId = subId;
+ mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId);
}
private void updateSummary(Preference preference) {
+ if (mSatelliteManager == null) {
+ logd("updateSummary - no SatelliteManager");
+ return;
+ }
try {
Set<Integer> restrictionReason =
mSatelliteManager.getAttachRestrictionReasonsForCarrier(mSubId);
@@ -148,4 +178,46 @@
private static void loge(String message) {
Log.e(TAG, message);
}
+
+ @VisibleForTesting
+ class CarrierRoamingNtnModeCallback extends TelephonyCallback implements
+ TelephonyCallback.CarrierRoamingNtnModeListener {
+ Preference mPref = null;
+
+ @Override
+ public void onCarrierRoamingNtnAvailableServicesChanged(int[] availableServices) {
+ CarrierRoamingNtnModeListener.super.onCarrierRoamingNtnAvailableServicesChanged(
+ availableServices);
+ List<Integer> availableServicesList = Arrays.stream(availableServices).boxed().toList();
+ boolean isSmsAvailable = availableServicesList.contains(SERVICE_TYPE_SMS);
+ boolean isDataAvailable = availableServicesList.contains(SERVICE_TYPE_DATA);
+ logd("isSmsAvailable : " + isSmsAvailable
+ + " / isDataAvailable " + isDataAvailable);
+ if (mPref == null) {
+ logd("Satellite preference is not initialized yet");
+ return;
+ }
+ if (isDataAvailable) {
+ mIsServiceDataType = true;
+ mPref.setTitle(R.string.title_satellite_setting_connectivity);
+ } else if (isSmsAvailable) {
+ mPref.setTitle(R.string.satellite_setting_title);
+ }
+ }
+
+ @Override
+ public void onCarrierRoamingNtnEligibleStateChanged(boolean eligible) {
+ // Do nothing
+ }
+
+ @Override
+ public void onCarrierRoamingNtnModeChanged(boolean active) {
+ // Do nothing
+ }
+
+ @Override
+ public void onCarrierRoamingNtnSignalStrengthChanged(NtnSignalStrength ntnSignalStrength) {
+ // Do nothing
+ }
+ }
}
diff --git a/src/com/android/settings/network/telephony/SatelliteSettingSosPreferenceController.java b/src/com/android/settings/network/telephony/SatelliteSettingSosPreferenceController.java
new file mode 100644
index 0000000..b9e04d8
--- /dev/null
+++ b/src/com/android/settings/network/telephony/SatelliteSettingSosPreferenceController.java
@@ -0,0 +1,54 @@
+/*
+ * 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 static android.telephony.CarrierConfigManager.KEY_SATELLITE_ESOS_SUPPORTED_BOOL;
+
+import android.content.Context;
+import android.os.PersistableBundle;
+
+import com.android.settings.flags.Flags;
+import com.android.settings.network.CarrierConfigCache;
+
+/** A controller for Satellite SOS entry preference. */
+public class SatelliteSettingSosPreferenceController extends TelephonyBasePreferenceController {
+ private static final String TAG = "SatelliteSettingSosPrefController";
+
+ public SatelliteSettingSosPreferenceController(Context context,
+ String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ /** Setup the subscription Id for the UI with specific UI group. */
+ public void init(int subId) {
+ mSubId = subId;
+ }
+
+ @Override
+ public int getAvailabilityStatus(int subId) {
+ if (Flags.satelliteOemSettingsUxMigration()) {
+ CarrierConfigCache carrierConfigCache = CarrierConfigCache.getInstance(mContext);
+ PersistableBundle bundle = carrierConfigCache.getConfigForSubId(subId);
+ if (bundle == null) {
+ return CONDITIONALLY_UNAVAILABLE;
+ }
+ boolean isCarrierSupport = bundle.getBoolean(KEY_SATELLITE_ESOS_SUPPORTED_BOOL);
+ return isCarrierSupport ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ }
+ return CONDITIONALLY_UNAVAILABLE;
+ }
+}
diff --git a/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryController.java b/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryController.java
index 688e7b4..c182059 100644
--- a/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryController.java
+++ b/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryController.java
@@ -33,7 +33,9 @@
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
+import com.android.settings.flags.Flags;
+import java.util.Arrays;
import java.util.List;
/** Preference controller for Satellite functions in mobile network settings. */
@@ -86,24 +88,29 @@
@Override
public void onResume(@NonNull LifecycleOwner owner) {
- mTelephonyManager.registerTelephonyCallback(mContext.getMainExecutor(),
- mCarrierRoamingNtnModeCallback);
+ if (Flags.satelliteOemSettingsUxMigration()) {
+ mTelephonyManager.registerTelephonyCallback(mContext.getMainExecutor(),
+ mCarrierRoamingNtnModeCallback);
+ }
}
@Override
public void onPause(@NonNull LifecycleOwner owner) {
- mTelephonyManager.unregisterTelephonyCallback(mCarrierRoamingNtnModeCallback);
+ if (Flags.satelliteOemSettingsUxMigration()) {
+ mTelephonyManager.unregisterTelephonyCallback(mCarrierRoamingNtnModeCallback);
+ }
}
@VisibleForTesting
class CarrierRoamingNtnModeCallback extends TelephonyCallback implements
TelephonyCallback.CarrierRoamingNtnModeListener {
@Override
- public void onCarrierRoamingNtnAvailableServicesChanged(List<Integer> availableServices) {
+ public void onCarrierRoamingNtnAvailableServicesChanged(int[] availableServices) {
CarrierRoamingNtnModeListener.super.onCarrierRoamingNtnAvailableServicesChanged(
availableServices);
- boolean isSmsAvailable = availableServices.contains(SERVICE_TYPE_SMS);
- boolean isDataAvailable = availableServices.contains(SERVICE_TYPE_DATA);
+ List<Integer> availableServicesList = Arrays.stream(availableServices).boxed().toList();
+ boolean isSmsAvailable = availableServicesList.contains(SERVICE_TYPE_SMS);
+ boolean isDataAvailable = availableServicesList.contains(SERVICE_TYPE_DATA);
Log.i(TAG, "isSmsAvailable : " + isSmsAvailable
+ " / isDataAvailable " + isDataAvailable);
if (mPreferenceCategory == null) {
diff --git a/src/com/android/settings/network/telephony/SatelliteSettingsSosFragment.java b/src/com/android/settings/network/telephony/SatelliteSettingsSosFragment.java
new file mode 100644
index 0000000..911939a
--- /dev/null
+++ b/src/com/android/settings/network/telephony/SatelliteSettingsSosFragment.java
@@ -0,0 +1,26 @@
+/*
+ * 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 com.android.settings.SettingsPreferenceFragment;
+
+public class SatelliteSettingsSosFragment extends SettingsPreferenceFragment {
+ @Override
+ public int getMetricsCategory() {
+ return 0;
+ }
+}
diff --git a/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.kt b/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.kt
index 67a2356..4bd91b2 100644
--- a/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.kt
+++ b/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.kt
@@ -25,18 +25,22 @@
import android.telephony.ServiceState
import android.telephony.SubscriptionManager
import android.telephony.TelephonyManager
+import android.telephony.satellite.SatelliteManager
+import android.telephony.satellite.SatelliteModemStateCallback
+import android.telephony.satellite.SelectedNbIotSatelliteSubscriptionCallback
+import android.util.Log
import androidx.annotation.VisibleForTesting
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.res.stringResource
+import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.compose.collectAsStateWithLifecycle
-import androidx.preference.Preference
-import androidx.preference.PreferenceScreen
import com.android.settings.R
import com.android.settings.Settings.NetworkSelectActivity
+import com.android.settings.flags.Flags
import com.android.settings.network.CarrierConfigCache
import com.android.settings.network.telephony.MobileNetworkUtils
import com.android.settings.network.telephony.allowedNetworkTypesFlow
@@ -46,8 +50,6 @@
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
import com.android.settingslib.spa.widget.preference.SwitchPreference
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
-import kotlin.properties.Delegates.notNull
-import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
@@ -59,6 +61,7 @@
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
+import kotlin.time.Duration.Companion.seconds
/**
* Preference controller for "Auto Select Network"
@@ -73,9 +76,13 @@
private val getConfigForSubId: (subId: Int) -> PersistableBundle = { subId ->
CarrierConfigCache.getInstance(context).getConfigForSubId(subId)
},
-) : ComposePreferenceController(context, key) {
+) : ComposePreferenceController(context, key), DefaultLifecycleObserver {
+
+ private var isSatelliteSessionStarted = false
+ private var isSelectedSubIdForSatellite = false
private lateinit var telephonyManager: TelephonyManager
+ private lateinit var satelliteManager: SatelliteManager
private val listeners = mutableListOf<OnNetworkSelectModeListener>()
@VisibleForTesting
@@ -83,6 +90,21 @@
private var subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID
+ val satelliteModemStateCallback = SatelliteModemStateCallback { state ->
+ isSatelliteSessionStarted = when (state) {
+ SatelliteManager.SATELLITE_MODEM_STATE_OFF,
+ SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE,
+ SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN -> false
+
+ else -> true
+ }
+ }
+
+ val selectedNbIotSatelliteSubscriptionCallback =
+ SelectedNbIotSatelliteSubscriptionCallback { selectedSubId ->
+ isSelectedSubIdForSatellite = selectedSubId == subId
+ }
+
/**
* Initialization based on given subscription id.
*/
@@ -90,7 +112,7 @@
this.subId = subId
telephonyManager = mContext.getSystemService(TelephonyManager::class.java)!!
.createForSubscriptionId(subId)
-
+ satelliteManager = mContext.getSystemService(SatelliteManager::class.java)!!
return this
}
@@ -117,7 +139,10 @@
SwitchPreference(object : SwitchPreferenceModel {
override val title = stringResource(R.string.select_automatically)
override val summary = { disallowedSummary }
- override val changeable = { disallowedSummary.isEmpty() }
+ override val changeable = {
+ disallowedSummary.isEmpty()
+ && !(isSatelliteSessionStarted && isSelectedSubIdForSatellite)
+ }
override val checked = { isAuto }
override val onCheckedChange: (Boolean) -> Unit = { newChecked ->
if (newChecked) {
@@ -132,6 +157,38 @@
})
}
+ override fun onStart(owner: LifecycleOwner) {
+ if (Flags.satelliteOemSettingsUxMigration()) {
+ if (satelliteManager != null) {
+ try {
+ satelliteManager.registerForModemStateChanged(
+ mContext.mainExecutor, satelliteModemStateCallback
+ )
+ satelliteManager.registerForSelectedNbIotSatelliteSubscriptionChanged(
+ mContext.mainExecutor, selectedNbIotSatelliteSubscriptionCallback
+ )
+ } catch (e: IllegalStateException) {
+ Log.w(TAG, "IllegalStateException $e")
+ }
+ }
+ }
+ }
+
+ override fun onStop(owner: LifecycleOwner) {
+ if (Flags.satelliteOemSettingsUxMigration()) {
+ if (satelliteManager != null) {
+ try {
+ satelliteManager.unregisterForModemStateChanged(satelliteModemStateCallback)
+ satelliteManager.unregisterForSelectedNbIotSatelliteSubscriptionChanged(
+ selectedNbIotSatelliteSubscriptionCallback
+ )
+ } catch (e: IllegalStateException) {
+ Log.w(TAG, "IllegalStateException $e")
+ }
+ }
+ }
+ }
+
private suspend fun getDisallowedSummary(serviceState: ServiceState): String =
withContext(Dispatchers.Default) {
if (!serviceState.roaming && onlyAutoSelectInHome()) {
@@ -213,6 +270,8 @@
}
companion object {
+ private const val TAG = "AutoSelectPreferenceController"
+
private val MINIMUM_DIALOG_TIME = 1.seconds
}
}
diff --git a/src/com/android/settings/notification/CallVolumePreference.kt b/src/com/android/settings/notification/CallVolumePreference.kt
index e09dc9b..031687f 100644
--- a/src/com/android/settings/notification/CallVolumePreference.kt
+++ b/src/com/android/settings/notification/CallVolumePreference.kt
@@ -32,6 +32,7 @@
import com.android.settingslib.metadata.PreferenceMetadata
import com.android.settingslib.metadata.RangeValue
import com.android.settingslib.metadata.ReadWritePermit
+import com.android.settingslib.metadata.SensitivityLevel
import com.android.settingslib.preference.PreferenceBinding
// LINT.IfChange
@@ -81,6 +82,9 @@
override fun getWritePermit(context: Context, value: Int?, myUid: Int, callingUid: Int) =
ReadWritePermit.ALLOW
+ override val sensitivityLevel
+ get() = SensitivityLevel.NO_SENSITIVITY
+
override fun getMinValue(context: Context) =
createAudioHelper(context).getMinVolume(getAudioStream(context))
diff --git a/src/com/android/settings/notification/MediaVolumePreference.kt b/src/com/android/settings/notification/MediaVolumePreference.kt
index 2533f0a..a6d9c41 100644
--- a/src/com/android/settings/notification/MediaVolumePreference.kt
+++ b/src/com/android/settings/notification/MediaVolumePreference.kt
@@ -30,6 +30,7 @@
import com.android.settingslib.metadata.PreferenceMetadata
import com.android.settingslib.metadata.RangeValue
import com.android.settingslib.metadata.ReadWritePermit
+import com.android.settingslib.metadata.SensitivityLevel
import com.android.settingslib.preference.PreferenceBinding
// LINT.IfChange
@@ -82,6 +83,9 @@
override fun getWritePermit(context: Context, value: Int?, myUid: Int, callingUid: Int) =
ReadWritePermit.ALLOW
+ override val sensitivityLevel
+ get() = SensitivityLevel.NO_SENSITIVITY
+
override fun getMinValue(context: Context) =
createAudioHelper(context).getMinVolume(STREAM_MUSIC)
diff --git a/src/com/android/settings/notification/PhoneRingtonePreferenceController.java b/src/com/android/settings/notification/PhoneRingtonePreferenceController.java
index 7bd78fe..2944b7d 100644
--- a/src/com/android/settings/notification/PhoneRingtonePreferenceController.java
+++ b/src/com/android/settings/notification/PhoneRingtonePreferenceController.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.media.RingtoneManager;
+import android.media.audio.Flags;
import com.android.settings.Utils;
@@ -36,6 +37,9 @@
@Override
public boolean isAvailable() {
+ if (isRingtoneVibrationEnabled()) {
+ return false;
+ }
return Utils.isVoiceCapable(mContext);
}
@@ -43,4 +47,9 @@
public int getRingtoneType() {
return RingtoneManager.TYPE_RINGTONE;
}
+
+ private boolean isRingtoneVibrationEnabled() {
+ return Flags.enableRingtoneHapticsCustomization() && mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_ringtoneVibrationSettingsSupported);
+ }
}
diff --git a/src/com/android/settings/notification/SeparateRingVolumePreference.kt b/src/com/android/settings/notification/SeparateRingVolumePreference.kt
index a9c167d..3edb4ac 100644
--- a/src/com/android/settings/notification/SeparateRingVolumePreference.kt
+++ b/src/com/android/settings/notification/SeparateRingVolumePreference.kt
@@ -39,6 +39,7 @@
import com.android.settingslib.metadata.PreferenceMetadata
import com.android.settingslib.metadata.RangeValue
import com.android.settingslib.metadata.ReadWritePermit
+import com.android.settingslib.metadata.SensitivityLevel
import com.android.settingslib.preference.PreferenceBinding
// LINT.IfChange
@@ -91,6 +92,9 @@
override fun getWritePermit(context: Context, value: Int?, myUid: Int, callingUid: Int) =
ReadWritePermit.ALLOW
+ override val sensitivityLevel
+ get() = SensitivityLevel.NO_SENSITIVITY
+
override fun getMinValue(context: Context) =
createAudioHelper(context).getMinVolume(STREAM_RING)
diff --git a/tests/robotests/src/com/android/settings/accessibility/VibrationIntensityScreenTest.kt b/tests/robotests/src/com/android/settings/accessibility/VibrationIntensityScreenTest.kt
index 99851de..40ed9a3 100644
--- a/tests/robotests/src/com/android/settings/accessibility/VibrationIntensityScreenTest.kt
+++ b/tests/robotests/src/com/android/settings/accessibility/VibrationIntensityScreenTest.kt
@@ -15,15 +15,40 @@
*/
package com.android.settings.accessibility
+import android.content.Context
+import android.content.ContextWrapper
+import android.content.res.Resources
+import android.os.Vibrator
+import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.flags.Flags
+import com.android.settings.R
import com.android.settingslib.preference.CatalystScreenTestCase
import com.google.common.truth.Truth.assertThat
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
+// LINT.IfChange
@RunWith(AndroidJUnit4::class)
class VibrationIntensityScreenTest : CatalystScreenTestCase() {
+ private lateinit var vibrator: Vibrator
+
+ private val resourcesSpy: Resources =
+ spy((ApplicationProvider.getApplicationContext() as Context).resources)
+
+ private val context: Context =
+ object : ContextWrapper(ApplicationProvider.getApplicationContext()) {
+ override fun getSystemService(name: String): Any? =
+ when {
+ name == getSystemServiceName(Vibrator::class.java) -> vibrator
+ else -> super.getSystemService(name)
+ }
+ override fun getResources(): Resources = resourcesSpy
+ }
override val preferenceScreenCreator = VibrationIntensityScreen()
@@ -34,4 +59,33 @@
fun key() {
assertThat(preferenceScreenCreator.key).isEqualTo(VibrationIntensityScreen.KEY)
}
+
+ @Test
+ fun isAvailable_noVibrator_unavailable() {
+ vibrator = mock { on { hasVibrator() } doReturn false }
+ resourcesSpy.stub {
+ on { getInteger(R.integer.config_vibration_supported_intensity_levels) } doReturn 3
+ }
+ assertThat(preferenceScreenCreator.isAvailable(context)).isFalse()
+ }
+
+ @Test
+ fun isAvailable_hasVibratorAndSingleIntensityLevel_unavailable() {
+ vibrator = mock { on { hasVibrator() } doReturn true }
+ resourcesSpy.stub {
+ on { getInteger(R.integer.config_vibration_supported_intensity_levels) } doReturn 1
+ }
+ assertThat(preferenceScreenCreator.isAvailable(context)).isFalse()
+ }
+
+ @Test
+ fun isAvailable_hasVibratorAndMultipleIntensityLevels_available() {
+ vibrator = mock { on { hasVibrator() } doReturn true }
+ resourcesSpy.stub {
+ on { getInteger(R.integer.config_vibration_supported_intensity_levels) } doReturn 2
+ }
+ assertThat(preferenceScreenCreator.isAvailable(context)).isTrue()
+ }
}
+// LINT.ThenChange(VibrationPreferenceControllerTest.java)
+
diff --git a/tests/robotests/src/com/android/settings/accessibility/VibrationMainSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/VibrationMainSwitchPreferenceControllerTest.java
index 6f57003..9caa211 100644
--- a/tests/robotests/src/com/android/settings/accessibility/VibrationMainSwitchPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/VibrationMainSwitchPreferenceControllerTest.java
@@ -41,6 +41,7 @@
import org.robolectric.RobolectricTestRunner;
/** Tests for {@link VibrationMainSwitchPreferenceController}. */
+// LINT.IfChange
@RunWith(RobolectricTestRunner.class)
public class VibrationMainSwitchPreferenceControllerTest {
@@ -104,3 +105,4 @@
return Settings.System.getInt(mContext.getContentResolver(), settingKey);
}
}
+// LINT.ThenChange(VibrationMainSwitchPreferenceTest.kt)
diff --git a/tests/robotests/src/com/android/settings/accessibility/VibrationMainSwitchPreferenceTest.kt b/tests/robotests/src/com/android/settings/accessibility/VibrationMainSwitchPreferenceTest.kt
new file mode 100644
index 0000000..fd781bc
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/VibrationMainSwitchPreferenceTest.kt
@@ -0,0 +1,77 @@
+/*
+ * 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.accessibility
+
+import android.content.Context
+import android.provider.Settings.System.VIBRATE_ON
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.preference.createAndBindWidget
+import com.android.settingslib.widget.MainSwitchPreference
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+// LINT.IfChange
+@RunWith(AndroidJUnit4::class)
+class VibrationMainSwitchPreferenceTest {
+ private val context: Context = ApplicationProvider.getApplicationContext()
+ private val preference = VibrationMainSwitchPreference()
+
+ @Test
+ fun checked_valueUnset_returnDefaultTrue() {
+ setVibrateOn(null)
+
+ assertThat(getMainSwitchPreference().isChecked).isTrue()
+ }
+
+ @Test
+ fun checked_valueEnabled_returnTrue() {
+ setVibrateOn(true)
+
+ assertThat(getMainSwitchPreference().isChecked).isTrue()
+ }
+
+ @Test
+ fun checked_valueDisabled_returnFalse() {
+ setVibrateOn(false)
+
+ assertThat(getMainSwitchPreference().isChecked).isFalse()
+ }
+
+ @Test
+ fun click_updatesCorrectly() {
+ setVibrateOn(null)
+ val widget = getMainSwitchPreference()
+
+ assertThat(widget.isChecked).isTrue()
+
+ widget.performClick()
+
+ assertThat(widget.isChecked).isFalse()
+
+ widget.performClick()
+
+ assertThat(widget.isChecked).isTrue()
+ }
+
+ private fun getMainSwitchPreference(): MainSwitchPreference =
+ preference.createAndBindWidget(context)
+
+ private fun setVibrateOn(enabled: Boolean?) =
+ preference.storage(context).setValue(VIBRATE_ON, Boolean::class.javaObjectType, enabled)
+}
+// LINT.ThenChange(VibrationMainSwitchPreferenceControllerTest.java)
diff --git a/tests/robotests/src/com/android/settings/accessibility/VibrationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/VibrationPreferenceControllerTest.java
index 59ed486..a0481e5 100644
--- a/tests/robotests/src/com/android/settings/accessibility/VibrationPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/VibrationPreferenceControllerTest.java
@@ -46,6 +46,7 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
+// LINT.IfChange
@RunWith(RobolectricTestRunner.class)
public class VibrationPreferenceControllerTest {
private static final String PREFERENCE_KEY = "preference_key";
@@ -158,3 +159,7 @@
return controller;
}
}
+// LINT.ThenChange(
+// VibrationIntensityScreenTest.kt,
+// VibrationScreenTest.kt,
+// )
diff --git a/tests/robotests/src/com/android/settings/accessibility/VibrationScreenTest.kt b/tests/robotests/src/com/android/settings/accessibility/VibrationScreenTest.kt
new file mode 100644
index 0000000..c6e5265
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/VibrationScreenTest.kt
@@ -0,0 +1,90 @@
+/*
+ * 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.accessibility
+
+import android.content.Context
+import android.content.ContextWrapper
+import android.content.res.Resources
+import android.os.Vibrator
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.flags.Flags
+import com.android.settings.R
+import com.android.settingslib.preference.CatalystScreenTestCase
+import com.google.common.truth.Truth.assertThat
+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
+
+// LINT.IfChange
+@RunWith(AndroidJUnit4::class)
+class VibrationScreenTest : CatalystScreenTestCase() {
+ private lateinit var vibrator: Vibrator
+
+ private val resourcesSpy: Resources =
+ spy((ApplicationProvider.getApplicationContext() as Context).resources)
+
+ private val context: Context =
+ object : ContextWrapper(ApplicationProvider.getApplicationContext()) {
+ override fun getSystemService(name: String): Any? =
+ when {
+ name == getSystemServiceName(Vibrator::class.java) -> vibrator
+ else -> super.getSystemService(name)
+ }
+ override fun getResources(): Resources = resourcesSpy
+ }
+
+ override val preferenceScreenCreator = VibrationScreen()
+
+ override val flagName: String
+ get() = Flags.FLAG_CATALYST_VIBRATION_INTENSITY_SCREEN
+
+ @Test
+ fun key() {
+ assertThat(preferenceScreenCreator.key).isEqualTo(VibrationScreen.KEY)
+ }
+
+ @Test
+ fun isAvailable_noVibrator_unavailable() {
+ vibrator = mock { on { hasVibrator() } doReturn false }
+ resourcesSpy.stub {
+ on { getInteger(R.integer.config_vibration_supported_intensity_levels) } doReturn 1
+ }
+ assertThat(preferenceScreenCreator.isAvailable(context)).isFalse()
+ }
+
+ @Test
+ fun isAvailable_hasVibratorAndMultipleIntensityLevels_unavailable() {
+ vibrator = mock { on { hasVibrator() } doReturn true }
+ resourcesSpy.stub {
+ on { getInteger(R.integer.config_vibration_supported_intensity_levels) } doReturn 3
+ }
+ assertThat(preferenceScreenCreator.isAvailable(context)).isFalse()
+ }
+
+ @Test
+ fun isAvailable_hasVibratorAndSingleIntensityLevel_available() {
+ vibrator = mock { on { hasVibrator() } doReturn true }
+ resourcesSpy.stub {
+ on { getInteger(R.integer.config_vibration_supported_intensity_levels) } doReturn 1
+ }
+ assertThat(preferenceScreenCreator.isAvailable(context)).isTrue()
+ }
+}
+// LINT.ThenChange(VibrationPreferenceControllerTest.java)
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsControllerTest.java
index d9054a8..cb891a2 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsCompanionAppsControllerTest.java
@@ -104,7 +104,6 @@
associationId,
/* userId */ 0,
packageName,
- /* tag */ null,
MacAddress.fromString(mCachedDevice.getAddress()),
/* displayName */ null,
/* deviceProfile */ "",
@@ -116,7 +115,8 @@
/* timeApprovedMs */ System.currentTimeMillis(),
/* lastTimeConnected */ Long.MAX_VALUE,
/* systemDataSyncFlags */ -1,
- /* deviceIcon */ null);
+ /* deviceIcon */ null,
+ /* deviceId */ null);
mAssociations.add(association);
showScreen(mController);
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java
index e21bf9a..2d007e1 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java
@@ -120,7 +120,12 @@
.thenAnswer(invocation -> ImmutableList.of(mConnectableProfiles));
setupDevice(mDeviceConfig);
- initController(List.of());
+ mController = new BluetoothDetailsProfilesController(mContext, mFragment, mLocalManager,
+ mCachedDevice, mLifecycle);
+ mProfiles.setKey(mController.getPreferenceKey());
+ mController.mProfilesContainer = mProfiles;
+ mScreen.removeAll();
+ mScreen.addPreference(mProfiles);
BluetoothProperties.le_audio_allow_list(Lists.newArrayList(LE_DEVICE_MODEL));
}
@@ -550,7 +555,8 @@
@Test
public void prefKeyInBlockingList_hideToggle() {
- initController(List.of("A2DP"));
+ mController.setInvisibleProfiles(List.of("A2DP"));
+ mController.setHasExtraSpace(true);
setupDevice(makeDefaultDeviceConfig());
addA2dpProfileToDevice(true, true, true);
@@ -565,7 +571,6 @@
@Test
public void prefKeyNotInBlockingList_showToggle() {
- initController(List.of());
setupDevice(makeDefaultDeviceConfig());
addA2dpProfileToDevice(true, true, true);
@@ -653,13 +658,4 @@
assertThat(switches.getFirst().getTitle()).isEqualTo(
mContext.getString(mLeAudioProfile.getNameResource(mDevice)));
}
-
- private void initController(List<String> invisibleProfiles) {
- mController = new BluetoothDetailsProfilesController(mContext, mFragment, mLocalManager,
- mCachedDevice, mLifecycle, invisibleProfiles, true);
- mProfiles.setKey(mController.getPreferenceKey());
- mController.mProfilesContainer = mProfiles;
- mScreen.removeAll();
- mScreen.addPreference(mProfiles);
- }
}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
index 7e90171..0e052ab 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
@@ -52,7 +52,6 @@
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
-import com.android.settings.bluetooth.ui.model.FragmentTypeModel;
import com.android.settings.bluetooth.ui.view.DeviceDetailsFragmentFormatter;
import com.android.settings.flags.Flags;
import com.android.settings.testutils.FakeFeatureFactory;
@@ -122,10 +121,7 @@
removeInputDeviceWithMatchingBluetoothAddress();
FakeFeatureFactory fakeFeatureFactory = FakeFeatureFactory.setupForTest();
when(fakeFeatureFactory.mBluetoothFeatureProvider.getDeviceDetailsFragmentFormatter(any(),
- any(), any(), eq(mCachedDevice))).thenReturn(mFormatter);
- when(mFormatter.getVisiblePreferenceKeys(
- FragmentTypeModel.DeviceDetailsMainFragment.INSTANCE))
- .thenReturn(null);
+ any(), any(), eq(mCachedDevice), any())).thenReturn(mFormatter);
mFragment = setupFragment();
mFragment.onAttach(mContext);
diff --git a/tests/robotests/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatterTest.kt b/tests/robotests/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatterTest.kt
index 28eaeaa..d0bd27d 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatterTest.kt
+++ b/tests/robotests/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatterTest.kt
@@ -39,6 +39,7 @@
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingStateModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.ToggleModel
+import com.android.settingslib.core.AbstractPreferenceController
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
@@ -73,6 +74,9 @@
@Mock private lateinit var cachedDevice: CachedBluetoothDevice
@Mock private lateinit var bluetoothAdapter: BluetoothAdapter
@Mock private lateinit var repository: DeviceSettingRepository
+ @Mock private lateinit var profileController: AbstractPreferenceController
+ @Mock private lateinit var headerController: AbstractPreferenceController
+ @Mock private lateinit var buttonController: AbstractPreferenceController
private lateinit var context: Context
private lateinit var fragment: TestFragment
@@ -98,56 +102,23 @@
fragment.preferenceScreen.run {
addPreference(Preference(context).apply { key = "bluetooth_device_header" })
addPreference(Preference(context).apply { key = "action_buttons" })
- addPreference(Preference(context).apply { key = "keyboard_settings" })
+ addPreference(Preference(context).apply { key = "bluetooth_profiles" })
}
+ `when`(profileController.preferenceKey).thenReturn("bluetooth_profiles")
+ `when`(headerController.preferenceKey).thenReturn("bluetooth_device_header")
+ `when`(buttonController.preferenceKey).thenReturn("action_buttons")
underTest =
DeviceDetailsFragmentFormatterImpl(
context,
fragment,
+ listOf(profileController, headerController, buttonController),
bluetoothAdapter,
cachedDevice,
testScope.testScheduler)
}
@Test
- fun getVisiblePreferenceKeysForMainPage_hasConfig_returnList() {
- testScope.runTest {
- `when`(repository.getDeviceSettingsConfig(cachedDevice))
- .thenReturn(
- DeviceSettingConfigModel(
- listOf(
- DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem(
- DeviceSettingId.DEVICE_SETTING_ID_HEADER,
- highlighted = false,
- preferenceKey = "bluetooth_device_header"
- ),
- DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem(
- DeviceSettingId.DEVICE_SETTING_ID_ACTION_BUTTONS, highlighted = false, preferenceKey = "action_buttons"),
- ),
- listOf(),
- null))
-
- val keys =
- underTest.getVisiblePreferenceKeys(FragmentTypeModel.DeviceDetailsMainFragment)
-
- assertThat(keys).containsExactly("bluetooth_device_header", "action_buttons")
- }
- }
-
- @Test
- fun getVisiblePreferenceKeysForMainPage_noConfig_returnNull() {
- testScope.runTest {
- `when`(repository.getDeviceSettingsConfig(cachedDevice)).thenReturn(null)
-
- val keys =
- underTest.getVisiblePreferenceKeys(FragmentTypeModel.DeviceDetailsMainFragment)
-
- assertThat(keys).isNull()
- }
- }
-
- @Test
fun getMenuItem_returnItem() {
testScope.runTest {
`when`(repository.getDeviceSettingsConfig(cachedDevice))
@@ -187,7 +158,7 @@
underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment)
assertThat(getDisplayedPreferences().mapNotNull { it.key })
- .containsExactly("bluetooth_device_header", "action_buttons", "keyboard_settings")
+ .containsExactly("bluetooth_device_header", "action_buttons", "bluetooth_profiles")
}
}
@@ -202,8 +173,8 @@
DeviceSettingId.DEVICE_SETTING_ID_HEADER,
highlighted = false, preferenceKey = "bluetooth_device_header"),
DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem(
- DeviceSettingId.DEVICE_SETTING_ID_KEYBOARD_SETTINGS,
- highlighted = false, preferenceKey = "keyboard_settings"),
+ DeviceSettingId.DEVICE_SETTING_ID_BLUETOOTH_PROFILES,
+ highlighted = false, preferenceKey = "bluetooth_profiles"),
),
listOf(),
null))
@@ -212,7 +183,7 @@
runCurrent()
assertThat(getDisplayedPreferences().mapNotNull { it.key })
- .containsExactly("bluetooth_device_header", "keyboard_settings")
+ .containsExactly("bluetooth_device_header", "bluetooth_profiles")
verify(featureFactory.metricsFeatureProvider)
.action(
SettingsEnums.PAGE_UNKNOWN,
@@ -224,7 +195,7 @@
SettingsEnums.PAGE_UNKNOWN,
SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_ITEM_SHOWN,
0,
- "keyboard_settings", 1)
+ "bluetooth_profiles", 1)
}
}
@@ -242,9 +213,9 @@
DeviceSettingConfigItemModel.AppProvidedItem(
DeviceSettingId.DEVICE_SETTING_ID_ANC, highlighted = false),
DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem(
- DeviceSettingId.DEVICE_SETTING_ID_KEYBOARD_SETTINGS,
+ DeviceSettingId.DEVICE_SETTING_ID_BLUETOOTH_PROFILES,
highlighted = false,
- preferenceKey = "keyboard_settings"),
+ preferenceKey = "bluetooth_profiles"),
),
listOf(),
null))
@@ -273,7 +244,7 @@
.containsExactly(
"bluetooth_device_header",
"DEVICE_SETTING_${DeviceSettingId.DEVICE_SETTING_ID_ANC}",
- "keyboard_settings")
+ "bluetooth_profiles")
verify(featureFactory.metricsFeatureProvider)
.action(
SettingsEnums.PAGE_UNKNOWN,
diff --git a/tests/robotests/src/com/android/settings/notification/PhoneRingtonePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/PhoneRingtonePreferenceControllerTest.java
index 24e8458..9e49653 100644
--- a/tests/robotests/src/com/android/settings/notification/PhoneRingtonePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/PhoneRingtonePreferenceControllerTest.java
@@ -21,17 +21,22 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.res.Resources;
import android.media.RingtoneManager;
+import android.media.audio.Flags;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.telephony.TelephonyManager;
+
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;
@RunWith(RobolectricTestRunner.class)
public class PhoneRingtonePreferenceControllerTest {
@@ -39,33 +44,60 @@
@Mock
private TelephonyManager mTelephonyManager;
- private Context mContext;
+ @Mock
+ private Context mMockContext;
+
+ @Mock
+ private Resources mMockResources;
+
private PhoneRingtonePreferenceController mController;
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- ShadowApplication shadowContext = ShadowApplication.getInstance();
- shadowContext.setSystemService(Context.TELEPHONY_SERVICE, mTelephonyManager);
- mContext = RuntimeEnvironment.application;
- mController = new PhoneRingtonePreferenceController(mContext);
+ when(mMockContext.getResources()).thenReturn(mMockResources);
+ when(mMockContext.getSystemService(
+ Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager);
+ mController = new PhoneRingtonePreferenceController(mMockContext);
}
@Test
+ @DisableFlags(Flags.FLAG_ENABLE_RINGTONE_HAPTICS_CUSTOMIZATION)
public void isAvailable_notVoiceCapable_shouldReturnFalse() {
+ when(mMockResources
+ .getBoolean(com.android.internal.R.bool.config_ringtoneVibrationSettingsSupported))
+ .thenReturn(false);
when(mTelephonyManager.isVoiceCapable()).thenReturn(false);
assertThat(mController.isAvailable()).isFalse();
}
@Test
+ @DisableFlags(Flags.FLAG_ENABLE_RINGTONE_HAPTICS_CUSTOMIZATION)
public void isAvailable_VoiceCapable_shouldReturnTrue() {
+ when(mMockResources
+ .getBoolean(com.android.internal.R.bool.config_ringtoneVibrationSettingsSupported))
+ .thenReturn(false);
when(mTelephonyManager.isVoiceCapable()).thenReturn(true);
assertThat(mController.isAvailable()).isTrue();
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_RINGTONE_HAPTICS_CUSTOMIZATION)
+ public void isAvailable_vibrationSupported_shouldReturnFalse() {
+ when(mMockResources
+ .getBoolean(com.android.internal.R.bool.config_ringtoneVibrationSettingsSupported))
+ .thenReturn(true);
+ when(mTelephonyManager.isVoiceCapable()).thenReturn(true);
+
+ assertThat(mController.isAvailable()).isFalse();
+ }
+
+ @Test
public void getRingtoneType_shouldReturnRingtone() {
assertThat(mController.getRingtoneType()).isEqualTo(RingtoneManager.TYPE_RINGTONE);
}
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.kt
index f821e1a..641866d 100644
--- a/tests/spa_unit/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.kt
@@ -18,10 +18,12 @@
import android.content.Context
import android.content.Intent
+import android.platform.test.annotations.EnableFlags
import android.provider.Settings
import android.telephony.CarrierConfigManager
import android.telephony.ServiceState
import android.telephony.TelephonyManager
+import android.telephony.satellite.SatelliteManager
import androidx.compose.ui.test.assertIsEnabled
import androidx.compose.ui.test.assertIsNotEnabled
import androidx.compose.ui.test.assertIsOff
@@ -36,6 +38,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R
import com.android.settings.Settings.NetworkSelectActivity
+import com.android.settings.flags.Flags
import com.android.settings.spa.preference.ComposePreference
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.delay
@@ -46,6 +49,8 @@
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mockito.`when`
+import org.mockito.junit.MockitoJUnit
import org.mockito.kotlin.any
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.doNothing
@@ -58,6 +63,9 @@
@RunWith(AndroidJUnit4::class)
class AutoSelectPreferenceControllerTest {
@get:Rule
+ val mockito = MockitoJUnit.rule()
+
+ @get:Rule
val composeTestRule = createComposeRule()
private val mockTelephonyManager = mock<TelephonyManager> {
@@ -65,8 +73,12 @@
on { simOperatorName } doReturn OPERATOR_NAME
}
+ private val mockSatelliteManager = mock<SatelliteManager> {
+ }
+
private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
+ on { getSystemService(SatelliteManager::class.java) } doReturn mockSatelliteManager
doNothing().whenever(mock).startActivity(any())
}
@@ -115,7 +127,6 @@
.assertIsOff()
}
-
@Test
fun isEnabled_isRoaming_enabled() {
serviceState.roaming = true
@@ -159,6 +170,54 @@
}
@Test
+ @EnableFlags(Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION)
+ fun isEnabled_isSatelliteSessionStartedAndSelectedSubForSatellite_disabled() {
+ controller.selectedNbIotSatelliteSubscriptionCallback
+ .onSelectedNbIotSatelliteSubscriptionChanged(SUB_ID)
+ controller.satelliteModemStateCallback
+ .onSatelliteModemStateChanged(SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED)
+
+ composeTestRule.setContent {
+ controller.Content()
+ }
+
+ composeTestRule.onNodeWithText(context.getString(R.string.select_automatically))
+ .assertIsNotEnabled()
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION)
+ fun isEnabled_isSatelliteSessionNotStartedButIsSelectedSubForSatellite_enabled() {
+ controller.selectedNbIotSatelliteSubscriptionCallback
+ .onSelectedNbIotSatelliteSubscriptionChanged(SUB_ID)
+ controller.satelliteModemStateCallback
+ .onSatelliteModemStateChanged(SatelliteManager.SATELLITE_MODEM_STATE_OFF)
+
+ composeTestRule.setContent {
+ controller.Content()
+ }
+
+ composeTestRule.onNodeWithText(context.getString(R.string.select_automatically))
+ .assertIsEnabled()
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION)
+ fun isEnabled_isSatelliteSessionStartedButNotSelectedSubForSatellite_enabled() {
+ controller.selectedNbIotSatelliteSubscriptionCallback
+ .onSelectedNbIotSatelliteSubscriptionChanged(0)
+ controller.satelliteModemStateCallback
+ .onSatelliteModemStateChanged(SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED)
+
+ composeTestRule.setContent {
+ controller.Content()
+ }
+
+ composeTestRule.onNodeWithText(context.getString(R.string.select_automatically))
+ .assertIsEnabled()
+ }
+
+ @Test
fun onClick_turnOff_startNetworkSelectActivity() {
serviceState.isManualSelection = false
diff --git a/tests/unit/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragmentTest.java b/tests/unit/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragmentTest.java
index 6365226..93ba97b 100644
--- a/tests/unit/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragmentTest.java
+++ b/tests/unit/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragmentTest.java
@@ -71,6 +71,7 @@
private ExternalDisplayPreferenceFragment mFragment;
private int mPreferenceIdFromResource;
private int mDisplayIdArg = INVALID_DISPLAY;
+ private boolean mLaunchedBuiltinSettings;
private int mResolutionSelectorDisplayId = INVALID_DISPLAY;
@Mock
private MetricsLogger mMockedMetricsLogger;
@@ -106,6 +107,10 @@
pref = mPreferenceScreen.findPreference(DisplayTopologyKt.PREFERENCE_KEY);
assertThat(pref).isNull();
+
+ pref = mPreferenceScreen.findPreference(
+ ExternalDisplayPreferenceFragment.BUILTIN_DISPLAY_LIST_PREFERENCE_KEY);
+ assertThat(pref).isNull();
}
@Test
@@ -124,6 +129,11 @@
mPreferenceScreen.findPreference(DISPLAYS_LIST_PREFERENCE_KEY);
assertThat(listPref).isNotNull();
assertThat(listPref.getPreferenceCount()).isEqualTo(1);
+
+ listPref = mPreferenceScreen.findPreference(
+ ExternalDisplayPreferenceFragment.BUILTIN_DISPLAY_LIST_PREFERENCE_KEY);
+ assertThat(listPref).isNotNull();
+ assertThat(listPref.getPreferenceCount()).isEqualTo(1);
}
@Test
@@ -138,11 +148,18 @@
var pref = mPreferenceScreen.findPreference(DisplayTopologyKt.PREFERENCE_KEY);
assertThat(pref).isNotNull();
- // TODO: add the built-in display to the list, which will cause this preference to not be
- // null.
PreferenceCategory listPref =
mPreferenceScreen.findPreference(DISPLAYS_LIST_PREFERENCE_KEY);
assertThat(listPref).isNull();
+
+ listPref = mPreferenceScreen.findPreference(
+ ExternalDisplayPreferenceFragment.BUILTIN_DISPLAY_LIST_PREFERENCE_KEY);
+ assertThat(listPref).isNotNull();
+ assertThat(listPref.getPreferenceCount()).isEqualTo(1);
+ var builtinPref = listPref.getPreference(0);
+ assertThat(builtinPref.getOnPreferenceClickListener().onPreferenceClick(builtinPref))
+ .isTrue();
+ assertThat(mLaunchedBuiltinSettings).isTrue();
}
@Test
@@ -428,11 +445,16 @@
}
@Override
- protected void launchDisplaySettings(final int displayId) {
+ protected void launchExternalDisplaySettings(final int displayId) {
mDisplayIdArg = displayId;
}
@Override
+ protected void launchBuiltinDisplaySettings() {
+ mLaunchedBuiltinSettings = true;
+ }
+
+ @Override
protected void writePreferenceClickMetric(Preference preference) {
mLogger.writePreferenceClickMetric(preference);
}
diff --git a/tests/unit/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java
index 54b78c7..95ae1d1 100644
--- a/tests/unit/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java
@@ -16,6 +16,9 @@
package com.android.settings.network.telephony;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_OFF;
+
import static androidx.lifecycle.Lifecycle.Event.ON_START;
import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.CDMA;
@@ -29,12 +32,15 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.PersistableBundle;
+import android.platform.test.annotations.EnableFlags;
import android.telephony.CarrierConfigManager;
import android.telephony.RadioAccessFamily;
import android.telephony.ServiceState;
@@ -51,6 +57,7 @@
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.android.settings.flags.Flags;
import com.android.settings.network.CarrierConfigCache;
import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -296,6 +303,48 @@
@UiThreadTest
@Test
+ @EnableFlags(Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION)
+ public void updateState_satelliteIsStartedAndSelectedSubForSatellite_disablePreference() {
+ mController.mSatelliteModemStateCallback
+ .onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_CONNECTED);
+ mController.mSelectedNbIotSatelliteSubscriptionCallback
+ .onSelectedNbIotSatelliteSubscriptionChanged(SUB_ID);
+
+ mController.updateState(mPreference);
+
+ assertFalse(mPreference.isEnabled());
+ }
+
+ @UiThreadTest
+ @Test
+ @EnableFlags(Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION)
+ public void updateState_satelliteIsIdle_enablePreference() {
+ mController.mSatelliteModemStateCallback
+ .onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_OFF);
+ mController.mSelectedNbIotSatelliteSubscriptionCallback
+ .onSelectedNbIotSatelliteSubscriptionChanged(SUB_ID);
+
+ mController.updateState(mPreference);
+
+ assertTrue(mPreference.isEnabled());
+ }
+
+ @UiThreadTest
+ @Test
+ @EnableFlags(Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION)
+ public void updateState_notSelectedSubForSatellite_enablePreference() {
+ mController.mSatelliteModemStateCallback
+ .onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_CONNECTED);
+ mController.mSelectedNbIotSatelliteSubscriptionCallback
+ .onSelectedNbIotSatelliteSubscriptionChanged(0);
+
+ mController.updateState(mPreference);
+
+ assertTrue(mPreference.isEnabled());
+ }
+
+ @UiThreadTest
+ @Test
public void onPreferenceChange_updateSuccess() {
mockEnabledNetworkMode(TelephonyManager.NETWORK_MODE_LTE_GSM_WCDMA);
doReturn(true).when(mTelephonyManager).setPreferredNetworkTypeBitmask(
diff --git a/tests/unit/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceControllerTest.java
index d397291..e0a5c18 100644
--- a/tests/unit/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceControllerTest.java
@@ -16,12 +16,17 @@
package com.android.settings.network.telephony;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_OFF;
+
import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.GSM;
import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.RAF_TD_SCDMA;
import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.WCDMA;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
@@ -30,15 +35,18 @@
import android.content.Context;
import android.os.PersistableBundle;
+import android.platform.test.annotations.EnableFlags;
import android.telephony.RadioAccessFamily;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import androidx.preference.ListPreference;
+import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.android.settings.flags.Flags;
import com.android.settings.network.CarrierConfigCache;
import com.android.settings.testutils.ResourcesUtils;
@@ -105,6 +113,48 @@
}
@Test
+ @UiThreadTest
+ @EnableFlags(Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION)
+ public void updateState_satelliteIsStartedAndSelectedSubForSatellite_disablePreference() {
+ mController.mSatelliteModemStateCallback
+ .onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_CONNECTED);
+ mController.mSelectedNbIotSatelliteSubscriptionCallback
+ .onSelectedNbIotSatelliteSubscriptionChanged(SUB_ID);
+
+ mController.updateState(mPreference);
+
+ assertFalse(mPreference.isEnabled());
+ }
+
+ @Test
+ @UiThreadTest
+ @EnableFlags(Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION)
+ public void updateState_satelliteIsIdle_enablePreference() {
+ mController.mSatelliteModemStateCallback
+ .onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_OFF);
+ mController.mSelectedNbIotSatelliteSubscriptionCallback
+ .onSelectedNbIotSatelliteSubscriptionChanged(SUB_ID);
+
+ mController.updateState(mPreference);
+
+ assertTrue(mPreference.isEnabled());
+ }
+
+ @Test
+ @UiThreadTest
+ @EnableFlags(Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION)
+ public void updateState_notSelectedSubForSatellite_enablePreference() {
+ mController.mSatelliteModemStateCallback
+ .onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_CONNECTED);
+ mController.mSelectedNbIotSatelliteSubscriptionCallback
+ .onSelectedNbIotSatelliteSubscriptionChanged(0);
+
+ mController.updateState(mPreference);
+
+ assertTrue(mPreference.isEnabled());
+ }
+
+ @Test
public void onPreferenceChange_updateNetworkMode() {
mController.onPreferenceChange(mPreference,
String.valueOf(TelephonyManager.NETWORK_MODE_LTE_TDSCDMA));
diff --git a/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryControllerTest.java
index 52c3179..299ea13 100644
--- a/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryControllerTest.java
+++ b/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryControllerTest.java
@@ -45,8 +45,6 @@
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
-import java.util.List;
-
@RunWith(AndroidJUnit4.class)
public class SatelliteSettingsPreferenceCategoryControllerTest {
private static final String KEY = "key";
@@ -113,10 +111,10 @@
mController.displayPreference(preferenceScreen);
mController.mCarrierRoamingNtnModeCallback.onCarrierRoamingNtnAvailableServicesChanged(
- List.of(SERVICE_TYPE_DATA));
+ new int[]{SERVICE_TYPE_DATA});
assertThat(preferenceCategory.getTitle()).isEqualTo(
- mContext.getString(R.string.satellite_setting_connectivity));
+ mContext.getString(R.string.title_satellite_setting_connectivity));
}
@@ -131,7 +129,7 @@
mController.displayPreference(preferenceScreen);
mController.mCarrierRoamingNtnModeCallback.onCarrierRoamingNtnAvailableServicesChanged(
- List.of(SERVICE_TYPE_SMS));
+ new int[]{SERVICE_TYPE_SMS});
assertThat(preferenceCategory.getTitle()).isEqualTo(
mContext.getString(R.string.satellite_setting_title));
diff --git a/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceControllerTest.java
new file mode 100644
index 0000000..6aa48e3
--- /dev/null
+++ b/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceControllerTest.java
@@ -0,0 +1,177 @@
+/*
+ * 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 static android.telephony.NetworkRegistrationInfo.SERVICE_TYPE_DATA;
+import static android.telephony.NetworkRegistrationInfo.SERVICE_TYPE_SMS;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
+import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
+
+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.content.Context;
+import android.os.Looper;
+import android.os.PersistableBundle;
+import android.platform.test.annotations.EnableFlags;
+import android.telephony.CarrierConfigManager;
+import android.telephony.TelephonyManager;
+import android.telephony.satellite.SatelliteManager;
+
+import androidx.preference.Preference;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.internal.telephony.flags.Flags;
+import com.android.settings.R;
+import com.android.settings.network.CarrierConfigCache;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(AndroidJUnit4.class)
+public class SatelliteSettingsPreferenceControllerTest {
+ private static final String KEY = "key";
+ private static final int TEST_SUB_ID = 0;
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+ @Mock
+ private CarrierConfigCache mCarrierConfigCache;
+ @Mock
+ private TelephonyManager mTelephonyManager;
+
+ private Context mContext = null;
+ private SatelliteManager mSatelliteManager;
+ private SatelliteSettingPreferenceController mController = null;
+ private PersistableBundle mCarrierConfig = new PersistableBundle();
+
+ @Before
+ public void setUp() {
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mSatelliteManager = new SatelliteManager(mContext);
+ CarrierConfigCache.setTestInstance(mContext, mCarrierConfigCache);
+ when(mContext.getSystemService(SatelliteManager.class)).thenReturn(mSatelliteManager);
+ when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
+ when(mTelephonyManager.createForSubscriptionId(TEST_SUB_ID)).thenReturn(mTelephonyManager);
+ mController = spy(new SatelliteSettingPreferenceController(mContext, KEY));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
+ public void getAvailabilityStatus_noSatellite_returnUnsupport() {
+ when(mContext.getSystemService(SatelliteManager.class)).thenReturn(null);
+ mController = new SatelliteSettingPreferenceController(mContext, KEY);
+
+ int result = mController.getAvailabilityStatus(TEST_SUB_ID);
+
+ assertThat(result).isEqualTo(UNSUPPORTED_ON_DEVICE);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
+ public void getAvailabilityStatus_carrierIsNotSupport_returnUnavailable() {
+ when(mContext.getSystemService(SatelliteManager.class)).thenReturn(null);
+ mCarrierConfig.putBoolean(
+ CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL,
+ false);
+ when(mCarrierConfigCache.getConfigForSubId(TEST_SUB_ID)).thenReturn(mCarrierConfig);
+
+ int result = mController.getAvailabilityStatus(TEST_SUB_ID);
+
+ assertThat(result).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
+ public void getAvailabilityStatus_carrierIsSupport_returnAvailable() {
+ when(mContext.getSystemService(SatelliteManager.class)).thenReturn(null);
+ mCarrierConfig.putBoolean(
+ CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL,
+ true);
+ when(mCarrierConfigCache.getConfigForSubId(TEST_SUB_ID)).thenReturn(mCarrierConfig);
+
+ int result = mController.getAvailabilityStatus(TEST_SUB_ID);
+
+ assertThat(result).isEqualTo(AVAILABLE);
+ }
+
+ @Test
+ @EnableFlags(com.android.settings.flags.Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION)
+ public void getAvailabilityStatus_registerTelephonyCallback_success() {
+ mController.init(TEST_SUB_ID);
+ mController.onResume(null);
+
+ verify(mTelephonyManager).registerTelephonyCallback(any(), any());
+ }
+
+ @Test
+ @EnableFlags(com.android.settings.flags.Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION)
+ public void getAvailabilityStatus_unregisterTelephonyCallback_success() {
+ mController.init(TEST_SUB_ID);
+ mController.onPause(null);
+
+ verify(mTelephonyManager).unregisterTelephonyCallback(any());
+ }
+
+ @Test
+ @EnableFlags(com.android.settings.flags.Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION)
+ public void getAvailabilityStatus_hasServiceDataType_showDataUi() {
+ mController.init(TEST_SUB_ID);
+ Preference preference = new Preference(mContext);
+ preference.setKey(KEY);
+ preference.setTitle("test title");
+ mController.updateState(preference);
+
+ mController.mCarrierRoamingNtnModeCallback.onCarrierRoamingNtnAvailableServicesChanged(
+ new int[]{SERVICE_TYPE_SMS, SERVICE_TYPE_DATA});
+
+ assertThat(preference.getTitle()).isEqualTo(
+ mContext.getString(R.string.title_satellite_setting_connectivity));
+ }
+
+ @Test
+ @EnableFlags(com.android.settings.flags.Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION)
+ public void getAvailabilityStatus_onlyHasServiceSmsType_showSmsUi() {
+ mController.init(TEST_SUB_ID);
+ Preference preference = new Preference(mContext);
+ preference.setKey(KEY);
+ preference.setTitle("test title");
+ mController.updateState(preference);
+
+ mController.mCarrierRoamingNtnModeCallback.onCarrierRoamingNtnAvailableServicesChanged(
+ new int[]{SERVICE_TYPE_SMS});
+
+ assertThat(preference.getTitle()).isEqualTo(
+ mContext.getString(R.string.satellite_setting_title));
+ }
+}
diff --git a/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsSosPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsSosPreferenceControllerTest.java
new file mode 100644
index 0000000..5c78a14
--- /dev/null
+++ b/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsSosPreferenceControllerTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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 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.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Looper;
+import android.os.PersistableBundle;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.telephony.CarrierConfigManager;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.internal.telephony.flags.Flags;
+import com.android.settings.network.CarrierConfigCache;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+@RunWith(AndroidJUnit4.class)
+public class SatelliteSettingsSosPreferenceControllerTest {
+ private static final String KEY = "key";
+ private static final int TEST_SUB_ID = 0;
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+
+ @Mock
+ private CarrierConfigCache mCarrierConfigCache;
+
+ private Context mContext = null;
+ private SatelliteSettingSosPreferenceController mController = null;
+ private PersistableBundle mCarrierConfig = new PersistableBundle();
+
+ @Before
+ public void setUp() {
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mController = new SatelliteSettingSosPreferenceController(mContext, KEY);
+ CarrierConfigCache.setTestInstance(mContext, mCarrierConfigCache);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
+ public void getAvailabilityStatus_carrierNotSupport_returnUnAvailable() {
+ mCarrierConfig.putBoolean(
+ CarrierConfigManager.KEY_SATELLITE_ESOS_SUPPORTED_BOOL,
+ false);
+ when(mCarrierConfigCache.getConfigForSubId(TEST_SUB_ID)).thenReturn(mCarrierConfig);
+ mController.init(TEST_SUB_ID);
+
+ int result = mController.getAvailabilityStatus(TEST_SUB_ID);
+
+ assertThat(result).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+ }
+
+ @Ignore("Avoid post submit test failed.")
+ @Test
+ @EnableFlags(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
+ public void getAvailabilityStatus_carrierSupported_returnAvailable() {
+ mCarrierConfig.putBoolean(
+ CarrierConfigManager.KEY_SATELLITE_ESOS_SUPPORTED_BOOL,
+ true);
+ when(mCarrierConfigCache.getConfigForSubId(TEST_SUB_ID)).thenReturn(mCarrierConfig);
+ mController.init(TEST_SUB_ID);
+
+ int result = mController.getAvailabilityStatus(TEST_SUB_ID);
+
+ assertThat(result).isEqualTo(AVAILABLE);
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG)
+ public void getAvailabilityStatus_featureDisabled_returnAvailable() {
+ int result = mController.getAvailabilityStatus(TEST_SUB_ID);
+
+ assertThat(result).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+ }
+}