1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.display.brightness.strategy; 18 19 import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE; 20 import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_OFF; 21 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.hardware.Sensor; 25 import android.hardware.SensorManager; 26 import android.os.Handler; 27 import android.os.SystemClock; 28 import android.util.IndentingPrintWriter; 29 30 import com.android.internal.annotations.VisibleForTesting; 31 import com.android.server.display.BrightnessMappingStrategy; 32 import com.android.server.display.DisplayBrightnessState; 33 import com.android.server.display.DisplayDeviceConfig; 34 import com.android.server.display.ScreenOffBrightnessSensorController; 35 import com.android.server.display.brightness.BrightnessReason; 36 import com.android.server.display.brightness.BrightnessUtils; 37 import com.android.server.display.brightness.StrategyExecutionRequest; 38 import com.android.server.display.brightness.StrategySelectionNotifyRequest; 39 import com.android.server.display.layout.Layout; 40 import com.android.server.display.utils.SensorUtils; 41 42 import java.io.PrintWriter; 43 44 /** 45 * This strategy is used when the screen has just turned ON, with auto-brightness ON but there is 46 * no valid lux values available yet. In such a case, if configured, we set the brightness state 47 * from this 48 */ 49 public final class AutoBrightnessFallbackStrategy implements DisplayBrightnessStrategy { 50 51 @Nullable 52 private ScreenOffBrightnessSensorController mScreenOffBrightnessSensorController; 53 @VisibleForTesting 54 @Nullable 55 Sensor mScreenOffBrightnessSensor; 56 57 // Indicates if the associated LogicalDisplay is enabled or not. 58 private boolean mIsDisplayEnabled; 59 60 // Represents if the associated display is a lead display or not. If not, the variable 61 // represents the lead display ID 62 private int mLeadDisplayId; 63 64 @NonNull 65 private final Injector mInjector; 66 AutoBrightnessFallbackStrategy(Injector injector)67 public AutoBrightnessFallbackStrategy(Injector injector) { 68 mInjector = (injector == null) ? new RealInjector() : injector; 69 } 70 71 @Override updateBrightness( StrategyExecutionRequest strategyExecutionRequest)72 public DisplayBrightnessState updateBrightness( 73 StrategyExecutionRequest strategyExecutionRequest) { 74 assert mScreenOffBrightnessSensorController != null; 75 float brightness = mScreenOffBrightnessSensorController.getAutomaticScreenBrightness(); 76 BrightnessReason brightnessReason = new BrightnessReason(); 77 brightnessReason.setReason(BrightnessReason.REASON_SCREEN_OFF_BRIGHTNESS_SENSOR); 78 return new DisplayBrightnessState.Builder() 79 .setBrightness(brightness) 80 .setBrightnessReason(brightnessReason) 81 .setDisplayBrightnessStrategyName(getName()) 82 .setShouldUpdateScreenBrightnessSetting(brightness 83 != strategyExecutionRequest.getCurrentScreenBrightness()) 84 .build(); 85 } 86 87 @NonNull 88 @Override getName()89 public String getName() { 90 return "AutoBrightnessFallbackStrategy"; 91 } 92 93 @Override getReason()94 public int getReason() { 95 return BrightnessReason.REASON_SCREEN_OFF_BRIGHTNESS_SENSOR; 96 } 97 98 @Override dump(PrintWriter writer)99 public void dump(PrintWriter writer) { 100 writer.println("AutoBrightnessFallbackStrategy:"); 101 writer.println(" mLeadDisplayId=" + mLeadDisplayId); 102 writer.println(" mIsDisplayEnabled=" + mIsDisplayEnabled); 103 writer.println(""); 104 if (mScreenOffBrightnessSensorController != null) { 105 IndentingPrintWriter ipw = new IndentingPrintWriter(writer, " "); 106 mScreenOffBrightnessSensorController.dump(ipw); 107 } 108 } 109 110 @Override strategySelectionPostProcessor( StrategySelectionNotifyRequest strategySelectionNotifyRequest)111 public void strategySelectionPostProcessor( 112 StrategySelectionNotifyRequest strategySelectionNotifyRequest) { 113 if (mScreenOffBrightnessSensorController != null) { 114 int policy = strategySelectionNotifyRequest.getDisplayPowerRequest().policy; 115 mScreenOffBrightnessSensorController.setLightSensorEnabled( 116 strategySelectionNotifyRequest.isAutoBrightnessEnabled() && mIsDisplayEnabled 117 && (policy == POLICY_OFF || (policy == POLICY_DOZE 118 && !strategySelectionNotifyRequest 119 .isAllowAutoBrightnessWhileDozingConfig())) 120 && mLeadDisplayId == Layout.NO_LEAD_DISPLAY); 121 } 122 } 123 124 /** 125 * Gets the associated ScreenOffBrightnessSensorController, controlling the brightness when 126 * auto-brightness is enabled, but the lux is not valid yet. 127 */ getScreenOffBrightnessSensorController()128 public ScreenOffBrightnessSensorController getScreenOffBrightnessSensorController() { 129 return mScreenOffBrightnessSensorController; 130 } 131 132 /** 133 * Sets up the auto brightness fallback sensor 134 */ setupAutoBrightnessFallbackSensor(SensorManager sensorManager, DisplayDeviceConfig displayDeviceConfig, Handler handler, BrightnessMappingStrategy brightnessMappingStrategy, boolean isDisplayEnabled, int leadDisplayId)135 public void setupAutoBrightnessFallbackSensor(SensorManager sensorManager, 136 DisplayDeviceConfig displayDeviceConfig, Handler handler, 137 BrightnessMappingStrategy brightnessMappingStrategy, boolean isDisplayEnabled, 138 int leadDisplayId) { 139 mIsDisplayEnabled = isDisplayEnabled; 140 mLeadDisplayId = leadDisplayId; 141 if (mScreenOffBrightnessSensorController != null) { 142 mScreenOffBrightnessSensorController.stop(); 143 mScreenOffBrightnessSensorController = null; 144 } 145 loadScreenOffBrightnessSensor(sensorManager, displayDeviceConfig); 146 int[] sensorValueToLux = displayDeviceConfig.getScreenOffBrightnessSensorValueToLux(); 147 if (mScreenOffBrightnessSensor != null && sensorValueToLux != null) { 148 mScreenOffBrightnessSensorController = 149 mInjector.getScreenOffBrightnessSensorController( 150 sensorManager, 151 mScreenOffBrightnessSensor, 152 handler, 153 SystemClock::uptimeMillis, 154 sensorValueToLux, 155 brightnessMappingStrategy); 156 } 157 } 158 159 /** 160 * Stops the associated ScreenOffBrightnessSensorController responsible for managing the 161 * brightness when this strategy is selected 162 */ stop()163 public void stop() { 164 if (mScreenOffBrightnessSensorController != null) { 165 mScreenOffBrightnessSensorController.stop(); 166 } 167 } 168 169 /** 170 * Checks if the strategy is valid, based on its internal state. Note that there can still be 171 * external factors like auto-brightness not being enabled because of which this strategy is not 172 * selected 173 */ isValid()174 public boolean isValid() { 175 return mScreenOffBrightnessSensorController != null 176 && BrightnessUtils.isValidBrightnessValue( 177 mScreenOffBrightnessSensorController.getAutomaticScreenBrightness()); 178 } 179 loadScreenOffBrightnessSensor(SensorManager sensorManager, DisplayDeviceConfig displayDeviceConfig)180 private void loadScreenOffBrightnessSensor(SensorManager sensorManager, 181 DisplayDeviceConfig displayDeviceConfig) { 182 mScreenOffBrightnessSensor = mInjector.getScreenOffBrightnessSensor(sensorManager, 183 displayDeviceConfig); 184 } 185 186 187 @VisibleForTesting 188 interface Injector { getScreenOffBrightnessSensor(SensorManager sensorManager, DisplayDeviceConfig displayDeviceConfig)189 Sensor getScreenOffBrightnessSensor(SensorManager sensorManager, 190 DisplayDeviceConfig displayDeviceConfig); 191 getScreenOffBrightnessSensorController( SensorManager sensorManager, Sensor lightSensor, Handler handler, ScreenOffBrightnessSensorController.Clock clock, int[] sensorValueToLux, BrightnessMappingStrategy brightnessMapper)192 ScreenOffBrightnessSensorController getScreenOffBrightnessSensorController( 193 SensorManager sensorManager, 194 Sensor lightSensor, 195 Handler handler, 196 ScreenOffBrightnessSensorController.Clock clock, 197 int[] sensorValueToLux, 198 BrightnessMappingStrategy brightnessMapper); 199 } 200 201 static class RealInjector implements Injector { 202 @Override getScreenOffBrightnessSensor(SensorManager sensorManager, DisplayDeviceConfig displayDeviceConfig)203 public Sensor getScreenOffBrightnessSensor(SensorManager sensorManager, 204 DisplayDeviceConfig displayDeviceConfig) { 205 return SensorUtils.findSensor(sensorManager, 206 displayDeviceConfig.getScreenOffBrightnessSensor(), SensorUtils.NO_FALLBACK); 207 } 208 209 @Override getScreenOffBrightnessSensorController( SensorManager sensorManager, Sensor lightSensor, Handler handler, ScreenOffBrightnessSensorController.Clock clock, int[] sensorValueToLux, BrightnessMappingStrategy brightnessMapper)210 public ScreenOffBrightnessSensorController getScreenOffBrightnessSensorController( 211 SensorManager sensorManager, Sensor lightSensor, Handler handler, 212 ScreenOffBrightnessSensorController.Clock clock, int[] sensorValueToLux, 213 BrightnessMappingStrategy brightnessMapper) { 214 return new ScreenOffBrightnessSensorController( 215 sensorManager, lightSensor, handler, clock, sensorValueToLux, brightnessMapper); 216 } 217 } 218 } 219