Merge changes from topic "do-block-brightness" into main

* changes:
  Maintaining lux buffers since elapsed time and not uptime
  Doze brightness for non-offloaded watchfaces
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index ec67212..b2dcf90 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -739,6 +739,9 @@
          *                  on is done.
          */
         void onBlockingScreenOn(Runnable unblocker);
+
+        /** Whether auto brightness update in doze is allowed */
+        boolean allowAutoBrightnessInDoze();
     }
 
     /** A session token that associates a internal display with a {@link DisplayOffloader}. */
@@ -749,6 +752,9 @@
         /** Whether the session is active. */
         boolean isActive();
 
+        /** Whether auto brightness update in doze is allowed */
+        boolean allowAutoBrightnessInDoze();
+
         /**
          * Update the brightness from the offload chip.
          * @param brightness The brightness value between {@link PowerManager.BRIGHTNESS_MIN} and
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 30d12e6..1949e6f 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -56,10 +56,12 @@
 import com.android.server.display.brightness.BrightnessEvent;
 import com.android.server.display.brightness.clamper.BrightnessClamperController;
 import com.android.server.display.config.HysteresisLevels;
+import com.android.server.display.feature.DisplayManagerFlags;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Manages the associated display brightness when in auto-brightness mode. This is also
@@ -206,7 +208,7 @@
     private float mScreenBrighteningThreshold;
     private float mScreenDarkeningThreshold;
     // The most recent light sample.
-    private float mLastObservedLux = INVALID_LUX;
+    private float mLastObservedLux;
 
     // The time of the most light recent sample.
     private long mLastObservedLuxTime;
@@ -277,6 +279,8 @@
     private Clock mClock;
     private final Injector mInjector;
 
+    private final DisplayManagerFlags mDisplayManagerFlags;
+
     AutomaticBrightnessController(Callbacks callbacks, Looper looper,
             SensorManager sensorManager, Sensor lightSensor,
             SparseArray<BrightnessMappingStrategy> brightnessMappingStrategyMap,
@@ -291,7 +295,8 @@
             BrightnessRangeController brightnessModeController,
             BrightnessThrottler brightnessThrottler, int ambientLightHorizonShort,
             int ambientLightHorizonLong, float userLux, float userNits,
-            BrightnessClamperController brightnessClamperController) {
+            BrightnessClamperController brightnessClamperController,
+            DisplayManagerFlags displayManagerFlags) {
         this(new Injector(), callbacks, looper, sensorManager, lightSensor,
                 brightnessMappingStrategyMap, lightSensorWarmUpTime, brightnessMin, brightnessMax,
                 dozeScaleFactor, lightSensorRate, initialLightSensorRate,
@@ -301,7 +306,7 @@
                 screenBrightnessThresholds, ambientBrightnessThresholdsIdle,
                 screenBrightnessThresholdsIdle, context, brightnessModeController,
                 brightnessThrottler, ambientLightHorizonShort, ambientLightHorizonLong, userLux,
-                userNits, brightnessClamperController
+                userNits, brightnessClamperController, displayManagerFlags
         );
     }
 
@@ -320,9 +325,10 @@
             BrightnessRangeController brightnessRangeController,
             BrightnessThrottler brightnessThrottler, int ambientLightHorizonShort,
             int ambientLightHorizonLong, float userLux, float userNits,
-            BrightnessClamperController brightnessClamperController) {
+            BrightnessClamperController brightnessClamperController,
+            DisplayManagerFlags displayManagerFlags) {
         mInjector = injector;
-        mClock = injector.createClock();
+        mClock = injector.createClock(displayManagerFlags.offloadControlsDozeAutoBrightness());
         mContext = context;
         mCallbacks = callbacks;
         mSensorManager = sensorManager;
@@ -367,6 +373,7 @@
         mBrightnessClamperController = brightnessClamperController;
         mBrightnessThrottler = brightnessThrottler;
         mBrightnessMappingStrategyMap = brightnessMappingStrategyMap;
+        mDisplayManagerFlags = displayManagerFlags;
 
         // Use the given short-term model
         if (userNits != BrightnessMappingStrategy.INVALID_NITS) {
@@ -429,34 +436,6 @@
         return mRawScreenAutoBrightness;
     }
 
-    /**
-     * Get the automatic screen brightness based on the last observed lux reading. Used e.g. when
-     * entering doze - we disable the light sensor, invalidate the lux, but we still need to set
-     * the initial brightness in doze mode.
-     */
-    public float getAutomaticScreenBrightnessBasedOnLastUsedLux(
-            BrightnessEvent brightnessEvent) {
-        float lastUsedLux = mAmbientLux;
-        if (lastUsedLux == INVALID_LUX) {
-            return PowerManager.BRIGHTNESS_INVALID_FLOAT;
-        }
-
-        float brightness = mCurrentBrightnessMapper.getBrightness(lastUsedLux,
-                mForegroundAppPackageName, mForegroundAppCategory);
-        if (shouldApplyDozeScaleFactor()) {
-            brightness *= mDozeScaleFactor;
-        }
-
-        if (brightnessEvent != null) {
-            brightnessEvent.setLux(lastUsedLux);
-            brightnessEvent.setRecommendedBrightness(brightness);
-            brightnessEvent.setFlags(brightnessEvent.getFlags()
-                    | (shouldApplyDozeScaleFactor() ? BrightnessEvent.FLAG_DOZE_SCALE : 0));
-            brightnessEvent.setAutoBrightnessMode(getMode());
-        }
-        return brightness;
-    }
-
     public boolean hasValidAmbientLux() {
         return mAmbientLuxValid;
     }
@@ -747,7 +726,6 @@
         mRecentLightSamples++;
         mAmbientLightRingBuffer.prune(time - mAmbientLightHorizonLong);
         mAmbientLightRingBuffer.push(time, lux);
-
         // Remember this sample value.
         mLastObservedLux = lux;
         mLastObservedLuxTime = time;
@@ -891,7 +869,7 @@
     }
 
     private void updateAmbientLux() {
-        long time = mClock.uptimeMillis();
+        long time = mClock.getSensorEventScaleTime();
         mAmbientLightRingBuffer.prune(time - mAmbientLightHorizonLong);
         updateAmbientLux(time);
     }
@@ -968,7 +946,16 @@
             Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for " +
                     nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime));
         }
-        mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, nextTransitionTime);
+
+        // The nextTransitionTime is computed as elapsedTime(Which also accounts for the time when
+        // android was sleeping) as the main reference. However, handlers work on the uptime(Not
+        // accounting for the time when android was sleeping)
+        mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX,
+                convertToUptime(nextTransitionTime));
+    }
+
+    private long convertToUptime(long time) {
+        return time - mClock.getSensorEventScaleTime() + mClock.uptimeMillis();
     }
 
     private void updateAutoBrightness(boolean sendUpdate, boolean isManuallySet) {
@@ -1185,15 +1172,13 @@
             }
             mPausedShortTermModel.copyFrom(tempShortTermModel);
         }
-
-        update();
     }
 
     /**
      * Responsible for switching the AutomaticBrightnessMode of the associated display. Also takes
      * care of resetting the short term model wherever required
      */
