Merge "Add content description string for '<1%'." into main
diff --git a/aconfig/settings_bluetooth_declarations.aconfig b/aconfig/settings_bluetooth_declarations.aconfig
index 3e771cd..3d4f415 100644
--- a/aconfig/settings_bluetooth_declarations.aconfig
+++ b/aconfig/settings_bluetooth_declarations.aconfig
@@ -13,4 +13,14 @@
   namespace: "pixel_cross_device_control"
   description: "Gates whether to enable checker for bluetooth profile toggle visibility"
   bug: "321178209"
+}
+
+flag {
+  name: "hide_le_audio_toggle_for_le_audio_only_device"
+  namespace: "pixel_cross_device_control"
+  description: "Gates whether to hide LeAudio toggle for LeAudio-only device"
+  bug: "333827147"
+  metadata {
+      purpose: PURPOSE_BUGFIX
+  }
 }
\ No newline at end of file
diff --git a/aconfig/settings_flag_declarations.aconfig b/aconfig/settings_flag_declarations.aconfig
index ac59f1b..c7a21e9 100644
--- a/aconfig/settings_flag_declarations.aconfig
+++ b/aconfig/settings_flag_declarations.aconfig
@@ -35,3 +35,10 @@
     description: "Feature flag to enable injection into PreferenceCategory."
     bug: "333547416"
 }
+
+flag {
+    name: "slices_retirement"
+    namespace: "android_settings"
+    description: "Feature flag to remove relevant slices dependencies."
+    bug: "297367302"
+}
diff --git a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
index a92b755..ca3786a 100644
--- a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
+++ b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
@@ -115,6 +115,7 @@
     private @Nullable Delegate mDelegate = null;
     private @Nullable String mFlagOverrideForTest = null;
     private @Nullable PreferenceScreen mPreferenceScreen = null;
+    private @Nullable PreferenceGroup mPreferenceGroup = null;
 
     private Optional<Boolean> mSimulateHiddenForTests = Optional.empty();
     private boolean mIsWorkProfile = false;
@@ -161,12 +162,6 @@
             return UNSUPPORTED_ON_DEVICE;
         }
 
-        // If there is no top provider or any providers in the list then
-        // we should hide this pref.
-        if (isHiddenDueToNoProviderSet()) {
-            return CONDITIONALLY_UNAVAILABLE;
-        }
-
         if (!hasNonPrimaryServices()) {
             return CONDITIONALLY_UNAVAILABLE;
         }
@@ -355,24 +350,11 @@
         }
 
         // Get the list of new providers and components.
-        List<CredentialProviderInfo> newProviders =
+        setAvailableServices(
                 mCredentialManager.getCredentialProviderServices(
                         getUser(),
-                        CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN);
-        Set<ComponentName> newComponents = buildComponentNameSet(newProviders, false);
-        Set<ComponentName> newPrimaryComponents = buildComponentNameSet(newProviders, true);
-
-        // Get the list of old components
-        Set<ComponentName> oldComponents = buildComponentNameSet(mServices, false);
-        Set<ComponentName> oldPrimaryComponents = buildComponentNameSet(mServices, true);
-
-        // If the sets are equal then don't update the UI.
-        if (oldComponents.equals(newComponents)
-                && oldPrimaryComponents.equals(newPrimaryComponents)) {
-            return;
-        }
-
-        setAvailableServices(newProviders, null);
+                        CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_INCLUDING_HIDDEN),
+                null);
 
         if (mPreferenceScreen != null) {
             displayPreference(mPreferenceScreen);
@@ -396,11 +378,7 @@
     }
 
     @VisibleForTesting
