Merge "Add illustrations to fold lock setting" into main
diff --git a/aconfig/settings_connecteddevice_flag_declarations.aconfig b/aconfig/settings_connecteddevice_flag_declarations.aconfig
index db42fff..eda2de6 100644
--- a/aconfig/settings_connecteddevice_flag_declarations.aconfig
+++ b/aconfig/settings_connecteddevice_flag_declarations.aconfig
@@ -4,5 +4,5 @@
   name: "enable_subsequent_pair_settings_integration"
   namespace: "pixel_cross_device_control"
   description: "Gates whether to enable subsequent pair Settings integration."
-  bug: "296507968"
+  bug: "299405720"
 }
diff --git a/res/xml/apps.xml b/res/xml/apps.xml
index db46a1a..90c40a6 100644
--- a/res/xml/apps.xml
+++ b/res/xml/apps.xml
@@ -116,7 +116,7 @@
 
     <Preference
         android:key="aspect_ratio_apps"
-        android:title="@string/aspect_ratio_title"
+        android:title="@string/aspect_ratio_experimental_title"
         android:summary="@string/summary_placeholder"
         android:order="22"
         settings:controller="com.android.settings.applications.appcompat.UserAspectRatioAppsPreferenceController"
diff --git a/res/xml/user_aspect_ratio_details.xml b/res/xml/user_aspect_ratio_details.xml
index ec76caa..f95b678 100644
--- a/res/xml/user_aspect_ratio_details.xml
+++ b/res/xml/user_aspect_ratio_details.xml
@@ -19,7 +19,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:settings="http://schemas.android.com/apk/res-auto"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:title="@string/aspect_ratio_title">
+    android:title="@string/aspect_ratio_experimental_title">
 
     <com.android.settingslib.widget.ActionButtonsPreference
         android:key="header_view" />
diff --git a/src/com/android/settings/connecteddevice/fastpair/FastPairDevicePreferenceController.java b/src/com/android/settings/connecteddevice/fastpair/FastPairDevicePreferenceController.java
index 47b2dae..6a5b6b9 100644
--- a/src/com/android/settings/connecteddevice/fastpair/FastPairDevicePreferenceController.java
+++ b/src/com/android/settings/connecteddevice/fastpair/FastPairDevicePreferenceController.java
@@ -142,7 +142,7 @@
         // The insertion point is defined as the point at which the key would be inserted into the
         // list: the index of the first element greater than the key, or list.size() if all elements
         // in the list are less than the specified key.
-        if (idx > 0) {
+        if (idx >= 0) {
             if (DEBUG) {
                 Log.d(TAG, "onDeviceAdd receives duplicate preference. Ignore.");
             }
diff --git a/src/com/android/settings/datausage/BillingCyclePreference.java b/src/com/android/settings/datausage/BillingCyclePreference.java
deleted file mode 100644
index 1bd2be8..0000000
--- a/src/com/android/settings/datausage/BillingCyclePreference.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2016 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.datausage;
-
-import android.app.settings.SettingsEnums;
-import android.content.Context;
-import android.content.Intent;
-import android.net.NetworkTemplate;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.telephony.TelephonyManager;
-import android.telephony.data.ApnSetting;
-import android.util.AttributeSet;
-
-import androidx.preference.Preference;
-
-import com.android.settings.R;
-import com.android.settings.core.SubSettingLauncher;
-import com.android.settings.network.MobileDataEnabledListener;
-
-/**
- * Preference which displays billing cycle of subscription
- */
-public class BillingCyclePreference extends Preference
-        implements TemplatePreference, MobileDataEnabledListener.Client {
-
-    private NetworkTemplate mTemplate;
-    private NetworkServices mServices;
-    private int mSubId;
-    private MobileDataEnabledListener mListener;
-
-    /**
-     * Preference constructor
-     *
-     * @param context Context of preference
-     * @param arrts The attributes of the XML tag that is inflating the preference
-     */
-    public BillingCyclePreference(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mListener = new MobileDataEnabledListener(context, this);
-    }
-
-    @Override
-    public void onAttached() {
-        super.onAttached();
-        mListener.start(mSubId);
-    }
-
-    @Override
-    public void onDetached() {
-        mListener.stop();
-        super.onDetached();
-    }
-
-    @Override
-    public void setTemplate(NetworkTemplate template, int subId,
-            NetworkServices services) {
-        mTemplate = template;
-        mSubId = subId;
-        mServices = services;
-        setSummary(null);
-
-        setIntent(getIntent());
-    }
-
-    private void updateEnabled() {
-        try {
-            setEnabled(mServices.mNetworkService.isBandwidthControlEnabled()
-                    && mServices.mTelephonyManager.createForSubscriptionId(mSubId)
-                            .isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
-                    && mServices.mUserManager.isAdminUser());
-        } catch (RemoteException e) {
-            setEnabled(false);
-        }
-    }
-
-    @Override
-    public Intent getIntent() {
-        final Bundle args = new Bundle();
-        args.putParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE, mTemplate);
-        return new SubSettingLauncher(getContext())
-                .setDestination(BillingCycleSettings.class.getName())
-                .setArguments(args)
-                .setTitleRes(R.string.billing_cycle)
-                .setSourceMetricsCategory(SettingsEnums.PAGE_UNKNOWN)
-                .toIntent();
-    }
-
-    /**
-     * Implementation of {@code MobileDataEnabledListener.Client}
-     */
-    public void onMobileDataEnabledChange() {
-        updateEnabled();
-    }
-}
diff --git a/src/com/android/settings/datausage/BillingCyclePreference.kt b/src/com/android/settings/datausage/BillingCyclePreference.kt
new file mode 100644
index 0000000..05066be
--- /dev/null
+++ b/src/com/android/settings/datausage/BillingCyclePreference.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.settings.datausage
+
+import android.app.settings.SettingsEnums
+import android.content.Context
+import android.content.Intent
+import android.net.NetworkTemplate
+import android.os.Bundle
+import android.util.AttributeSet
+import androidx.preference.Preference
+import com.android.settings.R
+import com.android.settings.core.SubSettingLauncher
+import com.android.settings.datausage.lib.BillingCycleRepository
+import com.android.settings.network.MobileDataEnabledListener
+
+/**
+ * Preference which displays billing cycle of subscription
+ *
+ * @param context Context of preference
+ * @param attrs   The attributes of the XML tag that is inflating the preference
+ */
+class BillingCyclePreference @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet?,
+    private val repository: BillingCycleRepository = BillingCycleRepository(context),
+) : Preference(context, attrs), TemplatePreference {
+    private lateinit var template: NetworkTemplate
+    private var subId = 0
+
+    private val listener = MobileDataEnabledListener(context) {
+        updateEnabled()
+    }
+
+    override fun setTemplate(template: NetworkTemplate, subId: Int) {
+        this.template = template
+        this.subId = subId
+        summary = null
+        updateEnabled()
+    }
+
+    override fun onAttached() {
+        super.onAttached()
+        listener.start(subId)
+    }
+
+    override fun onDetached() {
+        listener.stop()
+        super.onDetached()
+    }
+
+    private fun updateEnabled() {
+        isEnabled = repository.isModifiable(subId)
+    }
+
+    override fun getIntent(): Intent {
+        val args = Bundle().apply {
+            putParcelable(DataUsageList.EXTRA_NETWORK_TEMPLATE, template)
+        }
+        return SubSettingLauncher(context).apply {
+            setDestination(BillingCycleSettings::class.java.name)
+            setArguments(args)
+            setTitleRes(R.string.billing_cycle)
+            setSourceMetricsCategory(SettingsEnums.PAGE_UNKNOWN)
+        }.toIntent()
+    }
+}
diff --git a/src/com/android/settings/datausage/BillingCyclePreferenceController.java b/src/com/android/settings/datausage/BillingCyclePreferenceController.java
index 73216ab..8b55585 100644
--- a/src/com/android/settings/datausage/BillingCyclePreferenceController.java
+++ b/src/com/android/settings/datausage/BillingCyclePreferenceController.java
@@ -17,20 +17,12 @@
 package com.android.settings.datausage;
 
 import android.content.Context;
