Merge "Introducing the notion of DisplayBrightnessController, and making it use DisplayBrightnessModeStrategies"
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 6b3e673..1c2c895 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -412,7 +412,7 @@
      * the PowerManagerService to focus on the global power state and not
      * have to micro-manage screen off animations, auto-brightness and other effects.
      */
-    public static final class DisplayPowerRequest {
+    public static class DisplayPowerRequest {
         // Policy: Turn screen off as if the user pressed the power button
         // including playing a screen off animation if applicable.
         public static final int POLICY_OFF = 0;
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 300b589..990569c 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -68,6 +68,7 @@
 import com.android.server.display.RampAnimator.DualRampAnimator;
 import com.android.server.display.brightness.BrightnessEvent;
 import com.android.server.display.brightness.BrightnessReason;
+import com.android.server.display.brightness.DisplayBrightnessController;
 import com.android.server.display.color.ColorDisplayService.ColorDisplayServiceInternal;
 import com.android.server.display.color.ColorDisplayService.ReduceBrightColorsListener;
 import com.android.server.display.utils.SensorUtils;
@@ -209,9 +210,6 @@
     // True if auto-brightness should be used.
     private boolean mUseSoftwareAutoBrightnessConfig;
 
-    // True if should use light sensor to automatically determine doze screen brightness.
-    private final boolean mAllowAutoBrightnessWhileDozingConfig;
-
     // Whether or not the color fade on screen on / off is enabled.
     private final boolean mColorFadeEnabled;
 
@@ -348,6 +346,8 @@
     private final BrightnessEvent mLastBrightnessEvent;
     private final BrightnessEvent mTempBrightnessEvent;
 
+    private final DisplayBrightnessController mDisplayBrightnessController;
+
     // Keeps a record of brightness changes for dumpsys.
     private RingBuffer<BrightnessEvent> mBrightnessEventRingBuffer;
 
@@ -499,9 +499,6 @@
         mScreenBrightnessForVrRangeMinimum = clampAbsoluteBrightness(
                 pm.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM_VR));
 
-        mAllowAutoBrightnessWhileDozingConfig = resources.getBoolean(
-                R.bool.config_allowAutoBrightnessWhileDozing);
-
         loadBrightnessRampRates();
         mSkipScreenOnBrightnessRamp = resources.getBoolean(
                 R.bool.config_skipScreenOnBrightnessRamp);
@@ -565,6 +562,8 @@
         mBrightnessBucketsInDozeConfig = resources.getBoolean(
                 R.bool.config_displayBrightnessBucketsInDoze);
 
+        mDisplayBrightnessController =
+                new DisplayBrightnessController(context, null, mDisplayId);
         mCurrentScreenBrightnessSetting = getScreenBrightnessSetting();
         mScreenBrightnessForVr = getScreenBrightnessForVrSetting();
         mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
@@ -1113,7 +1112,6 @@
         final int previousPolicy;
         boolean mustInitialize = false;
         int brightnessAdjustmentFlags = 0;
-        mBrightnessReasonTemp.set(null);
         mTempBrightnessEvent.reset();
         synchronized (mLock) {
             if (mStopped) {
@@ -1149,7 +1147,6 @@
         // We might override this below based on other factors.
         // Initialise brightness as invalid.
         int state;
-        float brightnessState = PowerManager.BRIGHTNESS_INVALID_FLOAT;
         boolean performScreenOffTransition = false;
         switch (mPowerRequest.policy) {
             case DisplayPowerRequest.POLICY_OFF:
@@ -1162,10 +1159,6 @@
                 } else {
                     state = Display.STATE_DOZE;
                 }
-                if (!mAllowAutoBrightnessWhileDozingConfig) {
-                    brightnessState = mPowerRequest.dozeScreenBrightness;
-                    mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE);
-                }
                 break;
             case DisplayPowerRequest.POLICY_VR:
                 state = Display.STATE_VR;
@@ -1198,10 +1191,10 @@
         animateScreenStateChange(state, performScreenOffTransition);
         state = mPowerState.getScreenState();
 
-        if (state == Display.STATE_OFF) {
-            brightnessState = PowerManager.BRIGHTNESS_OFF_FLOAT;
-            mBrightnessReasonTemp.setReason(BrightnessReason.REASON_SCREEN_OFF);
-        }
+        DisplayBrightnessState displayBrightnessState = mDisplayBrightnessController
+                .updateBrightness(mPowerRequest, state);
+        float brightnessState = displayBrightnessState.getBrightness();
+        mBrightnessReasonTemp.set(displayBrightnessState.getBrightnessReason());
 
         // Always use the VR brightness when in the VR state.
         if (state == Display.STATE_VR) {
@@ -1219,7 +1212,8 @@
         }
 
         final boolean autoBrightnessEnabledInDoze =
-                mAllowAutoBrightnessWhileDozingConfig && Display.isDozeState(state);
+                mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig()
+                        && Display.isDozeState(state);
         final boolean autoBrightnessEnabled = mPowerRequest.useAutoBrightness
                 && (state == Display.STATE_ON || autoBrightnessEnabledInDoze)
                 && Float.isNaN(brightnessState)
@@ -2277,8 +2271,6 @@
         pw.println("  mScreenBrightnessForVrRangeMaximum=" + mScreenBrightnessForVrRangeMaximum);
         pw.println("  mScreenBrightnessForVrDefault=" + mScreenBrightnessForVrDefault);
         pw.println("  mUseSoftwareAutoBrightnessConfig=" + mUseSoftwareAutoBrightnessConfig);
-        pw.println("  mAllowAutoBrightnessWhileDozingConfig="
-                + mAllowAutoBrightnessWhileDozingConfig);
         pw.println("  mSkipScreenOnBrightnessRamp=" + mSkipScreenOnBrightnessRamp);
         pw.println("  mColorFadeFadesConfig=" + mColorFadeFadesConfig);
         pw.println("  mColorFadeEnabled=" + mColorFadeEnabled);
@@ -2378,6 +2370,11 @@
             mWakelockController.dumpLocal(pw);
         }
 
+        pw.println();
+        if (mDisplayBrightnessController != null) {
+            mDisplayBrightnessController.dump(pw);
+        }
+
         if (mDisplayPowerProximityStateController != null) {
             mDisplayPowerProximityStateController.dumpLocal(pw);
         }
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
new file mode 100644
index 0000000..fe4c101
--- /dev/null
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness;
+
+import android.content.Context;
+import android.hardware.display.DisplayManagerInternal;
+import android.util.IndentingPrintWriter;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy;
+
+import java.io.PrintWriter;
+
+/**
+ * Deploys different DozeBrightnessStrategy to choose the current brightness for a specified
+ * display. Applies the chosen brightness.
+ */
+public final class DisplayBrightnessController {
+    private final int mDisplayId;
+    // Selects an appropriate strategy based on the request provided by the clients.
+    private DisplayBrightnessStrategySelector mDisplayBrightnessStrategySelector;
+
+    /**
+     * The constructor of DisplayBrightnessController.
+     */
+    public DisplayBrightnessController(Context context, Injector injector, int displayId) {
+        if (injector == null) {
+            injector = new Injector();
+        }
+        mDisplayId = displayId;
+        mDisplayBrightnessStrategySelector = injector.getDisplayBrightnessStrategySelector(context,
+                displayId);
+    }
+
+    /**
+     * Updates the display brightness. This delegates the responsibility of selecting an appropriate
+     * strategy to DisplayBrightnessStrategySelector, which is then applied to evaluate the
+     * DisplayBrightnessState. In the future,
+     * 1. This will account for clamping the brightness if needed.
+     * 2. This will notify the system about the updated brightness
+     *
+     * @param displayPowerRequest The request to update the brightness
+     * @param targetDisplayState  The target display state of the system
+     */
+    public DisplayBrightnessState updateBrightness(
+            DisplayManagerInternal.DisplayPowerRequest displayPowerRequest,
+            int targetDisplayState) {
+        DisplayBrightnessStrategy displayBrightnessStrategy =
+                mDisplayBrightnessStrategySelector.selectStrategy(displayPowerRequest,
+                        targetDisplayState);
+        return displayBrightnessStrategy.updateBrightness(displayPowerRequest);
+    }
+
+    /**
+     * Returns a boolean flag indicating if the light sensor is to be used to decide the screen
+     * brightness when dozing
+     */
+    public boolean isAllowAutoBrightnessWhileDozingConfig() {
+        return mDisplayBrightnessStrategySelector.isAllowAutoBrightnessWhileDozingConfig();
+    }
+
+    /**
+     * Used to dump the state.
+     *
+     * @param writer The PrintWriter used to dump the state.
+     */
+    public void dump(PrintWriter writer) {
+        writer.println();
+        writer.println("DisplayBrightnessController:");
+        IndentingPrintWriter ipw = new IndentingPrintWriter(writer, " ");
+        mDisplayBrightnessStrategySelector.dump(ipw);
+    }
+
+    @VisibleForTesting
+    static class Injector {
+        DisplayBrightnessStrategySelector getDisplayBrightnessStrategySelector(Context context,
+                int displayId) {
+            return new DisplayBrightnessStrategySelector(context, /* injector= */ null, displayId);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
new file mode 100644
index 0000000..88707f0
--- /dev/null
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.hardware.display.DisplayManagerInternal;
+import android.util.Slog;
+import android.view.Display;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy;
+import com.android.server.display.brightness.strategy.DozeBrightnessStrategy;
+import com.android.server.display.brightness.strategy.InvalidBrightnessStrategy;
+import com.android.server.display.brightness.strategy.ScreenOffBrightnessStrategy;
+
+import java.io.PrintWriter;
+
+/**
+ * This maintains the logic needed to decide the eligible display brightness strategy.
+ */
+public class DisplayBrightnessStrategySelector {
+    private static final String TAG = "DisplayBrightnessStrategySelector";
+    // True if light sensor is to be used to automatically determine doze screen brightness.
+    private final boolean mAllowAutoBrightnessWhileDozingConfig;
+
+    // The brightness strategy used to manage the brightness state when the display is dozing.
+    private final DozeBrightnessStrategy mDozeBrightnessStrategy;
+    // The brightness strategy used to manage the brightness state when the display is in
+    // screen off state.
+    private final ScreenOffBrightnessStrategy mScreenOffBrightnessStrategy;
+    // The brightness strategy used to manage the brightness state when the request state is
+    // invalid.
+    private final InvalidBrightnessStrategy mInvalidBrightnessStrategy;
+
+    // We take note of the old brightness strategy so that we can know when the strategy changes.
+    private String mOldBrightnessStrategyName;
+
+    private final int mDisplayId;
+
+    /**
+     * The constructor of DozeBrightnessStrategy.
+     */
+    public DisplayBrightnessStrategySelector(Context context, Injector injector, int displayId) {
+        if (injector == null) {
+            injector = new Injector();
+        }
+        mDisplayId = displayId;
+        mDozeBrightnessStrategy = injector.getDozeBrightnessStrategy();
+        mScreenOffBrightnessStrategy = injector.getScreenOffBrightnessStrategy();
+        mInvalidBrightnessStrategy = injector.getInvalidBrightnessStrategy();
+        mAllowAutoBrightnessWhileDozingConfig = context.getResources().getBoolean(
+                R.bool.config_allowAutoBrightnessWhileDozing);
+        mOldBrightnessStrategyName = mInvalidBrightnessStrategy.getName();
+    }
+
+    /**
+     * Selects the appropriate DisplayBrightnessStrategy based on the request and the display state
+     * to which the display is transitioning
+     */
+    @NonNull
+    public DisplayBrightnessStrategy selectStrategy(
+            DisplayManagerInternal.DisplayPowerRequest displayPowerRequest,
+            int targetDisplayState) {
+        DisplayBrightnessStrategy displayBrightnessStrategy = mInvalidBrightnessStrategy;
+        if (targetDisplayState == Display.STATE_OFF) {
+            displayBrightnessStrategy = mScreenOffBrightnessStrategy;
+        } else if (shouldUseDozeBrightnessStrategy(displayPowerRequest)) {
+            displayBrightnessStrategy = mDozeBrightnessStrategy;
+        }
+
+        if (!mOldBrightnessStrategyName.equals(displayBrightnessStrategy.getName())) {
+            Slog.i(TAG,
+                    "Changing the DisplayBrightnessStrategy from " + mOldBrightnessStrategyName
+                            + " to" + displayBrightnessStrategy.getName() + " for display "
+                            + mDisplayId);
+            mOldBrightnessStrategyName = displayBrightnessStrategy.getName();
+        }
+        return displayBrightnessStrategy;
+    }
+
+    /**
+     * Returns a boolean flag indicating if the light sensor is to be used to decide the screen
+     * brightness when dozing
+     */
+    public boolean isAllowAutoBrightnessWhileDozingConfig() {
+        return mAllowAutoBrightnessWhileDozingConfig;
+    }
+
+    /**
+     * Dumps the state of this class.
+     */
+    public void dump(PrintWriter writer) {
+        writer.println();
+        writer.println("DisplayBrightnessStrategySelector:");
+        writer.println(
+                "  mAllowAutoBrightnessWhileDozingConfig=" + mAllowAutoBrightnessWhileDozingConfig);
+    }
+
+    /**
+     * Validates if the conditions are met to qualify for the DozeBrightnessStrategy.
+     */
+    private boolean shouldUseDozeBrightnessStrategy(
+            DisplayManagerInternal.DisplayPowerRequest displayPowerRequest) {
+        // We are not checking the targetDisplayState, but rather relying on the policy because
+        // a user can define a different display state(displayPowerRequest.dozeScreenState) too
+        // in the request with the Doze policy
+        if (displayPowerRequest.policy == DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE) {
+            if (!mAllowAutoBrightnessWhileDozingConfig) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @VisibleForTesting
+    static class Injector {
+        ScreenOffBrightnessStrategy getScreenOffBrightnessStrategy() {
+            return new ScreenOffBrightnessStrategy();
+        }
+
+        DozeBrightnessStrategy getDozeBrightnessStrategy() {
+            return new DozeBrightnessStrategy();
+        }
+
+        InvalidBrightnessStrategy getInvalidBrightnessStrategy() {
+            return new InvalidBrightnessStrategy();
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessModeStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessModeStrategy.java
deleted file mode 100644
index 3be5933..0000000
--- a/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessModeStrategy.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.display.brightness.strategy;
-
-import android.hardware.display.DisplayManagerInternal;
-
-import com.android.server.display.DisplayBrightnessState;
-
-import java.io.PrintWriter;
-
-/**
- * An interface to define the general skeleton of how a BrightnessModeStrategy should look like
- * This is responsible for deciding the DisplayBrightnessState that the display should change to,
- * not taking into account clamping that might be needed
- */
-public interface DisplayBrightnessModeStrategy {
-    /**
-     * Decides the DisplayBrightnessState that the system should change to.
-     *
-     * @param displayPowerRequest           The request to evaluate the updated brightness
-     * @param displayState                  The target displayState to which the system should
-     *                                      change to after processing the request
-     * @param displayBrightnessStateBuilder The DisplayBrightnessStateBuilder, consisting of
-     *                                      DisplayBrightnessState that have been constructed so far
-     */
-    DisplayBrightnessState.Builder updateBrightness(
-            DisplayManagerInternal.DisplayPowerRequest displayPowerRequest, int displayState,
-            DisplayBrightnessState.Builder displayBrightnessStateBuilder);
-
-    /**
-     * Used to dump the state.
-     *
-     * @param writer The PrintWriter used to dump the state.
-     */
-    void dump(PrintWriter writer);
-}
diff --git a/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategy.java
new file mode 100644
index 0000000..27d04fd
--- /dev/null
+++ b/services/core/java/com/android/server/display/brightness/strategy/DisplayBrightnessStrategy.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness.strategy;
+
+import android.annotation.NonNull;
+import android.hardware.display.DisplayManagerInternal;
+
+import com.android.server.display.DisplayBrightnessState;
+
+/**
+ * Decides the DisplayBrighntessState that the display should change to based on strategy-specific
+ * logic within each implementation. Clamping should be done outside of DisplayBrightnessStrategy if
+ * not an integral part of the strategy.
+ */
+public interface DisplayBrightnessStrategy {
+    /**
+     * Decides the DisplayBrightnessState that the system should change to.
+     *
+     * @param displayPowerRequest The request to evaluate the updated brightness
+     */
+    DisplayBrightnessState updateBrightness(
+            DisplayManagerInternal.DisplayPowerRequest displayPowerRequest);
+
+    /**
+     * Returns the name of the Strategy
+     */
+    @NonNull
+    String getName();
+}
diff --git a/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java
new file mode 100644
index 0000000..c8b2c83
--- /dev/null
+++ b/services/core/java/com/android/server/display/brightness/strategy/DozeBrightnessStrategy.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness.strategy;
+
+import android.hardware.display.DisplayManagerInternal;
+
+import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.brightness.BrightnessReason;
+
+/**
+ * Manages the brightness of the display when the system is in the doze state.
+ */
+public class DozeBrightnessStrategy implements DisplayBrightnessStrategy {
+
+    @Override
+    public DisplayBrightnessState updateBrightness(
+            DisplayManagerInternal.DisplayPowerRequest displayPowerRequest) {
+        // Todo(brup): Introduce a validator class and add validations before setting the brightness
+        BrightnessReason brightnessReason = new BrightnessReason();
+        brightnessReason.setReason(BrightnessReason.REASON_DOZE);
+        return new DisplayBrightnessState.Builder()
+                .setBrightness(displayPowerRequest.dozeScreenBrightness)
+                .setSdrBrightness(displayPowerRequest.dozeScreenBrightness)
+                .setBrightnessReason(brightnessReason)
+                .build();
+    }
+
+    @Override
+    public String getName() {
+        return "DozeBrightnessStrategy";
+    }
+
+}
diff --git a/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java
new file mode 100644
index 0000000..f6ddf4f
--- /dev/null
+++ b/services/core/java/com/android/server/display/brightness/strategy/InvalidBrightnessStrategy.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness.strategy;
+
+import android.hardware.display.DisplayManagerInternal;
+import android.os.PowerManager;
+
+import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.brightness.BrightnessReason;
+
+/**
+ * Manages the brightness of the display when the system is in the invalid state.
+ */
+public class InvalidBrightnessStrategy implements DisplayBrightnessStrategy {
+    @Override
+    public DisplayBrightnessState updateBrightness(
+            DisplayManagerInternal.DisplayPowerRequest displayPowerRequest) {
+        BrightnessReason brightnessReason = new BrightnessReason();
+        brightnessReason.set(null);
+        return new DisplayBrightnessState.Builder()
+                .setBrightness(PowerManager.BRIGHTNESS_INVALID_FLOAT)
+                .setSdrBrightness(PowerManager.BRIGHTNESS_INVALID_FLOAT)
+                .setBrightnessReason(brightnessReason)
+                .build();
+    }
+
+    @Override
+    public String getName() {
+        return "InvalidBrightnessStrategy";
+    }
+}
diff --git a/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java
new file mode 100644
index 0000000..4138513
--- /dev/null
+++ b/services/core/java/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategy.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness.strategy;
+
+import android.hardware.display.DisplayManagerInternal;
+import android.os.PowerManager;
+
+import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.brightness.BrightnessReason;
+
+/**
+ * Manages the brightness of the display when the system is in the ScreenOff state.
+ */
+public class ScreenOffBrightnessStrategy implements DisplayBrightnessStrategy {
+    @Override
+    public DisplayBrightnessState updateBrightness(
+            DisplayManagerInternal.DisplayPowerRequest displayPowerRequest) {
+        // Todo(brup): Introduce a validator class and add validations before setting the brightness
+        BrightnessReason brightnessReason = new BrightnessReason();
+        brightnessReason.setReason(BrightnessReason.REASON_SCREEN_OFF);
+        return new DisplayBrightnessState.Builder()
+                .setBrightness(PowerManager.BRIGHTNESS_OFF_FLOAT)
+                .setSdrBrightness(PowerManager.BRIGHTNESS_OFF_FLOAT)
+                .setBrightnessReason(brightnessReason)
+                .build();
+    }
+
+    @Override
+    public String getName() {
+        return "ScreenOffBrightnessStrategy";
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
new file mode 100644
index 0000000..cbeaf7b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessControllerTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
+import android.view.Display;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class DisplayBrightnessControllerTest {
+    private static final int DISPLAY_ID = 1;
+
+    @Mock
+    private DisplayBrightnessStrategySelector mDisplayBrightnessStrategySelector;
+    @Mock
+    private Context mContext;
+
+    private DisplayBrightnessController mDisplayBrightnessController;
+
+    @Before
+    public void before() {
+        MockitoAnnotations.initMocks(this);
+        DisplayBrightnessController.Injector injector = new DisplayBrightnessController.Injector() {
+            @Override
+            DisplayBrightnessStrategySelector getDisplayBrightnessStrategySelector(
+                    Context context, int displayId) {
+                return mDisplayBrightnessStrategySelector;
+            }
+        };
+        mDisplayBrightnessController = new DisplayBrightnessController(mContext, injector,
+                DISPLAY_ID);
+    }
+
+    @Test
+    public void updateBrightnessWorksAsExpected() {
+        DisplayPowerRequest displayPowerRequest = mock(DisplayPowerRequest.class);
+        DisplayBrightnessStrategy displayBrightnessStrategy = mock(DisplayBrightnessStrategy.class);
+        int targetDisplayState = Display.STATE_DOZE;
+        when(mDisplayBrightnessStrategySelector.selectStrategy(displayPowerRequest,
+                targetDisplayState)).thenReturn(displayBrightnessStrategy);
+        mDisplayBrightnessController.updateBrightness(displayPowerRequest, targetDisplayState);
+        verify(displayBrightnessStrategy).updateBrightness(displayPowerRequest);
+    }
+
+    @Test
+    public void isAllowAutoBrightnessWhileDozingConfigDelegatesToDozeBrightnessStrategy() {
+        mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig();
+        verify(mDisplayBrightnessStrategySelector).isAllowAutoBrightnessWhileDozingConfig();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
new file mode 100644
index 0000000..ba31e8c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.hardware.display.DisplayManagerInternal;
+import android.view.Display;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.R;
+import com.android.server.display.brightness.strategy.DozeBrightnessStrategy;
+import com.android.server.display.brightness.strategy.InvalidBrightnessStrategy;
+import com.android.server.display.brightness.strategy.ScreenOffBrightnessStrategy;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class DisplayBrightnessStrategySelectorTest {
+    private static final boolean DISALLOW_AUTO_BRIGHTNESS_WHILE_DOZING = false;
+    private static final int DISPLAY_ID = 1;
+
+    @Mock
+    private ScreenOffBrightnessStrategy mScreenOffBrightnessModeStrategy;
+    @Mock
+    private DozeBrightnessStrategy mDozeBrightnessModeStrategy;
+    @Mock
+    private InvalidBrightnessStrategy mInvalidBrightnessStrategy;
+    @Mock
+    private Context mContext;
+    @Mock
+    private Resources mResources;
+
+    private DisplayBrightnessStrategySelector mDisplayBrightnessStrategySelector;
+
+    @Before
+    public void before() {
+        MockitoAnnotations.initMocks(this);
+        when(mContext.getResources()).thenReturn(mResources);
+        DisplayBrightnessStrategySelector.Injector injector =
+                new DisplayBrightnessStrategySelector.Injector() {
+                    @Override
+                    ScreenOffBrightnessStrategy getScreenOffBrightnessStrategy() {
+                        return mScreenOffBrightnessModeStrategy;
+                    }
+
+                    @Override
+                    DozeBrightnessStrategy getDozeBrightnessStrategy() {
+                        return mDozeBrightnessModeStrategy;
+                    }
+
+                    @Override
+                    InvalidBrightnessStrategy getInvalidBrightnessStrategy() {
+                        return mInvalidBrightnessStrategy;
+                    }
+                };
+        mDisplayBrightnessStrategySelector = new DisplayBrightnessStrategySelector(mContext,
+                injector, DISPLAY_ID);
+
+    }
+
+    @Test
+    public void selectStrategySelectsDozeStrategyWhenValid() {
+        DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
+                DisplayManagerInternal.DisplayPowerRequest.class);
+        displayPowerRequest.policy = DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
+        when(mResources.getBoolean(R.bool.config_allowAutoBrightnessWhileDozing)).thenReturn(
+                DISALLOW_AUTO_BRIGHTNESS_WHILE_DOZING);
+        assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(displayPowerRequest,
+                Display.STATE_DOZE), mDozeBrightnessModeStrategy);
+    }
+
+    @Test
+    public void selectStrategySelectsScreenOffStrategyWhenValid() {
+        DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
+                DisplayManagerInternal.DisplayPowerRequest.class);
+        assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(displayPowerRequest,
+                Display.STATE_OFF), mScreenOffBrightnessModeStrategy);
+    }
+
+    @Test
+    public void selectStrategySelectsInvalidStrategyWhenNoStrategyIsValid() {
+        DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
+                DisplayManagerInternal.DisplayPowerRequest.class);
+        assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(displayPowerRequest,
+                Display.STATE_ON), mInvalidBrightnessStrategy);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java
new file mode 100644
index 0000000..29652ff
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/DozeBrightnessStrategyTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness.strategy;
+
+import static org.junit.Assert.assertEquals;
+
+import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.brightness.BrightnessReason;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DozeBrightnessStrategyTest {
+    private DozeBrightnessStrategy mDozeBrightnessModeStrategy;
+
+    @Before
+    public void before() {
+        mDozeBrightnessModeStrategy = new DozeBrightnessStrategy();
+    }
+
+    @Test
+    public void updateBrightnessWorksAsExpectedWhenScreenDozeStateIsRequested() {
+        DisplayPowerRequest displayPowerRequest = new DisplayPowerRequest();
+        float dozeScreenBrightness = 0.2f;
+        displayPowerRequest.dozeScreenBrightness = dozeScreenBrightness;
+        BrightnessReason brightnessReason = new BrightnessReason();
+        brightnessReason.setReason(BrightnessReason.REASON_DOZE);
+        DisplayBrightnessState expectedDisplayBrightnessState =
+                new DisplayBrightnessState.Builder()
+                        .setBrightness(dozeScreenBrightness)
+                        .setBrightnessReason(brightnessReason)
+                        .setSdrBrightness(dozeScreenBrightness)
+                        .build();
+        DisplayBrightnessState updatedDisplayBrightnessState =
+                mDozeBrightnessModeStrategy.updateBrightness(displayPowerRequest);
+        assertEquals(updatedDisplayBrightnessState, expectedDisplayBrightnessState);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java
new file mode 100644
index 0000000..0505475
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/ScreenOffBrightnessStrategyTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.display.brightness.strategy;
+
+import static org.junit.Assert.assertEquals;
+
+import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
+import android.os.PowerManager;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.brightness.BrightnessReason;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public final class ScreenOffBrightnessStrategyTest {
+
+    private ScreenOffBrightnessStrategy mScreenOffBrightnessModeStrategy;
+
+    @Before
+    public void before() {
+        mScreenOffBrightnessModeStrategy = new ScreenOffBrightnessStrategy();
+    }
+
+    @Test
+    public void updateBrightnessWorksAsExpectedWhenScreenOffDisplayState() {
+        DisplayPowerRequest displayPowerRequest = new DisplayPowerRequest();
+        BrightnessReason brightnessReason = new BrightnessReason();
+        brightnessReason.setReason(BrightnessReason.REASON_SCREEN_OFF);
+        DisplayBrightnessState expectedDisplayBrightnessState =
+                new DisplayBrightnessState.Builder()
+                        .setBrightness(PowerManager.BRIGHTNESS_OFF_FLOAT)
+                        .setSdrBrightness(PowerManager.BRIGHTNESS_OFF_FLOAT)
+                        .setBrightnessReason(brightnessReason)
+                        .build();
+        DisplayBrightnessState updatedDisplayBrightnessState =
+                mScreenOffBrightnessModeStrategy.updateBrightness(displayPowerRequest);
+        assertEquals(updatedDisplayBrightnessState, expectedDisplayBrightnessState);
+    }
+}