-    public boolean isHiddenDueToNoProviderSet() {
-        return isHiddenDueToNoProviderSet(getProviders());
-    }
-
-    private boolean isHiddenDueToNoProviderSet(
+    public boolean isHiddenDueToNoProviderSet(
             Pair<List<CombinedProviderInfo>, CombinedProviderInfo> providerPair) {
         if (mSimulateHiddenForTests.isPresent()) {
             return mSimulateHiddenForTests.get();
@@ -444,17 +422,67 @@
 
     @Override
     public void displayPreference(PreferenceScreen screen) {
-        super.displayPreference(screen);
+        final String prefKey = getPreferenceKey();
+        if (TextUtils.isEmpty(prefKey)) {
+            Log.w(TAG, "Skipping displayPreference because key is empty");
+            return;
+        }
 
-        // Since the UI is being cleared, clear any refs.
+        // Store this reference for later.
+        if (mPreferenceScreen == null) {
+            mPreferenceScreen = screen;
+            mPreferenceGroup = screen.findPreference(prefKey);
+        }
+
+        final Pair<List<CombinedProviderInfo>, CombinedProviderInfo> providerPair = getProviders();
+
+        maybeUpdateListOfPrefs(providerPair);
+        maybeUpdatePreferenceVisibility(providerPair);
+    }
+
+    private void maybeUpdateListOfPrefs(
+            Pair<List<CombinedProviderInfo>, CombinedProviderInfo> providerPair) {
+        if (mPreferenceScreen == null || mPreferenceGroup == null) {
+            return;
+        }
+
+        // Build the new list of prefs.
+        Map<String, CombiPreference> newPrefs =
+                buildPreferenceList(mPreferenceScreen.getContext(), providerPair);
+
+        // Determine if we need to update the prefs.
+        Set<String> existingPrefPackageNames = mPrefs.keySet();
+        if (existingPrefPackageNames.equals(newPrefs.keySet())) {
+            return;
+        }
+
+        // Since the UI is being cleared, clear any refs and prefs.
         mPrefs.clear();
+        mPreferenceGroup.removeAll();
 
-        mPreferenceScreen = screen;
-        PreferenceGroup group = screen.findPreference(getPreferenceKey());
-        group.removeAll();
+        // Populate the preference list with new data.
+        mPrefs.putAll(newPrefs);
+        for (CombiPreference pref : newPrefs.values()) {
+            mPreferenceGroup.addPreference(pref);
+        }
+    }
 
-        Context context = screen.getContext();
-        mPrefs.putAll(buildPreferenceList(context, group));
+    private void maybeUpdatePreferenceVisibility(
+            Pair<List<CombinedProviderInfo>, CombinedProviderInfo> providerPair) {
+        if (mPreferenceScreen == null || mPreferenceGroup == null) {
+            return;
+        }
+
+        final boolean isAvailable =
+                (getAvailabilityStatus() == AVAILABLE) && !isHiddenDueToNoProviderSet(providerPair);
+
+        if (isAvailable) {
+            mPreferenceScreen.addPreference(mPreferenceGroup);
+            mPreferenceGroup.setVisible(true);
+        } else {
+            mPreferenceScreen.removePreference(mPreferenceGroup);
+            mPreferenceGroup.setVisible(false);
+        }
     }
 
     /**
@@ -511,9 +539,9 @@
     /** Aggregates the list of services and builds a list of UI prefs to show. */
     @VisibleForTesting
     public @NonNull Map<String, CombiPreference> buildPreferenceList(
-            @NonNull Context context, @NonNull PreferenceGroup group) {
-        // Get the providers and extract the values.
-        Pair<List<CombinedProviderInfo>, CombinedProviderInfo> providerPair = getProviders();
+            @NonNull Context context,
+            @NonNull Pair<List<CombinedProviderInfo>, CombinedProviderInfo> providerPair) {
+        // Extract the values.
         CombinedProviderInfo topProvider = providerPair.second;
         List<CombinedProviderInfo> providers = providerPair.first;
 
@@ -554,7 +582,6 @@
                             combinedInfo.getSettingsActivity(),
                             combinedInfo.getDeviceAdminRestrictions(context, getUser()));
             output.put(packageName, pref);
-            group.addPreference(pref);
         }
 
         // Set the visibility if we have services.
@@ -1023,11 +1050,12 @@
             public void onClick(View buttonView) {
                 // Forward the event.
                 if (mSwitch != null && mOnClickListener != null) {
-                    if (!mOnClickListener.onCheckChanged(CombiPreference.this, mSwitch.isChecked())) {
-                      // The update was not successful since there were too
-                      // many enabled providers to manually reset any state.
-                      mChecked = false;
-                      mSwitch.setChecked(false);
+                    if (!mOnClickListener.onCheckChanged(
+                            CombiPreference.this, mSwitch.isChecked())) {
+                        // The update was not successful since there were too
+                        // many enabled providers to manually reset any state.
+                        mChecked = false;
+                        mSwitch.setChecked(false);
                     }
                 }
             }
@@ -1083,8 +1111,10 @@
 
             if (mSwitch != null && !TextUtils.isEmpty(appName)) {
                 mSwitch.setContentDescription(
-                    getContext().getString(
-                        R.string.credman_on_off_switch_content_description, appName));
+                        getContext()
+                                .getString(
+                                        R.string.credman_on_off_switch_content_description,
+                                        appName));
             }
         }
 
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
index 943d99b..3fa811a 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
@@ -43,6 +43,7 @@
 import com.android.settingslib.bluetooth.BluetoothUtils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.HeadsetProfile;
+import com.android.settingslib.bluetooth.HearingAidProfile;
 import com.android.settingslib.bluetooth.LeAudioProfile;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfile;
@@ -512,6 +513,19 @@
         refresh();
     }
 
+    private boolean isLeAudioOnlyDevice() {
+        if (mCachedDevice.getProfiles().stream()
+                .noneMatch(profile -> profile instanceof LeAudioProfile)) {
+            return false;
+        }
+        return mCachedDevice.getProfiles().stream()
+                .noneMatch(
+                        profile ->
+                                profile instanceof HearingAidProfile
+                                        || profile instanceof A2dpProfile
+                                        || profile instanceof HeadsetProfile);
+    }
+
     private void updateLeAudioConfig() {
         mIsLeContactSharingEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
                 SettingsUIDeviceConfig.BT_LE_AUDIO_CONTACT_SHARING_ENABLED, true);
@@ -520,6 +534,13 @@
         boolean isLeEnabledByDefault =
                 SystemProperties.getBoolean(LE_AUDIO_CONNECTION_BY_DEFAULT_PROPERTY, true);
         mIsLeAudioToggleEnabled = isLeAudioToggleVisible || isLeEnabledByDefault;