-    public void switchMode(@AutomaticBrightnessMode int mode) {
+    public void switchMode(@AutomaticBrightnessMode int mode, boolean sendUpdate) {
         if (!mBrightnessMappingStrategyMap.contains(mode)) {
             return;
         }
@@ -1208,6 +1193,11 @@
             resetShortTermModel();
             mCurrentBrightnessMapper = mBrightnessMappingStrategyMap.get(mode);
         }
+        if (sendUpdate) {
+            update();
+        } else {
+            updateAutoBrightness(/* sendUpdate= */ false, /* isManuallySet= */ false);
+        }
     }
 
     float getUserLux() {
@@ -1391,7 +1381,9 @@
         @Override
         public void onSensorChanged(SensorEvent event) {
             if (mLightSensorEnabled) {
-                final long time = mClock.uptimeMillis();
+                // The time received from the sensor is in nano seconds, hence changing it to ms
+                final long time = (mDisplayManagerFlags.offloadControlsDozeAutoBrightness())
+                        ? TimeUnit.NANOSECONDS.toMillis(event.timestamp) : mClock.uptimeMillis();
                 final float lux = event.values[0];
                 handleLightSensorEvent(time, lux);
             }
@@ -1424,6 +1416,12 @@
          * Returns current time in milliseconds since boot, not counting time spent in deep sleep.
          */
         long uptimeMillis();
+
+        /**
+         * Gets the time on either the elapsedTime or the uptime scale, depending on how we
+         * processing the events from the sensor
+         */
+        long getSensorEventScaleTime();
     }
 
     /**
@@ -1571,7 +1569,8 @@
             StringBuilder buf = new StringBuilder();
             buf.append('[');
             for (int i = 0; i < mCount; i++) {
-                final long next = i + 1 < mCount ? getTime(i + 1) : mClock.uptimeMillis();
+                final long next = i + 1 < mCount ? getTime(i + 1)
+                        : mClock.getSensorEventScaleTime();
                 if (i != 0) {
                     buf.append(", ");
                 }
@@ -1596,13 +1595,31 @@
         }
     }
 
+    private static class RealClock implements Clock {
+        private final boolean mOffloadControlsDozeBrightness;
+
+        RealClock(boolean offloadControlsDozeBrightness) {
+            mOffloadControlsDozeBrightness = offloadControlsDozeBrightness;
+        }
+
+        @Override
+        public long uptimeMillis() {
+            return SystemClock.uptimeMillis();
+        }
+
+        public long getSensorEventScaleTime() {
+            return (mOffloadControlsDozeBrightness)
+                    ? SystemClock.elapsedRealtime() : uptimeMillis();
+        }
+    }
+
     public static class Injector {
         public Handler getBackgroundThreadHandler() {
             return BackgroundThread.getHandler();
         }
 
-        Clock createClock() {
-            return SystemClock::uptimeMillis;
+        Clock createClock(boolean offloadControlsDozeBrightness) {
+            return new RealClock(offloadControlsDozeBrightness);
         }
     }
 }
diff --git a/services/core/java/com/android/server/display/DisplayOffloadSessionImpl.java b/services/core/java/com/android/server/display/DisplayOffloadSessionImpl.java
index 65c9f35..f77a360 100644
--- a/services/core/java/com/android/server/display/DisplayOffloadSessionImpl.java
+++ b/services/core/java/com/android/server/display/DisplayOffloadSessionImpl.java
@@ -52,6 +52,14 @@
     }
 
     @Override
+    public boolean allowAutoBrightnessInDoze() {
+        if (mDisplayOffloader == null) {
+            return false;
+        }
+        return mDisplayOffloader.allowAutoBrightnessInDoze();
+    }
+
+    @Override
     public void updateBrightness(float brightness) {
         if (mIsActive) {
             mDisplayPowerController.setBrightnessFromOffload(brightness);
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 0fcdf198..7d482f7 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1115,7 +1115,7 @@
                     screenBrightnessThresholdsIdle, mContext, mBrightnessRangeController,
                     mBrightnessThrottler, mDisplayDeviceConfig.getAmbientHorizonShort(),
                     mDisplayDeviceConfig.getAmbientHorizonLong(), userLux, userNits,
-                    mBrightnessClamperController);
+                    mBrightnessClamperController, mFlags);
             mDisplayBrightnessController.setUpAutoBrightness(
                     mAutomaticBrightnessController, mSensorManager, mDisplayDeviceConfig, mHandler,
                     defaultModeBrightnessMapper, mIsEnabled, mLeadDisplayId);
@@ -1185,7 +1185,8 @@
             @AutomaticBrightnessController.AutomaticBrightnessMode int mode) {
         boolean isIdle = mode == AUTO_BRIGHTNESS_MODE_IDLE;
         if (mAutomaticBrightnessController != null) {
-            mAutomaticBrightnessController.switchMode(mode);
+            // Set sendUpdate to true to make sure that updatePowerState() gets called
+            mAutomaticBrightnessController.switchMode(mode, /* sendUpdate= */ true);
             setAnimatorRampSpeeds(isIdle);
         }
         Message msg = mHandler.obtainMessage();
@@ -1334,7 +1335,6 @@
                 mDisplayStateController.shouldPerformScreenOffTransition());
         state = mPowerState.getScreenState();
 
-
         DisplayBrightnessState displayBrightnessState = mDisplayBrightnessController
                 .updateBrightness(mPowerRequest, state);
         float brightnessState = displayBrightnessState.getBrightness();
@@ -1366,17 +1366,26 @@
         // request changes.
         final boolean wasShortTermModelActive =
                 mAutomaticBrightnessStrategy.isShortTermModelActive();
+        boolean allowAutoBrightnessWhileDozing =
+                mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig();
+        if (mFlags.offloadControlsDozeAutoBrightness() && mFlags.isDisplayOffloadEnabled()
+                && mDisplayOffloadSession != null) {
+            allowAutoBrightnessWhileDozing &= mDisplayOffloadSession.allowAutoBrightnessInDoze();
+        }
         if (!mFlags.isRefactorDisplayPowerControllerEnabled()) {
             // Switch to doze auto-brightness mode if needed
             if (mFlags.areAutoBrightnessModesEnabled() && mAutomaticBrightnessController != null
                     && !mAutomaticBrightnessController.isInIdleMode()) {
+                // Set sendUpdate to false, we're already in updatePowerState() so there's no need
+                // to trigger it again
                 mAutomaticBrightnessController.switchMode(Display.isDozeState(state)
-                        ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT);
+                        ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT,
+                        /* sendUpdate= */ false);
             }
 
             mAutomaticBrightnessStrategy.setAutoBrightnessState(state,
-                    mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig(),
-                    mBrightnessReasonTemp.getReason(), mPowerRequest.policy,
+                    allowAutoBrightnessWhileDozing, mBrightnessReasonTemp.getReason(),
+                    mPowerRequest.policy,
                     mDisplayBrightnessController.getLastUserSetScreenBrightness(),
                     userSetBrightnessChanged);
         }