-import android.net.NetworkPolicyManager;
 import android.net.NetworkTemplate;
-import android.os.INetworkManagementService;
-import android.os.ServiceManager;
-import android.os.UserManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
 
 import androidx.preference.PreferenceScreen;
 
 import com.android.settings.core.BasePreferenceController;
-import com.android.settings.datausage.DataUsageUtils;
 import com.android.settings.datausage.lib.DataUsageLib;
-import com.android.settingslib.NetworkPolicyEditor;
 
 public class BillingCyclePreferenceController extends BasePreferenceController {
     private int mSubscriptionId;
@@ -48,18 +40,9 @@
         super.displayPreference(screen);
         BillingCyclePreference preference = screen.findPreference(getPreferenceKey());
 
-        TemplatePreference.NetworkServices services = new TemplatePreference.NetworkServices();
-        services.mNetworkService = INetworkManagementService.Stub.asInterface(
-                ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
-        services.mPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
-        services.mPolicyEditor = new NetworkPolicyEditor(services.mPolicyManager);
-        services.mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
-        services.mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
-        services.mUserManager = mContext.getSystemService(UserManager.class);
-
         NetworkTemplate template = DataUsageLib.getMobileTemplate(mContext, mSubscriptionId);
 
-        preference.setTemplate(template, mSubscriptionId, services);
+        preference.setTemplate(template, mSubscriptionId);
     }
 
     @Override
diff --git a/src/com/android/settings/datausage/CellDataPreference.java b/src/com/android/settings/datausage/CellDataPreference.java
index aa763ae..9374217 100644
--- a/src/com/android/settings/datausage/CellDataPreference.java
+++ b/src/com/android/settings/datausage/CellDataPreference.java
@@ -99,7 +99,7 @@
     }
 
     @Override
-    public void setTemplate(NetworkTemplate template, int subId, NetworkServices services) {
+    public void setTemplate(NetworkTemplate template, int subId) {
         if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
             throw new IllegalArgumentException("CellDataPreference needs a SubscriptionInfo");
         }
diff --git a/src/com/android/settings/datausage/DataUsagePreference.java b/src/com/android/settings/datausage/DataUsagePreference.java
index 0ed0ad3..0f7bf58 100644
--- a/src/com/android/settings/datausage/DataUsagePreference.java
+++ b/src/com/android/settings/datausage/DataUsagePreference.java
@@ -49,7 +49,7 @@
     }
 
     @Override
