Merge "Temporary failing tests under com.android.settings.bluetooth" into main
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6739a71..859a59c 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2656,6 +2656,8 @@
     <string name="adaptive_sleep_contextual_slice_title">Turn on screen attention</string>
     <!-- Description about the contextual adaptive sleep card [CHAR LIMIT=NONE]-->
     <string name="adaptive_sleep_contextual_slice_summary">Keep screen on when looking at it</string>
+    <!-- Description about the power consumption implication in screen timeout footer [CHAR LIMIT=NONE]-->
+    <string name="power_consumption_footer_summary">Longer screen timeout will use more battery.</string>
     <!-- auto_rotate settings screen, title about the camera privacy lock enabled [CHAR LIMIT=NONE]-->
     <string name="auto_rotate_camera_lock_title">Camera is locked</string>
     <!-- Description feature's privacy sensitive details to make sure users understand what feature users, what it saves/sends etc [CHAR LIMIT=NONE]-->
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBasePreferenceController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBasePreferenceController.java
index 9ebe26d..21f1c0e 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBasePreferenceController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBasePreferenceController.java
@@ -64,7 +64,7 @@
         mPreference.setVisible(isVisible);
     }
 
-    private boolean isBroadcasting() {
+    protected boolean isBroadcasting() {
         return mBroadcast != null && mBroadcast.isEnabled(null);
     }
 }
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDashboardFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDashboardFragment.java
index cf5881b..7f90ceb 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDashboardFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDashboardFragment.java
@@ -22,6 +22,7 @@
 
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
+import com.android.settings.connecteddevice.audiosharing.audiostreams.AudioStreamsCategoryController;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.widget.SettingsMainSwitchBar;
 
@@ -34,6 +35,7 @@
     private AudioSharingDeviceVolumeGroupController mAudioSharingDeviceVolumeGroupController;
     private CallsAndAlarmsPreferenceController mCallsAndAlarmsPreferenceController;
     private AudioSharingNamePreferenceController mAudioSharingNamePreferenceController;
+    private AudioStreamsCategoryController mAudioStreamsCategoryController;
 
     public AudioSharingDashboardFragment() {
         super();
@@ -73,6 +75,7 @@
         mCallsAndAlarmsPreferenceController = use(CallsAndAlarmsPreferenceController.class);
         mCallsAndAlarmsPreferenceController.init(this);
         mAudioSharingNamePreferenceController = use(AudioSharingNamePreferenceController.class);
+        mAudioStreamsCategoryController = use(AudioStreamsCategoryController.class);
     }
 
     @Override
@@ -98,5 +101,6 @@
         mAudioSharingDeviceVolumeGroupController.updateVisibility(isVisible);
         mCallsAndAlarmsPreferenceController.updateVisibility(isVisible);
         mAudioSharingNamePreferenceController.updateVisibility(isVisible);
+        mAudioStreamsCategoryController.updateVisibility(isVisible);
     }
 }
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java
index 9210074..a43e098 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java
@@ -35,6 +35,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.stream.Collectors;
 
 public class AudioSharingUtils {
@@ -230,6 +231,31 @@
         return false;
     }
 