@@ -1443,47 +1452,27 @@
         }
 
         if (Display.isDozeState(state)) {
-            // If there's an offload session, we need to set the initial doze brightness before
-            // the offload session starts controlling the brightness.
-            // During the transition DOZE_SUSPEND -> DOZE -> DOZE_SUSPEND, this brightness strategy
-            // will be selected again, meaning that no new brightness will be sent to the hardware
-            // and the display will stay at the brightness level set by the offload session.
+            // TODO(b/329676661): Introduce a config property to choose between this brightness
+            //  strategy and DOZE_DEFAULT
+            // On some devices, when auto-brightness is disabled and the device is dozing, we use
+            // the current brightness setting scaled by the doze scale factor
             if ((Float.isNaN(brightnessState)
                     || displayBrightnessState.getDisplayBrightnessStrategyName()
                     .equals(DisplayBrightnessStrategyConstants.FALLBACK_BRIGHTNESS_STRATEGY_NAME))
                     && mFlags.isDisplayOffloadEnabled()
-                    && mDisplayOffloadSession != null) {
-                if (mAutomaticBrightnessController != null
-                        && mAutomaticBrightnessStrategy.shouldUseAutoBrightness()) {
-                    // Use the auto-brightness curve and the last observed lux
-                    rawBrightnessState = mAutomaticBrightnessController
-                            .getAutomaticScreenBrightnessBasedOnLastUsedLux(
-                                    mTempBrightnessEvent);
-                } else {
-                    rawBrightnessState = getDozeBrightnessForOffload();
-                    mTempBrightnessEvent.setFlags(mTempBrightnessEvent.getFlags()
-                            | BrightnessEvent.FLAG_DOZE_SCALE);
-                }
-
-                if (BrightnessUtils.isValidBrightnessValue(rawBrightnessState)) {
-                    brightnessState = clampScreenBrightness(rawBrightnessState);
-                    mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_INITIAL);
-
-                    if (mAutomaticBrightnessController != null
-                            && mAutomaticBrightnessStrategy.shouldUseAutoBrightness()) {
-                        // Keep the brightness in the setting so that we can use it after the screen
-                        // turns on, until a lux sample becomes available. We don't do this when
-                        // auto-brightness is disabled - in that situation we still want to use
-                        // the last brightness from when the screen was on.
-                        updateScreenBrightnessSetting = currentBrightnessSetting != brightnessState;
-                    }
-                }
+                    && mDisplayOffloadSession != null
+                    && (mAutomaticBrightnessController == null
+                    || !mAutomaticBrightnessStrategy.shouldUseAutoBrightness())) {
+                rawBrightnessState = getDozeBrightnessForOffload();
+                brightnessState = clampScreenBrightness(rawBrightnessState);
+                mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_MANUAL);
+                mTempBrightnessEvent.setFlags(
+                        mTempBrightnessEvent.getFlags() | BrightnessEvent.FLAG_DOZE_SCALE);
             }
 
             // Use default brightness when dozing unless overridden.
-            if (Float.isNaN(brightnessState)
-                    || displayBrightnessState.getDisplayBrightnessStrategyName()
-                    .equals(DisplayBrightnessStrategyConstants.FALLBACK_BRIGHTNESS_STRATEGY_NAME)) {
+            if (Float.isNaN(brightnessState) && Display.isDozeState(state)
+                    && !mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig()) {
                 rawBrightnessState = mScreenBrightnessDozeConfig;
                 brightnessState = clampScreenBrightness(rawBrightnessState);
                 mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE_DEFAULT);
@@ -3169,7 +3158,8 @@
                 BrightnessRangeController brightnessModeController,
                 BrightnessThrottler brightnessThrottler, int ambientLightHorizonShort,
                 int ambientLightHorizonLong, float userLux, float userNits,
-                BrightnessClamperController brightnessClamperController) {
+                BrightnessClamperController brightnessClamperController,
+                DisplayManagerFlags displayManagerFlags) {
 
             return new AutomaticBrightnessController(callbacks, looper, sensorManager, lightSensor,
                     brightnessMappingStrategyMap, lightSensorWarmUpTime, brightnessMin,
@@ -3180,7 +3170,7 @@
                     screenBrightnessThresholds, ambientBrightnessThresholdsIdle,
                     screenBrightnessThresholdsIdle, context, brightnessModeController,
                     brightnessThrottler, ambientLightHorizonShort, ambientLightHorizonLong, userLux,
-                    userNits, brightnessClamperController);
+                    userNits, brightnessClamperController, displayManagerFlags);
         }
 
         BrightnessMappingStrategy getDefaultModeBrightnessMapper(Context context,
diff --git a/services/core/java/com/android/server/display/brightness/BrightnessReason.java b/services/core/java/com/android/server/display/brightness/BrightnessReason.java
index fc95d15..9bf10a7 100644
--- a/services/core/java/com/android/server/display/brightness/BrightnessReason.java
+++ b/services/core/java/com/android/server/display/brightness/BrightnessReason.java
@@ -40,8 +40,8 @@
     public static final int REASON_SCREEN_OFF_BRIGHTNESS_SENSOR = 9;
     public static final int REASON_FOLLOWER = 10;
     public static final int REASON_OFFLOAD = 11;
-    public static final int REASON_DOZE_INITIAL = 12;
-    public static final int REASON_MAX = REASON_DOZE_INITIAL;
+    public static final int REASON_DOZE_MANUAL = 12;
+    public static final int REASON_MAX = REASON_DOZE_MANUAL;
 
     public static final int MODIFIER_DIMMED = 0x1;
     public static final int MODIFIER_LOW_POWER = 0x2;
@@ -208,8 +208,8 @@
                 return "follower";
             case REASON_OFFLOAD:
                 return "offload";
-            case REASON_DOZE_INITIAL:
-                return "doze_initial";
+            case REASON_DOZE_MANUAL:
+                return "doze_manual";
             default:
                 return Integer.toString(reason);
         }
diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
index 37b6931..2907364 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy.java
@@ -15,8 +15,6 @@
  */
 package com.android.server.display.brightness.strategy;
 
-import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
-
 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT;
 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE;
 
@@ -129,9 +127,11 @@
     public void setAutoBrightnessState(int targetDisplayState,
             boolean allowAutoBrightnessWhileDozingConfig, int brightnessReason, int policy,
             float lastUserSetScreenBrightness, boolean userSetBrightnessChanged) {
-        switchMode(targetDisplayState);
+        // We are still in the process of updating the power state, so there's no need to trigger
+        // an update again
+        switchMode(targetDisplayState, /* sendUpdate= */ false);
         final boolean autoBrightnessEnabledInDoze =
-                allowAutoBrightnessWhileDozingConfig && policy == POLICY_DOZE;
+                allowAutoBrightnessWhileDozingConfig && Display.isDozeState(targetDisplayState);
         mIsAutoBrightnessEnabled = shouldUseAutoBrightness()
                 && (targetDisplayState == Display.STATE_ON || autoBrightnessEnabledInDoze)
                 && brightnessReason != BrightnessReason.REASON_OVERRIDE
@@ -371,23 +371,6 @@
     }
 
     /**
-     * Get the automatic screen brightness based on the last observed lux reading. Used e.g. when
-     * entering doze - we disable the light sensor, invalidate the lux, but we still need to set
-     * the initial brightness in doze mode.
-     * @param brightnessEvent Event object to populate with details about why the specific
-     *                        brightness was chosen.
-     */
-    public float getAutomaticScreenBrightnessBasedOnLastUsedLux(
-            BrightnessEvent brightnessEvent) {
-        float brightness = (mAutomaticBrightnessController != null)
-                ? mAutomaticBrightnessController
-                .getAutomaticScreenBrightnessBasedOnLastUsedLux(brightnessEvent)
-                : PowerManager.BRIGHTNESS_INVALID_FLOAT;
-        adjustAutomaticBrightnessStateIfValid(brightness);
-        return brightness;
-    }
-
-    /**
      * Returns if the auto brightness has been applied
      */
     public boolean hasAppliedAutoBrightness() {
@@ -495,14 +478,12 @@
             mIsShortTermModelActive = mAutomaticBrightnessController.hasUserDataPoints();
         }
     }
