1 /*
2  * Copyright (C) 2013 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.systemui.settings;
18 
19 import android.content.ContentResolver;
20 import android.content.Context;
21 import android.database.ContentObserver;
22 import android.net.Uri;
23 import android.os.AsyncTask;
24 import android.os.Handler;
25 import android.os.IPowerManager;
26 import android.os.PowerManager;
27 import android.os.RemoteException;
28 import android.os.ServiceManager;
29 import android.os.UserHandle;
30 import android.provider.Settings;
31 import android.widget.ImageView;
32 
33 import com.android.internal.logging.MetricsLogger;
34 
35 import java.util.ArrayList;
36 
37 public class BrightnessController implements ToggleSlider.Listener {
38     private static final String TAG = "StatusBar.BrightnessController";
39     private static final boolean SHOW_AUTOMATIC_ICON = false;
40 
41     /**
42      * {@link android.provider.Settings.System#SCREEN_AUTO_BRIGHTNESS_ADJ} uses the range [-1, 1].
43      * Using this factor, it is converted to [0, BRIGHTNESS_ADJ_RESOLUTION] for the SeekBar.
44      */
45     private static final float BRIGHTNESS_ADJ_RESOLUTION = 2048;
46 
47     private final int mMinimumBacklight;
48     private final int mMaximumBacklight;
49 
50     private final Context mContext;
51     private final ImageView mIcon;
52     private final ToggleSlider mControl;
53     private final boolean mAutomaticAvailable;
54     private final IPowerManager mPower;
55     private final CurrentUserTracker mUserTracker;
56     private final Handler mHandler;
57     private final BrightnessObserver mBrightnessObserver;
58 
59     private ArrayList<BrightnessStateChangeCallback> mChangeCallbacks =
60             new ArrayList<BrightnessStateChangeCallback>();
61 
62     private boolean mAutomatic;
63     private boolean mListening;
64     private boolean mExternalChange;
65 
66     public interface BrightnessStateChangeCallback {
onBrightnessLevelChanged()67         public void onBrightnessLevelChanged();
68     }
69 
70     /** ContentObserver to watch brightness **/
71     private class BrightnessObserver extends ContentObserver {
72 
73         private final Uri BRIGHTNESS_MODE_URI =
74                 Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE);
75         private final Uri BRIGHTNESS_URI =
76                 Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
77         private final Uri BRIGHTNESS_ADJ_URI =
78                 Settings.System.getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ);
79 
BrightnessObserver(Handler handler)80         public BrightnessObserver(Handler handler) {
81             super(handler);
82         }
83 
84         @Override
onChange(boolean selfChange)85         public void onChange(boolean selfChange) {
86             onChange(selfChange, null);
87         }
88 
89         @Override
onChange(boolean selfChange, Uri uri)90         public void onChange(boolean selfChange, Uri uri) {
91             if (selfChange) return;
92             try {
93                 mExternalChange = true;
94                 if (BRIGHTNESS_MODE_URI.equals(uri)) {
95                     updateMode();
96                     updateSlider();
97                 } else if (BRIGHTNESS_URI.equals(uri) && !mAutomatic) {
98                     updateSlider();
99                 } else if (BRIGHTNESS_ADJ_URI.equals(uri) && mAutomatic) {
100                     updateSlider();
101                 } else {
102                     updateMode();
103                     updateSlider();
104                 }
105                 for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
106                     cb.onBrightnessLevelChanged();
107                 }
108             } finally {
109                 mExternalChange = false;
110             }
111         }
112 
startObserving()113         public void startObserving() {
114             final ContentResolver cr = mContext.getContentResolver();
115             cr.unregisterContentObserver(this);
116             cr.registerContentObserver(
117                     BRIGHTNESS_MODE_URI,
118                     false, this, UserHandle.USER_ALL);
119             cr.registerContentObserver(
120                     BRIGHTNESS_URI,
121                     false, this, UserHandle.USER_ALL);
122             cr.registerContentObserver(
123                     BRIGHTNESS_ADJ_URI,
124                     false, this, UserHandle.USER_ALL);
125         }
126 
stopObserving()127         public void stopObserving() {
128             final ContentResolver cr = mContext.getContentResolver();
129             cr.unregisterContentObserver(this);
130         }
131 
132     }
133 
BrightnessController(Context context, ImageView icon, ToggleSlider control)134     public BrightnessController(Context context, ImageView icon, ToggleSlider control) {
135         mContext = context;
136         mIcon = icon;
137         mControl = control;
138         mHandler = new Handler();
139         mUserTracker = new CurrentUserTracker(mContext) {
140             @Override
141             public void onUserSwitched(int newUserId) {
142                 updateMode();
143                 updateSlider();
144             }
145         };
146         mBrightnessObserver = new BrightnessObserver(mHandler);
147 
148         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
149         mMinimumBacklight = pm.getMinimumScreenBrightnessSetting();
150         mMaximumBacklight = pm.getMaximumScreenBrightnessSetting();
151 
152         mAutomaticAvailable = context.getResources().getBoolean(
153                 com.android.internal.R.bool.config_automatic_brightness_available);
154         mPower = IPowerManager.Stub.asInterface(ServiceManager.getService("power"));
155     }
156 
addStateChangedCallback(BrightnessStateChangeCallback cb)157     public void addStateChangedCallback(BrightnessStateChangeCallback cb) {
158         mChangeCallbacks.add(cb);
159     }
160 
removeStateChangedCallback(BrightnessStateChangeCallback cb)161     public boolean removeStateChangedCallback(BrightnessStateChangeCallback cb) {
162         return mChangeCallbacks.remove(cb);
163     }
164 
165     @Override
onInit(ToggleSlider control)166     public void onInit(ToggleSlider control) {
167         // Do nothing
168     }
169 
registerCallbacks()170     public void registerCallbacks() {
171         if (mListening) {
172             return;
173         }
174 
175         mBrightnessObserver.startObserving();
176         mUserTracker.startTracking();
177 
178         // Update the slider and mode before attaching the listener so we don't
179         // receive the onChanged notifications for the initial values.
180         updateMode();
181         updateSlider();
182 
183         mControl.setOnChangedListener(this);
184         mListening = true;
185     }
186 
187     /** Unregister all call backs, both to and from the controller */
unregisterCallbacks()188     public void unregisterCallbacks() {
189         if (!mListening) {
190             return;
191         }
192 
193         mBrightnessObserver.stopObserving();
194         mUserTracker.stopTracking();
195         mControl.setOnChangedListener(null);
196         mListening = false;
197     }
198 
199     @Override
onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value, boolean stopTracking)200     public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value,
201             boolean stopTracking) {
202         updateIcon(mAutomatic);
203         if (mExternalChange) return;
204 
205         if (!mAutomatic) {
206             final int val = value + mMinimumBacklight;
207             if (stopTracking) {
208                 MetricsLogger.action(mContext, MetricsLogger.ACTION_BRIGHTNESS, val);
209             }
210             setBrightness(val);
211             if (!tracking) {
212                 AsyncTask.execute(new Runnable() {
213                         public void run() {
214                             Settings.System.putIntForUser(mContext.getContentResolver(),
215                                     Settings.System.SCREEN_BRIGHTNESS, val,
216                                     UserHandle.USER_CURRENT);
217                         }
218                     });
219             }
220         } else {
221             final float adj = value / (BRIGHTNESS_ADJ_RESOLUTION / 2f) - 1;
222             if (stopTracking) {
223                 MetricsLogger.action(mContext, MetricsLogger.ACTION_BRIGHTNESS_AUTO, value);
224             }
225             setBrightnessAdj(adj);
226             if (!tracking) {
227                 AsyncTask.execute(new Runnable() {
228                     public void run() {
229                         Settings.System.putFloatForUser(mContext.getContentResolver(),
230                                 Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adj,
231                                 UserHandle.USER_CURRENT);
232                     }
233                 });
234             }
235         }
236 
237         for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
238             cb.onBrightnessLevelChanged();
239         }
240     }
241 
setMode(int mode)242     private void setMode(int mode) {
243         Settings.System.putIntForUser(mContext.getContentResolver(),
244                 Settings.System.SCREEN_BRIGHTNESS_MODE, mode,
245                 mUserTracker.getCurrentUserId());
246     }
247 
setBrightness(int brightness)248     private void setBrightness(int brightness) {
249         try {
250             mPower.setTemporaryScreenBrightnessSettingOverride(brightness);
251         } catch (RemoteException ex) {
252         }
253     }
254 
setBrightnessAdj(float adj)255     private void setBrightnessAdj(float adj) {
256         try {
257             mPower.setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(adj);
258         } catch (RemoteException ex) {
259         }
260     }
261 
updateIcon(boolean automatic)262     private void updateIcon(boolean automatic) {
263         if (mIcon != null) {
264             mIcon.setImageResource(automatic && SHOW_AUTOMATIC_ICON ?
265                     com.android.systemui.R.drawable.ic_qs_brightness_auto_on :
266                     com.android.systemui.R.drawable.ic_qs_brightness_auto_off);
267         }
268     }
269 
270     /** Fetch the brightness mode from the system settings and update the icon */
updateMode()271     private void updateMode() {
272         if (mAutomaticAvailable) {
273             int automatic;
274             automatic = Settings.System.getIntForUser(mContext.getContentResolver(),
275                     Settings.System.SCREEN_BRIGHTNESS_MODE,
276                     Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
277                     UserHandle.USER_CURRENT);
278             mAutomatic = automatic != Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
279             updateIcon(mAutomatic);
280         } else {
281             mControl.setChecked(false);
282             updateIcon(false /*automatic*/);
283         }
284     }
285 
286     /** Fetch the brightness from the system settings and update the slider */
updateSlider()287     private void updateSlider() {
288         if (mAutomatic) {
289             float value = Settings.System.getFloatForUser(mContext.getContentResolver(),
290                     Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0,
291                     UserHandle.USER_CURRENT);
292             mControl.setMax((int) BRIGHTNESS_ADJ_RESOLUTION);
293             mControl.setValue((int) ((value + 1) * BRIGHTNESS_ADJ_RESOLUTION / 2f));
294         } else {
295             int value;
296             value = Settings.System.getIntForUser(mContext.getContentResolver(),
297                     Settings.System.SCREEN_BRIGHTNESS, mMaximumBacklight,
298                     UserHandle.USER_CURRENT);
299             mControl.setMax(mMaximumBacklight - mMinimumBacklight);
300             mControl.setValue(value - mMinimumBacklight);
301         }
302     }
303 
304 }
305