Merge "Change the label of CombinedBiometricProfileSettingsActivity." into udc-dev
diff --git a/res/layout/locale_order_list.xml b/res/layout/locale_order_list.xml
index acde145..5c1db15 100644
--- a/res/layout/locale_order_list.xml
+++ b/res/layout/locale_order_list.xml
@@ -14,11 +14,11 @@
      limitations under the License.
 -->
 
-<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layoutDirection="locale"
-            android:textDirection="locale">
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:layout_width="match_parent"
+             android:layout_height="match_parent"
+             android:layoutDirection="locale"
+             android:textDirection="locale">
 
     <LinearLayout
         android:layout_width="match_parent"
@@ -48,4 +48,4 @@
 
     </LinearLayout>
 
-</androidx.core.widget.NestedScrollView>
+</FrameLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index dea4320..5a5bc27 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -871,9 +871,9 @@
     <string name="biometric_settings_use_face_or_fingerprint_preference_summary">Using face or fingerprint</string>
     <!-- Button text shown during enrollment to proceed after a child user has handed the device to a parent or guardian. [CHAR LIMIT=22] -->
     <string name="biometric_settings_hand_back_to_guardian_ok">OK</string>
-    <!-- Dialog title for dialog which shows when trying to add fingerprint in split mode. [CHAR LIMIT=45] -->
+    <!-- Dialog title for dialog which shows when trying to add fingerprint in split mode. [CHAR LIMIT=80] -->
     <string name="biometric_settings_add_fingerprint_in_split_mode_title">Can\u2019t set up fingerprint</string>
-    <!-- Dialog message for dialog which shows when trying to add fingerprint in split mode. [CHAR LIMIT=45] -->
+    <!-- Dialog message for dialog which shows when trying to add fingerprint in split mode. [CHAR LIMIT=NONE] -->
     <string name="biometric_settings_add_fingerprint_in_split_mode_message">Exit split screen to set up Fingerprint Unlock</string>
     <!-- Button text shown in adding fingerprint dialog that allows the user to go back to the settings page [CHAR LIMIT=22] -->
     <string name="biometric_settings_add_fingerprint_in_split_mode_ok">OK</string>
@@ -11524,9 +11524,12 @@
     <!-- Summary for UWB preference. [CHAR_LIMIT=NONE]-->
     <string name="uwb_settings_summary">Helps identify the relative position of nearby devices that have UWB</string>
 
-    <!-- Summary for UWB preference when airplane mode is disabled. [CHAR_LIMIT=NONE]-->
+    <!-- Summary for UWB preference when airplane mode is enabled. [CHAR_LIMIT=NONE]-->
     <string name="uwb_settings_summary_airplane_mode">Turn off airplane mode to use UWB </string>
 
+    <!-- Summary for UWB preference when UWB is unavailable due to regulatory requirements. [CHAR_LIMIT=NONE]-->
+    <string name="uwb_settings_summary_no_uwb_regulatory">UWB is unavailable in the current location</string>
+
     <!-- Label for the camera use toggle [CHAR LIMIT=40] -->
     <string name="camera_toggle_title">Camera access</string>
     <!-- Label for the camera use toggle [CHAR LIMIT=40] -->
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
index 0be6c98..2121c60 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java
@@ -23,6 +23,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.Log;
 import android.view.View;
 import android.widget.AdapterView;
@@ -48,9 +49,11 @@
 import com.android.settingslib.core.lifecycle.events.OnResume;
 import com.android.settingslib.widget.FooterPreference;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /** Controller for battery usage breakdown preference group. */
 public class BatteryUsageBreakdownController extends BasePreferenceController
@@ -61,6 +64,7 @@
     private static final String SPINNER_PREFERENCE_KEY = "battery_usage_spinner";
     private static final String APP_LIST_PREFERENCE_KEY = "app_list";
     private static final String PACKAGE_NAME_NONE = "none";
+    private static final List<BatteryDiffEntry> EMPTY_ENTRY_LIST = new ArrayList<>();
 
     private static int sUiMode = Configuration.UI_MODE_NIGHT_UNDEFINED;
 