-
-
-    private void switchMode(int state) {
+    private void switchMode(int state, boolean sendUpdate) {
         if (mDisplayManagerFlags.areAutoBrightnessModesEnabled()
                 && mAutomaticBrightnessController != null
                 && !mAutomaticBrightnessController.isInIdleMode()) {
             mAutomaticBrightnessController.switchMode(Display.isDozeState(state)
-                    ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT);
+                    ? AUTO_BRIGHTNESS_MODE_DOZE : AUTO_BRIGHTNESS_MODE_DEFAULT, sendUpdate);
         }
     }
 
diff --git a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy2.java b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy2.java
index 58670c9..4d9c18a 100644
--- a/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy2.java
+++ b/services/core/java/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy2.java
@@ -15,8 +15,6 @@
  */
 package com.android.server.display.brightness.strategy;
 
-import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
-
 import android.annotation.Nullable;
 import android.content.Context;
 import android.hardware.display.BrightnessConfiguration;
@@ -110,7 +108,7 @@
             boolean allowAutoBrightnessWhileDozingConfig, int brightnessReason, int policy,
             float lastUserSetScreenBrightness, boolean userSetBrightnessChanged) {
         final boolean autoBrightnessEnabledInDoze =
-                allowAutoBrightnessWhileDozingConfig && policy == POLICY_DOZE;
+                allowAutoBrightnessWhileDozingConfig && Display.isDozeState(targetDisplayState);
         mIsAutoBrightnessEnabled = shouldUseAutoBrightness()
                 && (targetDisplayState == Display.STATE_ON || autoBrightnessEnabledInDoze)
                 && brightnessReason != BrightnessReason.REASON_OVERRIDE
@@ -273,23 +271,6 @@
     }
 
     /**
-     * Get the automatic screen brightness based on the last observed lux reading. Used e.g. when
-     * entering doze - we disable the light sensor, invalidate the lux, but we still need to set
-     * the initial brightness in doze mode.
-     * @param brightnessEvent Event object to populate with details about why the specific
-     *                        brightness was chosen.
-     */
-    public float getAutomaticScreenBrightnessBasedOnLastUsedLux(
-            BrightnessEvent brightnessEvent) {
-        float brightness = (mAutomaticBrightnessController != null)
-                ? mAutomaticBrightnessController
-                .getAutomaticScreenBrightnessBasedOnLastUsedLux(brightnessEvent)
-                : PowerManager.BRIGHTNESS_INVALID_FLOAT;
-        adjustAutomaticBrightnessStateIfValid(brightness);
-        return brightness;
-    }
-
-    /**
      * Gets the auto-brightness adjustment flag change reason
      */
     public int getAutoBrightnessAdjustmentReasonsFlags() {
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index a5414fc..8f775a5 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -154,6 +154,11 @@
             Flags::useFusionProxSensor
     );
 
+    private final FlagState mOffloadControlsDozeAutoBrightness = new FlagState(
+            Flags.FLAG_OFFLOAD_CONTROLS_DOZE_AUTO_BRIGHTNESS,
+            Flags::offloadControlsDozeAutoBrightness
+    );
+
     private final FlagState mPeakRefreshRatePhysicalLimit = new FlagState(
             Flags.FLAG_ENABLE_PEAK_REFRESH_RATE_PHYSICAL_LIMIT,
             Flags::enablePeakRefreshRatePhysicalLimit
@@ -327,6 +332,13 @@
         return mUseFusionProxSensor.getName();
     }
 
+    /**
+     * @return Whether DisplayOffload should control auto-brightness in doze
+     */
+    public boolean offloadControlsDozeAutoBrightness() {
+        return mOffloadControlsDozeAutoBrightness.isEnabled();
+    }
+
     public boolean isPeakRefreshRatePhysicalLimitEnabled() {
         return mPeakRefreshRatePhysicalLimit.isEnabled();
     }
@@ -373,6 +385,7 @@
         pw.println(" " + mRefactorDisplayPowerController);
         pw.println(" " + mResolutionBackupRestore);
         pw.println(" " + mUseFusionProxSensor);
+        pw.println(" " + mOffloadControlsDozeAutoBrightness);
         pw.println(" " + mPeakRefreshRatePhysicalLimit);
         pw.println(" " + mIgnoreAppPreferredRefreshRate);
         pw.println(" " + mSynthetic60hzModes);
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index 316b6db..697218d 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -246,6 +246,17 @@
 }
 
 flag {
+    name: "offload_controls_doze_auto_brightness"
+    namespace: "display_manager"
+    description: "Allows the registered DisplayOffloader to control if auto-brightness is used in doze"
+    bug: "327392714"
+    is_fixed_read_only: true
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "enable_peak_refresh_rate_physical_limit"
     namespace: "display_manager"
     description: "Flag for adding physical refresh rate limit if smooth display setting is on "
diff --git a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index 3628a57..d3efcb6 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -16,7 +16,6 @@
 
 package com.android.server.display;
 
-import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_DISABLED;
 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED;
 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT;
 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE;
@@ -44,6 +43,7 @@
 import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
 import android.os.Handler;
 import android.os.PowerManager;
+import android.os.SystemClock;
 import android.os.test.TestLooper;
 import android.util.SparseArray;
 import android.view.Display;
@@ -54,6 +54,7 @@
 
 import com.android.server.display.brightness.clamper.BrightnessClamperController;
 import com.android.server.display.config.HysteresisLevels;
+import com.android.server.display.feature.DisplayManagerFlags;
 import com.android.server.testutils.OffsettableClock;
 
 import org.junit.After;
@@ -68,6 +69,8 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class AutomaticBrightnessControllerTest {
+    private static final int ANDROID_SLEEP_TIME = 1000;
+    private static final int NANO_SECONDS_MULTIPLIER = 1000000;
     private static final float BRIGHTNESS_MIN_FLOAT = 0.0f;
     private static final float BRIGHTNESS_MAX_FLOAT = 1.0f;
     private static final int LIGHT_SENSOR_RATE = 20;
@@ -100,6 +103,8 @@
     @Mock BrightnessRangeController mBrightnessRangeController;
     @Mock
     BrightnessClamperController mBrightnessClamperController;
+    @Mock
+    DisplayManagerFlags mDisplayManagerFlags;
     @Mock BrightnessThrottler mBrightnessThrottler;
 
     @Before
@@ -148,8 +153,18 @@
                     }
 
                     @Override
-                    AutomaticBrightnessController.Clock createClock() {
-                        return mClock::now;
+                    AutomaticBrightnessController.Clock createClock(boolean isEnabled) {
+                        return new AutomaticBrightnessController.Clock() {
+                            @Override
+                            public long uptimeMillis() {
+                                return mClock.now();
+                            }
+
+                            @Override
+                            public long getSensorEventScaleTime() {
+                                return mClock.now() + ANDROID_SLEEP_TIME;
+                            }
+                        };
                     }
 
                 }, // pass in test looper instead, pass in offsettable clock
@@ -166,7 +181,7 @@
                 mContext, mBrightnessRangeController, mBrightnessThrottler,
                 useHorizon ? AMBIENT_LIGHT_HORIZON_SHORT : 1,
                 useHorizon ? AMBIENT_LIGHT_HORIZON_LONG : 10000, userLux, userNits,
-                mBrightnessClamperController
+                mBrightnessClamperController, mDisplayManagerFlags
         );
 
         when(mBrightnessRangeController.getCurrentBrightnessMax()).thenReturn(
@@ -350,7 +365,7 @@
 
         when(mBrightnessMappingStrategy.getShortTermModelTimeout()).thenReturn(2000L);
 
-        mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE);
+        mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE, /* sendUpdate= */ true);
         when(mBrightnessMappingStrategy.shouldResetShortTermModel(
                 123f, 0.5f)).thenReturn(true);
 