+        if (Flags.hideLeAudioToggleForLeAudioOnlyDevice() && isLeAudioOnlyDevice()) {
+            mIsLeAudioToggleEnabled = false;
+            Log.d(
+                    TAG,
+                    "Hide LeAudio toggle for LeAudio-only Device: "
+                            + mCachedDevice.getDevice().getAnonymizedAddress());
+        }
         Log.d(TAG, "BT_LE_AUDIO_CONTACT_SHARING_ENABLED:" + mIsLeContactSharingEnabled
                 + ", LE_AUDIO_TOGGLE_VISIBLE_PROPERTY:" + isLeAudioToggleVisible
                 + ", LE_AUDIO_CONNECTION_BY_DEFAULT_PROPERTY:" + isLeEnabledByDefault);
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
index 35a173b..dd30e69 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java
@@ -39,6 +39,9 @@
     /** Check whether the battery tips card is enabled in the battery usage page */
     boolean isBatteryTipsEnabled();
 
+    /** Check whether to log the optimization mode of app entry in period job */
+    boolean isAppOptimizationModeLogged();
+
     /**
      * Returns a threshold (in milliseconds) for the minimal screen on time in battery usage list
      */
diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
index f0616ed..5c66dbc 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java
@@ -84,6 +84,11 @@
     }
 
     @Override
+    public boolean isAppOptimizationModeLogged() {
+        return false;
+    }
+
+    @Override
     public double getBatteryUsageListScreenOnTimeThresholdInMs() {
         return 0;
     }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryOptimizationModeCache.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryOptimizationModeCache.java
new file mode 100644
index 0000000..6b35fb9
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryOptimizationModeCache.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.fuelgauge.batteryusage;
+
+import android.content.Context;
+import android.util.ArrayMap;
+
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settings.fuelgauge.BatteryOptimizeUtils;
+import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
+
+import java.util.Map;
+
+/** A cache to log battery optimization mode of an app */
+final class BatteryOptimizationModeCache {
+    private static final String TAG = "BatteryOptimizationModeCache";
+
+    @VisibleForTesting final Map<Integer, BatteryOptimizationMode> mBatteryOptimizeModeCacheMap;
+
+    private final Context mContext;
+
+    BatteryOptimizationModeCache(final Context context) {
+        mContext = context;
+        mBatteryOptimizeModeCacheMap = new ArrayMap<>();
+        PowerAllowlistBackend.getInstance(mContext).refreshList();
+    }
+
+    BatteryOptimizationMode getBatteryOptimizeMode(final int uid, final String packageName) {
+        if (!mBatteryOptimizeModeCacheMap.containsKey(uid)) {
+            final BatteryOptimizeUtils batteryOptimizeUtils =
+                    new BatteryOptimizeUtils(mContext, uid, packageName);
+            mBatteryOptimizeModeCacheMap.put(
+                    uid,
+                    BatteryOptimizationMode.forNumber(
+                            batteryOptimizeUtils.getAppOptimizationMode(/* refreshList= */ false)));
+        }
+        return mBatteryOptimizeModeCacheMap.get(uid);
+    }
+}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
index 870faec..26bb6dd 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageDataLoader.java
@@ -27,6 +27,7 @@
 import androidx.annotation.VisibleForTesting;
 
 import com.android.settings.fuelgauge.BatteryUsageHistoricalLogEntry.Action;
+import com.android.settings.fuelgauge.PowerUsageFeatureProvider;
 import com.android.settings.fuelgauge.batteryusage.bugreport.BatteryUsageLogUtils;
 import com.android.settings.overlay.FeatureFactory;
 
@@ -124,9 +125,15 @@
                         userIdsSeries,
                         /* isFromPeriodJob= */ true,
                         batteryDiffDataMap -> {
+                            final PowerUsageFeatureProvider featureProvider =
+                                    FeatureFactory.getFeatureFactory()
+                                            .getPowerUsageFeatureProvider();
                             DatabaseUtils.sendBatteryUsageSlotData(
                                     context,
-                                    ConvertUtils.convertToBatteryUsageSlotList(batteryDiffDataMap));
+                                    ConvertUtils.convertToBatteryUsageSlotList(
+                                            context,
+                                            batteryDiffDataMap,
+                                            featureProvider.isAppOptimizationModeLogged()));
                             if (batteryDiffDataMap.values().stream()
                                     .anyMatch(
                                             data ->
@@ -135,12 +142,10 @@
                                                                             .isEmpty()
                                                                     || !data.getAppDiffEntryList()
                                                                             .isEmpty()))) {
-                                FeatureFactory.getFeatureFactory()
-                                        .getPowerUsageFeatureProvider()
-                                        .detectPowerAnomaly(
-                                                context,
-                                                /* displayDrain= */ 0,
-                                                DetectRequestSourceType.TYPE_DATA_LOADER);
+                                featureProvider.detectPowerAnomaly(
+                                        context,
+                                        /* displayDrain= */ 0,
+                                        DetectRequestSourceType.TYPE_DATA_LOADER);
                             }
                         });
         if (batteryLevelData == null) {
diff --git a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
index df9f063..1cbe6da 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/ConvertUtils.java
@@ -345,10 +345,15 @@
 
     /** Converts from {@link Map<Long, BatteryDiffData>} to {@link List<BatteryUsageSlot>} */
     public static List<BatteryUsageSlot> convertToBatteryUsageSlotList(
-            final Map<Long, BatteryDiffData> batteryDiffDataMap) {
+            final Context context,
+            final Map<Long, BatteryDiffData> batteryDiffDataMap,
+            final boolean isAppOptimizationModeLogged) {
         List<BatteryUsageSlot> batteryUsageSlotList = new ArrayList<>();
+        final BatteryOptimizationModeCache optimizationModeCache =
+                isAppOptimizationModeLogged ? new BatteryOptimizationModeCache(context) : null;
         for (BatteryDiffData batteryDiffData : batteryDiffDataMap.values()) {
-            batteryUsageSlotList.add(convertToBatteryUsageSlot(batteryDiffData));
+            batteryUsageSlotList.add(
+                    convertToBatteryUsageSlot(batteryDiffData, optimizationModeCache));
         }
         return batteryUsageSlotList;
     }
@@ -479,9 +484,10 @@
         }
     }
 