-    public void setTemplate(NetworkTemplate template, int subId, NetworkServices services) {
+    public void setTemplate(NetworkTemplate template, int subId) {
         mTemplate = template;
         mSubId = subId;
         final DataUsageController controller = getDataUsageController();
diff --git a/src/com/android/settings/datausage/DataUsageSummary.java b/src/com/android/settings/datausage/DataUsageSummary.java
index d176402..6966611 100644
--- a/src/com/android/settings/datausage/DataUsageSummary.java
+++ b/src/com/android/settings/datausage/DataUsageSummary.java
@@ -183,9 +183,8 @@
     private void addMobileSection(int subId, SubscriptionInfo subInfo) {
         TemplatePreferenceCategory category = (TemplatePreferenceCategory)
                 inflatePreferences(R.xml.data_usage_cellular);
-        category.setTemplate(DataUsageLib.getMobileTemplate(getContext(), subId),
-                subId, services);
-        category.pushTemplates(services);
+        category.setTemplate(DataUsageLib.getMobileTemplate(getContext(), subId), subId);
+        category.pushTemplates();
         final CharSequence displayName = SubscriptionUtil.getUniqueSubscriptionDisplayName(
                 subInfo, getContext());
         if (subInfo != null && !TextUtils.isEmpty(displayName)) {
@@ -198,15 +197,14 @@
     void addWifiSection() {
         TemplatePreferenceCategory category = (TemplatePreferenceCategory)
                 inflatePreferences(R.xml.data_usage_wifi);
-        category.setTemplate(new NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI).build(),
-                0, services);
+        category.setTemplate(new NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI).build(), 0);
     }
 
     private void addEthernetSection() {
         TemplatePreferenceCategory category = (TemplatePreferenceCategory)
                 inflatePreferences(R.xml.data_usage_ethernet);
-        category.setTemplate(new NetworkTemplate.Builder(NetworkTemplate.MATCH_ETHERNET).build(),
-                0, services);
+        category.setTemplate(
+                new NetworkTemplate.Builder(NetworkTemplate.MATCH_ETHERNET).build(), 0);
     }
 
     private Preference inflatePreferences(int resId) {
@@ -259,10 +257,10 @@
     private void updateState() {
         PreferenceScreen screen = getPreferenceScreen();
         for (int i = 1; i < screen.getPreferenceCount(); i++) {
-          Preference currentPreference = screen.getPreference(i);
-          if (currentPreference instanceof TemplatePreferenceCategory) {
-            ((TemplatePreferenceCategory) currentPreference).pushTemplates(services);
-          }
+            Preference currentPreference = screen.getPreference(i);
+            if (currentPreference instanceof TemplatePreferenceCategory) {
+                ((TemplatePreferenceCategory) currentPreference).pushTemplates();
+            }
         }
     }
 
diff --git a/src/com/android/settings/datausage/NetworkRestrictionsPreference.java b/src/com/android/settings/datausage/NetworkRestrictionsPreference.java
deleted file mode 100644
index 9afc0c3..0000000
--- a/src/com/android/settings/datausage/NetworkRestrictionsPreference.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2016 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.datausage;
-
-import android.content.Context;
-import android.net.NetworkTemplate;
-import android.util.AttributeSet;
-
-import androidx.preference.Preference;
-
-public class NetworkRestrictionsPreference extends Preference implements TemplatePreference {
-
-    public NetworkRestrictionsPreference(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    @Override
-    public void setTemplate(NetworkTemplate template, int subId,
-            NetworkServices services) {
-        // TODO: Summary
-    }
-}
diff --git a/src/com/android/settings/datausage/TemplatePreference.java b/src/com/android/settings/datausage/TemplatePreference.java
index 43dda0a..6182229 100644
--- a/src/com/android/settings/datausage/TemplatePreference.java
+++ b/src/com/android/settings/datausage/TemplatePreference.java
@@ -25,7 +25,8 @@
 
 public interface TemplatePreference {
 
-    void setTemplate(NetworkTemplate template, int subId, NetworkServices services);
+    /** Sets the network template. */
+    void setTemplate(NetworkTemplate template, int subId);
 
     class NetworkServices {
         INetworkManagementService mNetworkService;
diff --git a/src/com/android/settings/datausage/TemplatePreferenceCategory.java b/src/com/android/settings/datausage/TemplatePreferenceCategory.java
index d26b9b1..9173676 100644
--- a/src/com/android/settings/datausage/TemplatePreferenceCategory.java
+++ b/src/com/android/settings/datausage/TemplatePreferenceCategory.java
@@ -31,8 +31,7 @@
     }
 
     @Override
-    public void setTemplate(NetworkTemplate template, int subId,
-            NetworkServices services) {
+    public void setTemplate(NetworkTemplate template, int subId) {
         mTemplate = template;
         mSubId = subId;
     }
@@ -46,12 +45,13 @@
         return super.addPreference(preference);
     }
 
-    public void pushTemplates(NetworkServices services) {
+    /** Pushes the templates. */
+    public void pushTemplates() {
         if (mTemplate == null) {
             throw new RuntimeException("null mTemplate for " + getKey());
         }
         for (int i = 0; i < getPreferenceCount(); i++) {
-            ((TemplatePreference) getPreference(i)).setTemplate(mTemplate, mSubId, services);
+            ((TemplatePreference) getPreference(i)).setTemplate(mTemplate, mSubId);
         }
     }
 
diff --git a/src/com/android/settings/datausage/lib/BillingCycleRepository.kt b/src/com/android/settings/datausage/lib/BillingCycleRepository.kt
new file mode 100644
index 0000000..779ae4a
--- /dev/null
+++ b/src/com/android/settings/datausage/lib/BillingCycleRepository.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.datausage.lib
+
+import android.content.Context
+import android.os.INetworkManagementService
+import android.os.ServiceManager
+import android.telephony.TelephonyManager
+import android.util.Log
+import com.android.settingslib.spaprivileged.framework.common.userManager
+
+class BillingCycleRepository(
+    context: Context,
+    private val networkService: INetworkManagementService =
+        INetworkManagementService.Stub.asInterface(
+            ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)
+        ),
+) {
+    private val userManager = context.userManager
+    private val telephonyManager = context.getSystemService(TelephonyManager::class.java)!!
+
+    fun isModifiable(subId: Int): Boolean =
+        isBandwidthControlEnabled() && userManager.isAdminUser && isDataEnabled(subId)
+
+    fun isBandwidthControlEnabled(): Boolean = try {
+        networkService.isBandwidthControlEnabled
+    } catch (e: Exception) {
+        Log.w(TAG, "problem talking with INetworkManagementService: ", e)
+        false
+    }
+
+    private fun isDataEnabled(subId: Int): Boolean =
+        telephonyManager.createForSubscriptionId(subId)
+            .isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
+
+    companion object {
+        private const val TAG = "BillingCycleRepository"
+    }
+}
diff --git a/src/com/android/settings/network/NetworkProviderSettings.java b/src/com/android/settings/network/NetworkProviderSettings.java
index ee398a4..f2688c6 100644
--- a/src/com/android/settings/network/NetworkProviderSettings.java
+++ b/src/com/android/settings/network/NetworkProviderSettings.java
@@ -329,7 +329,7 @@
         mDataUsagePreference = findPreference(PREF_KEY_DATA_USAGE);
         mDataUsagePreference.setVisible(DataUsageUtils.hasWifiRadio(getContext()));
         mDataUsagePreference.setTemplate(new NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI)
-                        .build(), 0 /*subId*/, null /*service*/);
+                        .build(), 0 /*subId*/);
         mResetInternetPreference = findPreference(PREF_KEY_RESET_INTERNET);
         if (mResetInternetPreference != null) {
             mResetInternetPreference.setVisible(false);
diff --git a/src/com/android/settings/network/apn/ApnEditPageProvider.kt b/src/com/android/settings/network/apn/ApnEditPageProvider.kt
index 756d90f..90d96c6 100644
--- a/src/com/android/settings/network/apn/ApnEditPageProvider.kt
+++ b/src/com/android/settings/network/apn/ApnEditPageProvider.kt
@@ -148,13 +148,13 @@
                 stringResource(R.string.apn_mnc),
                 enabled = apnData.mncEnabled
             ) { apnData = apnData.copy(mnc = it) }
+            // Warning: apnProtocol, apnRoaming, mvnoType string2Int
             SettingsExposedDropdownMenuBox(
-                label = stringResource(R.string.apn_auth_type),
-                options = authTypeOptions,
-                selectedOptionText =
-                authTypeOptions.getOrElse(apnData.authType) { "" },
-                enabled = apnData.authTypeEnabled,
-            ) { apnData = apnData.copy(authType = authTypeOptions.indexOf(it)) }
+                stringResource(R.string.apn_auth_type),
+                authTypeOptions,
+                apnData.authType,
+                apnData.authTypeEnabled,
+            ) { apnData = apnData.copy(authType = it) }
             SettingsOutlinedTextField(
                 apnData.apnType,
                 stringResource(R.string.apn_type),
diff --git a/src/com/android/settings/network/apn/ApnStatus.kt b/src/com/android/settings/network/apn/ApnStatus.kt
index 8a2d613..7f4c297 100644
--- a/src/com/android/settings/network/apn/ApnStatus.kt
+++ b/src/com/android/settings/network/apn/ApnStatus.kt
@@ -34,11 +34,11 @@
     val mnc: String = "",
     val authType: Int = -1,
     val apnType: String = "",
-    val apnProtocol: String = "",
-    val apnRoaming: String = "",
+    val apnProtocol: Int = -1,
+    val apnRoaming: Int = -1,
     val apnEnable: Boolean = true,
     val bearer: Int = 0,
-    val mvnoType: String = "",
+    val mvnoType: Int = -1,
     var mvnoValue: String = "",
     val bearerBitmask: Int = 0,
     val edited: Int = Telephony.Carriers.USER_EDITED,
diff --git a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt
index 5206343..61098e8 100644
--- a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt
+++ b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt
@@ -41,7 +41,7 @@
     if (!presenter.isAvailableFlow.collectAsStateWithLifecycle(initialValue = false).value) return
 
     Preference(object : PreferenceModel {
-        override val title = stringResource(R.string.aspect_ratio_title)
+        override val title = stringResource(R.string.aspect_ratio_experimental_title)
         override val summary = presenter.summaryFlow.collectAsStateWithLifecycle(
             initialValue = stringResource(R.string.summary_placeholder),
         )
diff --git a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
index a15401c..e74f1e3 100644
--- a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
+++ b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
@@ -82,7 +82,7 @@
     @VisibleForTesting
     fun EntryItem() =
         Preference(object : PreferenceModel {
-            override val title = stringResource(R.string.aspect_ratio_title)
+            override val title = stringResource(R.string.aspect_ratio_experimental_title)
             override val summary = getSummary().toState()
             override val onClick = navigator(name)
         })
@@ -104,7 +104,7 @@
     = { AppList() },
 ) {
     AppListPage(
-        title = stringResource(R.string.aspect_ratio_title),
+        title = stringResource(R.string.aspect_ratio_experimental_title),
         listModel = rememberContext(::UserAspectRatioAppListModel),
         appList = appList,
         header = {
diff --git a/src/com/android/settings/system/SystemDashboardFragment.java b/src/com/android/settings/system/SystemDashboardFragment.java
index 79c5b9f..678b675 100644
--- a/src/com/android/settings/system/SystemDashboardFragment.java
+++ b/src/com/android/settings/system/SystemDashboardFragment.java
@@ -16,9 +16,7 @@
 package com.android.settings.system;
 
 import android.app.settings.SettingsEnums;
-import android.content.Context;
 import android.os.Bundle;
-import android.provider.SearchIndexableResource;
 
 import androidx.preference.Preference;
 import androidx.preference.PreferenceGroup;
@@ -29,9 +27,6 @@
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settingslib.search.SearchIndexable;
 
-import java.util.Arrays;
-import java.util.List;
-
 @SearchIndexable
 public class SystemDashboardFragment extends DashboardFragment {
 
@@ -85,13 +80,5 @@
      * For Search.
      */
     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
-            new BaseSearchIndexProvider() {
-                @Override
-                public List<SearchIndexableResource> getXmlResourcesToIndex(
-                        Context context, boolean enabled) {
-                    final SearchIndexableResource sir = new SearchIndexableResource(context);
-                    sir.xmlResId = R.xml.system_dashboard_fragment;
-                    return Arrays.asList(sir);
-                }
-            };
-}
\ No newline at end of file
+            new BaseSearchIndexProvider(R.xml.system_dashboard_fragment);
+}
diff --git a/src/com/android/settings/system/SystemUpdateManagerExt.kt b/src/com/android/settings/system/SystemUpdateManagerExt.kt
new file mode 100644
index 0000000..8ddf174
--- /dev/null
+++ b/src/com/android/settings/system/SystemUpdateManagerExt.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.system
+
+import android.content.Context
+import android.os.Bundle
+import android.os.SystemUpdateManager
+import android.util.Log
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+
+private const val TAG = "SystemUpdateManagerExt"
+
+/**
+ * Gets the system update status.
+ *
+ * Note: [SystemUpdateManager.retrieveSystemUpdateInfo] must be called on worker thread to avoid
+ * StrictMode violation.
+ */
+suspend fun Context.getSystemUpdateInfo(): Bundle? = withContext(Dispatchers.Default) {
+    val updateManager = getSystemService(SystemUpdateManager::class.java)!!
+    try {
+        updateManager.retrieveSystemUpdateInfo()
+    } catch (e: Exception) {
+        Log.w(TAG, "Error getting system update info.")
+        null
+    }
+}
diff --git a/src/com/android/settings/system/SystemUpdatePreferenceController.java b/src/com/android/settings/system/SystemUpdatePreferenceController.java
deleted file mode 100644
index b2a22ff..0000000
--- a/src/com/android/settings/system/SystemUpdatePreferenceController.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright (C) 2016 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.system;
-
-import static android.content.Context.CARRIER_CONFIG_SERVICE;
-import static android.content.Context.SYSTEM_UPDATE_SERVICE;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.PersistableBundle;
-import android.os.SystemUpdateManager;
-import android.os.UserManager;
-import android.telephony.CarrierConfigManager;
-import android.text.TextUtils;
-import android.util.Log;
-
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.R;
-import com.android.settings.Utils;
-import com.android.settings.core.BasePreferenceController;
-
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.FutureTask;
-
-public class SystemUpdatePreferenceController extends BasePreferenceController {
-
-    private static final String TAG = "SysUpdatePrefContr";
-
-    private static final String KEY_SYSTEM_UPDATE_SETTINGS = "system_update_settings";
-
-    private final UserManager mUm;
-    private final SystemUpdateManager mUpdateManager;
-
-    public SystemUpdatePreferenceController(Context context) {
-        super(context, KEY_SYSTEM_UPDATE_SETTINGS);
-        mUm = UserManager.get(context);
-        mUpdateManager = (SystemUpdateManager) context.getSystemService(SYSTEM_UPDATE_SERVICE);
-    }
-
-    @Override
-    public int getAvailabilityStatus() {
-        return mContext.getResources().getBoolean(R.bool.config_show_system_update_settings)
-                && mUm.isAdminUser()
-                ? AVAILABLE
-                : UNSUPPORTED_ON_DEVICE;
-    }
-
-    @Override
-    public void displayPreference(PreferenceScreen screen) {
-        super.displayPreference(screen);
-        if (isAvailable()) {
-            Utils.updatePreferenceToSpecificActivityOrRemove(mContext, screen,
-                    getPreferenceKey(),
-                    Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY);
-        }
-    }
-
-    @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        if (TextUtils.equals(getPreferenceKey(), preference.getKey())) {
-            CarrierConfigManager configManager =
-                    (CarrierConfigManager) mContext.getSystemService(CARRIER_CONFIG_SERVICE);
-            PersistableBundle b = configManager.getConfig();
-            if (b != null && b.getBoolean(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_BOOL)) {
-                ciActionOnSysUpdate(b);
-            }
-        }
-        // always return false here because this handler does not want to block other handlers.
-        return false;
-    }
-
-    @Override
-    public CharSequence getSummary() {
-        CharSequence summary = mContext.getString(R.string.android_version_summary,
-                Build.VERSION.RELEASE_OR_PREVIEW_DISPLAY);
-        final FutureTask<Bundle> bundleFutureTask = new FutureTask<>(
-                // Put the API call in a future to avoid StrictMode violation.
-                () -> mUpdateManager.retrieveSystemUpdateInfo());
-        final Bundle updateInfo;
-        try {
-            bundleFutureTask.run();
-            updateInfo = bundleFutureTask.get();
-        } catch (InterruptedException | ExecutionException e) {
-            Log.w(TAG, "Error getting system update info.");
-            return summary;
-        }
-        switch (updateInfo.getInt(SystemUpdateManager.KEY_STATUS)) {
-            case SystemUpdateManager.STATUS_WAITING_DOWNLOAD:
-            case SystemUpdateManager.STATUS_IN_PROGRESS:
-            case SystemUpdateManager.STATUS_WAITING_INSTALL:
-            case SystemUpdateManager.STATUS_WAITING_REBOOT:
-                summary = mContext.getText(R.string.android_version_pending_update_summary);
-                break;
-            case SystemUpdateManager.STATUS_UNKNOWN:
-                Log.d(TAG, "Update statue unknown");
-                // fall through to next branch
-            case SystemUpdateManager.STATUS_IDLE:
-                final String version = updateInfo.getString(SystemUpdateManager.KEY_TITLE);
-                if (!TextUtils.isEmpty(version)) {
-                    summary = mContext.getString(R.string.android_version_summary, version);
-                }
-                break;
-        }
-        return summary;
-    }
-
-    /**
-     * Trigger client initiated action (send intent) on system update
-     */
-    private void ciActionOnSysUpdate(PersistableBundle b) {
-        String intentStr = b.getString(CarrierConfigManager.
-                KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING);
-        if (!TextUtils.isEmpty(intentStr)) {
-            String extra = b.getString(CarrierConfigManager.
-                    KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING);
-            String extraVal = b.getString(CarrierConfigManager.
-                    KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING);
-
-            Intent intent = new Intent(intentStr);
-            if (!TextUtils.isEmpty(extra)) {
-                intent.putExtra(extra, extraVal);
-            }
-            Log.d(TAG, "ciActionOnSysUpdate: broadcasting intent " + intentStr +
-                    " with extra " + extra + ", " + extraVal);
-            intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
-            mContext.getApplicationContext().sendBroadcast(intent);
-        }
-    }
-}
diff --git a/src/com/android/settings/system/SystemUpdatePreferenceController.kt b/src/com/android/settings/system/SystemUpdatePreferenceController.kt
new file mode 100644
index 0000000..01df065
--- /dev/null
+++ b/src/com/android/settings/system/SystemUpdatePreferenceController.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.system
+
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import android.os.PersistableBundle
+import android.os.SystemUpdateManager
+import android.os.UserManager
+import android.telephony.CarrierConfigManager
+import android.util.Log
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.lifecycleScope
+import androidx.lifecycle.repeatOnLifecycle
+import androidx.preference.Preference
+import androidx.preference.PreferenceScreen
+import com.android.settings.R
+import com.android.settings.Utils
+import com.android.settings.core.BasePreferenceController
+import com.android.settingslib.spaprivileged.framework.common.userManager
+import kotlinx.coroutines.launch
+
+open class SystemUpdatePreferenceController(context: Context, preferenceKey: String) :
+    BasePreferenceController(context, preferenceKey) {
+    private val userManager: UserManager = context.userManager
+    private lateinit var preference: Preference
+
+    override fun getAvailabilityStatus() =
+        if (mContext.resources.getBoolean(R.bool.config_show_system_update_settings) &&
+            userManager.isAdminUser
+        ) AVAILABLE else UNSUPPORTED_ON_DEVICE
+
+    override fun displayPreference(screen: PreferenceScreen) {
+        super.displayPreference(screen)
+        preference = screen.findPreference(preferenceKey)!!
+        if (isAvailable) {
+            Utils.updatePreferenceToSpecificActivityOrRemove(
+                mContext,
+                screen,
+                preferenceKey,
+                Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY,
+            )
+        }
+    }
+
+    override fun handlePreferenceTreeClick(preference: Preference): Boolean {
+        if (preferenceKey == preference.key) {
+            val configManager = mContext.getSystemService(CarrierConfigManager::class.java)!!
+            configManager.getConfig(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_BOOL)?.let {
+                if (it.getBoolean(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_BOOL)) {
+                    ciActionOnSysUpdate(it)
+                }
+            }
+        }
+        // always return false here because this handler does not want to block other handlers.
+        return false
+    }
+
+    override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
+        viewLifecycleOwner.lifecycleScope.launch {
+            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
+                preference.summary = calculateSummary()
+            }
+        }
+    }
+
+    private suspend fun calculateSummary(): String {
+        val updateInfo = mContext.getSystemUpdateInfo() ?: return getReleaseVersionSummary()
+
+        val status = updateInfo.getInt(SystemUpdateManager.KEY_STATUS)
+        if (status == SystemUpdateManager.STATUS_UNKNOWN) {
+            Log.d(TAG, "Update statue unknown")
+        }
+        when (status) {
+            SystemUpdateManager.STATUS_WAITING_DOWNLOAD,
+            SystemUpdateManager.STATUS_IN_PROGRESS,
+            SystemUpdateManager.STATUS_WAITING_INSTALL,
+            SystemUpdateManager.STATUS_WAITING_REBOOT -> {
+                return mContext.getString(R.string.android_version_pending_update_summary)
+            }
+
+            SystemUpdateManager.STATUS_IDLE,
+            SystemUpdateManager.STATUS_UNKNOWN -> {
+                val version = updateInfo.getString(SystemUpdateManager.KEY_TITLE)
+                if (!version.isNullOrEmpty()) {
+                    return mContext.getString(R.string.android_version_summary, version)
+                }
+            }
+        }
+        return getReleaseVersionSummary()
+    }
+
+    private fun getReleaseVersionSummary(): String = mContext.getString(
+        R.string.android_version_summary,
+        Build.VERSION.RELEASE_OR_PREVIEW_DISPLAY,
+    )
+
+    /**
+     * Trigger client initiated action (send intent) on system update
+     */
+    private fun ciActionOnSysUpdate(b: PersistableBundle) {
+        val intentStr = b.getString(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING)
+        if (intentStr.isNullOrEmpty()) return
+        val extra = b.getString(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING)
+        val extraVal =
+            b.getString(CarrierConfigManager.KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING)
+        Log.d(
+            TAG,
+            "ciActionOnSysUpdate: broadcasting intent $intentStr with extra $extra, $extraVal"
+        )
+        val intent = Intent(intentStr).apply {
+            if (!extra.isNullOrEmpty()) putExtra(extra, extraVal)
+            addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND)
+        }
+        mContext.applicationContext.sendBroadcast(intent)
+    }
+
+    companion object {
+        private const val TAG = "SysUpdatePrefContr"
+    }
+}
diff --git a/tests/robotests/res/values-mcc999/config.xml b/tests/robotests/res/values-mcc999/config.xml
index 82edea5..a5767e4 100644
--- a/tests/robotests/res/values-mcc999/config.xml
+++ b/tests/robotests/res/values-mcc999/config.xml
@@ -53,7 +53,6 @@
     <bool name="config_show_pointer_speed">false</bool>
     <bool name="config_show_vibrate_input_devices">false</bool>
     <bool name="config_show_reset_dashboard">false</bool>
-    <bool name="config_show_system_update_settings">false</bool>
     <bool name="config_show_device_model">false</bool>
     <bool name="config_show_top_level_accessibility">false</bool>
     <bool name="config_show_top_level_battery">false</bool>
diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsagePreferenceTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsagePreferenceTest.java
index 02f683a..4db2fe0 100644
--- a/tests/robotests/src/com/android/settings/datausage/DataUsagePreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/DataUsagePreferenceTest.java
@@ -61,7 +61,7 @@
 
         mPreference.setTemplate(new NetworkTemplate.Builder(NetworkTemplate.MATCH_MOBILE)
                 .setMeteredness(NetworkStats.METERED_YES).build(),
-                5 /* subId */, null /* services */);
+                5 /* subId */);
 
         verify(mPreference).setEnabled(false);
         verify(mPreference).setIntent(null);
@@ -73,7 +73,7 @@
 
         mPreference.setTemplate(new NetworkTemplate.Builder(NetworkTemplate.MATCH_MOBILE)
                 .setMeteredness(NetworkStats.METERED_YES).build(),
-                5 /* subId */, null /* services */);
+                5 /* subId */);
 
         verify(mPreference, never()).setEnabled(false);
         verify(mPreference).setIntent(any(Intent.class));