@@ -360,7 +375,7 @@
                 mBrightnessMappingStrategy.getShortTermModelTimeout() + 1000);
         mTestLooper.dispatchAll();
 
-        mController.switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT);
+        mController.switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT, /* sendUpdate= */ true);
         mTestLooper.moveTimeForward(4000);
         mTestLooper.dispatchAll();
 
@@ -394,14 +409,14 @@
         when(mBrightnessMappingStrategy.getUserBrightness()).thenReturn(0.51f);
         when(mBrightnessMappingStrategy.getUserLux()).thenReturn(123.0f);
 
-        mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE);
+        mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE, /* sendUpdate= */ true);
 
         // Time does not move forward, since clock is doesn't increment naturally.
         mTestLooper.dispatchAll();
 
         // Sensor reads 100000 lux,
         listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 678910));
-        mController.switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT);
+        mController.switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT, /* sendUpdate= */ true);
 
         // Verify short term model is not reset.
         verify(mBrightnessMappingStrategy, never()).clearUserDataPoints();
@@ -432,7 +447,7 @@
         when(mBrightnessMappingStrategy.getUserBrightness()).thenReturn(0.5f);
         when(mBrightnessMappingStrategy.getUserLux()).thenReturn(123f);
 
-        mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE);
+        mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE, /* sendUpdate= */ true);
         when(mIdleBrightnessMappingStrategy.getUserBrightness()).thenReturn(
                 PowerManager.BRIGHTNESS_INVALID_FLOAT);
         when(mIdleBrightnessMappingStrategy.getUserLux()).thenReturn(
@@ -446,7 +461,7 @@
                 mBrightnessMappingStrategy.getShortTermModelTimeout() + 1000);
         mTestLooper.dispatchAll();
 
-        mController.switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT);
+        mController.switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT, /* sendUpdate= */ true);
         mTestLooper.moveTimeForward(4000);
         mTestLooper.dispatchAll();
 
@@ -479,7 +494,7 @@
         when(mBrightnessMappingStrategy.getUserBrightness()).thenReturn(0.5f);
         when(mBrightnessMappingStrategy.getUserLux()).thenReturn(123f);
 
-        mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE);
+        mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE, /* sendUpdate= */ true);
         when(mIdleBrightnessMappingStrategy.getUserBrightness()).thenReturn(
                 PowerManager.BRIGHTNESS_INVALID_FLOAT);
         when(mIdleBrightnessMappingStrategy.getUserLux()).thenReturn(
@@ -493,7 +508,7 @@
         // Do not fast-forward time.
         mTestLooper.dispatchAll();
 
-        mController.switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT);
+        mController.switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT, /* sendUpdate= */ true);
         // Do not fast-forward time
         mTestLooper.dispatchAll();
 
@@ -523,7 +538,7 @@
 
         // No user brightness interaction.
 
-        mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE);
+        mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE, /* sendUpdate= */ true);
         when(mIdleBrightnessMappingStrategy.getUserBrightness()).thenReturn(
                 PowerManager.BRIGHTNESS_INVALID_FLOAT);
         when(mIdleBrightnessMappingStrategy.getUserLux()).thenReturn(
@@ -534,7 +549,7 @@
         // Do not fast-forward time.
         mTestLooper.dispatchAll();
 
-        mController.switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT);
+        mController.switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT, /* sendUpdate= */ true);
         // Do not fast-forward time
         mTestLooper.dispatchAll();
 
@@ -568,7 +583,7 @@
         verify(mBrightnessMappingStrategy, times(3)).getBrightness(anyFloat(), any(), anyInt());
 
         // Now let's do the same for idle mode
-        mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE);
+        mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE, /* sendUpdate= */ true);
         // Called once when switching,
         // setAmbientLux() is called twice and once in updateAutoBrightness(),
         // nextAmbientLightBrighteningTransition() and nextAmbientLightDarkeningTransition() are
@@ -800,6 +815,43 @@
     }
 
     @Test
+    public void testAmbientLuxBuffers_prunedBeyondLongHorizonExceptLatestValue() throws Exception {
+        when(mDisplayManagerFlags.offloadControlsDozeAutoBrightness()).thenReturn(true);
+        ArgumentCaptor<SensorEventListener> listenerCaptor =
+                ArgumentCaptor.forClass(SensorEventListener.class);
+        verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
+                eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+        SensorEventListener listener = listenerCaptor.getValue();
+
+        // Choose values such that the ring buffer's capacity is extended and the buffer is pruned
+        int increment = 11;
+        int lux = 5000;
+        for (int i = 0; i < 1000; i++) {
+            lux += increment;
+            mClock.fastForward(increment);
+            listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux,
+                    (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
+        }
+        mClock.fastForward(AMBIENT_LIGHT_HORIZON_LONG + 10);
+        int newLux = 2000;
+        listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, newLux,
+                (mClock.now() + ANDROID_SLEEP_TIME) * NANO_SECONDS_MULTIPLIER));
+
+        float[] sensorValues = mController.getLastSensorValues();
+        long[] sensorTimestamps = mController.getLastSensorTimestamps();
+        // Only the values within the horizon should be kept
+        assertEquals(2, sensorValues.length);
+        assertEquals(2, sensorTimestamps.length);
+
+        assertEquals(lux, sensorValues[0], EPSILON);
+        assertEquals(newLux, sensorValues[1], EPSILON);
+        assertEquals(mClock.now() + ANDROID_SLEEP_TIME - AMBIENT_LIGHT_HORIZON_LONG,
+                sensorTimestamps[0]);
+        assertEquals(mClock.now() + ANDROID_SLEEP_TIME,
+                sensorTimestamps[1]);
+    }
+
+    @Test
     public void testGetSensorReadingsFullBuffer() throws Exception {
         ArgumentCaptor<SensorEventListener> listenerCaptor =
                 ArgumentCaptor.forClass(SensorEventListener.class);
@@ -966,7 +1018,7 @@
                 BrightnessMappingStrategy.INVALID_NITS, /* applyDebounce= */ true,
                 /* useHorizon= */ false);
 
-        mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE);
+        mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE, /* sendUpdate= */ true);
 
         ArgumentCaptor<SensorEventListener> listenerCaptor =
                 ArgumentCaptor.forClass(SensorEventListener.class);
@@ -1003,7 +1055,7 @@
                 BrightnessMappingStrategy.INVALID_NITS, /* applyDebounce= */ true,
                 /* useHorizon= */ false);
 
-        mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE);
+        mController.switchMode(AUTO_BRIGHTNESS_MODE_IDLE, /* sendUpdate= */ true);
 
         ArgumentCaptor<SensorEventListener> listenerCaptor =
                 ArgumentCaptor.forClass(SensorEventListener.class);
@@ -1030,35 +1082,6 @@
     }
 
     @Test