-
     @VisibleForTesting
-    static BatteryUsageDiff convertToBatteryUsageDiff(BatteryDiffEntry batteryDiffEntry) {
+    static BatteryUsageDiff convertToBatteryUsageDiff(
+            final BatteryDiffEntry batteryDiffEntry,
+            final @Nullable BatteryOptimizationModeCache optimizationModeCache) {
         BatteryUsageDiff.Builder builder =
                 BatteryUsageDiff.newBuilder()
                         .setUid(batteryDiffEntry.mUid)
@@ -511,11 +517,18 @@
         if (batteryDiffEntry.mLegacyLabel != null) {
             builder.setLabel(batteryDiffEntry.mLegacyLabel);
         }
+        // Log the battery optimization mode of AppEntry while converting to batteryUsageSlot.
+        if (optimizationModeCache != null && !batteryDiffEntry.isSystemEntry()) {
+            builder.setAppOptimizationMode(
+                    optimizationModeCache.getBatteryOptimizeMode(
+                            (int) batteryDiffEntry.mUid, batteryDiffEntry.getPackageName()));
+        }
         return builder.build();
     }
 
     private static BatteryUsageSlot convertToBatteryUsageSlot(
-            final BatteryDiffData batteryDiffData) {
+            final BatteryDiffData batteryDiffData,
+            final @Nullable BatteryOptimizationModeCache optimizationModeCache) {
         if (batteryDiffData == null) {
             return BatteryUsageSlot.getDefaultInstance();
         }
@@ -527,10 +540,11 @@
                         .setEndBatteryLevel(batteryDiffData.getEndBatteryLevel())
                         .setScreenOnTime(batteryDiffData.getScreenOnTime());
         for (BatteryDiffEntry batteryDiffEntry : batteryDiffData.getAppDiffEntryList()) {
-            builder.addAppUsage(convertToBatteryUsageDiff(batteryDiffEntry));
+            builder.addAppUsage(convertToBatteryUsageDiff(batteryDiffEntry, optimizationModeCache));
         }
         for (BatteryDiffEntry batteryDiffEntry : batteryDiffData.getSystemDiffEntryList()) {
-            builder.addSystemUsage(convertToBatteryUsageDiff(batteryDiffEntry));
+            builder.addSystemUsage(
+                    convertToBatteryUsageDiff(batteryDiffEntry, /* optimizationModeCache= */ null));
         }
         return builder.build();
     }
diff --git a/src/com/android/settings/fuelgauge/protos/battery_usage_slot.proto b/src/com/android/settings/fuelgauge/protos/battery_usage_slot.proto
index 7f67770..4e3e3c4 100644
--- a/src/com/android/settings/fuelgauge/protos/battery_usage_slot.proto
+++ b/src/com/android/settings/fuelgauge/protos/battery_usage_slot.proto
@@ -14,6 +14,13 @@
   repeated BatteryUsageDiff system_usage = 7;
 }
 
+enum BatteryOptimizationMode {
+  MODE_UNKNOWN = 0;
+  MODE_RESTRICTED = 1;
+  MODE_UNRESTRICTED = 2;
+  MODE_OPTIMIZED = 3;
+}
+
 message BatteryUsageDiff {
   optional int64 uid = 1;
   optional int64 user_id = 2;
@@ -32,4 +39,5 @@
   optional int64 background_usage_time = 15;
   optional int64 screen_on_time = 16;
   optional int64 foreground_service_usage_time = 17;
+  optional BatteryOptimizationMode app_optimization_mode = 18;
 }