diff --git a/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java b/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
index 643d364..a91af12 100644
--- a/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/network/NetworkProviderSettingsTest.java
@@ -317,7 +317,7 @@
         mNetworkProviderSettings.onCreate(Bundle.EMPTY);
 
         verify(mDataUsagePreference).setVisible(true);
-        verify(mDataUsagePreference).setTemplate(any(), eq(0) /*subId*/, eq(null) /*service*/);
+        verify(mDataUsagePreference).setTemplate(any(), eq(0) /*subId*/);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java
index c8cf290..54a6bd4 100644
--- a/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/NotificationAssistantPreferenceControllerTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -235,7 +236,7 @@
         mPreferenceController.getDefaultNASIntent();
         mPreferenceController.updateState(mPreference);
 
-        verify(mPreference).setSwitchEnabled(eq(false));
+        verify(mPreference, atLeastOnce()).setSwitchEnabled(eq(false));
         assertFalse(mPreference.isEnabled());
     }
 }
diff --git a/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceTest.java b/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceTest.java
index 6abfe69..942db3f 100644
--- a/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/notification/VolumeSeekBarPreferenceTest.java
@@ -116,6 +116,7 @@
         when(mPreference.isEnabled()).thenReturn(true);
         doCallRealMethod().when(mPreference).init();
 