-    public void testBrightnessBasedOnLastUsedLux() throws Exception {
-        ArgumentCaptor<SensorEventListener> listenerCaptor =
-                ArgumentCaptor.forClass(SensorEventListener.class);
-        verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
-                eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
-        SensorEventListener listener = listenerCaptor.getValue();
-
-        // Set up system to return 0.3f as a brightness value
-        float lux = 100.0f;
-        // Brightness as float (from 0.0f to 1.0f)
-        float normalizedBrightness = 0.3f;
-        when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux)).thenReturn(lux);
-        when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux)).thenReturn(lux);
-        when(mBrightnessMappingStrategy.getBrightness(eq(lux), /* packageName= */ eq(null),
-                /* category= */ anyInt())).thenReturn(normalizedBrightness);
-        when(mBrightnessThrottler.getBrightnessCap()).thenReturn(BRIGHTNESS_MAX_FLOAT);
-
-        // Send a new sensor value, disable the sensor and verify
-        listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux));
-        mController.configure(AUTO_BRIGHTNESS_DISABLED, /* configuration= */ null,
-                /* brightness= */ 0, /* userChangedBrightness= */ false, /* adjustment= */ 0,
-                /* userChanged= */ false, DisplayPowerRequest.POLICY_BRIGHT, Display.STATE_ON,
-                /* shouldResetShortTermModel= */ true);
-        assertEquals(normalizedBrightness,
-                mController.getAutomaticScreenBrightnessBasedOnLastUsedLux(
-                        /* brightnessEvent= */ null), EPSILON);
-    }
-
-    @Test
     public void testAutoBrightnessInDoze() throws Exception {
         ArgumentCaptor<SensorEventListener> listenerCaptor =
                 ArgumentCaptor.forClass(SensorEventListener.class);
@@ -1089,9 +1112,6 @@
         assertEquals(normalizedBrightness * DOZE_SCALE_FACTOR,
                 mController.getAutomaticScreenBrightness(
                         /* brightnessEvent= */ null), EPSILON);
-        assertEquals(normalizedBrightness * DOZE_SCALE_FACTOR,
-                mController.getAutomaticScreenBrightnessBasedOnLastUsedLux(
-                        /* brightnessEvent= */ null), EPSILON);
     }
 
     @Test
@@ -1113,7 +1133,7 @@
         when(mBrightnessThrottler.getBrightnessCap()).thenReturn(BRIGHTNESS_MAX_FLOAT);
 
         // Switch mode to DOZE
-        mController.switchMode(AUTO_BRIGHTNESS_MODE_DOZE);
+        mController.switchMode(AUTO_BRIGHTNESS_MODE_DOZE, /* sendUpdate= */ false);
 
         // Set policy to DOZE
         mController.configure(AUTO_BRIGHTNESS_ENABLED, /* configuration= */ null,
@@ -1127,9 +1147,6 @@
         // The brightness should not be scaled by the doze factor
         assertEquals(normalizedBrightness,
                 mController.getAutomaticScreenBrightness(/* brightnessEvent= */ null), EPSILON);
-        assertEquals(normalizedBrightness,
-                mController.getAutomaticScreenBrightnessBasedOnLastUsedLux(
-                        /* brightnessEvent= */ null), EPSILON);
     }
 
     @Test
@@ -1162,8 +1179,63 @@
         // The brightness should not be scaled by the doze factor
         assertEquals(normalizedBrightness,
                 mController.getAutomaticScreenBrightness(/* brightnessEvent= */ null), EPSILON);
+    }
+
+    @Test
+    public void testSwitchMode_UpdateBrightnessImmediately() throws Exception {
+        ArgumentCaptor<SensorEventListener> listenerCaptor =
+                ArgumentCaptor.forClass(SensorEventListener.class);
+        verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
+                eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+        SensorEventListener listener = listenerCaptor.getValue();
+
+        // Set up system to return 0.3f as a brightness value
+        float lux = 100.0f;
+        // Brightness as float (from 0.0f to 1.0f)
+        float normalizedBrightness = 0.3f;
+        when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux)).thenReturn(lux);
+        when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux)).thenReturn(lux);
+        when(mDozeBrightnessMappingStrategy.getBrightness(eq(lux), /* packageName= */ eq(null),
+                /* category= */ anyInt())).thenReturn(normalizedBrightness);
+        when(mBrightnessThrottler.getBrightnessCap()).thenReturn(BRIGHTNESS_MAX_FLOAT);
+
+        // Send a new sensor value
+        listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux));
+
+        // Switch mode to DOZE
+        mController.switchMode(AUTO_BRIGHTNESS_MODE_DOZE, /* sendUpdate= */ false);
+
         assertEquals(normalizedBrightness,
-                mController.getAutomaticScreenBrightnessBasedOnLastUsedLux(
-                        /* brightnessEvent= */ null), EPSILON);
+                mController.getAutomaticScreenBrightness(/* brightnessEvent= */ null), EPSILON);
+    }
+
+    @Test
+    public void testSwitchMode_UpdateBrightnessInBackground() throws Exception {
+        ArgumentCaptor<SensorEventListener> listenerCaptor =
+                ArgumentCaptor.forClass(SensorEventListener.class);
+        verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
+                eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+        SensorEventListener listener = listenerCaptor.getValue();
+
+        // Set up system to return 0.3f as a brightness value
+        float lux = 100.0f;
+        // Brightness as float (from 0.0f to 1.0f)
+        float normalizedBrightness = 0.3f;
+        when(mAmbientBrightnessThresholds.getBrighteningThreshold(lux)).thenReturn(lux);
+        when(mAmbientBrightnessThresholds.getDarkeningThreshold(lux)).thenReturn(lux);
+        when(mDozeBrightnessMappingStrategy.getBrightness(eq(lux), /* packageName= */ eq(null),
+                /* category= */ anyInt())).thenReturn(normalizedBrightness);
+        when(mBrightnessThrottler.getBrightnessCap()).thenReturn(BRIGHTNESS_MAX_FLOAT);
+
+        // Send a new sensor value
+        listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux));
+
+        // Switch mode to DOZE
+        mController.switchMode(AUTO_BRIGHTNESS_MODE_DOZE, /* sendUpdate= */ true);
+        mClock.fastForward(SystemClock.uptimeMillis());
+        mTestLooper.dispatchAll();
+
+        assertEquals(normalizedBrightness,
+                mController.getAutomaticScreenBrightness(/* brightnessEvent= */ null), EPSILON);
     }
 }
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index e5685c7..98f572d 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -1021,6 +1021,36 @@
     }
 
     @Test