diff --git a/src/com/android/settings/notification/modes/ZenModesBackend.java b/src/com/android/settings/notification/modes/ZenModesBackend.java
index 388f13b..d6a2ef5 100644
--- a/src/com/android/settings/notification/modes/ZenModesBackend.java
+++ b/src/com/android/settings/notification/modes/ZenModesBackend.java
@@ -141,7 +141,7 @@
 
     void deactivateMode(ZenMode mode) {
         if (mode.isManualDnd()) {
-            // TODO: b/326061620 - This shouldn't snooze any rules that are active.
+            // When calling with fromUser=true this will not snooze other modes.
             mNotificationManager.setZenMode(Settings.Global.ZEN_MODE_OFF, null, TAG,
                     /* fromUser= */ true);
         } else {
diff --git a/src/com/android/settings/security/ScreenPinningSettings.java b/src/com/android/settings/security/ScreenPinningSettings.java
index 4d3743c..45c3d84 100644
--- a/src/com/android/settings/security/ScreenPinningSettings.java
+++ b/src/com/android/settings/security/ScreenPinningSettings.java
@@ -240,9 +240,9 @@
             mUseScreenLock.setChecked(isScreenLockUsed());
             mUseScreenLock.setTitle(getCurrentSecurityTitle(mLockPatternUtils));
         } else {
-            mFooterPreference.setSummary(getAppPinningContent());
             mUseScreenLock.setEnabled(false);
         }
+        mFooterPreference.setSummary(getAppPinningContent());
     }
 
     private boolean isGuestModeSupported() {
diff --git a/src/com/android/settings/spa/network/SimOnboardingLabelSim.kt b/src/com/android/settings/spa/network/SimOnboardingLabelSim.kt
index 66b7d4b..2b40a91 100644
--- a/src/com/android/settings/spa/network/SimOnboardingLabelSim.kt
+++ b/src/com/android/settings/spa/network/SimOnboardingLabelSim.kt
@@ -85,13 +85,16 @@
     onboardingService: SimOnboardingService,
     subInfo: SubscriptionInfo,
 ) {
+    val originalSimCarrierName = subInfo.displayName.toString()
     var titleSimName by remember {
         mutableStateOf(onboardingService.getSubscriptionInfoDisplayName(subInfo))
     }
     val phoneNumber = phoneNumber(subInfo)
     val alertDialogPresenter = rememberAlertDialogPresenter(
         confirmButton = AlertDialogButton(stringResource(R.string.mobile_network_sim_name_rename)) {
-            onboardingService.addItemForRenaming(subInfo, titleSimName)
+            onboardingService.addItemForRenaming(
+                subInfo, if (titleSimName.isEmpty()) originalSimCarrierName else titleSimName
+            )
         },
         dismissButton = AlertDialogButton(stringResource(R.string.cancel)) {
             titleSimName = onboardingService.getSubscriptionInfoDisplayName(subInfo)
@@ -105,6 +108,7 @@
             SettingsOutlinedTextField(
                 value = titleSimName,
                 label = stringResource(R.string.sim_onboarding_label_sim_dialog_label),
+                placeholder = {Text(text = originalSimCarrierName)},
                 modifier = Modifier.fillMaxWidth()
             ) {
                 titleSimName = it
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java
index 9b1466b..9b92234 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsProfilesControllerTest.java
@@ -558,4 +558,49 @@
         List<SwitchPreferenceCompat> switches = getProfileSwitches(false);
         assertThat(switches.get(0).isVisible()).isTrue();
     }
+
+    @Test
+    public void classicAudioDeviceWithLeAudio_showLeAudioToggle() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_HIDE_LE_AUDIO_TOGGLE_FOR_LE_AUDIO_ONLY_DEVICE);
+        setupDevice(makeDefaultDeviceConfig());
+
+        LeAudioProfile leAudioProfile = mock(LeAudioProfile.class);
+        when(leAudioProfile.getNameResource(mDevice))
+                .thenReturn(com.android.settingslib.R.string.bluetooth_profile_le_audio);
+        when(leAudioProfile.isProfileReady()).thenReturn(true);
+        when(leAudioProfile.toString()).thenReturn("LE_AUDIO");
+        when(mProfileManager.getLeAudioProfile()).thenReturn(leAudioProfile);
+        mConnectableProfiles.add(leAudioProfile);
+        when(mCachedDevice.getProfiles())
+                .thenAnswer(
+                        invocation ->
+                                ImmutableList.of(
+                                        leAudioProfile, addMockA2dpProfile(false, false, false)));
+
+        showScreen(mController);
+
+        List<SwitchPreferenceCompat> switches = getProfileSwitches(false);
+        assertThat(switches.get(0).isVisible()).isTrue();
+    }
+
+    @Test
+    public void leAudioOnlyDevice_hideLeAudioToggle() {
+        mSetFlagsRule.enableFlags(Flags.FLAG_HIDE_LE_AUDIO_TOGGLE_FOR_LE_AUDIO_ONLY_DEVICE);
+        setupDevice(makeDefaultDeviceConfig());
+
+        LeAudioProfile leAudioProfile = mock(LeAudioProfile.class);
+        when(leAudioProfile.getNameResource(mDevice))
+                .thenReturn(com.android.settingslib.R.string.bluetooth_profile_le_audio);
+        when(leAudioProfile.isProfileReady()).thenReturn(true);
+        when(leAudioProfile.toString()).thenReturn("LE_AUDIO");
+        when(mProfileManager.getLeAudioProfile()).thenReturn(leAudioProfile);
+        mConnectableProfiles.add(leAudioProfile);
+        when(mCachedDevice.getProfiles())
+                .thenAnswer(invocation -> ImmutableList.of(leAudioProfile));
+
+        showScreen(mController);
+
+        List<SwitchPreferenceCompat> switches = getProfileSwitches(false);
+        assertThat(switches.get(0).isVisible()).isFalse();
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
index db4c359..3158688 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImplTest.java
@@ -73,6 +73,11 @@
     }
 
     @Test
+    public void testIsAppOptimizationModeLogged_returnFalse() {
+        assertThat(mPowerFeatureProvider.isAppOptimizationModeLogged()).isFalse();
+    }
+
+    @Test
     public void testGetBatteryUsageListConsumePowerThreshold_return0() {
         assertThat(mPowerFeatureProvider.getBatteryUsageListConsumePowerThreshold()).isEqualTo(0.0);
     }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
index 5ce449b..3ed2dd1 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/ConvertUtilsTest.java
@@ -382,9 +382,13 @@
                         /* foregroundServiceUsageConsumePower= */ 1.3,
                         /* backgroundUsageConsumePower= */ 1.4,
                         /* cachedUsageConsumePower= */ 1.5);