+    /**
+     * Retrieves the one and only active Bluetooth LE Audio sink device, regardless if the device is
+     * currently in an audio sharing session.
+     *
+     * @param manager The LocalBluetoothManager instance used to fetch connected devices.
+     * @return An Optional containing the active LE Audio device, or an empty Optional if not found.
+     */
+    public static Optional<CachedBluetoothDevice> getActiveSinkOnAssistant(
+            LocalBluetoothManager manager) {
+        if (manager == null) {
+            Log.w(TAG, "getActiveSinksOnAssistant(): LocalBluetoothManager is null!");
+            return Optional.empty();
+        }
+        var groupedDevices = AudioSharingUtils.fetchConnectedDevicesByGroupId(manager);
+        var leadDevices =
+                AudioSharingUtils.buildOrderedConnectedLeadDevices(manager, groupedDevices, false);
+
+        if (!leadDevices.isEmpty() && AudioSharingUtils.isActiveLeAudioDevice(leadDevices.get(0))) {
+            return Optional.of(leadDevices.get(0));
+        } else {
+            Log.w(TAG, "getActiveSinksOnAssistant(): No active lead device!");
+        }
+        return Optional.empty();
+    }
+
     /** Toast message on main thread. */
     public static void toastMessage(Context context, String message) {
         ThreadUtils.postOnMainThread(
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceSummaryUpdater.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceSummaryUpdater.java
index cf79596..0d3b1b1 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceSummaryUpdater.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsActiveDeviceSummaryUpdater.java
@@ -30,8 +30,6 @@
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.utils.ThreadUtils;
 
-import java.util.Optional;
-
 public class AudioStreamsActiveDeviceSummaryUpdater implements BluetoothCallback {
     private static final String TAG = "AudioStreamsActiveDeviceSummaryUpdater";
     private static final boolean DEBUG = BluetoothUtils.D;
@@ -82,31 +80,13 @@
     }
 
     private String getSummary() {
-        var activeSink = getActiveSinkOnAssistant(mBluetoothManager);
+        var activeSink = AudioSharingUtils.getActiveSinkOnAssistant(mBluetoothManager);
         if (activeSink.isEmpty()) {
             return "No active LE Audio device";
         }
         return activeSink.get().getName();
     }
 
-    private static Optional<CachedBluetoothDevice> getActiveSinkOnAssistant(
-            LocalBluetoothManager manager) {
-        if (manager == null) {
-            Log.w(TAG, "getActiveSinksOnAssistant(): LocalBluetoothManager is null!");
-            return Optional.empty();
-        }
-        var groupedDevices = AudioSharingUtils.fetchConnectedDevicesByGroupId(manager);
-        var leadDevices =
-                AudioSharingUtils.buildOrderedConnectedLeadDevices(manager, groupedDevices, false);
-
-        if (!leadDevices.isEmpty() && AudioSharingUtils.isActiveLeAudioDevice(leadDevices.get(0))) {
-            return Optional.of(leadDevices.get(0));
-        } else {
-            Log.w(TAG, "getActiveSinksOnAssistant(): No active lead device!");
-        }
-        return Optional.empty();
-    }
-
     /** Interface definition for a callback to be invoked when the summary has been changed. */
     interface OnSummaryChangeListener {
         /**
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsCategoryController.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsCategoryController.java
index 84a7be9..f80fdab 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsCategoryController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsCategoryController.java
@@ -16,15 +16,64 @@
 
 package com.android.settings.connecteddevice.audiosharing.audiostreams;
 
+import android.annotation.Nullable;
+import android.bluetooth.BluetoothProfile;
 import android.content.Context;
+import android.util.Log;
 
+import androidx.annotation.NonNull;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
+
+import com.android.settings.bluetooth.Utils;
+import com.android.settings.connecteddevice.audiosharing.AudioSharingBasePreferenceController;
+import com.android.settings.connecteddevice.audiosharing.AudioSharingUtils;
 import com.android.settings.flags.Flags;
-import com.android.settings.widget.PreferenceCategoryController;
+import com.android.settingslib.bluetooth.BluetoothCallback;
+import com.android.settingslib.bluetooth.BluetoothUtils;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.utils.ThreadUtils;
 
-public class AudioStreamsCategoryController extends PreferenceCategoryController {
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+public class AudioStreamsCategoryController extends AudioSharingBasePreferenceController
+        implements DefaultLifecycleObserver {
+    private static final String TAG = "AudioStreamsCategoryController";
+    private static final boolean DEBUG = BluetoothUtils.D;
+    private final LocalBluetoothManager mLocalBtManager;
+    private final Executor mExecutor;
+    private final BluetoothCallback mBluetoothCallback =
+            new BluetoothCallback() {
+                @Override
+                public void onActiveDeviceChanged(
+                        @Nullable CachedBluetoothDevice activeDevice, int bluetoothProfile) {
+                    if (bluetoothProfile == BluetoothProfile.LE_AUDIO) {
+                        updateVisibility(isBroadcasting());
+                    }
+                }
+            };
 
     public AudioStreamsCategoryController(Context context, String key) {
         super(context, key);
+        mLocalBtManager = Utils.getLocalBtManager(mContext);
+        mExecutor = Executors.newSingleThreadExecutor();
+    }
+
+    @Override
+    public void onStart(@NonNull LifecycleOwner owner) {
+        if (mLocalBtManager != null) {
+            mLocalBtManager.getEventManager().registerCallback(mBluetoothCallback);
+        }
+        updateVisibility(isBroadcasting());
+    }
+
+    @Override
+    public void onStop(@NonNull LifecycleOwner owner) {
+        if (mLocalBtManager != null) {
+            mLocalBtManager.getEventManager().unregisterCallback(mBluetoothCallback);
+        }
     }
 
     @Override
@@ -33,4 +82,23 @@
                 ? AVAILABLE
                 : UNSUPPORTED_ON_DEVICE;
     }
+
+    @Override
+    public void updateVisibility(boolean isBroadcasting) {
+        mExecutor.execute(
+                () -> {
+                    boolean hasActiveLe =
+                            AudioSharingUtils.getActiveSinkOnAssistant(mLocalBtManager).isPresent();
+                    if (DEBUG) {
+                        Log.d(
+                                TAG,
+                                "updateVisibility() isBroadcasting : "
+                                        + isBroadcasting
+                                        + " hasActiveLe : "
+                                        + hasActiveLe);
+                    }
+                    ThreadUtils.postOnMainThread(
+                            () -> super.updateVisibility(hasActiveLe && !isBroadcasting));
+                });
+    }
 }
diff --git a/src/com/android/settings/deviceinfo/batteryinfo/BatteryInfoFragment.java b/src/com/android/settings/deviceinfo/batteryinfo/BatteryInfoFragment.java
index 1731212..c017022 100644
--- a/src/com/android/settings/deviceinfo/batteryinfo/BatteryInfoFragment.java
+++ b/src/com/android/settings/deviceinfo/batteryinfo/BatteryInfoFragment.java
@@ -17,15 +17,15 @@
 package com.android.settings.deviceinfo.batteryinfo;
 
 import android.app.settings.SettingsEnums;
+import android.content.Context;
 
 import com.android.settings.R;
 import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.overlay.FeatureFactory;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settingslib.search.SearchIndexable;
 
-/**
- * A fragment that shows battery hardware information.
- */
+/** A fragment that shows battery hardware information. */
 @SearchIndexable
 public class BatteryInfoFragment extends DashboardFragment {
 
@@ -47,5 +47,12 @@
     }
 
     public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
-            new BaseSearchIndexProvider(R.xml.battery_info);
+            new BaseSearchIndexProvider(R.xml.battery_info) {
+                @Override
+                protected boolean isPageSearchEnabled(Context context) {
+                    return FeatureFactory.getFeatureFactory()
+                            .getBatterySettingsFeatureProvider()
+                            .isBatteryInfoEnabled(context);
+                }
+            };
 }
diff --git a/src/com/android/settings/display/ScreenTimeoutSettings.java b/src/com/android/settings/display/ScreenTimeoutSettings.java
index 43dd31c..f7be319 100644
--- a/src/com/android/settings/display/ScreenTimeoutSettings.java
+++ b/src/com/android/settings/display/ScreenTimeoutSettings.java
@@ -93,6 +93,9 @@
     FooterPreference mDisableOptionsPreference;
 
     @VisibleForTesting
+    FooterPreference mPowerConsumptionPreference;
+
+    @VisibleForTesting
     AdaptiveSleepPermissionPreferenceController mAdaptiveSleepPermissionController;
 
     @VisibleForTesting
@@ -216,6 +219,9 @@
         if (mAdmin != null) {
             setupDisabledFooterPreference();
             screen.addPreference(mDisableOptionsPreference);
+        } else {
+            setupPowerConsumptionFooterPreference();
+            screen.addPreference(mPowerConsumptionPreference);
         }
     }
 
@@ -236,8 +242,20 @@
         mDisableOptionsPreference.setIcon(R.drawable.ic_info_outline_24dp);
 
         // The 'disabled by admin' preference should always be at the end of the setting page.
-        mDisableOptionsPreference.setOrder(DEFAULT_ORDER_OF_LOWEST_PREFERENCE);
         mPrivacyPreference.setOrder(DEFAULT_ORDER_OF_LOWEST_PREFERENCE - 1);
+        mDisableOptionsPreference.setOrder(DEFAULT_ORDER_OF_LOWEST_PREFERENCE);
+    }
+
+    @VisibleForTesting
+    void setupPowerConsumptionFooterPreference() {
+        mPowerConsumptionPreference = new FooterPreference(getContext());
+        mPowerConsumptionPreference.setTitle(R.string.power_consumption_footer_summary);
+        mPowerConsumptionPreference.setSelectable(false);
+        mPowerConsumptionPreference.setIcon(R.drawable.ic_info_outline_24dp);
+
+        // The 'Longer screen timeout' preference should always be at the end of the setting page.
+        mPrivacyPreference.setOrder(DEFAULT_ORDER_OF_LOWEST_PREFERENCE - 1);
+        mPowerConsumptionPreference.setOrder(DEFAULT_ORDER_OF_LOWEST_PREFERENCE);
     }
 
     @Override