+    public void testAutoBrightnessEnabled_DisplayIsInDoze_OffloadAllows() {
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.SCREEN_BRIGHTNESS_MODE,
+                Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, true);
+        mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
+        when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
+        when(mDisplayManagerFlagsMock.offloadControlsDozeAutoBrightness()).thenReturn(true);
+        when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(true);
+        mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
+
+        DisplayPowerRequest dpr = new DisplayPowerRequest();
+        dpr.policy = DisplayPowerRequest.POLICY_DOZE;
+        when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE);
+        mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+        advanceTime(1); // Run updatePowerState
+
+        verify(mHolder.automaticBrightnessController).configure(
+                AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED,
+                /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT,
+                /* userChangedBrightness= */ false, /* adjustment= */ 0,
+                /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_DOZE,
+                Display.STATE_DOZE, /* shouldResetShortTermModel= */ false
+        );
+        verify(mHolder.hbmController)
+                .setAutoBrightnessEnabled(AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED);
+    }
+
+    @Test
     public void testAutoBrightnessDisabled_ManualBrightnessMode() {
         Settings.System.putInt(mContext.getContentResolver(),
                 Settings.System.SCREEN_BRIGHTNESS_MODE,
@@ -1067,7 +1097,7 @@
     }
 
     @Test
-    public void testAutoBrightnessDisabled_DisplayIsInDoze() {
+    public void testAutoBrightnessDisabled_DisplayIsInDoze_ConfigDoesNotAllow() {
         Settings.System.putInt(mContext.getContentResolver(),
                 Settings.System.SCREEN_BRIGHTNESS_MODE,
                 Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
@@ -1093,6 +1123,36 @@
     }
 
     @Test
+    public void testAutoBrightnessDisabled_DisplayIsInDoze_OffloadDoesNotAllow() {
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.SCREEN_BRIGHTNESS_MODE,
+                Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, true);
+        mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
+        when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
+        when(mDisplayManagerFlagsMock.offloadControlsDozeAutoBrightness()).thenReturn(true);
+        when(mDisplayOffloadSession.allowAutoBrightnessInDoze()).thenReturn(false);
+        mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
+
+        DisplayPowerRequest dpr = new DisplayPowerRequest();
+        dpr.policy = DisplayPowerRequest.POLICY_DOZE;
+        when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE);
+        mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+        advanceTime(1); // Run updatePowerState
+
+        verify(mHolder.automaticBrightnessController).configure(
+                AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE,
+                /* configuration= */ null, PowerManager.BRIGHTNESS_INVALID_FLOAT,
+                /* userChangedBrightness= */ false, /* adjustment= */ 0,
+                /* userChangedAutoBrightnessAdjustment= */ false, DisplayPowerRequest.POLICY_DOZE,
+                Display.STATE_DOZE, /* shouldResetShortTermModel= */ false
+        );
+        verify(mHolder.hbmController).setAutoBrightnessEnabled(
+                AutomaticBrightnessController.AUTO_BRIGHTNESS_OFF_DUE_TO_DISPLAY_STATE);
+    }
+
+    @Test
     public void testAutoBrightnessDisabled_FollowerDisplay() {
         Settings.System.putInt(mContext.getContentResolver(),
                 Settings.System.SCREEN_BRIGHTNESS_MODE,
@@ -1191,7 +1251,8 @@
                 /* ambientLightHorizonLong= */ anyInt(),
                 eq(lux),
                 eq(nits),
-                any(BrightnessClamperController.class)
+                any(BrightnessClamperController.class),
+                any(DisplayManagerFlags.class)
         );
     }
 
@@ -1668,7 +1729,8 @@
         mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
         advanceTime(1); // Run updatePowerState
 
-        verify(mHolder.automaticBrightnessController).switchMode(AUTO_BRIGHTNESS_MODE_DOZE);
+        verify(mHolder.automaticBrightnessController)
+                .switchMode(AUTO_BRIGHTNESS_MODE_DOZE, /* sendUpdate= */ false);
 
         // Back to default mode
         when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_ON);
@@ -1676,7 +1738,8 @@
         mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
         advanceTime(1); // Run updatePowerState
 
-        verify(mHolder.automaticBrightnessController).switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT);
+        verify(mHolder.automaticBrightnessController)
+                .switchMode(AUTO_BRIGHTNESS_MODE_DEFAULT, /* sendUpdate= */ false);
     }
 
     @Test
@@ -1690,7 +1753,7 @@
         advanceTime(1); // Run updatePowerState
 
         verify(mHolder.automaticBrightnessController, never())
-                .switchMode(AUTO_BRIGHTNESS_MODE_DOZE);
+                .switchMode(eq(AUTO_BRIGHTNESS_MODE_DOZE), /* sendUpdate= */ anyBoolean());
     }
 
     @Test
@@ -1703,7 +1766,7 @@
         advanceTime(1); // Run updatePowerState
 
         verify(mHolder.automaticBrightnessController, never())
-                .switchMode(AUTO_BRIGHTNESS_MODE_DOZE);
+                .switchMode(eq(AUTO_BRIGHTNESS_MODE_DOZE), /* sendUpdate= */ anyBoolean());
     }
 
     @Test
@@ -1764,37 +1827,7 @@
     }
 
     @Test
-    public void testInitialDozeBrightness_AutoBrightnessEnabled() {
-        when(mDisplayManagerFlagsMock.areAutoBrightnessModesEnabled()).thenReturn(true);
-        when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
-        mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
-        Settings.System.putInt(mContext.getContentResolver(),
-                Settings.System.SCREEN_BRIGHTNESS_MODE,
-                Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, false);
-        float brightness = 0.277f;
-        when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
-        when(mHolder.automaticBrightnessController
-                .getAutomaticScreenBrightnessBasedOnLastUsedLux(any(BrightnessEvent.class)))
-                .thenReturn(brightness);
-        when(mHolder.hbmController.getCurrentBrightnessMax())
-                .thenReturn(PowerManager.BRIGHTNESS_MAX);
-        when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE);
-
-        DisplayPowerRequest dpr = new DisplayPowerRequest();
-        dpr.policy = DisplayPowerRequest.POLICY_DOZE;
-        mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
-        advanceTime(1); // Run updatePowerState
-
-        verify(mHolder.animator).animateTo(eq(brightness),
-                /* linearSecondTarget= */ anyFloat(), /* rate= */ anyFloat(),
-                /* ignoreAnimationLimits= */ anyBoolean());
-        verify(mHolder.brightnessSetting).setBrightness(brightness);
-    }
-
-    @Test
-    public void testInitialDozeBrightness_AutoBrightnessDisabled() {
+    public void testDozeManualBrightness() {
         when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
         mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
         Settings.System.putInt(mContext.getContentResolver(),
@@ -1827,22 +1860,17 @@
     }
 
     @Test
-    public void testInitialDozeBrightness_AbcIsNull() {
-        when(mDisplayManagerFlagsMock.areAutoBrightnessModesEnabled()).thenReturn(true);
+    public void testDozeManualBrightness_AbcIsNull() {
         when(mDisplayManagerFlagsMock.isDisplayOffloadEnabled()).thenReturn(true);
-        Settings.System.putInt(mContext.getContentResolver(),
-                Settings.System.SCREEN_BRIGHTNESS_MODE,
-                Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
-        mContext.getOrCreateTestableResources().addOverride(
-                com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, false);
         mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ true,
                 /* isAutoBrightnessAvailable= */ false);
         mHolder.dpc.setDisplayOffloadSession(mDisplayOffloadSession);
+        Settings.System.putInt(mContext.getContentResolver(),
+                Settings.System.SCREEN_BRIGHTNESS_MODE,
+                Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
         float brightness = 0.277f;
         when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
-        when(mHolder.automaticBrightnessController
-                .getAutomaticScreenBrightnessBasedOnLastUsedLux(any(BrightnessEvent.class)))
-                .thenReturn(brightness);
+        when(mHolder.brightnessSetting.getBrightness()).thenReturn(brightness);
         when(mHolder.hbmController.getCurrentBrightnessMax())
                 .thenReturn(PowerManager.BRIGHTNESS_MAX);
         when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE);
@@ -1850,13 +1878,20 @@
         DisplayPowerRequest dpr = new DisplayPowerRequest();
         dpr.policy = DisplayPowerRequest.POLICY_DOZE;
         mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
-        advanceTime(1); // Run updatePowerState
+        advanceTime(1); // Run updatePowerState, initialize
 
-        // Automatic Brightness Controller is null so no initial doze brightness should be set and
-        // we should not crash
-        verify(mHolder.animator, never()).animateTo(eq(brightness),
+        ArgumentCaptor<BrightnessSetting.BrightnessSettingListener> listenerCaptor =
+                ArgumentCaptor.forClass(BrightnessSetting.BrightnessSettingListener.class);
+        verify(mHolder.brightnessSetting).registerListener(listenerCaptor.capture());
+        BrightnessSetting.BrightnessSettingListener listener = listenerCaptor.getValue();
+        listener.onBrightnessChanged(brightness);
+        advanceTime(1); // Send messages, run updatePowerState
+
+        verify(mHolder.animator).animateTo(eq(brightness * DOZE_SCALE_FACTOR),
                 /* linearSecondTarget= */ anyFloat(), /* rate= */ anyFloat(),
                 /* ignoreAnimationLimits= */ anyBoolean());
+        assertEquals(brightness * DOZE_SCALE_FACTOR, mHolder.dpc.getDozeBrightnessForOffload(),
+                /* delta= */ 0);
     }
 
     @Test
@@ -1864,6 +1899,8 @@
         float brightness = 0.121f;
         when(mPowerManagerMock.getBrightnessConstraint(
                 PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DOZE)).thenReturn(brightness);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, false);
         mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
         when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
         when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
@@ -1881,6 +1918,31 @@
                 eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false));
     }
 