+        BatteryOptimizationModeCache optimizationModeCache =
+                new BatteryOptimizationModeCache(mContext);
+        optimizationModeCache.mBatteryOptimizeModeCacheMap.put(
+                (int) batteryDiffEntry.mUid, BatteryOptimizationMode.MODE_OPTIMIZED);
 
         final BatteryUsageDiff batteryUsageDiff =
-                ConvertUtils.convertToBatteryUsageDiff(batteryDiffEntry);
+                ConvertUtils.convertToBatteryUsageDiff(batteryDiffEntry, optimizationModeCache);
 
         assertThat(batteryUsageDiff.getUid()).isEqualTo(101L);
         assertThat(batteryUsageDiff.getUserId()).isEqualTo(1001L);
@@ -402,6 +406,8 @@
         assertThat(batteryUsageDiff.getBackgroundUsageTime()).isEqualTo(5678L);
         assertThat(batteryUsageDiff.getScreenOnTime()).isEqualTo(123L);
         assertThat(batteryUsageDiff.getKey()).isEqualTo("key");
+        assertThat(batteryUsageDiff.getAppOptimizationMode())
+                .isEqualTo(BatteryOptimizationMode.MODE_OPTIMIZED);
         assertThat(batteryUsageDiff.hasPackageName()).isFalse();
         assertThat(batteryUsageDiff.hasLabel()).isFalse();
     }
@@ -591,7 +597,7 @@
                 Map.of(11L, batteryDiffData1, 21L, batteryDiffData2, 31L, batteryDiffData3);
 
         final List<BatteryUsageSlot> batteryUsageSlotList =
-                ConvertUtils.convertToBatteryUsageSlotList(batteryDiffDataMap);
+                ConvertUtils.convertToBatteryUsageSlotList(mContext, batteryDiffDataMap, false);
 
         assertThat(batteryUsageSlotList).hasSize(3);
         assertThat(batteryUsageSlotList.stream().map((s) -> s.getScreenOnTime()).sorted().toList())
diff --git a/tests/robotests/src/com/android/settings/security/ScreenPinningSettingsTest.java b/tests/robotests/src/com/android/settings/security/ScreenPinningSettingsTest.java
index 045ef65..99b41f4 100644
--- a/tests/robotests/src/com/android/settings/security/ScreenPinningSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/security/ScreenPinningSettingsTest.java
@@ -18,34 +18,48 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.robolectric.Shadows.shadowOf;
+
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
+import android.content.Intent;
+import android.icu.text.MessageFormat;
 import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
 
+import androidx.fragment.app.Fragment;
 import androidx.test.core.app.ApplicationProvider;
 
 import com.android.settings.R;
+import com.android.settings.SettingsActivity;
 import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
 import com.android.settingslib.search.SearchIndexableRaw;
+import com.android.settingslib.widget.FooterPreference;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.android.controller.ActivityController;
 import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowUserManager;
 
 import java.util.List;
+import java.util.function.Consumer;
 
 @RunWith(RobolectricTestRunner.class)
 @Config(shadows = ShadowLockPatternUtils.class)
 public class ScreenPinningSettingsTest {
-
+    private static final String KEY_FOOTER = "screen_pinning_settings_screen_footer";
     private Context mContext;
+    private UserManager mUserManager;
 
     @Before
     public void setUp() {
         mContext = ApplicationProvider.getApplicationContext();
+        mUserManager = mContext.getSystemService(UserManager.class);
     }
 
     @After
@@ -110,4 +124,97 @@
         assertThat(indexRaws.get(0).title).isEqualTo(
                 mContext.getString(R.string.screen_pinning_unlock_none));
     }