+        mPreference.setStream(STREAM);
         mPreference.init();
 
         verify(mPreference, never()).updateContentDescription(CONTENT_DESCRIPTION);
@@ -136,6 +137,7 @@
     @Test
     public void init_changeProgress_overrideStateDescriptionCalled() {
         final int progress = 4;
+        when(mPreference.isEnabled()).thenReturn(true);
         when(mPreference.formatStateDescription(progress)).thenReturn(CONTENT_DESCRIPTION);
         doCallRealMethod().when(mPreference).init();
 
@@ -157,6 +159,7 @@
         when(mAudioManager.getStreamMaxVolume(STREAM)).thenReturn(max);
         when(mAudioManager.getStreamMinVolumeInt(STREAM)).thenReturn(min);
         when(mAudioManager.getStreamVolume(STREAM)).thenReturn(progress);
+        when(mPreference.isEnabled()).thenReturn(true);
         when(mPreference.getMin()).thenReturn(min);
         when(mPreference.getMax()).thenReturn(max);
         when(mPreference.getContext()).thenReturn(mContext);
@@ -168,6 +171,8 @@
         mPreference.setStream(STREAM);
         mPreference.init();
 
+        verify(mSeekBarVolumizerFactory).create(eq(STREAM), eq(null), mSbvc.capture());
+
         // On progress change, Round down the percent to match it with what the talkback says.
         // (b/285458191)
         // when progress is 4, the percent is 0.187. The state description should be set to 18%.
diff --git a/tests/robotests/src/com/android/settings/notification/app/ConversationPriorityPreferenceTest.java b/tests/robotests/src/com/android/settings/notification/app/ConversationPriorityPreferenceTest.java
index 2d2fcc8..178aee5 100644
--- a/tests/robotests/src/com/android/settings/notification/app/ConversationPriorityPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/ConversationPriorityPreferenceTest.java
@@ -21,17 +21,15 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.content.Context;
-import android.graphics.drawable.Drawable;
 import android.util.Pair;
+import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.widget.TextView;
 
 import androidx.preference.PreferenceViewHolder;
 
@@ -50,7 +48,8 @@
 
     @Before
     public void setUp() {
-        mContext = RuntimeEnvironment.application;
+        Context context = spy(RuntimeEnvironment.application.getApplicationContext());
+        mContext = new ContextThemeWrapper(context, R.style.Theme_Settings);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/notification/app/ImportancePreferenceTest.java b/tests/robotests/src/com/android/settings/notification/app/ImportancePreferenceTest.java
index 39a5714..c5733bf 100644
--- a/tests/robotests/src/com/android/settings/notification/app/ImportancePreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/notification/app/ImportancePreferenceTest.java
@@ -28,13 +28,15 @@
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
+import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TextView;
 
+import androidx.preference.PreferenceViewHolder;
+
 import com.android.settings.R;
-import com.android.settings.notification.app.ImportancePreference;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -42,8 +44,6 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
-import androidx.preference.PreferenceViewHolder;
-
 @RunWith(RobolectricTestRunner.class)
 public class ImportancePreferenceTest {
 
@@ -51,7 +51,8 @@
 
     @Before
     public void setUp() {
-        mContext = RuntimeEnvironment.application;
+        Context context = spy(RuntimeEnvironment.application.getApplicationContext());
+        mContext = new ContextThemeWrapper(context, R.style.Theme_Settings);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/system/SystemUpdatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/system/SystemUpdatePreferenceControllerTest.java
deleted file mode 100644
index 61aa294..0000000
--- a/tests/robotests/src/com/android/settings/system/SystemUpdatePreferenceControllerTest.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2016 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.system;
-
-import static android.os.SystemUpdateManager.KEY_STATUS;
-import static android.os.SystemUpdateManager.KEY_TITLE;
-import static android.os.SystemUpdateManager.STATUS_IDLE;
-import static android.os.SystemUpdateManager.STATUS_UNKNOWN;
-import static android.os.SystemUpdateManager.STATUS_WAITING_DOWNLOAD;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.SystemUpdateManager;
-
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.R;
-import com.android.settings.testutils.shadow.ShadowUserManager;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowApplication;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowUserManager.class)
-public class SystemUpdatePreferenceControllerTest {
-
-    @Mock
-    private PreferenceScreen mScreen;
-    @Mock
-    private SystemUpdateManager mSystemUpdateManager;
-
-    private Context mContext;
-    private ShadowUserManager mShadowUserManager;
-    private SystemUpdatePreferenceController mController;
-    private Preference mPreference;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
-        mShadowUserManager = ShadowUserManager.getShadow();
-
-        ShadowApplication.getInstance().setSystemService(Context.SYSTEM_UPDATE_SERVICE,
-                mSystemUpdateManager);
-        mController = new SystemUpdatePreferenceController(mContext);
-        mPreference = new Preference(RuntimeEnvironment.application);
-        mPreference.setKey(mController.getPreferenceKey());
-        when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
-    }
-
-    @After
-    public void cleanUp() {
-        mShadowUserManager.setIsAdminUser(false);
-    }
-
-    @Test
-    public void updateNonIndexable_ifAvailable_shouldNotUpdate() {
-        final List<String> keys = new ArrayList<>();
-        mShadowUserManager.setIsAdminUser(true);
-
-        mController.updateNonIndexableKeys(keys);
-
-        assertThat(keys).isEmpty();
-    }
-
-    @Test
-    public void updateNonIndexable_ifNotAvailable_shouldUpdate() {
-        mShadowUserManager.setIsAdminUser(false);
-        final List<String> keys = new ArrayList<>();
-
-        mController.updateNonIndexableKeys(keys);
-
-        assertThat(keys).hasSize(1);
-    }
-
-    @Test
-    public void displayPrefs_ifVisible_butNotAdminUser_shouldNotDisplay() {
-        mShadowUserManager.setIsAdminUser(false);
-        mController.displayPreference(mScreen);
-
-        assertThat(mPreference.isVisible()).isFalse();
-    }
-
-    @Test
-    @Config(qualifiers = "mcc999")
-    public void displayPrefs_ifAdminUser_butNotVisible_shouldNotDisplay() {
-        mShadowUserManager.setIsAdminUser(true);
-        mController.displayPreference(mScreen);
-
-        assertThat(mPreference.isVisible()).isFalse();
-    }
-
-    @Test
-    public void displayPrefs_ifAvailable_shouldDisplay() {
-        mShadowUserManager.setIsAdminUser(true);
-
-        mController.displayPreference(mScreen);
-
-        assertThat(mPreference.isVisible()).isTrue();
-    }
-
-    @Test
-    public void updateState_systemUpdateStatusUnknown_shouldSetToAndroidVersion() {
-        final Bundle bundle = new Bundle();
-        bundle.putInt(KEY_STATUS, STATUS_UNKNOWN);
-        when(mSystemUpdateManager.retrieveSystemUpdateInfo()).thenReturn(bundle);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.getSummary())
-                .isEqualTo(mContext.getString(R.string.android_version_summary,
-                        Build.VERSION.RELEASE_OR_PREVIEW_DISPLAY));
-    }
-
-    @Test
-    public void updateState_systemUpdateStatusIdle_shouldSetToAndroidVersion() {
-        final String testReleaseName = "ANDROID TEST VERSION";
-
-        final Bundle bundle = new Bundle();
-        bundle.putInt(KEY_STATUS, STATUS_IDLE);
-        bundle.putString(KEY_TITLE, testReleaseName);
-        when(mSystemUpdateManager.retrieveSystemUpdateInfo()).thenReturn(bundle);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.getSummary())
-                .isEqualTo(mContext.getString(R.string.android_version_summary, testReleaseName));
-    }
-
-    @Test
-    public void updateState_systemUpdateInProgress_shouldSetToUpdatePending() {
-        final Bundle bundle = new Bundle();
-        bundle.putInt(KEY_STATUS, STATUS_WAITING_DOWNLOAD);
-        when(mSystemUpdateManager.retrieveSystemUpdateInfo()).thenReturn(bundle);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.getSummary())
-                .isEqualTo(mContext.getString(R.string.android_version_pending_update_summary));
-    }
-}
diff --git a/tests/spa_unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.kt b/tests/spa_unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.kt
new file mode 100644
index 0000000..2e2620b
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.datausage
+
+import android.content.Context
+import android.net.NetworkTemplate
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.datausage.lib.BillingCycleRepository
+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
+
+@RunWith(AndroidJUnit4::class)
+class BillingCyclePreferenceTest {
+
+    private val mockBillingCycleRepository = mock<BillingCycleRepository> {
+        on { isModifiable(SUB_ID) } doReturn false
+    }
+
+    private val context: Context = ApplicationProvider.getApplicationContext()
+
+    private val preference = BillingCyclePreference(context, null, mockBillingCycleRepository)
+
+    @Test
+    fun isEnabled_initialState() {
+        val enabled = preference.isEnabled
+
+        assertThat(enabled).isTrue()
+    }
+
+    @Test
+    fun isEnabled_afterSetTemplate_updated() {
+        preference.setTemplate(mock<NetworkTemplate>(), SUB_ID)
+
+        val enabled = preference.isEnabled
+
+        assertThat(enabled).isFalse()
+    }
+
+    private companion object {
+        const val SUB_ID = 1
+    }
+}
diff --git a/tests/spa_unit/src/com/android/settings/datausage/lib/BillingCycleRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/datausage/lib/BillingCycleRepositoryTest.kt
new file mode 100644
index 0000000..deaaf2d
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/datausage/lib/BillingCycleRepositoryTest.kt
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.datausage.lib
+
+import android.content.Context
+import android.os.INetworkManagementService
+import android.os.UserManager
+import android.telephony.TelephonyManager
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spaprivileged.framework.common.userManager
+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.whenever
+
+@RunWith(AndroidJUnit4::class)
+class BillingCycleRepositoryTest {
+
+    private val mockNetworkManagementService = mock<INetworkManagementService> {
+        on { isBandwidthControlEnabled } doReturn true
+    }
+
+    private val mockUserManager = mock<UserManager> {
+        on { isAdminUser } doReturn true
+    }
+
+    private val mockTelephonyManager = mock<TelephonyManager> {
+        on { createForSubscriptionId(SUB_ID) } doReturn mock
+        on { isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER) } doReturn false
+    }
+
+    private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+        on { userManager } doReturn mockUserManager
+        on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager
+    }
+
+    private val repository = BillingCycleRepository(context, mockNetworkManagementService)
+
+    @Test
+    fun isModifiable_bandwidthControlDisabled_returnFalse() {
+        whenever(mockNetworkManagementService.isBandwidthControlEnabled).thenReturn(false)
+
+        val modifiable = repository.isModifiable(SUB_ID)
+
+        assertThat(modifiable).isFalse()
+    }
+
+    @Test
+    fun isModifiable_notAdminUser_returnFalse() {
+        whenever(mockUserManager.isAdminUser).thenReturn(false)
+
+        val modifiable = repository.isModifiable(SUB_ID)
+
+        assertThat(modifiable).isFalse()
+    }
+
+    @Test
+    fun isModifiable_dataDisabled_returnFalse() {
+        whenever(
+            mockTelephonyManager.isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
+        ).thenReturn(false)
+
+        val modifiable = repository.isModifiable(SUB_ID)
+
+        assertThat(modifiable).isFalse()
+    }
+
+    @Test
+    fun isModifiable_meetAllRequirements_returnTrue() {
+        whenever(mockNetworkManagementService.isBandwidthControlEnabled).thenReturn(true)
+        whenever(mockUserManager.isAdminUser).thenReturn(true)
+        whenever(
+            mockTelephonyManager.isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
+        ).thenReturn(true)
+
+        val modifiable = repository.isModifiable(SUB_ID)
+
+        assertThat(modifiable).isTrue()
+    }
+
+    @Test
+    fun isBandwidthControlEnabled_bandwidthControlDisabled_returnFalse() {
+        whenever(mockNetworkManagementService.isBandwidthControlEnabled).thenReturn(false)
+
+        val enabled = repository.isBandwidthControlEnabled()
+
+        assertThat(enabled).isFalse()
+    }
+
+    @Test
+    fun isBandwidthControlEnabled_bandwidthControlEnabled_returnTrue() {
+        whenever(mockNetworkManagementService.isBandwidthControlEnabled).thenReturn(true)
+
+        val enabled = repository.isBandwidthControlEnabled()
+
+        assertThat(enabled).isTrue()
+    }
+
+    private companion object {
+        const val SUB_ID = 1
+    }
+}
diff --git a/tests/spa_unit/src/com/android/settings/network/apn/ApnEditPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/network/apn/ApnEditPageProviderTest.kt
index c6c37d5..590fe9e 100644
--- a/tests/spa_unit/src/com/android/settings/network/apn/ApnEditPageProviderTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/apn/ApnEditPageProviderTest.kt
@@ -49,13 +49,14 @@
     private val apnType = "apn_type"
     private val apnRoaming = "IPv4"
     private val apnEnable = context.resources.getString(R.string.carrier_enabled)
