blob: d3f997a0450034640ba3571de723fec1008bd5b7 [file] [log] [blame]
Michael Wright0087a142013-02-05 16:29:39 -08001/*
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
17package com.android.systemui.settings;
18
19import android.content.ContentResolver;
20import android.content.Context;
Michael Wright0087a142013-02-05 16:29:39 -080021import android.database.ContentObserver;
22import android.net.Uri;
23import android.os.AsyncTask;
24import android.os.Handler;
25import android.os.IPowerManager;
Jorim Jaggic6da82f2016-08-02 16:11:25 +020026import android.os.Looper;
27import android.os.Message;
Michael Wright0087a142013-02-05 16:29:39 -080028import android.os.PowerManager;
29import android.os.RemoteException;
30import android.os.ServiceManager;
31import android.os.UserHandle;
32import android.provider.Settings;
Santos Cordon3107d292016-09-20 15:50:35 -070033import android.service.vr.IVrManager;
34import android.service.vr.IVrStateCallbacks;
35import android.util.Log;
Michael Wright0087a142013-02-05 16:29:39 -080036import android.widget.ImageView;
37
Jason Monk97b87a92015-06-23 15:04:44 -040038import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010039import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
Jason Monk9c7844c2017-01-18 15:21:53 -050040import com.android.systemui.Dependency;
Jason Monk97b87a92015-06-23 15:04:44 -040041
Michael Wright0087a142013-02-05 16:29:39 -080042import java.util.ArrayList;
43
44public class BrightnessController implements ToggleSlider.Listener {
45 private static final String TAG = "StatusBar.BrightnessController";
John Spurlock6d205262014-06-10 19:26:14 -040046 private static final boolean SHOW_AUTOMATIC_ICON = false;
Michael Wright0087a142013-02-05 16:29:39 -080047
Adrian Roosdaf7d412014-05-13 14:55:09 +020048 /**
49 * {@link android.provider.Settings.System#SCREEN_AUTO_BRIGHTNESS_ADJ} uses the range [-1, 1].
50 * Using this factor, it is converted to [0, BRIGHTNESS_ADJ_RESOLUTION] for the SeekBar.
51 */
Adrian Roos27a2ce22015-06-02 13:44:46 -070052 private static final float BRIGHTNESS_ADJ_RESOLUTION = 2048;
Adrian Roosdaf7d412014-05-13 14:55:09 +020053
Jorim Jaggic6da82f2016-08-02 16:11:25 +020054 private static final int MSG_UPDATE_ICON = 0;
55 private static final int MSG_UPDATE_SLIDER = 1;
56 private static final int MSG_SET_CHECKED = 2;
57 private static final int MSG_ATTACH_LISTENER = 3;
58 private static final int MSG_DETACH_LISTENER = 4;
Santos Cordon3107d292016-09-20 15:50:35 -070059 private static final int MSG_VR_MODE_CHANGED = 5;
Jorim Jaggic6da82f2016-08-02 16:11:25 +020060
Michael Wright0087a142013-02-05 16:29:39 -080061 private final int mMinimumBacklight;
62 private final int mMaximumBacklight;
Santos Cordon3107d292016-09-20 15:50:35 -070063 private final int mMinimumBacklightForVr;
64 private final int mMaximumBacklightForVr;
Michael Wright0087a142013-02-05 16:29:39 -080065
66 private final Context mContext;
67 private final ImageView mIcon;
68 private final ToggleSlider mControl;
69 private final boolean mAutomaticAvailable;
70 private final IPowerManager mPower;
71 private final CurrentUserTracker mUserTracker;
Santos Cordon3107d292016-09-20 15:50:35 -070072 private final IVrManager mVrManager;
Jorim Jaggic6da82f2016-08-02 16:11:25 +020073
Jason Monk9c7844c2017-01-18 15:21:53 -050074 private final Handler mBackgroundHandler;
Michael Wright0087a142013-02-05 16:29:39 -080075 private final BrightnessObserver mBrightnessObserver;
76
77 private ArrayList<BrightnessStateChangeCallback> mChangeCallbacks =
78 new ArrayList<BrightnessStateChangeCallback>();
79
Santos Cordon3107d292016-09-20 15:50:35 -070080 private volatile boolean mAutomatic; // Brightness adjusted automatically using ambient light.
81 private volatile boolean mIsVrModeEnabled;
Jorim Jaggi3f48f462014-07-08 16:53:29 +020082 private boolean mListening;
Adrian Roosb7ebbde2014-08-15 20:11:38 +020083 private boolean mExternalChange;
Adrian Roosdaf7d412014-05-13 14:55:09 +020084
Michael Wright0087a142013-02-05 16:29:39 -080085 public interface BrightnessStateChangeCallback {
86 public void onBrightnessLevelChanged();
87 }
88
89 /** ContentObserver to watch brightness **/
90 private class BrightnessObserver extends ContentObserver {
91
92 private final Uri BRIGHTNESS_MODE_URI =
93 Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE);
94 private final Uri BRIGHTNESS_URI =
95 Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
Santos Cordon3107d292016-09-20 15:50:35 -070096 private final Uri BRIGHTNESS_FOR_VR_URI =
97 Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_FOR_VR);
Adrian Roosdaf7d412014-05-13 14:55:09 +020098 private final Uri BRIGHTNESS_ADJ_URI =
99 Settings.System.getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ);
Michael Wright0087a142013-02-05 16:29:39 -0800100
101 public BrightnessObserver(Handler handler) {
102 super(handler);
103 }
104
105 @Override
106 public void onChange(boolean selfChange) {
107 onChange(selfChange, null);
108 }
109
110 @Override
111 public void onChange(boolean selfChange, Uri uri) {
112 if (selfChange) return;
Jorim Jaggic6da82f2016-08-02 16:11:25 +0200113
114 if (BRIGHTNESS_MODE_URI.equals(uri)) {
115 mBackgroundHandler.post(mUpdateModeRunnable);
116 mBackgroundHandler.post(mUpdateSliderRunnable);
117 } else if (BRIGHTNESS_URI.equals(uri) && !mAutomatic) {
118 mBackgroundHandler.post(mUpdateSliderRunnable);
Santos Cordon3107d292016-09-20 15:50:35 -0700119 } else if (BRIGHTNESS_FOR_VR_URI.equals(uri)) {
120 mBackgroundHandler.post(mUpdateSliderRunnable);
Jorim Jaggic6da82f2016-08-02 16:11:25 +0200121 } else if (BRIGHTNESS_ADJ_URI.equals(uri) && mAutomatic) {
122 mBackgroundHandler.post(mUpdateSliderRunnable);
123 } else {
124 mBackgroundHandler.post(mUpdateModeRunnable);
125 mBackgroundHandler.post(mUpdateSliderRunnable);
126 }
127 for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
128 cb.onBrightnessLevelChanged();
Michael Wright0087a142013-02-05 16:29:39 -0800129 }
130 }
131
132 public void startObserving() {
133 final ContentResolver cr = mContext.getContentResolver();
134 cr.unregisterContentObserver(this);
135 cr.registerContentObserver(
136 BRIGHTNESS_MODE_URI,
137 false, this, UserHandle.USER_ALL);
138 cr.registerContentObserver(
139 BRIGHTNESS_URI,
140 false, this, UserHandle.USER_ALL);
Adrian Roosdaf7d412014-05-13 14:55:09 +0200141 cr.registerContentObserver(
Santos Cordon3107d292016-09-20 15:50:35 -0700142 BRIGHTNESS_FOR_VR_URI,
143 false, this, UserHandle.USER_ALL);
144 cr.registerContentObserver(
Adrian Roosdaf7d412014-05-13 14:55:09 +0200145 BRIGHTNESS_ADJ_URI,
146 false, this, UserHandle.USER_ALL);
Michael Wright0087a142013-02-05 16:29:39 -0800147 }
148
149 public void stopObserving() {
150 final ContentResolver cr = mContext.getContentResolver();
151 cr.unregisterContentObserver(this);
152 }
153
154 }
155
Jorim Jaggic6da82f2016-08-02 16:11:25 +0200156 private final Runnable mStartListeningRunnable = new Runnable() {
157 @Override
158 public void run() {
159 mBrightnessObserver.startObserving();
160 mUserTracker.startTracking();
161
162 // Update the slider and mode before attaching the listener so we don't
163 // receive the onChanged notifications for the initial values.
164 mUpdateModeRunnable.run();
165 mUpdateSliderRunnable.run();
166
167 mHandler.sendEmptyMessage(MSG_ATTACH_LISTENER);
168 }
169 };
170
171 private final Runnable mStopListeningRunnable = new Runnable() {
172 @Override
173 public void run() {
174 mBrightnessObserver.stopObserving();
175 mUserTracker.stopTracking();
176
177 mHandler.sendEmptyMessage(MSG_DETACH_LISTENER);
178 }
179 };
180
181 /**
182 * Fetch the brightness mode from the system settings and update the icon. Should be called from
183 * background thread.
184 */
185 private final Runnable mUpdateModeRunnable = new Runnable() {
186 @Override
187 public void run() {
188 if (mAutomaticAvailable) {
189 int automatic;
190 automatic = Settings.System.getIntForUser(mContext.getContentResolver(),
191 Settings.System.SCREEN_BRIGHTNESS_MODE,
192 Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
193 UserHandle.USER_CURRENT);
194 mAutomatic = automatic != Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
195 mHandler.obtainMessage(MSG_UPDATE_ICON, mAutomatic ? 1 : 0).sendToTarget();
196 } else {
197 mHandler.obtainMessage(MSG_SET_CHECKED, 0).sendToTarget();
198 mHandler.obtainMessage(MSG_UPDATE_ICON, 0 /* automatic */).sendToTarget();
199 }
200 }
201 };
202
203 /**
204 * Fetch the brightness from the system settings and update the slider. Should be called from
205 * background thread.
206 */
207 private final Runnable mUpdateSliderRunnable = new Runnable() {
208 @Override
209 public void run() {
Santos Cordon3107d292016-09-20 15:50:35 -0700210 if (mIsVrModeEnabled) {
211 int value = Settings.System.getIntForUser(mContext.getContentResolver(),
212 Settings.System.SCREEN_BRIGHTNESS_FOR_VR, mMaximumBacklight,
213 UserHandle.USER_CURRENT);
214 mHandler.obtainMessage(MSG_UPDATE_SLIDER,
215 mMaximumBacklightForVr - mMinimumBacklightForVr,
216 value - mMinimumBacklightForVr).sendToTarget();
217 } else if (mAutomatic) {
Jorim Jaggic6da82f2016-08-02 16:11:25 +0200218 float value = Settings.System.getFloatForUser(mContext.getContentResolver(),
219 Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0,
220 UserHandle.USER_CURRENT);
221 mHandler.obtainMessage(MSG_UPDATE_SLIDER, (int) BRIGHTNESS_ADJ_RESOLUTION,
222 (int) ((value + 1) * BRIGHTNESS_ADJ_RESOLUTION / 2f)).sendToTarget();
223 } else {
224 int value;
225 value = Settings.System.getIntForUser(mContext.getContentResolver(),
226 Settings.System.SCREEN_BRIGHTNESS, mMaximumBacklight,
227 UserHandle.USER_CURRENT);
228 mHandler.obtainMessage(MSG_UPDATE_SLIDER, mMaximumBacklight - mMinimumBacklight,
229 value - mMinimumBacklight).sendToTarget();
230 }
231 }
232 };
233
Santos Cordon3107d292016-09-20 15:50:35 -0700234 private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
235 @Override
236 public void onVrStateChanged(boolean enabled) {
237 mHandler.obtainMessage(MSG_VR_MODE_CHANGED, enabled ? 1 : 0, 0)
238 .sendToTarget();
239 }
240 };
241
Jorim Jaggic6da82f2016-08-02 16:11:25 +0200242 private final Handler mHandler = new Handler() {
243 @Override
244 public void handleMessage(Message msg) {
245 mExternalChange = true;
246 try {
247 switch (msg.what) {
248 case MSG_UPDATE_ICON:
249 updateIcon(msg.arg1 != 0);
250 break;
251 case MSG_UPDATE_SLIDER:
252 mControl.setMax(msg.arg1);
253 mControl.setValue(msg.arg2);
254 break;
255 case MSG_SET_CHECKED:
256 mControl.setChecked(msg.arg1 != 0);
257 break;
258 case MSG_ATTACH_LISTENER:
259 mControl.setOnChangedListener(BrightnessController.this);
260 break;
261 case MSG_DETACH_LISTENER:
262 mControl.setOnChangedListener(null);
Jorim Jaggi4adee262016-09-21 14:49:46 -0700263 break;
Santos Cordon3107d292016-09-20 15:50:35 -0700264 case MSG_VR_MODE_CHANGED:
265 updateVrMode(msg.arg1 != 0);
266 break;
Jorim Jaggic6da82f2016-08-02 16:11:25 +0200267 default:
268 super.handleMessage(msg);
269 }
270 } finally {
271 mExternalChange = false;
272 }
273 }
274 };
275
Michael Wright0087a142013-02-05 16:29:39 -0800276 public BrightnessController(Context context, ImageView icon, ToggleSlider control) {
277 mContext = context;
278 mIcon = icon;
279 mControl = control;
Jason Monk9c7844c2017-01-18 15:21:53 -0500280 mBackgroundHandler = new Handler((Looper) Dependency.get(Dependency.BG_LOOPER));
Michael Wright0087a142013-02-05 16:29:39 -0800281 mUserTracker = new CurrentUserTracker(mContext) {
282 @Override
283 public void onUserSwitched(int newUserId) {
Jorim Jaggic6da82f2016-08-02 16:11:25 +0200284 mBackgroundHandler.post(mUpdateModeRunnable);
285 mBackgroundHandler.post(mUpdateSliderRunnable);
Michael Wright0087a142013-02-05 16:29:39 -0800286 }
287 };
288 mBrightnessObserver = new BrightnessObserver(mHandler);
Michael Wright0087a142013-02-05 16:29:39 -0800289
290 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
291 mMinimumBacklight = pm.getMinimumScreenBrightnessSetting();
292 mMaximumBacklight = pm.getMaximumScreenBrightnessSetting();
Santos Cordon3107d292016-09-20 15:50:35 -0700293 mMinimumBacklightForVr = pm.getMinimumScreenBrightnessForVrSetting();
294 mMaximumBacklightForVr = pm.getMaximumScreenBrightnessForVrSetting();
Michael Wright0087a142013-02-05 16:29:39 -0800295
296 mAutomaticAvailable = context.getResources().getBoolean(
297 com.android.internal.R.bool.config_automatic_brightness_available);
Craig Donner8deb67c2017-02-07 18:10:32 -0800298 mPower = IPowerManager.Stub.asInterface(ServiceManager.getService(
299 Context.POWER_SERVICE));
300 mVrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
301 Context.VR_SERVICE));
Michael Wright0087a142013-02-05 16:29:39 -0800302 }
303
304 public void addStateChangedCallback(BrightnessStateChangeCallback cb) {
305 mChangeCallbacks.add(cb);
306 }
307
308 public boolean removeStateChangedCallback(BrightnessStateChangeCallback cb) {
309 return mChangeCallbacks.remove(cb);
310 }
311
312 @Override
313 public void onInit(ToggleSlider control) {
314 // Do nothing
315 }
316
Jorim Jaggif056e352014-05-11 23:09:22 +0200317 public void registerCallbacks() {
Jorim Jaggi3f48f462014-07-08 16:53:29 +0200318 if (mListening) {
319 return;
320 }
Alan Viverette5a399492014-07-14 16:19:38 -0700321
Santos Cordon3107d292016-09-20 15:50:35 -0700322 if (mVrManager != null) {
323 try {
324 mVrManager.registerListener(mVrStateCallbacks);
325 mIsVrModeEnabled = mVrManager.getVrModeState();
326 } catch (RemoteException e) {
327 Log.e(TAG, "Failed to register VR mode state listener: ", e);
328 }
329 }
330
Jorim Jaggic6da82f2016-08-02 16:11:25 +0200331 mBackgroundHandler.post(mStartListeningRunnable);
Alan Viverette5a399492014-07-14 16:19:38 -0700332 mListening = true;
Jorim Jaggif056e352014-05-11 23:09:22 +0200333 }
334
Michael Wright0087a142013-02-05 16:29:39 -0800335 /** Unregister all call backs, both to and from the controller */
336 public void unregisterCallbacks() {
Jorim Jaggi3f48f462014-07-08 16:53:29 +0200337 if (!mListening) {
338 return;
339 }
Alan Viverette5a399492014-07-14 16:19:38 -0700340
Santos Cordon3107d292016-09-20 15:50:35 -0700341 if (mVrManager != null) {
342 try {
343 mVrManager.unregisterListener(mVrStateCallbacks);
344 } catch (RemoteException e) {
345 Log.e(TAG, "Failed to unregister VR mode state listener: ", e);
346 }
347 }
348
Jorim Jaggic6da82f2016-08-02 16:11:25 +0200349 mBackgroundHandler.post(mStopListeningRunnable);
Alan Viverette5a399492014-07-14 16:19:38 -0700350 mListening = false;
Michael Wright0087a142013-02-05 16:29:39 -0800351 }
352
Adrian Roos5fd872e2014-08-12 17:28:58 +0200353 @Override
Muyuan Li3b0f8922016-04-18 19:27:29 -0700354 public void onChanged(ToggleSlider toggleSlider, boolean tracking, boolean automatic,
355 int value, boolean stopTracking) {
Adrian Roosdaf7d412014-05-13 14:55:09 +0200356 updateIcon(mAutomatic);
Adrian Roosb7ebbde2014-08-15 20:11:38 +0200357 if (mExternalChange) return;
358
Santos Cordon3107d292016-09-20 15:50:35 -0700359 if (mIsVrModeEnabled) {
360 final int val = value + mMinimumBacklightForVr;
361 if (stopTracking) {
362 MetricsLogger.action(mContext, MetricsEvent.ACTION_BRIGHTNESS_FOR_VR, val);
363 }
364 setBrightness(val);
365 if (!tracking) {
366 AsyncTask.execute(new Runnable() {
367 public void run() {
368 Settings.System.putIntForUser(mContext.getContentResolver(),
369 Settings.System.SCREEN_BRIGHTNESS_FOR_VR, val,
370 UserHandle.USER_CURRENT);
371 }
372 });
373 }
374 } else if (!mAutomatic) {
Michael Wright0087a142013-02-05 16:29:39 -0800375 final int val = value + mMinimumBacklight;
Jason Monk97b87a92015-06-23 15:04:44 -0400376 if (stopTracking) {
Chris Wrenf6e9228b2016-01-26 18:04:35 -0500377 MetricsLogger.action(mContext, MetricsEvent.ACTION_BRIGHTNESS, val);
Jason Monk97b87a92015-06-23 15:04:44 -0400378 }
Michael Wright0087a142013-02-05 16:29:39 -0800379 setBrightness(val);
380 if (!tracking) {
381 AsyncTask.execute(new Runnable() {
382 public void run() {
383 Settings.System.putIntForUser(mContext.getContentResolver(),
384 Settings.System.SCREEN_BRIGHTNESS, val,
385 UserHandle.USER_CURRENT);
386 }
387 });
388 }
Adrian Roosdaf7d412014-05-13 14:55:09 +0200389 } else {
390 final float adj = value / (BRIGHTNESS_ADJ_RESOLUTION / 2f) - 1;
Jason Monk97b87a92015-06-23 15:04:44 -0400391 if (stopTracking) {
Chris Wrenf6e9228b2016-01-26 18:04:35 -0500392 MetricsLogger.action(mContext, MetricsEvent.ACTION_BRIGHTNESS_AUTO, value);
Jason Monk97b87a92015-06-23 15:04:44 -0400393 }
Adrian Roos6e2d4652014-05-14 20:01:43 +0200394 setBrightnessAdj(adj);
Adrian Roosdaf7d412014-05-13 14:55:09 +0200395 if (!tracking) {
396 AsyncTask.execute(new Runnable() {
397 public void run() {
398 Settings.System.putFloatForUser(mContext.getContentResolver(),
399 Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adj,
400 UserHandle.USER_CURRENT);
401 }
402 });
403 }
Michael Wright0087a142013-02-05 16:29:39 -0800404 }
405
406 for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
407 cb.onBrightnessLevelChanged();
408 }
409 }
410
411 private void setMode(int mode) {
412 Settings.System.putIntForUser(mContext.getContentResolver(),
413 Settings.System.SCREEN_BRIGHTNESS_MODE, mode,
414 mUserTracker.getCurrentUserId());
415 }
416
417 private void setBrightness(int brightness) {
418 try {
419 mPower.setTemporaryScreenBrightnessSettingOverride(brightness);
420 } catch (RemoteException ex) {
421 }
422 }
423
Adrian Roos6e2d4652014-05-14 20:01:43 +0200424 private void setBrightnessAdj(float adj) {
Adrian Roosdaf7d412014-05-13 14:55:09 +0200425 try {
426 mPower.setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(adj);
427 } catch (RemoteException ex) {
428 }
429 }
430
Michael Wright0087a142013-02-05 16:29:39 -0800431 private void updateIcon(boolean automatic) {
432 if (mIcon != null) {
John Spurlock6d205262014-06-10 19:26:14 -0400433 mIcon.setImageResource(automatic && SHOW_AUTOMATIC_ICON ?
Michael Wright0087a142013-02-05 16:29:39 -0800434 com.android.systemui.R.drawable.ic_qs_brightness_auto_on :
435 com.android.systemui.R.drawable.ic_qs_brightness_auto_off);
436 }
437 }
Santos Cordon3107d292016-09-20 15:50:35 -0700438
439 private void updateVrMode(boolean isEnabled) {
440 if (mIsVrModeEnabled != isEnabled) {
441 mIsVrModeEnabled = isEnabled;
442 mBackgroundHandler.post(mUpdateSliderRunnable);
443 }
444 }
Michael Wright0087a142013-02-05 16:29:39 -0800445}