+
+    @Test
+    public void onCreate_lockToAppEnabled_guestModeSupported_verifyFooterText() {
+        setupLockToAppState(/* enabled= */ true);
+        setupGuestModeState(/* supported= */ true);
+
+        launchFragmentAndRunTest(fragment -> {
+            FooterPreference footer = fragment.findPreference(KEY_FOOTER);
+
+            assertThat(footer.getSummary())
+                    .isEqualTo(getExpectedFooterText(/* guestModeSupported= */ true));
+        });
+    }
+
+    @Test
+    public void onCreate_lockToAppEnabled_guestModeNotSupported_verifyFooterText() {
+        setupLockToAppState(/* enabled= */ true);
+        setupGuestModeState(/* supported= */ false);
+
+        launchFragmentAndRunTest(fragment -> {
+            FooterPreference footer = fragment.findPreference(KEY_FOOTER);
+
+            assertThat(footer.getSummary())
+                    .isEqualTo(getExpectedFooterText(/* guestModeSupported= */ false));
+        });
+    }
+
+    @Test
+    public void onCreate_lockToAppDisabled_guestModeSupported_verifyFooterText() {
+        setupLockToAppState(/* enabled= */ false);
+        setupGuestModeState(/* supported= */ true);
+
+        launchFragmentAndRunTest(fragment -> {
+            FooterPreference footer = fragment.findPreference(KEY_FOOTER);
+
+            assertThat(footer.getSummary())
+                    .isEqualTo(getExpectedFooterText(/* guestModeSupported= */ true));
+        });
+    }
+
+    @Test
+    public void onCreate_lockToAppDisabled_guestModeNotSupported_verifyFooterText() {
+        setupLockToAppState(/* enabled= */ false);
+        setupGuestModeState(/* supported= */ false);
+
+        launchFragmentAndRunTest(fragment -> {
+            FooterPreference footer = fragment.findPreference(KEY_FOOTER);
+
+            assertThat(footer.getSummary())
+                    .isEqualTo(getExpectedFooterText(/* guestModeSupported= */ false));
+        });
+    }
+
+    private CharSequence getExpectedFooterText(boolean guestModeSupported) {
+        final int stringResource = guestModeSupported
+                ? R.string.screen_pinning_guest_user_description
+                : R.string.screen_pinning_description;
+        return MessageFormat.format(mContext.getString(stringResource), 1, 2, 3);
+    }
+
+    private void setupLockToAppState(boolean enabled) {
+        Settings.System.putInt(mContext.getContentResolver(), Settings.System.LOCK_TO_APP_ENABLED,
+                enabled ? 1 : 0);
+    }
+
+    private void setupGuestModeState(boolean supported) {
+        ShadowUserManager shadowUserManager = shadowOf(mUserManager);
+        shadowUserManager.setSupportsMultipleUsers(supported);
+        shadowUserManager.setUserRestriction(
+                UserHandle.of(UserHandle.myUserId()), UserManager.DISALLOW_USER_SWITCH, !supported);
+    }
+
+    private void launchFragmentAndRunTest(Consumer<ScreenPinningSettings> test) {
+        Intent intent = new Intent();
+        intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT,
+                SecurityAdvancedSettings.class.getName());
+        // ScreenPinningSettings is tightly coupled with the SettingsActivity
+        // In order to successfully launch the ScreenPinningSettings, have to use an indirect route
+        // to launch the SecurityAdvancedSetting first, then replace it with ScreenPinningSettings.
+        try (ActivityController<SettingsActivity> controller =
+                     ActivityController.of(new SettingsActivity(), intent)) {
+            controller.create().start().resume();
+
+            controller.get().getSupportFragmentManager().beginTransaction().replace(
+                    R.id.main_content, ScreenPinningSettings.class, null).commitNow();
+            Fragment fragment = controller.get().getSupportFragmentManager()
+                    .findFragmentById(R.id.main_content);
+            assertThat(fragment).isNotNull();
+            assertThat(fragment).isInstanceOf(ScreenPinningSettings.class);
+
+            test.accept((ScreenPinningSettings) fragment);
+        }
+    }
 }
diff --git a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
index c0023ee..3cd1533 100644
--- a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
@@ -17,7 +17,6 @@
 package com.android.settings.applications.credentials;
 
 import static com.android.settings.core.BasePreferenceController.AVAILABLE;
-import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
 import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -36,7 +35,9 @@
 import android.net.Uri;
 import android.os.Looper;
 import android.provider.Settings;
+import android.util.Pair;
 
+import androidx.annotation.Nullable;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceCategory;
 import androidx.preference.PreferenceManager;
@@ -124,19 +125,37 @@
         controller.setSimulateConnectedForTests(true);
         assertThat(controller.isConnected()).isTrue();
         controller.setSimulateHiddenForTests(Optional.of(false));
-        assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
+        assertThat(controller.isHiddenDueToNoProviderSet(createPair())).isFalse();
         assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
     }
 
     @Test