@@ -183,7 +187,7 @@
                         if (mSpinnerPosition != position) {
                             mSpinnerPosition = position;
                             mHandler.post(() -> {
-                                removeAndCacheAllPreferences();
+                                removeAndCacheAllUnusedPreferences();
                                 addAllPreferences();
                                 mMetricsFeatureProvider.action(
                                         mPrefContext,
@@ -238,27 +242,34 @@
     private void showSpinnerAndAppList() {
         if (mBatteryDiffData == null) {
             mHandler.post(() -> {
-                removeAndCacheAllPreferences();
+                removeAndCacheAllUnusedPreferences();
             });
             return;
         }
         mSpinnerPreference.setVisible(true);
         mAppListPreferenceGroup.setVisible(true);
         mHandler.post(() -> {
-            removeAndCacheAllPreferences();
+            removeAndCacheAllUnusedPreferences();
             addAllPreferences();
         });
     }
 
+    private List<BatteryDiffEntry> getBatteryDiffEntries() {
+        if (mBatteryDiffData == null) {
+            return EMPTY_ENTRY_LIST;
+        }
+        return mSpinnerPosition == 0
+                ? mBatteryDiffData.getAppDiffEntryList()
+                : mBatteryDiffData.getSystemDiffEntryList();
+    }
+
     @VisibleForTesting
     void addAllPreferences() {
         if (mBatteryDiffData == null) {
             return;
         }
         final long start = System.currentTimeMillis();
-        final List<BatteryDiffEntry> entries = mSpinnerPosition == 0
-                ? mBatteryDiffData.getAppDiffEntryList()
-                : mBatteryDiffData.getSystemDiffEntryList();
+        final List<BatteryDiffEntry> entries = getBatteryDiffEntries();
         int prefIndex = mAppListPreferenceGroup.getPreferenceCount();
         for (BatteryDiffEntry entry : entries) {
             boolean isAdded = false;
@@ -272,7 +283,6 @@
             PowerGaugePreference pref = mAppListPreferenceGroup.findPreference(prefKey);
             if (pref != null) {
                 isAdded = true;
-                Log.w(TAG, "preference should be removed for:" + entry.getPackageName());
             } else {
                 pref = (PowerGaugePreference) mPreferenceCache.get(prefKey);
             }
@@ -301,16 +311,25 @@
     }
 
     @VisibleForTesting
-    void removeAndCacheAllPreferences() {
+    void removeAndCacheAllUnusedPreferences() {
+        List<BatteryDiffEntry> entries = getBatteryDiffEntries();
+        Set<String> entryKeySet = new ArraySet<>();
+        for (BatteryDiffEntry entry : entries) {
+            entryKeySet.add(entry.getKey());
+        }
+
         final int prefsCount = mAppListPreferenceGroup.getPreferenceCount();
-        for (int index = 0; index < prefsCount; index++) {
+        for (int index = prefsCount - 1; index >= 0; index--) {
             final Preference pref = mAppListPreferenceGroup.getPreference(index);
-            if (TextUtils.isEmpty(pref.getKey())) {
+            if (entryKeySet.contains(pref.getKey())) {
+                // The pref is still used, don't remove.
                 continue;
             }
-            mPreferenceCache.put(pref.getKey(), pref);
+            if (!TextUtils.isEmpty(pref.getKey())) {
+                mPreferenceCache.put(pref.getKey(), pref);
+            }
+            mAppListPreferenceGroup.removePreference(pref);
         }
-        mAppListPreferenceGroup.removeAll();
     }
 
     @VisibleForTesting
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
index 6270eb3..ec1a4be 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DataProcessor.java
@@ -1446,31 +1446,39 @@
         final int workProfileUserId =
                 userHandle != null ? userHandle.getIdentifier() : Integer.MIN_VALUE;
         // Each time slot usage diff data =
-        //     Math.abs(timestamp[i+2] data - timestamp[i+1] data) +
-        //     Math.abs(timestamp[i+1] data - timestamp[i] data);
-        // since we want to aggregate every two hours data into a single time slot.
+        //     sum(Math.abs(timestamp[i+1] data - timestamp[i] data));
+        // since we want to aggregate every hour usage diff data into a single time slot.
         for (int dailyIndex = 0; dailyIndex < hourlyBatteryLevelsPerDay.size(); dailyIndex++) {
             final Map<Integer, BatteryDiffData> dailyDiffMap = new ArrayMap<>();
             resultMap.put(dailyIndex, dailyDiffMap);
             if (hourlyBatteryLevelsPerDay.get(dailyIndex) == null) {
                 continue;
             }
-            final List<Long> timestamps = hourlyBatteryLevelsPerDay.get(dailyIndex).getTimestamps();
-            for (int hourlyIndex = 0; hourlyIndex < timestamps.size() - 1; hourlyIndex++) {
+            final List<Long> hourlyTimestamps =
+                    hourlyBatteryLevelsPerDay.get(dailyIndex).getTimestamps();
+            for (int hourlyIndex = 0; hourlyIndex < hourlyTimestamps.size() - 1; hourlyIndex++) {
+                final Long startTimestamp = hourlyTimestamps.get(hourlyIndex);
+                final Long endTimestamp = hourlyTimestamps.get(hourlyIndex + 1);
+                final long slotDuration = endTimestamp - startTimestamp;
+                List<Map<String, BatteryHistEntry>> slotBatteryHistoryList = new ArrayList<>();
+                for (Long timestamp = startTimestamp; timestamp <= endTimestamp;
+                        timestamp += DateUtils.HOUR_IN_MILLIS) {
+                    slotBatteryHistoryList.add(
+                            batteryHistoryMap.getOrDefault(timestamp, EMPTY_BATTERY_MAP));
+                }
                 final BatteryDiffData hourlyBatteryDiffData =
                         insertHourlyUsageDiffDataPerSlot(
                                 context,
                                 currentUserId,
                                 workProfileUserId,
-                                hourlyIndex,
-                                timestamps,
+                                slotDuration,
                                 systemAppsPackageNames,
                                 systemAppsUids,
                                 appUsagePeriodMap == null
                                         || appUsagePeriodMap.get(dailyIndex) == null
                                         ? null
                                         : appUsagePeriodMap.get(dailyIndex).get(hourlyIndex),
-                                batteryHistoryMap);
+                                slotBatteryHistoryList);
                 dailyDiffMap.put(hourlyIndex, hourlyBatteryDiffData);
             }
         }
@@ -1508,54 +1516,42 @@
             final Context context,
             final int currentUserId,
             final int workProfileUserId,
-            final int currentIndex,
-            final List<Long> timestamps,
+            final long slotDuration,
             final Set<String> systemAppsPackageNames,
             final Set<Integer> systemAppsUids,
             final Map<Long, Map<String, List<AppUsagePeriod>>> appUsageMap,
-            final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
+            final List<Map<String, BatteryHistEntry>> slotBatteryHistoryList) {
         final List<BatteryDiffEntry> appEntries = new ArrayList<>();
         final List<BatteryDiffEntry> systemEntries = new ArrayList<>();
 
-        final Long currentTimestamp = timestamps.get(currentIndex);
-        final Long nextTimestamp = currentTimestamp + DateUtils.HOUR_IN_MILLIS;
-        final Long nextTwoTimestamp = nextTimestamp + DateUtils.HOUR_IN_MILLIS;
-        // Fetches BatteryHistEntry data from corresponding time slot.
-        final Map<String, BatteryHistEntry> currentBatteryHistMap =
-                batteryHistoryMap.getOrDefault(currentTimestamp, EMPTY_BATTERY_MAP);
-        final Map<String, BatteryHistEntry> nextBatteryHistMap =
-                batteryHistoryMap.getOrDefault(nextTimestamp, EMPTY_BATTERY_MAP);
-        final Map<String, BatteryHistEntry> nextTwoBatteryHistMap =
-                batteryHistoryMap.getOrDefault(nextTwoTimestamp, EMPTY_BATTERY_MAP);
-        // We should not get the empty list since we have at least one fake data to record
-        // the battery level and status in each time slot, the empty list is used to
-        // represent there is no enough data to apply interpolation arithmetic.
-        if (currentBatteryHistMap.isEmpty()
-                || nextBatteryHistMap.isEmpty()
-                || nextTwoBatteryHistMap.isEmpty()) {
-            return null;
-        }
-
         // Collects all keys in these three time slot records as all populations.
         final Set<String> allBatteryHistEntryKeys = new ArraySet<>();
-        allBatteryHistEntryKeys.addAll(currentBatteryHistMap.keySet());
-        allBatteryHistEntryKeys.addAll(nextBatteryHistMap.keySet());
-        allBatteryHistEntryKeys.addAll(nextTwoBatteryHistMap.keySet());
+        for (Map<String, BatteryHistEntry> slotBatteryHistMap : slotBatteryHistoryList) {
+            if (slotBatteryHistMap.isEmpty()) {
+                // We should not get the empty list since we have at least one fake data to record
+                // the battery level and status in each time slot, the empty list is used to
+                // represent there is no enough data to apply interpolation arithmetic.
+                return null;
+            }
+            allBatteryHistEntryKeys.addAll(slotBatteryHistMap.keySet());
+        }
 
         // Calculates all packages diff usage data in a specific time slot.
         for (String key : allBatteryHistEntryKeys) {
             if (key == null) {
                 continue;
             }
-            final BatteryHistEntry currentEntry =
-                    currentBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
-            final BatteryHistEntry nextEntry =
-                    nextBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
-            final BatteryHistEntry nextTwoEntry =
-                    nextTwoBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
 
-            final BatteryHistEntry selectedBatteryEntry =
-                    selectBatteryHistEntry(currentEntry, nextEntry, nextTwoEntry);
+            BatteryHistEntry selectedBatteryEntry = null;
+            final List<BatteryHistEntry> batteryHistEntries = new ArrayList<>();
+            for (Map<String, BatteryHistEntry> slotBatteryHistMap : slotBatteryHistoryList) {
+                BatteryHistEntry entry =
+                        slotBatteryHistMap.getOrDefault(key, EMPTY_BATTERY_HIST_ENTRY);
+                batteryHistEntries.add(entry);
+                if (selectedBatteryEntry == null && entry != EMPTY_BATTERY_HIST_ENTRY) {
+                    selectedBatteryEntry = entry;
+                }
+            }
             if (selectedBatteryEntry == null) {
                 continue;
             }
@@ -1568,41 +1564,45 @@
             }
 
             // Cumulative values is a specific time slot for a specific app.
-            long foregroundUsageTimeInMs =
-                    getDiffValue(
-                            currentEntry.mForegroundUsageTimeInMs,
-                            nextEntry.mForegroundUsageTimeInMs,
-                            nextTwoEntry.mForegroundUsageTimeInMs);
-            long backgroundUsageTimeInMs =
-                    getDiffValue(
-                            currentEntry.mBackgroundUsageTimeInMs,
-                            nextEntry.mBackgroundUsageTimeInMs,
-                            nextTwoEntry.mBackgroundUsageTimeInMs);
-            double consumePower =
-                    getDiffValue(
-                            currentEntry.mConsumePower,
-                            nextEntry.mConsumePower,
-                            nextTwoEntry.mConsumePower);
-            double foregroundUsageConsumePower =
-                    getDiffValue(
-                            currentEntry.mForegroundUsageConsumePower,
-                            nextEntry.mForegroundUsageConsumePower,
-                            nextTwoEntry.mForegroundUsageConsumePower);
-            double foregroundServiceUsageConsumePower =
-                    getDiffValue(
-                            currentEntry.mForegroundServiceUsageConsumePower,
-                            nextEntry.mForegroundServiceUsageConsumePower,
-                            nextTwoEntry.mForegroundServiceUsageConsumePower);
-            double backgroundUsageConsumePower =
-                    getDiffValue(
-                            currentEntry.mBackgroundUsageConsumePower,
-                            nextEntry.mBackgroundUsageConsumePower,
-                            nextTwoEntry.mBackgroundUsageConsumePower);
-            double cachedUsageConsumePower =
-                    getDiffValue(
-                            currentEntry.mCachedUsageConsumePower,
-                            nextEntry.mCachedUsageConsumePower,
-                            nextTwoEntry.mCachedUsageConsumePower);
+            long foregroundUsageTimeInMs = 0;
+            long backgroundUsageTimeInMs = 0;
+            double consumePower = 0;
+            double foregroundUsageConsumePower = 0;
+            double foregroundServiceUsageConsumePower = 0;
+            double backgroundUsageConsumePower = 0;
+            double cachedUsageConsumePower = 0;
+            for (int i = 0; i < batteryHistEntries.size() - 1; i++) {
+                final BatteryHistEntry currentEntry = batteryHistEntries.get(i);
+                final BatteryHistEntry nextEntry = batteryHistEntries.get(i + 1);
+                foregroundUsageTimeInMs +=
+                        getDiffValue(
+                                currentEntry.mForegroundUsageTimeInMs,
+                                nextEntry.mForegroundUsageTimeInMs);
+                backgroundUsageTimeInMs +=
+                        getDiffValue(
+                                currentEntry.mBackgroundUsageTimeInMs,
+                                nextEntry.mBackgroundUsageTimeInMs);
+                consumePower +=
+                        getDiffValue(
+                                currentEntry.mConsumePower,
+                                nextEntry.mConsumePower);
+                foregroundUsageConsumePower +=
+                        getDiffValue(
+                                currentEntry.mForegroundUsageConsumePower,
+                                nextEntry.mForegroundUsageConsumePower);
+                foregroundServiceUsageConsumePower +=
+                        getDiffValue(
+                                currentEntry.mForegroundServiceUsageConsumePower,
+                                nextEntry.mForegroundServiceUsageConsumePower);
+                backgroundUsageConsumePower +=
+                        getDiffValue(
+                                currentEntry.mBackgroundUsageConsumePower,
+                                nextEntry.mBackgroundUsageConsumePower);
+                cachedUsageConsumePower +=
+                        getDiffValue(
+                                currentEntry.mCachedUsageConsumePower,
+                                nextEntry.mCachedUsageConsumePower);
+            }
             // Excludes entry since we don't have enough data to calculate.
             if (foregroundUsageTimeInMs == 0
                     && backgroundUsageTimeInMs == 0
@@ -1613,13 +1613,13 @@
             // will apply the interpolation arithmetic.
             final float totalUsageTimeInMs =
                     foregroundUsageTimeInMs + backgroundUsageTimeInMs;
-            if (totalUsageTimeInMs > TOTAL_HOURLY_TIME_THRESHOLD) {
-                final float ratio = TOTAL_HOURLY_TIME_THRESHOLD / totalUsageTimeInMs;
+            if (totalUsageTimeInMs > slotDuration) {
+                final float ratio = slotDuration / totalUsageTimeInMs;
                 if (sDebug) {
                     Log.w(TAG, String.format("abnormal usage time %d|%d for:\n%s",
                             Duration.ofMillis(foregroundUsageTimeInMs).getSeconds(),
                             Duration.ofMillis(backgroundUsageTimeInMs).getSeconds(),
-                            currentEntry));
+                            selectedBatteryEntry));
                 }
                 foregroundUsageTimeInMs =
                         Math.round(foregroundUsageTimeInMs * ratio);
@@ -1634,14 +1634,14 @@
 
             // Compute the screen on time and make sure it won't exceed the threshold.
             final long screenOnTime = Math.min(
-                    (long) TOTAL_HOURLY_TIME_THRESHOLD,
+                    (long) slotDuration,
                     getScreenOnTime(
                             appUsageMap,
                             selectedBatteryEntry.mUserId,
                             selectedBatteryEntry.mPackageName));
             // Make sure the background + screen-on time will not exceed the threshold.
             backgroundUsageTimeInMs = Math.min(
-                    backgroundUsageTimeInMs, (long) TOTAL_HOURLY_TIME_THRESHOLD - screenOnTime);
+                    backgroundUsageTimeInMs, (long) slotDuration - screenOnTime);
             final BatteryDiffEntry currentBatteryDiffEntry = new BatteryDiffEntry(
                     context,
                     foregroundUsageTimeInMs,
@@ -1948,23 +1948,12 @@
         return calendar.getTimeInMillis();
     }
 
-    private static long getDiffValue(long v1, long v2, long v3) {
-        return (v2 > v1 ? v2 - v1 : 0) + (v3 > v2 ? v3 - v2 : 0);
+    private static long getDiffValue(long v1, long v2) {
+        return v2 > v1 ? v2 - v1 : 0;
     }
 
-    private static double getDiffValue(double v1, double v2, double v3) {
-        return (v2 > v1 ? v2 - v1 : 0) + (v3 > v2 ? v3 - v2 : 0);
-    }
-
-    @Nullable
-    private static BatteryHistEntry selectBatteryHistEntry(
-            final BatteryHistEntry... batteryHistEntries) {
-        for (BatteryHistEntry entry : batteryHistEntries) {
-            if (entry != null && entry != EMPTY_BATTERY_HIST_ENTRY) {
-                return entry;
-            }
-        }
-        return null;
+    private static double getDiffValue(double v1, double v2) {
+        return v2 > v1 ? v2 - v1 : 0;
     }
 
     private static Set<String> getSystemAppsPackageNames(Context context) {
diff --git a/src/com/android/settings/localepicker/LocaleListEditor.java b/src/com/android/settings/localepicker/LocaleListEditor.java
index bdb9295..6317f24 100644
--- a/src/com/android/settings/localepicker/LocaleListEditor.java
+++ b/src/com/android/settings/localepicker/LocaleListEditor.java
@@ -329,6 +329,7 @@
         list.setLayoutManager(llm);
 
         list.setHasFixedSize(true);
+        list.setNestedScrollingEnabled(false);
         mAdapter.setRecyclerView(list);
         list.setAdapter(mAdapter);
 
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
index ce83053..83d2117 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
@@ -351,9 +351,14 @@
     }
 
     @Override
+    public void onPause() {
+        mMobileNetworkRepository.removeRegister(this);
+        super.onPause();
+    }
+
+    @Override
     public void onDestroy() {
         super.onDestroy();
-        mMobileNetworkRepository.removeRegister(this);
     }
 
     @VisibleForTesting
diff --git a/src/com/android/settings/security/MemtagHelper.java b/src/com/android/settings/security/MemtagHelper.java
index b04dcf9..a09a219 100644
--- a/src/com/android/settings/security/MemtagHelper.java
+++ b/src/com/android/settings/security/MemtagHelper.java
@@ -17,6 +17,7 @@
 package com.android.settings.security;
 
 import android.os.SystemProperties;
+import android.text.TextUtils;
 
 import com.android.internal.os.Zygote;
 import com.android.settings.R;
@@ -25,18 +26,15 @@
 import java.util.Arrays;
 
 public class MemtagHelper {
+    public static final String DEVICE_CONFIG_PROP =
+            "persist.device_config.runtime_native_boot.bootloader_override";
+
     public static boolean isForcedOff() {
-        return "force_off"
-                .equals(
-                        SystemProperties.get(
-                                "persist.device_config.memory_safety_native_boot.bootloader_override"));
+        return TextUtils.equals("force_on", SystemProperties.get(DEVICE_CONFIG_PROP));
     }
 
     public static boolean isForcedOn() {
-        return "force_on"
-                .equals(
-                        SystemProperties.get(
-                                "persist.device_config.memory_safety_native_boot.bootloader_override"));
+        return TextUtils.equals("force_on", SystemProperties.get(DEVICE_CONFIG_PROP));
     }
 
     public static boolean isChecked() {
diff --git a/src/com/android/settings/users/TimeoutToDockUserPreferenceController.java b/src/com/android/settings/users/TimeoutToDockUserPreferenceController.java
index 57e8d40..322a4ab 100644
--- a/src/com/android/settings/users/TimeoutToDockUserPreferenceController.java
+++ b/src/com/android/settings/users/TimeoutToDockUserPreferenceController.java
@@ -20,6 +20,7 @@
 
 import android.content.Context;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 
 import androidx.preference.PreferenceScreen;
@@ -34,6 +35,8 @@
  * automatically switch to the designated Dock User when the device is docked.
  */
 public class TimeoutToDockUserPreferenceController extends BasePreferenceController {
+    private final UserManager mUserManager;
+
     private final String[] mEntries;
     private final String[] mValues;
 
@@ -41,6 +44,8 @@
             String preferenceKey) {
         super(context, preferenceKey);
 
+        mUserManager = context.getSystemService(UserManager.class);
+
         mEntries = mContext.getResources().getStringArray(
                 com.android.settings.R.array.switch_to_dock_user_when_docked_timeout_entries);
         mValues = mContext.getResources().getStringArray(
@@ -62,9 +67,10 @@
             return UNSUPPORTED_ON_DEVICE;
         }
 
-        // Multi-user feature disabled by user.
+        // Multi-user feature disabled by user, or user switching blocked on the user.
         if (Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.USER_SWITCHER_ENABLED, 0) != 1) {
+                Settings.Global.USER_SWITCHER_ENABLED, 0) != 1
+                || mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)) {
             return CONDITIONALLY_UNAVAILABLE;
         }
 
diff --git a/src/com/android/settings/uwb/UwbPreferenceController.java b/src/com/android/settings/uwb/UwbPreferenceController.java
index fb0836d..7f19765 100644
--- a/src/com/android/settings/uwb/UwbPreferenceController.java
+++ b/src/com/android/settings/uwb/UwbPreferenceController.java
@@ -16,6 +16,11 @@
 
 package com.android.settings.uwb;
 
+import static android.uwb.UwbManager.AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_REGULATION;
+import static android.uwb.UwbManager.AdapterStateCallback.STATE_DISABLED;
+import static android.uwb.UwbManager.AdapterStateCallback.STATE_ENABLED_ACTIVE;
+import static android.uwb.UwbManager.AdapterStateCallback.STATE_ENABLED_INACTIVE;
+
 import static androidx.lifecycle.Lifecycle.Event.ON_START;
 import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
 
@@ -25,7 +30,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.os.Handler;
-import android.provider.Settings;
+import android.os.HandlerExecutor;
 import android.uwb.UwbManager;
 import android.uwb.UwbManager.AdapterStateCallback;
 
@@ -39,52 +44,68 @@
 import com.android.settings.core.TogglePreferenceController;
 
 import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
 
 /** Controller for "UWB" toggle. */
 public class UwbPreferenceController extends TogglePreferenceController implements
-        AdapterStateCallback, LifecycleObserver {
-    @VisibleForTesting
-    static final String KEY_UWB_SETTINGS = "uwb_settings";
-    @VisibleForTesting
-    UwbManager mUwbManager;
-    @VisibleForTesting
-    boolean mAirplaneModeOn;
-    @VisibleForTesting
+        LifecycleObserver {
+    private final UwbManager mUwbManager;
+    private final UwbUtils mUwbUtils;
+    private boolean mAirplaneModeOn;
+    private /* @AdapterStateCallback.State */ int mState;
+    private /* @AdapterStateCallback.StateChangedReason */ int mStateReason;
     private final BroadcastReceiver mAirplaneModeChangedReceiver;
+    private final AdapterStateCallback mAdapterStateCallback;
     private final Executor mExecutor;
     private final Handler mHandler;
     private Preference mPreference;
 
-    public UwbPreferenceController(Context context, String key) {
+    @VisibleForTesting
+    public UwbPreferenceController(Context context, String key, UwbUtils uwbUtils) {
         super(context, key);
-        mExecutor = Executors.newSingleThreadExecutor();
         mHandler = new Handler(context.getMainLooper());
+        mExecutor = new HandlerExecutor(mHandler);
+        mUwbUtils = uwbUtils;
         if (isUwbSupportedOnDevice()) {
             mUwbManager = context.getSystemService(UwbManager.class);
-        }
-        mAirplaneModeOn = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
-        mAirplaneModeChangedReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                mAirplaneModeOn = Settings.Global.getInt(mContext.getContentResolver(),
-                        Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
+            mAirplaneModeChangedReceiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    mAirplaneModeOn = mUwbUtils.isAirplaneModeOn(mContext);
+                    updateState(mPreference);
+                }
+            };
+            mAdapterStateCallback = (state, reason) -> {
+                mState = state;
+                mStateReason = reason;
                 updateState(mPreference);
-            }
-        };
+            };
+        } else {
+            mUwbManager = null;
+            mAirplaneModeChangedReceiver = null;
+            mAdapterStateCallback = null;
+        }
+    }
+
+    public UwbPreferenceController(Context context, String key) {
+        this(context, key, new UwbUtils());
     }
 
     public boolean isUwbSupportedOnDevice() {
         return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB);
     }
 
+    private boolean isUwbDisabledDueToRegulatory() {
+        return mState == STATE_DISABLED && mStateReason == STATE_CHANGED_REASON_SYSTEM_REGULATION;
+    }
+
     @Override
     public int getAvailabilityStatus() {
         if (!isUwbSupportedOnDevice()) {
             return UNSUPPORTED_ON_DEVICE;
         } else if (mAirplaneModeOn) {
             return DISABLED_DEPENDENT_SETTING;
+        } else if (isUwbDisabledDueToRegulatory()) {
+            return CONDITIONALLY_UNAVAILABLE;
         } else {
             return AVAILABLE;
         }
@@ -101,14 +122,11 @@
         if (!isUwbSupportedOnDevice()) {
             return false;
         }
-        int state = mUwbManager.getAdapterState();
-        return state == STATE_ENABLED_ACTIVE || state == STATE_ENABLED_INACTIVE;
+        return mState == STATE_ENABLED_ACTIVE || mState == STATE_ENABLED_INACTIVE;
     }
 
     @Override
     public boolean setChecked(boolean isChecked) {
-        mAirplaneModeOn = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
         if (isUwbSupportedOnDevice()) {
             if (mAirplaneModeOn) {
                 mUwbManager.setUwbEnabled(false);
@@ -119,32 +137,25 @@
         return true;
     }
 
-    @Override
-    public void onStateChanged(int state, int reason) {
-        Runnable runnable = () -> updateState(mPreference);
-        mHandler.post(runnable);
-    }
-
     /** Called when activity starts being displayed to user. */
     @OnLifecycleEvent(ON_START)
     public void onStart() {
         if (isUwbSupportedOnDevice()) {
-            mUwbManager.registerAdapterStateCallback(mExecutor, this);
-        }
-        if (mAirplaneModeChangedReceiver != null) {
+            mState = mUwbManager.getAdapterState();
+            mStateReason = AdapterStateCallback.STATE_CHANGED_REASON_ERROR_UNKNOWN;
+            mAirplaneModeOn = mUwbUtils.isAirplaneModeOn(mContext);
+            mUwbManager.registerAdapterStateCallback(mExecutor, mAdapterStateCallback);
             mContext.registerReceiver(mAirplaneModeChangedReceiver,
-                    new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
+                    new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED), null, mHandler);
+            refreshSummary(mPreference);
         }
-        refreshSummary(mPreference);
     }
 
     /** Called when activity stops being displayed to user. */
     @OnLifecycleEvent(ON_STOP)
     public void onStop() {
         if (isUwbSupportedOnDevice()) {
-            mUwbManager.unregisterAdapterStateCallback(this);
-        }
-        if (mAirplaneModeChangedReceiver != null) {
+            mUwbManager.unregisterAdapterStateCallback(mAdapterStateCallback);
             mContext.unregisterReceiver(mAirplaneModeChangedReceiver);
         }
     }
@@ -153,13 +164,16 @@
     public void updateState(Preference preference) {
         super.updateState(preference);
         preference.setEnabled(!mAirplaneModeOn);
-        refreshSummary(preference);
+        refreshSummary(mPreference);
     }
 
     @Override
     public CharSequence getSummary() {
         if (mAirplaneModeOn) {
             return mContext.getResources().getString(R.string.uwb_settings_summary_airplane_mode);
+        } else if (isUwbDisabledDueToRegulatory()) {
+            return mContext.getResources().getString(
+                    R.string.uwb_settings_summary_no_uwb_regulatory);
         } else {
             return mContext.getResources().getString(R.string.uwb_settings_summary);
         }
diff --git a/src/com/android/settings/uwb/UwbUtils.java b/src/com/android/settings/uwb/UwbUtils.java
new file mode 100644
index 0000000..940e1af
--- /dev/null
+++ b/src/com/android/settings/uwb/UwbUtils.java
@@ -0,0 +1,34 @@
+/*
+ * 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.uwb;
+
+import android.content.Context;
+import android.provider.Settings;
+
+/**
+ * Utils to help mock static methods in {@link UwbPreferenceController}.
+ */
+public class UwbUtils {
+    /**
+     * Returns whether airplane mode is on or off.
+     */
+    public boolean isAirplaneModeOn(Context context) {
+        return Settings.Global.getInt(context.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
+    }
+}
+
diff --git a/tests/robotests/Android.bp b/tests/robotests/Android.bp
index 9cc8439..94febff 100644
--- a/tests/robotests/Android.bp
+++ b/tests/robotests/Android.bp
@@ -42,6 +42,7 @@
         "androidx.test.core",
         "androidx.test.runner",
         "androidx.test.ext.junit",
+        "frameworks-base-testutils",
         "guava",
         "jsr305",
         "settings-contextual-card-protos-lite",
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
index 37f05bc..16fec09 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java
@@ -55,6 +55,7 @@
 @RunWith(RobolectricTestRunner.class)
 public final class BatteryUsageBreakdownControllerTest {
     private static final String PREF_KEY = "pref_key";
+    private static final String PREF_KEY2 = "pref_key2";
     private static final String PREF_SUMMARY = "fake preference summary";
 
     @Mock
@@ -175,7 +176,24 @@
     }
 
     @Test
-    public void removeAndCacheAllPreferences_buildCacheAndRemoveAllPreference() {
+    public void removeAndCacheAllUnusedPreferences_removePerf_buildCacheAndRemoveAllPreference() {
+        doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
+        doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).getPreference(0);
+        doReturn(PREF_KEY2).when(mBatteryHistEntry).getKey();
+        doReturn(PREF_KEY).when(mPowerGaugePreference).getKey();
+        doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY);
+        // Ensures the testing data is correct.
+        assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty();
+
+        mBatteryUsageBreakdownController.removeAndCacheAllUnusedPreferences();
+
+        assertThat(mBatteryUsageBreakdownController.mPreferenceCache.get(PREF_KEY))
+                .isEqualTo(mPowerGaugePreference);
+        verify(mAppListPreferenceGroup).removePreference(mPowerGaugePreference);
+    }
+
+    @Test
+    public void removeAndCacheAllUnusedPreferences_keepPerf_KeepAllPreference() {
         doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount();
         doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).getPreference(0);
         doReturn(PREF_KEY).when(mBatteryHistEntry).getKey();
@@ -184,11 +202,10 @@
         // Ensures the testing data is correct.
         assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty();
 
-        mBatteryUsageBreakdownController.removeAndCacheAllPreferences();
+        mBatteryUsageBreakdownController.removeAndCacheAllUnusedPreferences();
 
-        assertThat(mBatteryUsageBreakdownController.mPreferenceCache.get(PREF_KEY))
-                .isEqualTo(mPowerGaugePreference);
-        verify(mAppListPreferenceGroup).removeAll();
+        verify(mAppListPreferenceGroup, never()).removePreference(any());
+        assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty();
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/security/MemtagHelperTest.java b/tests/robotests/src/com/android/settings/security/MemtagHelperTest.java
index 4ef7de4..e3be8e2 100644
--- a/tests/robotests/src/com/android/settings/security/MemtagHelperTest.java
+++ b/tests/robotests/src/com/android/settings/security/MemtagHelperTest.java
@@ -33,8 +33,6 @@
 public class MemtagHelperTest {
     private final String mMemtagProperty = "arm64.memtag.bootctl";
     private final String mMemtagSupportedProperty = "ro.arm64.memtag.bootctl_settings_toggle";
-    private final String mDeviceConfigOverride =
-            "persist.device_config.memory_safety_native_boot.bootloader_override";
 
     @Test
     public void isChecked_empty_isFalse() {
@@ -80,7 +78,7 @@
 
     @Test
     public void getAvailabilityStatus_isForcedOff_isDISABLED_DEPENDENT_SETTING() {
-        ShadowSystemProperties.override(mDeviceConfigOverride, "force_off");
+        ShadowSystemProperties.override(MemtagHelper.DEVICE_CONFIG_PROP, "force_off");
         ShadowSystemProperties.override(mMemtagSupportedProperty, "true");
         assertThat(MemtagHelper.getAvailabilityStatus())
                 .isEqualTo(BasePreferenceController.DISABLED_DEPENDENT_SETTING);
@@ -88,7 +86,7 @@
 
     @Test
     public void getAvailabilityStatus_isForcedOn_isDISABLED_DEPENDENT_SETTING() {
-        ShadowSystemProperties.override(mDeviceConfigOverride, "force_on");
+        ShadowSystemProperties.override(MemtagHelper.DEVICE_CONFIG_PROP, "force_on");
         ShadowSystemProperties.override(mMemtagSupportedProperty, "true");
         assertThat(MemtagHelper.getAvailabilityStatus())
                 .isEqualTo(BasePreferenceController.DISABLED_DEPENDENT_SETTING);
@@ -96,7 +94,7 @@
 
     @Test
     public void getAvailabilityStatus_isUnsupported_isUNSUPPORTED_ON_DEVICE() {
-        ShadowSystemProperties.override(mDeviceConfigOverride, "");
+        ShadowSystemProperties.override(MemtagHelper.DEVICE_CONFIG_PROP, "");
         ShadowSystemProperties.override(mMemtagSupportedProperty, "false");
         assertThat(MemtagHelper.getAvailabilityStatus())
                 .isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE);
@@ -127,7 +125,7 @@
     @Config(shadows = {ZygoteShadow.class})
     public void getSummary_memtagAndZygoteSupportsMemoryTagging_memtag_on() {
         ZygoteShadow.setSupportsMemoryTagging(true);
-        ShadowSystemProperties.override(mDeviceConfigOverride, "");
+        ShadowSystemProperties.override(MemtagHelper.DEVICE_CONFIG_PROP, "");
         ShadowSystemProperties.override(mMemtagProperty, "memtag");
         assertThat(MemtagHelper.getSummary()).isEqualTo(R.string.memtag_on);
     }
@@ -136,7 +134,7 @@
     @Config(shadows = {ZygoteShadow.class})
     public void getSummary_noMemtagAndZygoteSupportsMemoryTagging_memtag_off_pending() {
         ZygoteShadow.setSupportsMemoryTagging(true);
-        ShadowSystemProperties.override(mDeviceConfigOverride, "");
+        ShadowSystemProperties.override(MemtagHelper.DEVICE_CONFIG_PROP, "");
         ShadowSystemProperties.override(mMemtagProperty, "");
         assertThat(MemtagHelper.getSummary()).isEqualTo(R.string.memtag_off_pending);
     }
@@ -145,7 +143,7 @@
     @Config(shadows = {ZygoteShadow.class})
     public void getSummary_noMemtagAndNoZygoteSupportsMemoryTagging_memtag_off() {
         ZygoteShadow.setSupportsMemoryTagging(false);
-        ShadowSystemProperties.override(mDeviceConfigOverride, "");
+        ShadowSystemProperties.override(MemtagHelper.DEVICE_CONFIG_PROP, "");
         ShadowSystemProperties.override(mMemtagProperty, "");
         assertThat(MemtagHelper.getSummary()).isEqualTo(R.string.memtag_off);
     }
@@ -154,7 +152,7 @@
     @Config(shadows = {ZygoteShadow.class})
     public void getSummary_memtagAndNoZygoteSupportsMemoryTagging_memtag_on_pending() {
         ZygoteShadow.setSupportsMemoryTagging(false);
-        ShadowSystemProperties.override(mDeviceConfigOverride, "");
+        ShadowSystemProperties.override(MemtagHelper.DEVICE_CONFIG_PROP, "");
         ShadowSystemProperties.override(mMemtagProperty, "memtag");
         assertThat(MemtagHelper.getSummary()).isEqualTo(R.string.memtag_on_pending);
     }
@@ -163,7 +161,7 @@
     @Config(shadows = {ZygoteShadow.class})
     public void getSummary_forceOffOverride_memtag_force_off() {
         ZygoteShadow.setSupportsMemoryTagging(false);
-        ShadowSystemProperties.override(mDeviceConfigOverride, "force_off");
+        ShadowSystemProperties.override(MemtagHelper.DEVICE_CONFIG_PROP, "force_off");
         ShadowSystemProperties.override(mMemtagProperty, "memtag");
         assertThat(MemtagHelper.getSummary()).isEqualTo(R.string.memtag_force_off);
     }
@@ -172,20 +170,20 @@
     @Config(shadows = {ZygoteShadow.class})
     public void getSummary_forceOffOverride_memtag_force_on() {
         ZygoteShadow.setSupportsMemoryTagging(false);
-        ShadowSystemProperties.override(mDeviceConfigOverride, "force_on");
+        ShadowSystemProperties.override(MemtagHelper.DEVICE_CONFIG_PROP, "force_on");
         ShadowSystemProperties.override(mMemtagProperty, "memtag");
         assertThat(MemtagHelper.getSummary()).isEqualTo(R.string.memtag_force_on);
     }
 
     @Test
     public void isForcedOn_forceOnOverride_isTrue() {
-        ShadowSystemProperties.override(mDeviceConfigOverride, "force_on");
+        ShadowSystemProperties.override(MemtagHelper.DEVICE_CONFIG_PROP, "force_on");
         assertThat(MemtagHelper.isForcedOn()).isTrue();
     }
 
     @Test
     public void isForcedOff_forceOffOverride_isTrue() {
-        ShadowSystemProperties.override(mDeviceConfigOverride, "force_off");
+        ShadowSystemProperties.override(MemtagHelper.DEVICE_CONFIG_PROP, "force_off");
         assertThat(MemtagHelper.isForcedOff()).isTrue();
     }
 }
diff --git a/tests/robotests/src/com/android/settings/users/TimeoutToDockUserPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/users/TimeoutToDockUserPreferenceControllerTest.java
index 2e7e2d7..3d8e893 100644
--- a/tests/robotests/src/com/android/settings/users/TimeoutToDockUserPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/users/TimeoutToDockUserPreferenceControllerTest.java
@@ -27,6 +27,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 
 import androidx.test.core.app.ApplicationProvider;
@@ -41,6 +42,8 @@
 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.annotation.Config;
 
@@ -51,6 +54,9 @@
     private Resources mResources;
     private TimeoutToDockUserPreferenceController mController;
 
+    @Mock
+    private UserManager mUserManager;
+
     private static final String FAKE_PREFERENCE_KEY = "timeout_to_dock_user_preference";
 
     private String[] mEntries;
@@ -58,9 +64,12 @@
 
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
         mContext = spy(ApplicationProvider.getApplicationContext());
         mResources = spy(mContext.getResources());
         doReturn(mResources).when(mContext).getResources();
+        when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
 
         mEntries = mResources.getStringArray(
                 R.array.switch_to_dock_user_when_docked_timeout_entries);
@@ -78,6 +87,9 @@
         Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.USER_SWITCHER_ENABLED,
                 1);
 
+        // User switching not blocked.
+        when(mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)).thenReturn(false);
+
         // Set to user 1;
         ShadowUserHandle.setUid(1);
     }
@@ -107,6 +119,14 @@
     }
 
     @Test
+    public void getAvailabilityStatus_userSwitchingBlocked_returnConditionallyUnavailable() {
+        when(mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)).thenReturn(true);
+
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(
+                BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
+    }
+
+    @Test
     public void getAvailabilityStatus_isCurrentlyMainUser_returnDisabledForUser() {
         when(Utils.canCurrentUserDream(mContext)).thenReturn(true);
 
diff --git a/tests/robotests/src/com/android/settings/uwb/UwbPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/uwb/UwbPreferenceControllerTest.java
index 94d797a..23aca51 100644
--- a/tests/robotests/src/com/android/settings/uwb/UwbPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/uwb/UwbPreferenceControllerTest.java
@@ -16,110 +16,157 @@
 
 package com.android.settings.uwb;
 
+import static android.uwb.UwbManager.AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_POLICY;
+import static android.uwb.UwbManager.AdapterStateCallback.STATE_CHANGED_REASON_SYSTEM_REGULATION;
+import static android.uwb.UwbManager.AdapterStateCallback.STATE_DISABLED;
+import static android.uwb.UwbManager.AdapterStateCallback.STATE_ENABLED_ACTIVE;
+import static android.uwb.UwbManager.AdapterStateCallback.STATE_ENABLED_INACTIVE;
+
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyString;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.test.TestLooper;
 import android.uwb.UwbManager;
 
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
 import com.android.settings.core.BasePreferenceController;
 
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
 
 /** Unit tests for UWB preference toggle. */
 @RunWith(RobolectricTestRunner.class)
 public class UwbPreferenceControllerTest {
+    private static final String TEST_SUMMARY = "uwb";
+    private static final String TEST_AIRPLANE_SUMMARY = "apm_uwb";
+    private static final String TEST_NO_UWB_REGULATORY_SUMMARY = "regulatory_uwb";
     @Rule
     public MockitoRule rule = MockitoJUnit.rule();
 
+    @Mock
     private Context mContext;
+    @Mock
     private PackageManager mPackageManager;
     private UwbPreferenceController mController;
-
+    private ArgumentCaptor<UwbManager.AdapterStateCallback> mAdapterStateCallbackArgumentCaptor =
+            ArgumentCaptor.forClass(UwbManager.AdapterStateCallback.class);
+    private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverArgumentCaptor =
+            ArgumentCaptor.forClass(BroadcastReceiver.class);
+    private TestLooper mTestLooper;
     @Mock
     private UwbManager mUwbManager;
+    @Mock
+    private UwbUtils mUwbUtils;
+    @Mock
+    private Preference mPreference;
+    @Mock
+    private PreferenceScreen mPreferenceScreen;
+    @Mock
+    private Resources mResources;
 
     @Before
-    public void setUp() {
-        mContext = spy(RuntimeEnvironment.application);
-        mPackageManager = spy(mContext.getPackageManager());
-        mController = new UwbPreferenceController(mContext, "uwb_settings");
-        mController.mUwbManager = mUwbManager;
-    }
-
-    @Test
-    public void getAvailabilityStatus_uwbDisabled_shouldReturnDisabled() {
+    public void setUp() throws Exception {
+        mTestLooper = new TestLooper();
         doReturn(mPackageManager).when(mContext).getPackageManager();
         doReturn(true).when(mPackageManager)
                 .hasSystemFeature(PackageManager.FEATURE_UWB);
-        mController.mAirplaneModeOn = true;
+        when(mResources.getString(R.string.uwb_settings_summary))
+                .thenReturn(TEST_SUMMARY);
+        when(mResources.getString(R.string.uwb_settings_summary_airplane_mode))
+                .thenReturn(TEST_AIRPLANE_SUMMARY);
+        when(mResources.getString(R.string.uwb_settings_summary_no_uwb_regulatory))
+                .thenReturn(TEST_NO_UWB_REGULATORY_SUMMARY);
+        when(mContext.getMainLooper()).thenReturn(mTestLooper.getLooper());
+        when(mContext.getSystemService(UwbManager.class)).thenReturn(mUwbManager);
+        when(mContext.getResources()).thenReturn(mResources);
+        when(mUwbUtils.isAirplaneModeOn(any())).thenReturn(false);
+        doReturn(STATE_ENABLED_ACTIVE).when(mUwbManager).getAdapterState();
+        mController = new UwbPreferenceController(mContext, "uwb_settings", mUwbUtils);
+        when(mPreferenceScreen.findPreference(anyString())).thenReturn(mPreference);
+        mController.displayPreference(mPreferenceScreen);
+    }
 
+    private void startControllerAndCaptureCallbacks() {
+        mController.onStart();
+        verify(mContext).registerReceiver(
+                mBroadcastReceiverArgumentCaptor.capture(), any(), any(), any());
+        verify(mUwbManager).registerAdapterStateCallback(
+                any(), mAdapterStateCallbackArgumentCaptor.capture());
+    }
+
+    @Test
+    public void getAvailabilityStatus_uwbDisabled_shouldReturnDisabled() throws Exception {
+        when(mUwbUtils.isAirplaneModeOn(any())).thenReturn(true);
+        startControllerAndCaptureCallbacks();
         assertThat(mController.getAvailabilityStatus())
                 .isEqualTo(BasePreferenceController.DISABLED_DEPENDENT_SETTING);
     }
 
     @Test
-    public void getAvailabilityStatus_uwbShown_shouldReturnAvailable() {
-        doReturn(mPackageManager).when(mContext).getPackageManager();
-        doReturn(true).when(mPackageManager)
-                .hasSystemFeature(PackageManager.FEATURE_UWB);
-        mController.mAirplaneModeOn = false;
-
+    public void getAvailabilityStatus_uwbShown_shouldReturnAvailable() throws Exception {
+        when(mUwbUtils.isAirplaneModeOn(any())).thenReturn(false);
+        startControllerAndCaptureCallbacks();
         assertThat(mController.getAvailabilityStatus())
                 .isEqualTo(BasePreferenceController.AVAILABLE);
     }
 
     @Test
     public void getAvailabilityStatus_uwbNotShown_shouldReturnUnsupported() {
-        doReturn(mPackageManager).when(mContext).getPackageManager();
         doReturn(false).when(mPackageManager)
                 .hasSystemFeature(PackageManager.FEATURE_UWB);
 
+        mController.onStart();
+        verify(mContext, never()).registerReceiver(any(), any(), any(), any());
+        verify(mUwbManager, never()).registerAdapterStateCallback(any(), any());
         assertThat(mController.getAvailabilityStatus())
                 .isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE);
     }
 
     @Test
     public void isChecked_uwbEnabled_shouldReturnTrue() {
-        doReturn(mPackageManager).when(mContext).getPackageManager();
-        doReturn(true).when(mPackageManager)
-                .hasSystemFeature(PackageManager.FEATURE_UWB);
-        doReturn(mController.STATE_ENABLED_ACTIVE).when(mUwbManager).getAdapterState();
+        doReturn(STATE_ENABLED_ACTIVE).when(mUwbManager).getAdapterState();
 
+        startControllerAndCaptureCallbacks();
         assertThat(mController.isChecked()).isTrue();
     }
 
     @Test
     public void isChecked_uwbDisabled_shouldReturnFalse() {
-        doReturn(mPackageManager).when(mContext).getPackageManager();
-        doReturn(true).when(mPackageManager)
-                .hasSystemFeature(PackageManager.FEATURE_UWB);
-        doReturn(mController.STATE_DISABLED).when(mUwbManager).getAdapterState();
+        doReturn(STATE_DISABLED).when(mUwbManager).getAdapterState();
 
+        startControllerAndCaptureCallbacks();
         assertThat(mController.isChecked()).isFalse();
     }
 
     @Test
     public void setChecked_uwbDisabled_shouldEnableUwb() {
         clearInvocations(mUwbManager);
-        doReturn(mPackageManager).when(mContext).getPackageManager();
-        doReturn(true).when(mPackageManager)
-                .hasSystemFeature(PackageManager.FEATURE_UWB);
 
+        startControllerAndCaptureCallbacks();
         mController.setChecked(true);
 
         verify(mUwbManager).setUwbEnabled(true);
@@ -129,14 +176,65 @@
     @Test
     public void setChecked_uwbEnabled_shouldDisableUwb() {
         clearInvocations(mUwbManager);
-        doReturn(mPackageManager).when(mContext).getPackageManager();
-        doReturn(true).when(mPackageManager)
-                .hasSystemFeature(PackageManager.FEATURE_UWB);
 
+        startControllerAndCaptureCallbacks();
         mController.setChecked(false);
 
         verify(mUwbManager).setUwbEnabled(false);
         verify(mUwbManager, never()).setUwbEnabled(true);
     }
+
+    @Test
+    public void updateStateAndSummary_uwbDisabledAndEnabled() {
+        startControllerAndCaptureCallbacks();
+        clearInvocations(mUwbManager, mPreference);
+
+        mAdapterStateCallbackArgumentCaptor.getValue().onStateChanged(
+                STATE_DISABLED, STATE_CHANGED_REASON_SYSTEM_POLICY);
+
+        verify(mPreference).setEnabled(true);
+        assertThat(mController.isChecked()).isFalse();
+        verify(mPreference, times(2)).setSummary(TEST_SUMMARY);
+
+        mAdapterStateCallbackArgumentCaptor.getValue().onStateChanged(
+                STATE_ENABLED_INACTIVE, STATE_CHANGED_REASON_SYSTEM_POLICY);
+
+        verify(mPreference, times(2)).setEnabled(true);
+        assertThat(mController.isChecked()).isTrue();
+        verify(mPreference, times(4)).setSummary(TEST_SUMMARY);
+    }
+
+    @Test
+    public void updateStateAndSummary_apmEnabledAndDisabled() {
+        startControllerAndCaptureCallbacks();
+        clearInvocations(mUwbManager, mPreference);
+
+        when(mUwbUtils.isAirplaneModeOn(any())).thenReturn(true);
+        mBroadcastReceiverArgumentCaptor.getValue().onReceive(
+                mock(Context.class), mock(Intent.class));
+
+        verify(mPreference).setEnabled(false);
+        verify(mPreference, times(2)).setSummary(TEST_AIRPLANE_SUMMARY);
+
+        when(mUwbUtils.isAirplaneModeOn(any())).thenReturn(false);
+        mBroadcastReceiverArgumentCaptor.getValue().onReceive(
+                mock(Context.class), mock(Intent.class));
+
+        verify(mPreference).setEnabled(true);
+        verify(mPreference, times(2)).setSummary(TEST_SUMMARY);
+    }
+
+    @Test
+    public void updateStateAndSummary_uwbDisabledDueToRegulatory() {
+        startControllerAndCaptureCallbacks();
+        clearInvocations(mUwbManager, mPreference);
+
+        mAdapterStateCallbackArgumentCaptor.getValue().onStateChanged(
+                STATE_DISABLED, STATE_CHANGED_REASON_SYSTEM_REGULATION);
+
+        assertThat(mController.getAvailabilityStatus())
+                .isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
+        verify(mPreference, times(2)).setSummary(TEST_NO_UWB_REGULATORY_SUMMARY);
+    }
 }