diff --git a/src/com/android/settings/fuelgauge/BatterySettingsMigrateChecker.java b/src/com/android/settings/fuelgauge/BatterySettingsMigrateChecker.java
index dd49c8b..066e0fc 100644
--- a/src/com/android/settings/fuelgauge/BatterySettingsMigrateChecker.java
+++ b/src/com/android/settings/fuelgauge/BatterySettingsMigrateChecker.java
@@ -51,8 +51,7 @@
         context = context.getApplicationContext();
         verifySaverConfiguration(context);
         verifyBatteryOptimizeModes(context);
-        // Initialize and sync settings into SharedPreferences for migration.
-        DynamicDenylistManager.getInstance(context);
+        DynamicDenylistManager.getInstance(context).onBootComplete();
     }
 
     /** Avoid users set important apps into the unexpected battery optimize modes */
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
index 9fb70fa..bfa501c 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
@@ -63,7 +63,7 @@
         }
         final String action = intent.getAction();
         Log.d(TAG, "onReceive:" + action);
-        if (DatabaseUtils.isWorkProfile(context)) {
+        if (com.android.settingslib.fuelgauge.BatteryUtils.isWorkProfile(context)) {
             Log.w(TAG, "do nothing for work profile action=" + action);
             return;
         }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
index 4f2ee79..095a65a 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
@@ -37,6 +37,7 @@
 import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDatabase;
 import com.android.settings.fuelgauge.batteryusage.db.BatteryUsageSlotDao;
 import com.android.settings.fuelgauge.batteryusage.db.BatteryUsageSlotEntity;
+import com.android.settingslib.fuelgauge.BatteryUtils;
 
 import java.time.Clock;
 import java.time.Duration;
@@ -109,7 +110,7 @@
 
     @Override
     public boolean onCreate() {
-        if (DatabaseUtils.isWorkProfile(getContext())) {
+        if (BatteryUtils.isWorkProfile(getContext())) {
             Log.w(TAG, "do not create provider for work profile");
             return false;
         }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java
index 94f9dc3..dd48483 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java
@@ -27,6 +27,7 @@
 import com.android.settings.fuelgauge.BatteryUsageHistoricalLogEntry.Action;
 import com.android.settings.fuelgauge.batteryusage.bugreport.BatteryUsageLogUtils;
 import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.fuelgauge.BatteryUtils;
 
 import java.time.Duration;
 
@@ -56,7 +57,7 @@
     @Override
     public void onReceive(Context context, Intent intent) {
         final String action = intent == null ? "" : intent.getAction();
-        if (DatabaseUtils.isWorkProfile(context)) {
+        if (BatteryUtils.isWorkProfile(context)) {
             Log.w(TAG, "do not start job for work profile action=" + action);
             return;
         }
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
index f96ed5b..7160da4 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
@@ -159,12 +159,6 @@
 
     private DatabaseUtils() {}
 
-    /** Returns true if current user is a work profile user. */
-    public static boolean isWorkProfile(Context context) {
-        final UserManager userManager = context.getSystemService(UserManager.class);
-        return userManager.isManagedProfile();
-    }
-
     /** Returns the latest timestamp current user data in app usage event table. */
     public static long getAppUsageStartTimestampOfUser(
             Context context, final long userId, final long earliestTimestamp) {
@@ -502,7 +496,7 @@
 
     /** Returns the context with profile parent identity when current user is work profile. */
     public static Context getParentContext(Context context) {
-        if (isWorkProfile(context)) {
+        if (com.android.settingslib.fuelgauge.BatteryUtils.isWorkProfile(context)) {
             try {
                 return context.createPackageContextAsUser(
                         /* packageName= */ context.getPackageName(),
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
index bd77feb..5c73adb 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
@@ -24,6 +24,7 @@
 
 import com.android.settings.fuelgauge.BatteryUsageHistoricalLogEntry.Action;
 import com.android.settings.fuelgauge.batteryusage.bugreport.BatteryUsageLogUtils;
+import com.android.settingslib.fuelgauge.BatteryUtils;
 
 /** Receives the periodic alarm {@link PendingIntent} callback. */
 public final class PeriodicJobReceiver extends BroadcastReceiver {
@@ -49,7 +50,7 @@
             Log.w(TAG, "receive unexpected action=" + action);
             return;
         }
-        if (DatabaseUtils.isWorkProfile(context)) {
+        if (BatteryUtils.isWorkProfile(context)) {
             BatteryUsageLogUtils.writeLog(
                     context, Action.SCHEDULE_JOB, "do not refresh job for work profile");
             Log.w(TAG, "do not refresh job for work profile action=" + action);
diff --git a/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java b/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java
index 7dc7700..ff953e7 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java
@@ -23,7 +23,7 @@
 import android.net.Uri;
 import android.util.Log;
 
-import com.android.settings.fuelgauge.batteryusage.DatabaseUtils;
+import com.android.settingslib.fuelgauge.BatteryUtils;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -49,7 +49,7 @@
             Log.w(TAG, "failed to dump BatteryUsage state: null application context");
             return;
         }
-        if (DatabaseUtils.isWorkProfile(context)) {
+        if (BatteryUtils.isWorkProfile(context)) {
             Log.w(TAG, "ignore battery usage states dump in the work profile");
             return;
         }
diff --git a/src/com/android/settings/fuelgauge/datasaver/DynamicDenylistManager.java b/src/com/android/settings/fuelgauge/datasaver/DynamicDenylistManager.java
index e9e1218..4a25238 100644
--- a/src/com/android/settings/fuelgauge/datasaver/DynamicDenylistManager.java
+++ b/src/com/android/settings/fuelgauge/datasaver/DynamicDenylistManager.java
@@ -23,12 +23,14 @@
 
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
 import android.net.NetworkPolicyManager;
 import android.util.ArraySet;
 import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
 
+import java.io.PrintWriter;
 import java.util.Set;
 
 /** A class to dynamically manage per apps {@link NetworkPolicyManager} POLICY_ flags. */
@@ -137,16 +139,34 @@
             return;
         }
         synchronized (mLock) {
-            for (int uid : mNetworkPolicyManager
-                    .getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND)) {
-                if (!getDenylistAllUids(getManualDenylistPref()).contains(uid)) {
-                    mNetworkPolicyManager.setUidPolicy(uid, POLICY_NONE);
+            final int[] uids = mNetworkPolicyManager
+                    .getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND);
+            if (uids != null && uids.length != 0) {
+                for (int uid : uids) {
+                    if (!getDenylistAllUids(getManualDenylistPref()).contains(uid)) {
+                        mNetworkPolicyManager.setUidPolicy(uid, POLICY_NONE);
+                    }
                 }
             }
         }
         clearSharedPreferences();
     }
 
+    /** Reset the POLICY_REJECT_METERED uids when device is boot completed. */
+    public void onBootComplete() {
+        resetDenylistIfNeeded(/* packageName= */ null, /* force= */ true);
+        syncPolicyIfNeeded();
+    }
+
+    /** Dump the data stored in the {@link SharedPreferences}. */
+    public void dump(PrintWriter writer) {
+        writer.println("Dump of DynamicDenylistManager:");
+        writer.println("\tManualDenylist: " + getPackageNames(mContext,
+                getDenylistAllUids(getManualDenylistPref())));
+        writer.println("\tDynamicDenylist: " + getPackageNames(mContext,
+                getDenylistAllUids(getDynamicDenylistPref())));
+    }
+
     private Set<Integer> getDenylistAllUids(SharedPreferences sharedPreferences) {
         final ArraySet<Integer> uids = new ArraySet<>();
         for (String key : sharedPreferences.getAll().keySet()) {
@@ -186,4 +206,14 @@
     SharedPreferences getDynamicDenylistPref() {
         return mContext.getSharedPreferences(PREF_KEY_DYNAMIC_DENY, Context.MODE_PRIVATE);
     }
+
+    private static String getPackageNames(Context context, Set<Integer> uids) {
+        if (uids == null || uids.isEmpty()) {
+            return null;
+        }
+        final PackageManager pm = context.getPackageManager();
+        final StringBuilder builder = new StringBuilder();
+        uids.forEach(uid -> builder.append(pm.getNameForUid(uid) + " "));
+        return builder.toString();
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/batteryinfo/BatteryInfoFragmentTest.java b/tests/robotests/src/com/android/settings/deviceinfo/batteryinfo/BatteryInfoFragmentTest.java
new file mode 100644
index 0000000..d0dda84
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/deviceinfo/batteryinfo/BatteryInfoFragmentTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.deviceinfo.batteryinfo;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.testutils.FakeFeatureFactory;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.util.ReflectionHelpers;
+
+@RunWith(org.robolectric.RobolectricTestRunner.class)
+public class BatteryInfoFragmentTest {
+    private Context mContext;
+    private FakeFeatureFactory mFactory;
+    private BatteryInfoFragment mFragment;
+
+    @Before
+    public void setUp() {
+        mContext = ApplicationProvider.getApplicationContext();
+        mFactory = FakeFeatureFactory.setupForTest();
+        mFragment = new BatteryInfoFragment();
+    }
+
+    @Test
+    public void isPageSearchEnabled_batteryInfoEnabled_returnTrue() {
+        when(mFactory.batterySettingsFeatureProvider.isBatteryInfoEnabled(mContext))
+                .thenReturn(true);
+
+        final BaseSearchIndexProvider provider =
+                (BaseSearchIndexProvider) mFragment.SEARCH_INDEX_DATA_PROVIDER;
+
+        final Object obj =
+                org.robolectric.util.ReflectionHelpers.callInstanceMethod(
+                        provider, /*methodName=*/ "isPageSearchEnabled",
+                        ReflectionHelpers.ClassParameter.from(Context.class, mContext));
+        final boolean isEnabled = (Boolean) obj;
+        assertThat(isEnabled).isTrue();
+    }
+
+    @Test
+    public void isPageSearchEnabled_batteryInfoDisabled_returnFalse() {
+        when(mFactory.batterySettingsFeatureProvider.isBatteryInfoEnabled(mContext))
+                .thenReturn(false);
+
+        final BaseSearchIndexProvider provider =
+                (BaseSearchIndexProvider) mFragment.SEARCH_INDEX_DATA_PROVIDER;
+
+        final Object obj =
+                org.robolectric.util.ReflectionHelpers.callInstanceMethod(
+                        provider, /*methodName=*/ "isPageSearchEnabled",
+                        ReflectionHelpers.ClassParameter.from(Context.class, mContext));
+        final boolean isEnabled = (Boolean) obj;
+        assertThat(isEnabled).isFalse();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/display/ScreenTimeoutSettingsTest.java b/tests/robotests/src/com/android/settings/display/ScreenTimeoutSettingsTest.java
index c33bd21..9e193ff 100644
--- a/tests/robotests/src/com/android/settings/display/ScreenTimeoutSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/display/ScreenTimeoutSettingsTest.java
@@ -93,6 +93,9 @@
     FooterPreference mDisableOptionsPreference;
 
     @Mock
+    FooterPreference mPowerConsumptionPreference;
+
+    @Mock
     private PackageManager mPackageManager;
 
     @Before
@@ -182,11 +185,28 @@
     public void updateCandidates_enforcedAdmin_showDisabledByAdminPreference() {
         mSettings.mAdmin = new RestrictedLockUtils.EnforcedAdmin();
         mSettings.mDisableOptionsPreference = mDisableOptionsPreference;
+        mSettings.mPowerConsumptionPreference = mPowerConsumptionPreference;
         doNothing().when(mSettings).setupDisabledFooterPreference();
+        doNothing().when(mSettings).setupPowerConsumptionFooterPreference();
 
         mSettings.updateCandidates();
 
         verify(mPreferenceScreen, atLeast(1)).addPreference(mDisableOptionsPreference);
+        verify(mPreferenceScreen, never()).addPreference(mPowerConsumptionPreference);
+    }
+
+    @Test
+    public void updateCandidates_withoutAdmin_showPowerConsumptionPreference() {
+        mSettings.mAdmin = null;
+        mSettings.mDisableOptionsPreference = mDisableOptionsPreference;
+        mSettings.mPowerConsumptionPreference = mPowerConsumptionPreference;
+        doNothing().when(mSettings).setupDisabledFooterPreference();
+        doNothing().when(mSettings).setupPowerConsumptionFooterPreference();
+
+        mSettings.updateCandidates();
+
+        verify(mPreferenceScreen, never()).addPreference(mDisableOptionsPreference);
+        verify(mPreferenceScreen, atLeast(1)).addPreference(mPowerConsumptionPreference);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
index c31a2b6..d89e61b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
@@ -92,17 +92,6 @@
     }
 
     @Test
-    public void isWorkProfile_defaultValue_returnFalse() {
-        assertThat(DatabaseUtils.isWorkProfile(mContext)).isFalse();
-    }
-
-    @Test
-    public void isWorkProfile_withManagedUser_returnTrue() {
-        BatteryTestUtils.setWorkProfile(mContext);
-        assertThat(DatabaseUtils.isWorkProfile(mContext)).isTrue();
-    }
-
-    @Test
     public void sendAppUsageEventData_returnsExpectedList() {
         // Configures the testing AppUsageEvent data.
         final List<AppUsageEvent> appUsageEventList = new ArrayList<>();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/datasaver/DynamicDenylistManagerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/datasaver/DynamicDenylistManagerTest.java
index 3202610..c29541c 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/datasaver/DynamicDenylistManagerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/datasaver/DynamicDenylistManagerTest.java
@@ -36,6 +36,7 @@
 
 import android.content.Context;
 import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
 import android.net.NetworkPolicyManager;
 import android.util.ArraySet;
 
@@ -48,6 +49,8 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
+import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
@@ -67,6 +70,8 @@
 
     @Mock
     private NetworkPolicyManager mNetworkPolicyManager;
+    @Mock
+    private PackageManager mPackageManager;
 
     @Before
     public void setUp() {
@@ -357,12 +362,66 @@
         assertThat(mDynamicDenyListPref.getAll()).isEmpty();
     }
 
+    @Test
+    public void dump_dumpExpectedResult() {
+        initDynamicDenylistManager(EMPTY_ARRAY);
+        setupPreference(mManualDenyListPref, FAKE_UID_1);
+        setupPreference(mDynamicDenyListPref, FAKE_UID_2);
+        final StringWriter stringWriter = new StringWriter();
+        final PrintWriter printWriter = new PrintWriter(stringWriter);
+        when(mPackageManager.getNameForUid(FAKE_UID_1_INT)).thenReturn("app1");
+        when(mPackageManager.getNameForUid(FAKE_UID_2_INT)).thenReturn("app2");
+
+        mDynamicDenylistManager.dump(printWriter);
+
+        final String dumpResults = stringWriter.toString();
+        assertThat(dumpResults.contains("ManualDenylist: app1")).isTrue();
+        assertThat(dumpResults.contains("DynamicDenylist: app2")).isTrue();
+    }
+
+    @Test
+    public void dump_withEmptySharedPreferences_dumpExpectedResult() {
+        initDynamicDenylistManager(EMPTY_ARRAY, EMPTY_ARRAY);
+        mDynamicDenylistManager.clearSharedPreferences();
+        final StringWriter stringWriter = new StringWriter();
+        final PrintWriter printWriter = new PrintWriter(stringWriter);
+
+        mDynamicDenylistManager.dump(printWriter);
+
+        final String dumpResults = stringWriter.toString();
+        assertThat(dumpResults.contains("ManualDenylist: null")).isTrue();
+        assertThat(dumpResults.contains("DynamicDenylist: null")).isTrue();
+    }
+
+    @Test
+    public void onBootComplete_resetIntoManualMode() {
+        initDynamicDenylistManager(new int[] {FAKE_UID_1_INT});
+        setDenylist(new ArraySet<>(List.of(FAKE_UID_2_INT)));
+        // Ensure the testing environment for manual denylist.
+        assertThat(mManualDenyListPref.getAll()).hasSize(2);
+        assertTrue(mManualDenyListPref.contains(PREF_KEY_MANUAL_DENYLIST_SYNCED));
+        assertTrue(mManualDenyListPref.contains(FAKE_UID_1));
+        // Ensure the testing environment for dynamic denylist.
+        assertThat(mDynamicDenyListPref.getAll()).hasSize(1);
+
+        mDynamicDenylistManager.onBootComplete();
+
+        // Keep the users set uids in the manual denylist.
+        assertThat(mManualDenyListPref.getAll()).hasSize(2);
+        assertTrue(mManualDenyListPref.contains(PREF_KEY_MANUAL_DENYLIST_SYNCED));
+        assertTrue(mManualDenyListPref.contains(FAKE_UID_1));
+        // Clear the uids in the dynamic denylist.
+        assertThat(mDynamicDenyListPref.getAll()).isEmpty();
+    }
+
     private void initDynamicDenylistManager(int[] preload) {
         initDynamicDenylistManager(preload, preload);
     }
 
     private void initDynamicDenylistManager(int[] preload1, int[] preload2) {
         final Context context = spy(RuntimeEnvironment.application.getApplicationContext());
+        when(context.getApplicationContext()).thenReturn(context);
+        when(context.getPackageManager()).thenReturn(mPackageManager);
         when(mNetworkPolicyManager.getUidsWithPolicy(anyInt()))
                 .thenReturn(preload1).thenReturn(preload2);
         mDynamicDenylistManager = new DynamicDenylistManager(context, mNetworkPolicyManager);