+    private val apnProtocolOptions = context.resources.getStringArray(R.array.apn_protocol_entries).toList()
     private val apnData = ApnData(
         name = apnName,
         mmsc = mmsc,
         mmsProxy = mmsProxy,
         mnc = mnc,
         apnType = apnType,
-        apnRoaming = apnRoaming,
+        apnRoaming = apnProtocolOptions.indexOf(apnRoaming),
         apnEnable = true
     )
 
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreferenceTest.kt
index 265d92d..46ee3f1 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreferenceTest.kt
@@ -145,7 +145,7 @@
 
         composeTestRule.onNode(
             hasTextExactly(
-                context.getString(R.string.aspect_ratio_title),
+                context.getString(R.string.aspect_ratio_experimental_title),
                 context.getString(R.string.user_aspect_ratio_app_default)
             ),
         ).assertIsDisplayed().assertIsEnabled()
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
index b36a74c..f550326 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
@@ -59,7 +59,7 @@
     @Test
     fun injectEntry_title() {
         setInjectEntry()
-        composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_title))
+        composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_experimental_title))
             .assertIsDisplayed()
     }
 
@@ -74,7 +74,7 @@
     @Test
     fun injectEntry_onClick_navigate() {
         setInjectEntry()
-        composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_title))
+        composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_experimental_title))
             .performClick()
         assertThat(fakeNavControllerWrapper.navigateCalledWith).isEqualTo("UserAspectRatioAppsPage")
     }
