1 /*
2  * Copyright (C) 2021 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;
18 
19 import android.annotation.NonNull;
20 import android.os.Handler;
21 import android.os.Looper;
22 import android.os.Message;
23 import android.util.Slog;
24 
25 import com.android.internal.annotations.GuardedBy;
26 
27 import java.util.concurrent.CopyOnWriteArraySet;
28 
29 /**
30  * Saves brightness to a persistent data store, enabling each logical display to have its own
31  * brightness.
32  */
33 public class BrightnessSetting {
34     private static final String TAG = "BrightnessSetting";
35 
36     private static final int MSG_BRIGHTNESS_CHANGED = 1;
37 
38     private final PersistentDataStore mPersistentDataStore;
39     private final DisplayManagerService.SyncRoot mSyncRoot;
40 
41     private final LogicalDisplay mLogicalDisplay;
42 
43     private int mUserSerial;
44     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
45         @Override
46         public void handleMessage(Message msg) {
47             if (msg.what == MSG_BRIGHTNESS_CHANGED) {
48                 float brightnessVal = Float.intBitsToFloat(msg.arg1);
49                 notifyListeners(brightnessVal);
50             }
51         }
52     };
53 
54     private final CopyOnWriteArraySet<BrightnessSettingListener> mListeners =
55             new CopyOnWriteArraySet<>();
56 
57     @GuardedBy("mSyncRoot")
58     private float mBrightness;
59 
BrightnessSetting(int userSerial, @NonNull PersistentDataStore persistentDataStore, @NonNull LogicalDisplay logicalDisplay, DisplayManagerService.SyncRoot syncRoot)60     BrightnessSetting(int userSerial,
61             @NonNull PersistentDataStore persistentDataStore,
62             @NonNull LogicalDisplay logicalDisplay,
63             DisplayManagerService.SyncRoot syncRoot) {
64         mPersistentDataStore = persistentDataStore;
65         mLogicalDisplay = logicalDisplay;
66         mUserSerial = userSerial;
67         mBrightness = mPersistentDataStore.getBrightness(
68                 mLogicalDisplay.getPrimaryDisplayDeviceLocked(), userSerial);
69         mSyncRoot = syncRoot;
70     }
71 
72     /**
73      * Returns the brightness from the brightness setting
74      *
75      * @return brightness for the current display
76      */
getBrightness()77     public float getBrightness() {
78         synchronized (mSyncRoot) {
79             return mBrightness;
80         }
81     }
82 
83     /**
84      * Registers listener for brightness setting change events.
85      */
registerListener(BrightnessSettingListener l)86     public void registerListener(BrightnessSettingListener l) {
87         if (mListeners.contains(l)) {
88             Slog.wtf(TAG, "Duplicate Listener added");
89         }
90         mListeners.add(l);
91     }
92 
93     /**
94      * Unregisters listener for brightness setting change events.
95      *
96      * @param l listener
97      */
unregisterListener(BrightnessSettingListener l)98     public void unregisterListener(BrightnessSettingListener l) {
99         mListeners.remove(l);
100     }
101 
102     /** Sets the user serial for the brightness setting */
setUserSerial(int userSerial)103     public void setUserSerial(int userSerial) {
104         mUserSerial = userSerial;
105     }
106 
107     /**
108      * Sets the brightness and broadcasts the change to the listeners.
109      * @param brightness The value to which the brightness is to be set.
110      */
setBrightness(float brightness)111     public void setBrightness(float brightness) {
112         if (Float.isNaN(brightness)) {
113             Slog.w(TAG, "Attempting to set invalid brightness");
114             return;
115         }
116         synchronized (mSyncRoot) {
117             // If the brightness is the same, we still need to update any listeners as the act of
118             // setting the brightness alone has side effects, like clearing any temporary
119             // brightness. We can skip persisting to disk, however, since it hasn't actually
120             // changed.
121             if (brightness != mBrightness) {
122                 mPersistentDataStore.setBrightness(mLogicalDisplay.getPrimaryDisplayDeviceLocked(),
123                         brightness, mUserSerial
124                 );
125             }
126             mBrightness = brightness;
127             int toSend = Float.floatToIntBits(mBrightness);
128             Message msg = mHandler.obtainMessage(MSG_BRIGHTNESS_CHANGED, toSend, 0);
129             mHandler.sendMessage(msg);
130         }
131     }
132 
133     /**
134      * Sets the brightness. Does not send update event to listeners.
135      * @param brightness The value to which the brightness is to be set.
136      */
setBrightnessNoNotify(float brightness)137     public void setBrightnessNoNotify(float brightness) {
138         if (Float.isNaN(brightness)) {
139             Slog.w(TAG, "Attempting to init invalid brightness");
140             return;
141         }
142         synchronized (mSyncRoot) {
143             if (brightness != mBrightness) {
144                 mPersistentDataStore.setBrightness(mLogicalDisplay.getPrimaryDisplayDeviceLocked(),
145                         brightness, mUserSerial
146                 );
147             }
148             mBrightness = brightness;
149         }
150     }
151 
152     /**
153      * @return The brightness for the default display in nits. Used when the underlying display
154      * device has changed but we want to persist the nit value.
155      */
getBrightnessNitsForDefaultDisplay()156     public float getBrightnessNitsForDefaultDisplay() {
157         return mPersistentDataStore.getBrightnessNitsForDefaultDisplay();
158     }
159 
160     /**
161      * Set brightness in nits for the default display. Used when we want to persist the nit value
162      * even if the underlying display device changes.
163      * @param nits The brightness value in nits
164      */
setBrightnessNitsForDefaultDisplay(float nits)165     public void setBrightnessNitsForDefaultDisplay(float nits) {
166         mPersistentDataStore.setBrightnessNitsForDefaultDisplay(nits);
167     }
168 
notifyListeners(float brightness)169     private void notifyListeners(float brightness) {
170         for (BrightnessSettingListener l : mListeners) {
171             l.onBrightnessChanged(brightness);
172         }
173     }
174 
175     /**
176      * Listener for changes to system brightness.
177      */
178     public interface BrightnessSettingListener {
179 
180         /**
181          * Notify that the brightness has changed.
182          */
onBrightnessChanged(float brightness)183         void onBrightnessChanged(float brightness);
184     }
185 }
186