2 * Copyright (C) 2013 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.systemui.settings;
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.Looper;
27 import android.os.Message;
28 import android.os.PowerManager;
29 import android.os.RemoteException;
30 import android.os.ServiceManager;
31 import android.os.UserHandle;
32 import android.provider.Settings;
33 import android.service.vr.IVrManager;
34 import android.service.vr.IVrStateCallbacks;
35 import android.util.Log;
36 import android.widget.ImageView;
38 import com.android.internal.logging.MetricsLogger;
39 import com.android.internal.logging.MetricsProto.MetricsEvent;
41 import java.util.ArrayList;
43 public class BrightnessController implements ToggleSlider.Listener {
44 private static final String TAG = "StatusBar.BrightnessController";
45 private static final boolean SHOW_AUTOMATIC_ICON = false;
48 * {@link android.provider.Settings.System#SCREEN_AUTO_BRIGHTNESS_ADJ} uses the range [-1, 1].
49 * Using this factor, it is converted to [0, BRIGHTNESS_ADJ_RESOLUTION] for the SeekBar.
51 private static final float BRIGHTNESS_ADJ_RESOLUTION = 2048;
53 private static final int MSG_UPDATE_ICON = 0;
54 private static final int MSG_UPDATE_SLIDER = 1;
55 private static final int MSG_SET_CHECKED = 2;
56 private static final int MSG_ATTACH_LISTENER = 3;
57 private static final int MSG_DETACH_LISTENER = 4;
58 private static final int MSG_VR_MODE_CHANGED = 5;
60 private final int mMinimumBacklight;
61 private final int mMaximumBacklight;
62 private final int mMinimumBacklightForVr;
63 private final int mMaximumBacklightForVr;
65 private final Context mContext;
66 private final ImageView mIcon;
67 private final ToggleSlider mControl;
68 private final boolean mAutomaticAvailable;
69 private final IPowerManager mPower;
70 private final CurrentUserTracker mUserTracker;
71 private final IVrManager mVrManager;
73 private Handler mBackgroundHandler;
74 private final BrightnessObserver mBrightnessObserver;
76 private ArrayList<BrightnessStateChangeCallback> mChangeCallbacks =
77 new ArrayList<BrightnessStateChangeCallback>();
79 private volatile boolean mAutomatic; // Brightness adjusted automatically using ambient light.
80 private volatile boolean mIsVrModeEnabled;
81 private boolean mListening;
82 private boolean mExternalChange;
84 public interface BrightnessStateChangeCallback {
85 public void onBrightnessLevelChanged();
88 /** ContentObserver to watch brightness **/
89 private class BrightnessObserver extends ContentObserver {
91 private final Uri BRIGHTNESS_MODE_URI =
92 Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE);
93 private final Uri BRIGHTNESS_URI =
94 Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
95 private final Uri BRIGHTNESS_FOR_VR_URI =
96 Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_FOR_VR);
97 private final Uri BRIGHTNESS_ADJ_URI =
98 Settings.System.getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ);
100 public BrightnessObserver(Handler handler) {
105 public void onChange(boolean selfChange) {
106 onChange(selfChange, null);
110 public void onChange(boolean selfChange, Uri uri) {
111 if (selfChange) return;
113 if (BRIGHTNESS_MODE_URI.equals(uri)) {
114 mBackgroundHandler.post(mUpdateModeRunnable);
115 mBackgroundHandler.post(mUpdateSliderRunnable);
116 } else if (BRIGHTNESS_URI.equals(uri) && !mAutomatic) {
117 mBackgroundHandler.post(mUpdateSliderRunnable);
118 } else if (BRIGHTNESS_FOR_VR_URI.equals(uri)) {
119 mBackgroundHandler.post(mUpdateSliderRunnable);
120 } else if (BRIGHTNESS_ADJ_URI.equals(uri) && mAutomatic) {
121 mBackgroundHandler.post(mUpdateSliderRunnable);
123 mBackgroundHandler.post(mUpdateModeRunnable);
124 mBackgroundHandler.post(mUpdateSliderRunnable);
126 for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
127 cb.onBrightnessLevelChanged();
131 public void startObserving() {
132 final ContentResolver cr = mContext.getContentResolver();
133 cr.unregisterContentObserver(this);
134 cr.registerContentObserver(
136 false, this, UserHandle.USER_ALL);
137 cr.registerContentObserver(
139 false, this, UserHandle.USER_ALL);
140 cr.registerContentObserver(
141 BRIGHTNESS_FOR_VR_URI,
142 false, this, UserHandle.USER_ALL);
143 cr.registerContentObserver(
145 false, this, UserHandle.USER_ALL);
148 public void stopObserving() {
149 final ContentResolver cr = mContext.getContentResolver();
150 cr.unregisterContentObserver(this);
155 private final Runnable mStartListeningRunnable = new Runnable() {
158 mBrightnessObserver.startObserving();
159 mUserTracker.startTracking();
161 // Update the slider and mode before attaching the listener so we don't
162 // receive the onChanged notifications for the initial values.
163 mUpdateModeRunnable.run();
164 mUpdateSliderRunnable.run();
166 mHandler.sendEmptyMessage(MSG_ATTACH_LISTENER);
170 private final Runnable mStopListeningRunnable = new Runnable() {
173 mBrightnessObserver.stopObserving();
174 mUserTracker.stopTracking();
176 mHandler.sendEmptyMessage(MSG_DETACH_LISTENER);
181 * Fetch the brightness mode from the system settings and update the icon. Should be called from
184 private final Runnable mUpdateModeRunnable = new Runnable() {
187 if (mAutomaticAvailable) {
189 automatic = Settings.System.getIntForUser(mContext.getContentResolver(),
190 Settings.System.SCREEN_BRIGHTNESS_MODE,
191 Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL,
192 UserHandle.USER_CURRENT);
193 mAutomatic = automatic != Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL;
194 mHandler.obtainMessage(MSG_UPDATE_ICON, mAutomatic ? 1 : 0).sendToTarget();
196 mHandler.obtainMessage(MSG_SET_CHECKED, 0).sendToTarget();
197 mHandler.obtainMessage(MSG_UPDATE_ICON, 0 /* automatic */).sendToTarget();
203 * Fetch the brightness from the system settings and update the slider. Should be called from
206 private final Runnable mUpdateSliderRunnable = new Runnable() {
209 if (mIsVrModeEnabled) {
210 int value = Settings.System.getIntForUser(mContext.getContentResolver(),
211 Settings.System.SCREEN_BRIGHTNESS_FOR_VR, mMaximumBacklight,
212 UserHandle.USER_CURRENT);
213 mHandler.obtainMessage(MSG_UPDATE_SLIDER,
214 mMaximumBacklightForVr - mMinimumBacklightForVr,
215 value - mMinimumBacklightForVr).sendToTarget();
216 } else if (mAutomatic) {
217 float value = Settings.System.getFloatForUser(mContext.getContentResolver(),
218 Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0,
219 UserHandle.USER_CURRENT);
220 mHandler.obtainMessage(MSG_UPDATE_SLIDER, (int) BRIGHTNESS_ADJ_RESOLUTION,
221 (int) ((value + 1) * BRIGHTNESS_ADJ_RESOLUTION / 2f)).sendToTarget();
224 value = Settings.System.getIntForUser(mContext.getContentResolver(),
225 Settings.System.SCREEN_BRIGHTNESS, mMaximumBacklight,
226 UserHandle.USER_CURRENT);
227 mHandler.obtainMessage(MSG_UPDATE_SLIDER, mMaximumBacklight - mMinimumBacklight,
228 value - mMinimumBacklight).sendToTarget();
233 private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
235 public void onVrStateChanged(boolean enabled) {
236 mHandler.obtainMessage(MSG_VR_MODE_CHANGED, enabled ? 1 : 0, 0)
241 private final Handler mHandler = new Handler() {
243 public void handleMessage(Message msg) {
244 mExternalChange = true;
247 case MSG_UPDATE_ICON:
248 updateIcon(msg.arg1 != 0);
250 case MSG_UPDATE_SLIDER:
251 mControl.setMax(msg.arg1);
252 mControl.setValue(msg.arg2);
254 case MSG_SET_CHECKED:
255 mControl.setChecked(msg.arg1 != 0);
257 case MSG_ATTACH_LISTENER:
258 mControl.setOnChangedListener(BrightnessController.this);
260 case MSG_DETACH_LISTENER:
261 mControl.setOnChangedListener(null);
263 case MSG_VR_MODE_CHANGED:
264 updateVrMode(msg.arg1 != 0);
267 super.handleMessage(msg);
270 mExternalChange = false;
275 public BrightnessController(Context context, ImageView icon, ToggleSlider control) {
279 mBackgroundHandler = new Handler(Looper.getMainLooper());
280 mUserTracker = new CurrentUserTracker(mContext) {
282 public void onUserSwitched(int newUserId) {
283 mBackgroundHandler.post(mUpdateModeRunnable);
284 mBackgroundHandler.post(mUpdateSliderRunnable);
287 mBrightnessObserver = new BrightnessObserver(mHandler);
289 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
290 mMinimumBacklight = pm.getMinimumScreenBrightnessSetting();
291 mMaximumBacklight = pm.getMaximumScreenBrightnessSetting();
292 mMinimumBacklightForVr = pm.getMinimumScreenBrightnessForVrSetting();
293 mMaximumBacklightForVr = pm.getMaximumScreenBrightnessForVrSetting();
295 mAutomaticAvailable = context.getResources().getBoolean(
296 com.android.internal.R.bool.config_automatic_brightness_available);
297 mPower = IPowerManager.Stub.asInterface(ServiceManager.getService("power"));
298 mVrManager = IVrManager.Stub.asInterface(ServiceManager.getService("vrmanager"));
301 public void setBackgroundLooper(Looper backgroundLooper) {
302 mBackgroundHandler = new Handler(backgroundLooper);
305 public void addStateChangedCallback(BrightnessStateChangeCallback cb) {
306 mChangeCallbacks.add(cb);
309 public boolean removeStateChangedCallback(BrightnessStateChangeCallback cb) {
310 return mChangeCallbacks.remove(cb);
314 public void onInit(ToggleSlider control) {
318 public void registerCallbacks() {
323 if (mVrManager != null) {
325 mVrManager.registerListener(mVrStateCallbacks);
326 mIsVrModeEnabled = mVrManager.getVrModeState();
327 } catch (RemoteException e) {
328 Log.e(TAG, "Failed to register VR mode state listener: ", e);
332 mBackgroundHandler.post(mStartListeningRunnable);
336 /** Unregister all call backs, both to and from the controller */
337 public void unregisterCallbacks() {
342 if (mVrManager != null) {
344 mVrManager.unregisterListener(mVrStateCallbacks);
345 } catch (RemoteException e) {
346 Log.e(TAG, "Failed to unregister VR mode state listener: ", e);
350 mBackgroundHandler.post(mStopListeningRunnable);
355 public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value,
356 boolean stopTracking) {
357 updateIcon(mAutomatic);
358 if (mExternalChange) return;
360 if (mIsVrModeEnabled) {
361 final int val = value + mMinimumBacklightForVr;
363 MetricsLogger.action(mContext, MetricsEvent.ACTION_BRIGHTNESS_FOR_VR, val);
367 AsyncTask.execute(new Runnable() {
369 Settings.System.putIntForUser(mContext.getContentResolver(),
370 Settings.System.SCREEN_BRIGHTNESS_FOR_VR, val,
371 UserHandle.USER_CURRENT);
375 } else if (!mAutomatic) {
376 final int val = value + mMinimumBacklight;
378 MetricsLogger.action(mContext, MetricsEvent.ACTION_BRIGHTNESS, val);
382 AsyncTask.execute(new Runnable() {
384 Settings.System.putIntForUser(mContext.getContentResolver(),
385 Settings.System.SCREEN_BRIGHTNESS, val,
386 UserHandle.USER_CURRENT);
391 final float adj = value / (BRIGHTNESS_ADJ_RESOLUTION / 2f) - 1;
393 MetricsLogger.action(mContext, MetricsEvent.ACTION_BRIGHTNESS_AUTO, value);
395 setBrightnessAdj(adj);
397 AsyncTask.execute(new Runnable() {
399 Settings.System.putFloatForUser(mContext.getContentResolver(),
400 Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adj,
401 UserHandle.USER_CURRENT);
407 for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
408 cb.onBrightnessLevelChanged();
412 private void setMode(int mode) {
413 Settings.System.putIntForUser(mContext.getContentResolver(),
414 Settings.System.SCREEN_BRIGHTNESS_MODE, mode,
415 mUserTracker.getCurrentUserId());
418 private void setBrightness(int brightness) {
420 mPower.setTemporaryScreenBrightnessSettingOverride(brightness);
421 } catch (RemoteException ex) {
425 private void setBrightnessAdj(float adj) {
427 mPower.setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(adj);
428 } catch (RemoteException ex) {
432 private void updateIcon(boolean automatic) {
434 mIcon.setImageResource(automatic && SHOW_AUTOMATIC_ICON ?
435 com.android.systemui.R.drawable.ic_qs_brightness_auto_on :
436 com.android.systemui.R.drawable.ic_qs_brightness_auto_off);
440 private void updateVrMode(boolean isEnabled) {
441 if (mIsVrModeEnabled != isEnabled) {
442 mIsVrModeEnabled = isEnabled;
443 mBackgroundHandler.post(mUpdateSliderRunnable);