Merge "Add loading screen for Device details fragment to avoid ANR" 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 05b3b3f..ea505da 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -12287,7 +12287,7 @@
     <!-- 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 <xliff:g id="subject" example="satellite messaging">%1$s</xliff:g></string>
     <!-- Summary for category "About satellite messaging" [CHAR_LIMIT=NONE] -->
@@ -12328,6 +12328,12 @@
     <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>
 
 
 
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/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/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/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/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/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/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/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/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/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/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);
+    }
+}