-    public void getAvailabilityStatus_isHidden_returnsConditionallyUnavailable() {
+    public void isHiddenDueToNoProviderSet_hiddenDueToEmptyPair() {
         CredentialManagerPreferenceController controller =
                 createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
-        controller.setSimulateConnectedForTests(true);
-        assertThat(controller.isConnected()).isTrue();
-        controller.setSimulateHiddenForTests(Optional.of(true));
-        assertThat(controller.isHiddenDueToNoProviderSet()).isTrue();
-        assertThat(controller.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+        assertThat(controller.isHiddenDueToNoProviderSet(createPair())).isTrue();
+    }
+
+    @Test
+    public void isHiddenDueToNoProviderSet_hiddenDueToNoPrimaryProvider() {
+        CredentialManagerPreferenceController controller =
+                createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
+
+        Pair<List<CombinedProviderInfo>, CombinedProviderInfo> testPair =
+                new Pair<>(Lists.newArrayList(createCombinedProviderInfo()), null);
+        assertThat(controller.isHiddenDueToNoProviderSet(testPair)).isTrue();
+    }
+
+    @Test
+    public void isHiddenDueToNoProviderSet_validDataSoNotHidden() {
+        CredentialManagerPreferenceController controller =
+                createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
+
+        Pair<List<CombinedProviderInfo>, CombinedProviderInfo> testPair =
+                new Pair<>(
+                        Lists.newArrayList(createCombinedProviderInfo()),
+                        createCombinedProviderInfo());
+        assertThat(controller.isHiddenDueToNoProviderSet(testPair)).isFalse();
     }
 
     @Test
@@ -146,7 +165,7 @@
         controller.setSimulateConnectedForTests(true);
         controller.setSimulateHiddenForTests(Optional.of(false));
 
-        assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
+        assertThat(controller.isHiddenDueToNoProviderSet(createPair())).isFalse();
         assertThat(controller.isConnected()).isTrue();
         assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
 
@@ -170,7 +189,7 @@
         controller.setSimulateConnectedForTests(true);
         assertThat(controller.isConnected()).isTrue();
         controller.setSimulateHiddenForTests(Optional.of(false));
-        assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
+        assertThat(controller.isHiddenDueToNoProviderSet(createPair())).isFalse();
         assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
 
         // Test the data is correct.
@@ -214,7 +233,7 @@
         controller.setSimulateConnectedForTests(true);
         assertThat(controller.isConnected()).isTrue();
         controller.setSimulateHiddenForTests(Optional.of(false));
-        assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
+        assertThat(controller.isHiddenDueToNoProviderSet(createPair())).isFalse();
         assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
 
         // Ensure that we stay under 5 providers (one is reserved for primary).
@@ -283,7 +302,7 @@
         controller.setSimulateConnectedForTests(true);
         assertThat(controller.isConnected()).isTrue();
         controller.setSimulateHiddenForTests(Optional.of(false));
-        assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
+        assertThat(controller.isHiddenDueToNoProviderSet(createPair())).isFalse();
         assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
 
         // Test the data is correct.
@@ -336,17 +355,26 @@
                 createControllerWithServices(
                         Lists.newArrayList(serviceA1, serviceB1, serviceC1, serviceC2, serviceC3));
         controller.setSimulateConnectedForTests(true);
-        controller.setSimulateHiddenForTests(Optional.of(false));
 
-        assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
         assertThat(controller.isConnected()).isTrue();
         assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
 
-        controller.displayPreference(mScreen);
-        assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(3);
+        CombinedProviderInfo combinedProviderA =
+                new CombinedProviderInfo(Lists.newArrayList(serviceA1), null, false, false);
+        CombinedProviderInfo combinedProviderB =
+                new CombinedProviderInfo(Lists.newArrayList(serviceB1), null, false, false);
+        CombinedProviderInfo combinedProviderC =
+                new CombinedProviderInfo(
+                        Lists.newArrayList(serviceC1, serviceC2, serviceC3), null, false, false);
+        Pair<List<CombinedProviderInfo>, CombinedProviderInfo> providerPair =
+                createPair(
+                        Lists.newArrayList(combinedProviderA, combinedProviderB, combinedProviderC),
+                        createCombinedProviderInfo());
+
+        assertThat(controller.isHiddenDueToNoProviderSet(providerPair)).isFalse();
 
         Map<String, CredentialManagerPreferenceController.CombiPreference> prefs =
-                controller.buildPreferenceList(mContext, mCredentialsPreferenceCategory);
+                controller.buildPreferenceList(mContext, providerPair);
         assertThat(prefs.keySet())
                 .containsExactly(TEST_PACKAGE_NAME_A, TEST_PACKAGE_NAME_B, TEST_PACKAGE_NAME_C);
         assertThat(prefs.size()).isEqualTo(3);
@@ -531,8 +559,7 @@
     @Test
     public void hasNonPrimaryServices_allServicesArePrimary() {
         CredentialManagerPreferenceController controller =
-                createControllerWithServices(
-                    Lists.newArrayList(createCredentialProviderPrimary()));
+                createControllerWithServices(Lists.newArrayList(createCredentialProviderPrimary()));
         assertThat(controller.hasNonPrimaryServices()).isFalse();
     }
 
@@ -540,8 +567,8 @@
     public void hasNonPrimaryServices_mixtureOfServices() {
         CredentialManagerPreferenceController controller =
                 createControllerWithServices(
-                    Lists.newArrayList(createCredentialProviderInfo(),
-                        createCredentialProviderPrimary()));
+                        Lists.newArrayList(
+                                createCredentialProviderInfo(), createCredentialProviderPrimary()));
         assertThat(controller.hasNonPrimaryServices()).isTrue();
     }
 
@@ -599,11 +626,25 @@
 
     private CredentialProviderInfo createCredentialProviderPrimary() {
         return createCredentialProviderInfoBuilder(
-            "com.android.primary", "CredManProvider", "Service Label", "App Name")
+                        "com.android.primary", "CredManProvider", "Service Label", "App Name")
                 .setPrimary(true)
                 .build();
     }
 
+    private Pair<List<CombinedProviderInfo>, CombinedProviderInfo> createPair() {
+        return createPair(Lists.newArrayList(), null);
+    }
+
+    private Pair<List<CombinedProviderInfo>, CombinedProviderInfo> createPair(
+            List<CombinedProviderInfo> providers, @Nullable CombinedProviderInfo primaryProvider) {
+        return new Pair<>(providers, primaryProvider);
+    }
+
+    private CombinedProviderInfo createCombinedProviderInfo() {
+        return new CombinedProviderInfo(
+                Lists.newArrayList(createCredentialProviderInfo()), null, false, false);
+    }
+
     private CredentialProviderInfo createCredentialProviderInfoWithSubtitle(
             String packageName, String className, CharSequence label, CharSequence subtitle) {
         ServiceInfo si = new ServiceInfo();