1 /*
2  * Copyright (C) 2022 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;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.Context;
22 import android.hardware.display.DisplayManagerInternal;
23 import android.util.IndentingPrintWriter;
24 import android.util.Slog;
25 import android.view.Display;
26 
27 import com.android.internal.R;
28 import com.android.internal.annotations.VisibleForTesting;
29 import com.android.server.display.brightness.strategy.AutoBrightnessFallbackStrategy;
30 import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy;
31 import com.android.server.display.brightness.strategy.AutomaticBrightnessStrategy2;
32 import com.android.server.display.brightness.strategy.BoostBrightnessStrategy;
33 import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy;
34 import com.android.server.display.brightness.strategy.DozeBrightnessStrategy;
35 import com.android.server.display.brightness.strategy.FallbackBrightnessStrategy;
36 import com.android.server.display.brightness.strategy.FollowerBrightnessStrategy;
37 import com.android.server.display.brightness.strategy.InvalidBrightnessStrategy;
38 import com.android.server.display.brightness.strategy.OffloadBrightnessStrategy;
39 import com.android.server.display.brightness.strategy.OverrideBrightnessStrategy;
40 import com.android.server.display.brightness.strategy.ScreenOffBrightnessStrategy;
41 import com.android.server.display.brightness.strategy.TemporaryBrightnessStrategy;
42 import com.android.server.display.feature.DisplayManagerFlags;
43 
44 import java.io.PrintWriter;
45 
46 /**
47  * This maintains the logic needed to decide the eligible display brightness strategy.
48  */
49 public class DisplayBrightnessStrategySelector {
50     private static final String TAG = "DisplayBrightnessStrategySelector";
51     // True if the config to use the light sensor to automatically determine doze screen brightness
52     // is enabled. Note that the actual value representing if the auto-brightness is to be kept
53     // enabled while dozing can differ, but is dependent on this
54     private final boolean mAllowAutoBrightnessWhileDozingConfig;
55 
56     // True if light sensor is to be used to automatically determine doze screen brightness.
57     private boolean mAllowAutoBrightnessWhileDozing;
58 
59     // The brightness strategy used to manage the brightness state when the display is dozing.
60     private final DozeBrightnessStrategy mDozeBrightnessStrategy;
61     // The brightness strategy used to manage the brightness state when the display is in
62     // screen off state.
63     private final ScreenOffBrightnessStrategy mScreenOffBrightnessStrategy;
64     // The brightness strategy used to manage the brightness state when the request state is
65     // invalid.
66     private final OverrideBrightnessStrategy mOverrideBrightnessStrategy;
67     // The brightness strategy used to manage the brightness state in temporary state
68     private final TemporaryBrightnessStrategy mTemporaryBrightnessStrategy;
69     // The brightness strategy used to manage the brightness state when boost is requested
70     private final BoostBrightnessStrategy mBoostBrightnessStrategy;
71     // The brightness strategy used for additional displays
72     private final FollowerBrightnessStrategy mFollowerBrightnessStrategy;
73     // The brightness strategy used to manage the brightness state when the request is invalid.
74     private final InvalidBrightnessStrategy mInvalidBrightnessStrategy;
75     // Controls brightness when automatic (adaptive) brightness is running.
76     private final AutomaticBrightnessStrategy2 mAutomaticBrightnessStrategy;
77 
78     // The automatic strategy which controls the brightness when adaptive mode is ON.
79     private final AutomaticBrightnessStrategy mAutomaticBrightnessStrategy1;
80 
81     // The deprecated AutomaticBrightnessStrategy. Avoid using it for any new features without
82     // consulting with the display frameworks team. Use {@link AutomaticBrightnessStrategy} instead.
83     // This will be removed once the flag
84     // {@link DisplayManagerFlags#isRefactorDisplayPowerControllerEnabled is fully rolled out
85     private final AutomaticBrightnessStrategy2 mAutomaticBrightnessStrategy2;
86     // Controls the brightness if adaptive brightness is on and there exists an active offload
87     // session. Brightness value is provided by the offload session.
88     @Nullable
89     private final OffloadBrightnessStrategy mOffloadBrightnessStrategy;
90 
91     @Nullable
92     private final AutoBrightnessFallbackStrategy mAutoBrightnessFallbackStrategy;
93 
94     @Nullable
95     private final FallbackBrightnessStrategy mFallbackBrightnessStrategy;
96 
97     // A collective representation of all the strategies that the selector is aware of. This is
98     // non null, but the strategies this is tracking can be null
99     @NonNull
100     @VisibleForTesting
101     final DisplayBrightnessStrategy[] mDisplayBrightnessStrategies;
102 
103     @NonNull
104     private final DisplayManagerFlags mDisplayManagerFlags;
105 
106     // We take note of the old brightness strategy so that we can know when the strategy changes.
107     private String mOldBrightnessStrategyName;
108 
109     private final int mDisplayId;
110 
111     /**
112      * The constructor of DozeBrightnessStrategy.
113      */
DisplayBrightnessStrategySelector(Context context, Injector injector, int displayId, DisplayManagerFlags flags)114     public DisplayBrightnessStrategySelector(Context context, Injector injector, int displayId,
115             DisplayManagerFlags flags) {
116         if (injector == null) {
117             injector = new Injector();
118         }
119         mDisplayManagerFlags = flags;
120         mDisplayId = displayId;
121         mDozeBrightnessStrategy = injector.getDozeBrightnessStrategy();
122         mScreenOffBrightnessStrategy = injector.getScreenOffBrightnessStrategy();
123         mOverrideBrightnessStrategy = injector.getOverrideBrightnessStrategy();
124         mTemporaryBrightnessStrategy = injector.getTemporaryBrightnessStrategy();
125         mBoostBrightnessStrategy = injector.getBoostBrightnessStrategy();
126         mFollowerBrightnessStrategy = injector.getFollowerBrightnessStrategy(displayId);
127         mInvalidBrightnessStrategy = injector.getInvalidBrightnessStrategy();
128         mAutomaticBrightnessStrategy1 =
129                 (!mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()) ? null
130                         : injector.getAutomaticBrightnessStrategy1(context, displayId,
131                                 mDisplayManagerFlags);
132         mAutomaticBrightnessStrategy2 =
133                 (mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()) ? null
134                         : injector.getAutomaticBrightnessStrategy2(context, displayId);
135         mAutomaticBrightnessStrategy =
136                 (mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled())
137                         ? mAutomaticBrightnessStrategy1 : mAutomaticBrightnessStrategy2;
138         mAutoBrightnessFallbackStrategy = (mDisplayManagerFlags
139                 .isRefactorDisplayPowerControllerEnabled())
140                 ? injector.getAutoBrightnessFallbackStrategy() : null;
141         if (flags.isDisplayOffloadEnabled()) {
142             mOffloadBrightnessStrategy = injector
143                     .getOffloadBrightnessStrategy(mDisplayManagerFlags);
144         } else {
145             mOffloadBrightnessStrategy = null;
146         }
147         mFallbackBrightnessStrategy = (mDisplayManagerFlags
148                 .isRefactorDisplayPowerControllerEnabled())
149                 ? injector.getFallbackBrightnessStrategy() : null;
150         mDisplayBrightnessStrategies = new DisplayBrightnessStrategy[]{mInvalidBrightnessStrategy,
151                 mScreenOffBrightnessStrategy, mDozeBrightnessStrategy, mFollowerBrightnessStrategy,
152                 mBoostBrightnessStrategy, mOverrideBrightnessStrategy, mTemporaryBrightnessStrategy,
153                 mAutomaticBrightnessStrategy1, mOffloadBrightnessStrategy,
154                 mAutoBrightnessFallbackStrategy, mFallbackBrightnessStrategy};
155         mAllowAutoBrightnessWhileDozingConfig = context.getResources().getBoolean(
156                 R.bool.config_allowAutoBrightnessWhileDozing);
157         mAllowAutoBrightnessWhileDozing = mAllowAutoBrightnessWhileDozingConfig;
158         mOldBrightnessStrategyName = mInvalidBrightnessStrategy.getName();
159     }
160 
161     /**
162      * Selects the appropriate DisplayBrightnessStrategy based on the request and the display state
163      * to which the display is transitioning
164      */
165     @NonNull
selectStrategy( StrategySelectionRequest strategySelectionRequest)166     public DisplayBrightnessStrategy selectStrategy(
167             StrategySelectionRequest strategySelectionRequest) {
168         DisplayBrightnessStrategy displayBrightnessStrategy = mInvalidBrightnessStrategy;
169         int targetDisplayState = strategySelectionRequest.getTargetDisplayState();
170         DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = strategySelectionRequest
171                 .getDisplayPowerRequest();
172         setAllowAutoBrightnessWhileDozing(strategySelectionRequest.getDisplayOffloadSession());
173         if (targetDisplayState == Display.STATE_OFF) {
174             displayBrightnessStrategy = mScreenOffBrightnessStrategy;
175         } else if (shouldUseDozeBrightnessStrategy(displayPowerRequest)) {
176             displayBrightnessStrategy = mDozeBrightnessStrategy;
177         } else if (BrightnessUtils.isValidBrightnessValue(
178                 mFollowerBrightnessStrategy.getBrightnessToFollow())) {
179             displayBrightnessStrategy = mFollowerBrightnessStrategy;
180         } else if (displayPowerRequest.boostScreenBrightness) {
181             displayBrightnessStrategy = mBoostBrightnessStrategy;
182         } else if (BrightnessUtils
183                 .isValidBrightnessValue(displayPowerRequest.screenBrightnessOverride)) {
184             displayBrightnessStrategy = mOverrideBrightnessStrategy;
185         } else if (BrightnessUtils.isValidBrightnessValue(
186                 mTemporaryBrightnessStrategy.getTemporaryScreenBrightness())) {
187             displayBrightnessStrategy = mTemporaryBrightnessStrategy;
188         } else if (mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()
189                 && isAutomaticBrightnessStrategyValid(strategySelectionRequest)) {
190             displayBrightnessStrategy = mAutomaticBrightnessStrategy1;
191         } else if (mAutomaticBrightnessStrategy.shouldUseAutoBrightness()
192                 && mOffloadBrightnessStrategy != null && BrightnessUtils.isValidBrightnessValue(
193                 mOffloadBrightnessStrategy.getOffloadScreenBrightness())) {
194             displayBrightnessStrategy = mOffloadBrightnessStrategy;
195         } else if (isAutoBrightnessFallbackStrategyValid()) {
196             displayBrightnessStrategy = mAutoBrightnessFallbackStrategy;
197         } else {
198             // This will become the ultimate fallback strategy once the flag has been fully rolled
199             // out
200             if (mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()) {
201                 displayBrightnessStrategy = mFallbackBrightnessStrategy;
202             }
203         }
204 
205         if (mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()) {
206             postProcess(constructStrategySelectionNotifyRequest(displayBrightnessStrategy,
207                     strategySelectionRequest));
208         }
209 
210         if (!mOldBrightnessStrategyName.equals(displayBrightnessStrategy.getName())) {
211             Slog.i(TAG,
212                     "Changing the DisplayBrightnessStrategy from " + mOldBrightnessStrategyName
213                             + " to " + displayBrightnessStrategy.getName() + " for display "
214                             + mDisplayId);
215             mOldBrightnessStrategyName = displayBrightnessStrategy.getName();
216         }
217         return displayBrightnessStrategy;
218     }
219 
getTemporaryDisplayBrightnessStrategy()220     public TemporaryBrightnessStrategy getTemporaryDisplayBrightnessStrategy() {
221         return mTemporaryBrightnessStrategy;
222     }
223 
getFollowerDisplayBrightnessStrategy()224     public FollowerBrightnessStrategy getFollowerDisplayBrightnessStrategy() {
225         return mFollowerBrightnessStrategy;
226     }
227 
getAutomaticBrightnessStrategy()228     public AutomaticBrightnessStrategy2 getAutomaticBrightnessStrategy() {
229         return mAutomaticBrightnessStrategy;
230     }
231 
232     @Nullable
getOffloadBrightnessStrategy()233     public OffloadBrightnessStrategy getOffloadBrightnessStrategy() {
234         return mOffloadBrightnessStrategy;
235     }
236 
237     /**
238      * Returns a boolean flag indicating if the light sensor is to be used to decide the screen
239      * brightness when dozing
240      */
isAllowAutoBrightnessWhileDozing()241     public boolean isAllowAutoBrightnessWhileDozing() {
242         return mAllowAutoBrightnessWhileDozing;
243     }
244 
245     /**
246      * Returns the config value indicating whether auto brightness while dozing is to be
247      * allowed ot not
248      */
isAllowAutoBrightnessWhileDozingConfig()249     public boolean isAllowAutoBrightnessWhileDozingConfig() {
250         return mAllowAutoBrightnessWhileDozingConfig;
251     }
252 
253     @Nullable
getAutoBrightnessFallbackStrategy()254     public AutoBrightnessFallbackStrategy getAutoBrightnessFallbackStrategy() {
255         return mAutoBrightnessFallbackStrategy;
256     }
257 
258     /**
259      * Dumps the state of this class.
260      */
dump(PrintWriter writer)261     public void dump(PrintWriter writer) {
262         writer.println();
263         writer.println("DisplayBrightnessStrategySelector:");
264         writer.println("  mDisplayId= " + mDisplayId);
265         writer.println("  mOldBrightnessStrategyName= " + mOldBrightnessStrategyName);
266         writer.println(
267                 "  mAllowAutoBrightnessWhileDozingConfig= "
268                         + mAllowAutoBrightnessWhileDozingConfig);
269         writer.println(
270                 "  mAllowAutoBrightnessWhileDozing= " + mAllowAutoBrightnessWhileDozing);
271         IndentingPrintWriter ipw = new IndentingPrintWriter(writer, " ");
272         for (DisplayBrightnessStrategy displayBrightnessStrategy : mDisplayBrightnessStrategies) {
273             if (displayBrightnessStrategy != null) {
274                 displayBrightnessStrategy.dump(ipw);
275             }
276         }
277     }
278 
279     @VisibleForTesting
setAllowAutoBrightnessWhileDozing( DisplayManagerInternal.DisplayOffloadSession displayOffloadSession)280     void setAllowAutoBrightnessWhileDozing(
281             DisplayManagerInternal.DisplayOffloadSession displayOffloadSession) {
282         mAllowAutoBrightnessWhileDozing = mAllowAutoBrightnessWhileDozingConfig;
283         if (mDisplayManagerFlags.offloadControlsDozeAutoBrightness()
284                 && mDisplayManagerFlags.isDisplayOffloadEnabled()
285                 && displayOffloadSession != null) {
286             mAllowAutoBrightnessWhileDozing &= displayOffloadSession.allowAutoBrightnessInDoze();
287         }
288     }
289 
isAutoBrightnessFallbackStrategyValid()290     private boolean isAutoBrightnessFallbackStrategyValid() {
291         return mDisplayManagerFlags.isRefactorDisplayPowerControllerEnabled()
292                 && mAutoBrightnessFallbackStrategy != null
293                 && getAutomaticBrightnessStrategy().shouldUseAutoBrightness()
294                 && mAutoBrightnessFallbackStrategy.isValid();
295     }
296 
isAutomaticBrightnessStrategyValid( StrategySelectionRequest strategySelectionRequest)297     private boolean isAutomaticBrightnessStrategyValid(
298             StrategySelectionRequest strategySelectionRequest) {
299         mAutomaticBrightnessStrategy1.setAutoBrightnessState(
300                 strategySelectionRequest.getTargetDisplayState(),
301                 mAllowAutoBrightnessWhileDozing,
302                 BrightnessReason.REASON_UNKNOWN,
303                 strategySelectionRequest.getDisplayPowerRequest().policy,
304                 strategySelectionRequest.getLastUserSetScreenBrightness(),
305                 strategySelectionRequest.isUserSetBrightnessChanged());
306         return mAutomaticBrightnessStrategy1.isAutoBrightnessValid();
307     }
308 
constructStrategySelectionNotifyRequest( DisplayBrightnessStrategy selectedDisplayBrightnessStrategy, StrategySelectionRequest strategySelectionRequest)309     private StrategySelectionNotifyRequest constructStrategySelectionNotifyRequest(
310             DisplayBrightnessStrategy selectedDisplayBrightnessStrategy,
311             StrategySelectionRequest strategySelectionRequest) {
312         return new StrategySelectionNotifyRequest(
313                 strategySelectionRequest.getDisplayPowerRequest(),
314                 strategySelectionRequest.getTargetDisplayState(),
315                 selectedDisplayBrightnessStrategy,
316                 strategySelectionRequest.getLastUserSetScreenBrightness(),
317                 strategySelectionRequest.isUserSetBrightnessChanged(),
318                 mAllowAutoBrightnessWhileDozing,
319                 getAutomaticBrightnessStrategy().shouldUseAutoBrightness());
320     }
321 
postProcess(StrategySelectionNotifyRequest strategySelectionNotifyRequest)322     private void postProcess(StrategySelectionNotifyRequest strategySelectionNotifyRequest) {
323         for (DisplayBrightnessStrategy displayBrightnessStrategy : mDisplayBrightnessStrategies) {
324             if (displayBrightnessStrategy != null) {
325                 displayBrightnessStrategy.strategySelectionPostProcessor(
326                         strategySelectionNotifyRequest);
327             }
328         }
329     }
330 
331     /**
332      * Validates if the conditions are met to qualify for the DozeBrightnessStrategy.
333      */
shouldUseDozeBrightnessStrategy( DisplayManagerInternal.DisplayPowerRequest displayPowerRequest)334     private boolean shouldUseDozeBrightnessStrategy(
335             DisplayManagerInternal.DisplayPowerRequest displayPowerRequest) {
336         // We are not checking the targetDisplayState, but rather relying on the policy because
337         // a user can define a different display state(displayPowerRequest.dozeScreenState) too
338         // in the request with the Doze policy
339         return displayPowerRequest.policy == DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE
340                 && !mAllowAutoBrightnessWhileDozing
341                 && BrightnessUtils.isValidBrightnessValue(displayPowerRequest.dozeScreenBrightness);
342     }
343 
344     @VisibleForTesting
345     static class Injector {
getScreenOffBrightnessStrategy()346         ScreenOffBrightnessStrategy getScreenOffBrightnessStrategy() {
347             return new ScreenOffBrightnessStrategy();
348         }
349 
getDozeBrightnessStrategy()350         DozeBrightnessStrategy getDozeBrightnessStrategy() {
351             return new DozeBrightnessStrategy();
352         }
353 
getOverrideBrightnessStrategy()354         OverrideBrightnessStrategy getOverrideBrightnessStrategy() {
355             return new OverrideBrightnessStrategy();
356         }
357 
getTemporaryBrightnessStrategy()358         TemporaryBrightnessStrategy getTemporaryBrightnessStrategy() {
359             return new TemporaryBrightnessStrategy();
360         }
361 
getBoostBrightnessStrategy()362         BoostBrightnessStrategy getBoostBrightnessStrategy() {
363             return new BoostBrightnessStrategy();
364         }
365 
getFollowerBrightnessStrategy(int displayId)366         FollowerBrightnessStrategy getFollowerBrightnessStrategy(int displayId) {
367             return new FollowerBrightnessStrategy(displayId);
368         }
369 
getInvalidBrightnessStrategy()370         InvalidBrightnessStrategy getInvalidBrightnessStrategy() {
371             return new InvalidBrightnessStrategy();
372         }
373 
getAutomaticBrightnessStrategy1(Context context, int displayId, DisplayManagerFlags displayManagerFlags)374         AutomaticBrightnessStrategy getAutomaticBrightnessStrategy1(Context context,
375                 int displayId, DisplayManagerFlags displayManagerFlags) {
376             return new AutomaticBrightnessStrategy(context, displayId, displayManagerFlags);
377         }
378 
getAutomaticBrightnessStrategy2(Context context, int displayId)379         AutomaticBrightnessStrategy2 getAutomaticBrightnessStrategy2(Context context,
380                 int displayId) {
381             return new AutomaticBrightnessStrategy2(context, displayId);
382         }
383 
getOffloadBrightnessStrategy( DisplayManagerFlags displayManagerFlags)384         OffloadBrightnessStrategy getOffloadBrightnessStrategy(
385                 DisplayManagerFlags displayManagerFlags) {
386             return new OffloadBrightnessStrategy(displayManagerFlags);
387         }
388 
getAutoBrightnessFallbackStrategy()389         AutoBrightnessFallbackStrategy getAutoBrightnessFallbackStrategy() {
390             return new AutoBrightnessFallbackStrategy(/* injector= */ null);
391         }
392 
getFallbackBrightnessStrategy()393         FallbackBrightnessStrategy getFallbackBrightnessStrategy() {
394             return new FallbackBrightnessStrategy();
395         }
396     }
397 }
398