+    @Test
+    public void testDefaultDozeBrightness_ShouldNotBeUsedIfAutoBrightnessAllowedInDoze() {
+        float brightness = 0.121f;
+        when(mPowerManagerMock.getBrightnessConstraint(
+                PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DOZE)).thenReturn(brightness);
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing, true);
+        mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID);
+        when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
+        when(mHolder.automaticBrightnessController.getAutomaticScreenBrightness(
+                any(BrightnessEvent.class))).thenReturn(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+        when(mHolder.hbmController.getCurrentBrightnessMax())
+                .thenReturn(PowerManager.BRIGHTNESS_MAX);
+        when(mHolder.displayPowerState.getScreenState()).thenReturn(Display.STATE_DOZE);
+
+        DisplayPowerRequest dpr = new DisplayPowerRequest();
+        dpr.policy = DisplayPowerRequest.POLICY_DOZE;
+        mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
+        advanceTime(1); // Run updatePowerState
+
+        verify(mHolder.animator, never()).animateTo(eq(brightness),
+                /* linearSecondTarget= */ anyFloat(), /* rate= */ anyFloat(),
+                /* ignoreAnimationLimits= */ anyBoolean());
+    }
+
     /**
      * Creates a mock and registers it to {@link LocalServices}.
      */
@@ -2186,7 +2248,8 @@
                 BrightnessRangeController brightnessRangeController,
                 BrightnessThrottler brightnessThrottler, int ambientLightHorizonShort,
                 int ambientLightHorizonLong, float userLux, float userNits,
-                BrightnessClamperController brightnessClamperController) {
+                BrightnessClamperController brightnessClamperController,
+                DisplayManagerFlags displayManagerFlags) {
             return mAutomaticBrightnessController;
         }
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 7fd96c5..12050e1 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -1246,6 +1246,11 @@
 
             @Override
             public void onBlockingScreenOn(Runnable unblocker) {}
+
+            @Override
+            public boolean allowAutoBrightnessInDoze() {
+                return true;
+            }
         });
 
         mDisplayOffloadSession = new DisplayOffloadSessionImpl(mDisplayOffloader,
diff --git a/services/tests/displayservicetests/src/com/android/server/display/TestUtils.java b/services/tests/displayservicetests/src/com/android/server/display/TestUtils.java
index 8b45145..18dfcc1 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/TestUtils.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/TestUtils.java
@@ -30,13 +30,21 @@
 public final class TestUtils {
 
     public static SensorEvent createSensorEvent(Sensor sensor, int value) throws Exception {
+        return createSensorEvent(sensor, value, SystemClock.elapsedRealtimeNanos());
+    }
+
+    /**
+     * Creates a light sensor event
+     */
+    public static SensorEvent createSensorEvent(Sensor sensor, int value, long timestamp)
+            throws Exception {
         final Constructor<SensorEvent> constructor =
                 SensorEvent.class.getDeclaredConstructor(int.class);
         constructor.setAccessible(true);
         final SensorEvent event = constructor.newInstance(1);
         event.sensor = sensor;
         event.values[0] = value;
-        event.timestamp = SystemClock.elapsedRealtimeNanos();
+        event.timestamp = timestamp;
         return event;
     }
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy2Test.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy2Test.java
index 09f5bb6..498bffd 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy2Test.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategy2Test.java
@@ -343,17 +343,11 @@
                 AutomaticBrightnessController.class);
         when(automaticBrightnessController.getAutomaticScreenBrightness(any(BrightnessEvent.class)))
                 .thenReturn(automaticScreenBrightness);
-        when(automaticBrightnessController.getAutomaticScreenBrightnessBasedOnLastUsedLux(
-                any(BrightnessEvent.class)))
-                .thenReturn(automaticScreenBrightness);
         mAutomaticBrightnessStrategy.setAutomaticBrightnessController(
                 automaticBrightnessController);
         assertEquals(automaticScreenBrightness,
                 mAutomaticBrightnessStrategy.getAutomaticScreenBrightness(
                         new BrightnessEvent(DISPLAY_ID)), 0.0f);
-        assertEquals(automaticScreenBrightness,
-                mAutomaticBrightnessStrategy.getAutomaticScreenBrightnessBasedOnLastUsedLux(
-                        new BrightnessEvent(DISPLAY_ID)), 0.0f);
     }
 
     @Test
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
index d19f479..afb5a5c 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/strategy/AutomaticBrightnessStrategyTest.java
@@ -18,6 +18,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.mock;
@@ -273,7 +274,8 @@
         mAutomaticBrightnessStrategy.setAutoBrightnessState(Display.STATE_ON,
                 allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
                 userSetBrightnessChanged);
-        verify(mAutomaticBrightnessController, never()).switchMode(anyInt());
+        verify(mAutomaticBrightnessController, never())
+                .switchMode(anyInt(), /* sendUpdate= */ anyBoolean());
 
         // Validate interaction when automaticBrightnessController is in non-idle mode, and display
         // state is ON
@@ -282,7 +284,8 @@
                 allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
                 userSetBrightnessChanged);
         verify(mAutomaticBrightnessController).switchMode(
-                AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT);
+                AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DEFAULT,
+                /* sendUpdate= */ false);
 
         // Validate interaction when automaticBrightnessController is in non-idle mode, and display
         // state is DOZE
@@ -290,7 +293,8 @@
                 allowAutoBrightnessWhileDozing, brightnessReason, policy, lastUserSetBrightness,
                 userSetBrightnessChanged);
         verify(mAutomaticBrightnessController).switchMode(
-                AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE);
+                AutomaticBrightnessController.AUTO_BRIGHTNESS_MODE_DOZE,
+                /* sendUpdate= */ false);
     }
 
     @Test
@@ -388,17 +392,11 @@
                 AutomaticBrightnessController.class);
         when(automaticBrightnessController.getAutomaticScreenBrightness(any(BrightnessEvent.class)))
                 .thenReturn(automaticScreenBrightness);
-        when(automaticBrightnessController.getAutomaticScreenBrightnessBasedOnLastUsedLux(
-                any(BrightnessEvent.class)))
-                .thenReturn(automaticScreenBrightness);
         mAutomaticBrightnessStrategy.setAutomaticBrightnessController(
                 automaticBrightnessController);
         assertEquals(automaticScreenBrightness,
                 mAutomaticBrightnessStrategy.getAutomaticScreenBrightness(
                         new BrightnessEvent(DISPLAY_ID), false), 0.0f);
-        assertEquals(automaticScreenBrightness,
-                mAutomaticBrightnessStrategy.getAutomaticScreenBrightnessBasedOnLastUsedLux(
-                        new BrightnessEvent(DISPLAY_ID)), 0.0f);
     }
 
     @Test