@@ -93,7 +93,7 @@
             UserAspectRatioAppList {}
         }
 
-        composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_title))
+        composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_experimental_title))
             .assertIsDisplayed()
     }
 
diff --git a/tests/spa_unit/src/com/android/settings/system/SystemUpdateManagerExtKtTest.kt b/tests/spa_unit/src/com/android/settings/system/SystemUpdateManagerExtKtTest.kt
new file mode 100644
index 0000000..0ba91df
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/system/SystemUpdateManagerExtKtTest.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.system
+
+import android.content.Context
+import android.os.Bundle
+import android.os.SystemUpdateManager
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+
+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.whenever
+
+@RunWith(AndroidJUnit4::class)
+class SystemUpdateManagerExtKtTest {
+
+    private val mockSystemUpdateManager = mock<SystemUpdateManager>()
+
+    private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+        on { getSystemService(SystemUpdateManager::class.java) } doReturn mockSystemUpdateManager
+    }
+
+    @Test
+    fun getSystemUpdateInfo() = runTest {
+        val bundle = Bundle()
+        whenever(mockSystemUpdateManager.retrieveSystemUpdateInfo()).thenReturn(bundle)
+
+        val info = context.getSystemUpdateInfo()
+
+        assertThat(info).isSameInstanceAs(bundle)
+    }
+}
diff --git a/tests/spa_unit/src/com/android/settings/system/SystemUpdatePreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/system/SystemUpdatePreferenceControllerTest.kt
new file mode 100644
index 0000000..17cdf04
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/system/SystemUpdatePreferenceControllerTest.kt
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.system
+
+import android.content.Context
+import android.os.Build
+import android.os.Bundle
+import android.os.SystemClock
+import android.os.SystemUpdateManager
+import android.os.UserManager
+import androidx.lifecycle.testing.TestLifecycleOwner
+import androidx.preference.Preference
+import androidx.preference.PreferenceScreen
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.R
+import com.android.settingslib.spaprivileged.framework.common.userManager
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+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.whenever
+
+@RunWith(AndroidJUnit4::class)
+class SystemUpdatePreferenceControllerTest {
+    private val mockUserManager = mock<UserManager>()
+    private val mockSystemUpdateManager = mock<SystemUpdateManager>()
+
+    private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+        on { userManager } doReturn mockUserManager
+        on { getSystemService(SystemUpdateManager::class.java) } doReturn mockSystemUpdateManager
+    }
+
+    private val resources = spy(context.resources) {
+        on { getBoolean(R.bool.config_show_system_update_settings) } doReturn true
+    }
+
+    private val preference = Preference(context).apply { key = KEY }
+    private val preferenceScreen = mock<PreferenceScreen> {
+        onGeneric { findPreference(KEY) } doReturn preference
+    }
+    private val controller = SystemUpdatePreferenceController(context, KEY)
+
+    @Before
+    fun setUp() {
+        whenever(context.resources).thenReturn(resources)
+    }
+
+    @Test
+    fun updateNonIndexable_ifAvailable_shouldNotUpdate() {
+        whenever(mockUserManager.isAdminUser).thenReturn(true)
+        val keys = mutableListOf<String>()
+
+        controller.updateNonIndexableKeys(keys)
+
+        assertThat(keys).isEmpty()
+    }
+
+    @Test
+    fun updateNonIndexable_ifNotAvailable_shouldUpdate() {
+        whenever(mockUserManager.isAdminUser).thenReturn(false)
+        val keys = mutableListOf<String>()
+
+        controller.updateNonIndexableKeys(keys)
+
+        assertThat(keys).containsExactly(KEY)
+    }
+
+    @Test
+    fun displayPrefs_ifVisible_butNotAdminUser_shouldNotDisplay() {
+        whenever(mockUserManager.isAdminUser).thenReturn(false)
+
+        controller.displayPreference(preferenceScreen)
+
+        assertThat(preference.isVisible).isFalse()
+    }
+
+    @Test
+    fun displayPrefs_ifAdminUser_butNotVisible_shouldNotDisplay() {
+        whenever(mockUserManager.isAdminUser).thenReturn(true)
+        whenever(resources.getBoolean(R.bool.config_show_system_update_settings)).thenReturn(false)
+
+        controller.displayPreference(preferenceScreen)
+
+        assertThat(preference.isVisible).isFalse()
+    }
+
+    @Test
+    fun displayPrefs_ifAvailable_shouldDisplay() {
+        whenever(mockUserManager.isAdminUser).thenReturn(true)
+
+        controller.displayPreference(preferenceScreen)
+
+        assertThat(preference.isVisible).isTrue()
+    }
+
+    @Test
+    fun updateState_systemUpdateStatusUnknown_shouldSetToAndroidVersion() {
+        val bundle = Bundle().apply {
+            putInt(SystemUpdateManager.KEY_STATUS, SystemUpdateManager.STATUS_UNKNOWN)
+        }
+        whenever(mockSystemUpdateManager.retrieveSystemUpdateInfo()).thenReturn(bundle)
+        controller.displayPreference(preferenceScreen)
+
+        controller.onViewCreated(TestLifecycleOwner())
+        SystemClock.sleep(100)
+
+        assertThat(preference.summary).isEqualTo(
+            context.getString(
+                R.string.android_version_summary,
+                Build.VERSION.RELEASE_OR_PREVIEW_DISPLAY,
+            )
+        )
+    }
+
+    @Test
+    fun updateState_systemUpdateStatusIdle_shouldSetToAndroidVersion() {
+        val testReleaseName = "ANDROID TEST VERSION"
+        val bundle = Bundle().apply {
+            putInt(SystemUpdateManager.KEY_STATUS, SystemUpdateManager.STATUS_IDLE)
+            putString(SystemUpdateManager.KEY_TITLE, testReleaseName)
+        }
+        whenever(mockSystemUpdateManager.retrieveSystemUpdateInfo()).thenReturn(bundle)
+        controller.displayPreference(preferenceScreen)
+
+        controller.onViewCreated(TestLifecycleOwner())
+        SystemClock.sleep(100)
+
+        assertThat(preference.summary)
+            .isEqualTo(context.getString(R.string.android_version_summary, testReleaseName))
+    }
+
+    @Test
+    fun updateState_systemUpdateInProgress_shouldSetToUpdatePending() {
+        val bundle = Bundle().apply {
+            putInt(SystemUpdateManager.KEY_STATUS, SystemUpdateManager.STATUS_WAITING_DOWNLOAD)
+        }
+        whenever(mockSystemUpdateManager.retrieveSystemUpdateInfo()).thenReturn(bundle)
+        controller.displayPreference(preferenceScreen)
+
+        controller.onViewCreated(TestLifecycleOwner())
+        SystemClock.sleep(100)
+
+        assertThat(preference.summary)
+            .isEqualTo(context.getString(R.string.android_version_pending_update_summary))
+    }
+
+    private companion object {
+        const val KEY = "test_key"
+    }
+}
diff --git a/tests/unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.java b/tests/unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.java
deleted file mode 100644
index f74768f..0000000
--- a/tests/unit/src/com/android/settings/datausage/BillingCyclePreferenceTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.datausage;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.os.INetworkManagementService;
-import android.os.RemoteException;
-import android.os.UserManager;
-import android.telephony.TelephonyManager;
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@RunWith(AndroidJUnit4.class)
-public class BillingCyclePreferenceTest {
-
-    private Context mContext;
-    private BillingCyclePreference mPreference;
-    private TemplatePreference.NetworkServices mServices;
-    @Mock
-    private INetworkManagementService mNetManageSerice;
-    @Mock
-    private TelephonyManager mTelephonyManager;
-    @Mock
-    private UserManager mUserManager;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = spy(ApplicationProvider.getApplicationContext());
-
-        mServices = new TemplatePreference.NetworkServices();
-        mServices.mNetworkService = mNetManageSerice;
-        mServices.mTelephonyManager = mTelephonyManager;
-        mServices.mUserManager = mUserManager;
-
-        doReturn(mTelephonyManager).when(mTelephonyManager)
-                .createForSubscriptionId(anyInt());
-
-        mPreference = spy(new BillingCyclePreference(mContext, null /* attrs */));
-        mPreference.setTemplate(null, 0, mServices);
-    }
-
-    @Test
-    public void testPreferenceUpdate_onMobileDataEnabledChange_accessDataEnabledApi() {
-        try {
-            doReturn(true).when(mNetManageSerice).isBandwidthControlEnabled();
-        } catch (RemoteException exception) {}
-        doReturn(true).when(mUserManager).isAdminUser();
-        mPreference.onMobileDataEnabledChange();
-
-        verify(mTelephonyManager)
-                .isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER);
-    }
-}
\ No newline at end of file