OSDN Git Service

14c41616c8e523a7a1f2c97708610a57dd89ee88
[android-x86/frameworks-base.git] / packages / SystemUI / src / com / android / systemui / settings / BrightnessController.java
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.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;
37
38 import com.android.internal.logging.MetricsLogger;
39 import com.android.internal.logging.MetricsProto.MetricsEvent;
40
41 import java.util.ArrayList;
42
43 public class BrightnessController implements ToggleSlider.Listener {
44     private static final String TAG = "StatusBar.BrightnessController";
45     private static final boolean SHOW_AUTOMATIC_ICON = false;
46
47     /**
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.
50      */
51     private static final float BRIGHTNESS_ADJ_RESOLUTION = 2048;
52
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;
59
60     private final int mMinimumBacklight;
61     private final int mMaximumBacklight;
62     private final int mMinimumBacklightForVr;
63     private final int mMaximumBacklightForVr;
64
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;
72
73     private Handler mBackgroundHandler;
74     private final BrightnessObserver mBrightnessObserver;
75
76     private ArrayList<BrightnessStateChangeCallback> mChangeCallbacks =
77             new ArrayList<BrightnessStateChangeCallback>();
78
79     private volatile boolean mAutomatic;  // Brightness adjusted automatically using ambient light.
80     private volatile boolean mIsVrModeEnabled;
81     private boolean mListening;
82     private boolean mExternalChange;
83
84     public interface BrightnessStateChangeCallback {
85         public void onBrightnessLevelChanged();
86     }
87
88     /** ContentObserver to watch brightness **/
89     private class BrightnessObserver extends ContentObserver {
90
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);
99
100         public BrightnessObserver(Handler handler) {
101             super(handler);
102         }
103
104         @Override
105         public void onChange(boolean selfChange) {
106             onChange(selfChange, null);
107         }
108
109         @Override
110         public void onChange(boolean selfChange, Uri uri) {
111             if (selfChange) return;
112
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);
122             } else {
123                 mBackgroundHandler.post(mUpdateModeRunnable);
124                 mBackgroundHandler.post(mUpdateSliderRunnable);
125             }
126             for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
127                 cb.onBrightnessLevelChanged();
128             }
129         }
130
131         public void startObserving() {
132             final ContentResolver cr = mContext.getContentResolver();
133             cr.unregisterContentObserver(this);
134             cr.registerContentObserver(
135                     BRIGHTNESS_MODE_URI,
136                     false, this, UserHandle.USER_ALL);
137             cr.registerContentObserver(
138                     BRIGHTNESS_URI,
139                     false, this, UserHandle.USER_ALL);
140             cr.registerContentObserver(
141                     BRIGHTNESS_FOR_VR_URI,
142                     false, this, UserHandle.USER_ALL);
143             cr.registerContentObserver(
144                     BRIGHTNESS_ADJ_URI,
145                     false, this, UserHandle.USER_ALL);
146         }
147
148         public void stopObserving() {
149             final ContentResolver cr = mContext.getContentResolver();
150             cr.unregisterContentObserver(this);
151         }
152
153     }
154
155     private final Runnable mStartListeningRunnable = new Runnable() {
156         @Override
157         public void run() {
158             mBrightnessObserver.startObserving();
159             mUserTracker.startTracking();
160
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();
165
166             mHandler.sendEmptyMessage(MSG_ATTACH_LISTENER);
167         }
168     };
169
170     private final Runnable mStopListeningRunnable = new Runnable() {
171         @Override
172         public void run() {
173             mBrightnessObserver.stopObserving();
174             mUserTracker.stopTracking();
175
176             mHandler.sendEmptyMessage(MSG_DETACH_LISTENER);
177         }
178     };
179
180     /**
181      * Fetch the brightness mode from the system settings and update the icon. Should be called from
182      * background thread.
183      */
184     private final Runnable mUpdateModeRunnable = new Runnable() {
185         @Override
186         public void run() {
187             if (mAutomaticAvailable) {
188                 int automatic;
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();
195             } else {
196                 mHandler.obtainMessage(MSG_SET_CHECKED, 0).sendToTarget();
197                 mHandler.obtainMessage(MSG_UPDATE_ICON, 0 /* automatic */).sendToTarget();
198             }
199         }
200     };
201
202     /**
203      * Fetch the brightness from the system settings and update the slider. Should be called from
204      * background thread.
205      */
206     private final Runnable mUpdateSliderRunnable = new Runnable() {
207         @Override
208         public void run() {
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();
222             } else {
223                 int value;
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();
229             }
230         }
231     };
232
233     private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
234         @Override
235         public void onVrStateChanged(boolean enabled) {
236             mHandler.obtainMessage(MSG_VR_MODE_CHANGED, enabled ? 1 : 0, 0)
237                     .sendToTarget();
238         }
239     };
240
241     private final Handler mHandler = new Handler() {
242         @Override
243         public void handleMessage(Message msg) {
244             mExternalChange = true;
245             try {
246                 switch (msg.what) {
247                     case MSG_UPDATE_ICON:
248                         updateIcon(msg.arg1 != 0);
249                         break;
250                     case MSG_UPDATE_SLIDER:
251                         mControl.setMax(msg.arg1);
252                         mControl.setValue(msg.arg2);
253                         break;
254                     case MSG_SET_CHECKED:
255                         mControl.setChecked(msg.arg1 != 0);
256                         break;
257                     case MSG_ATTACH_LISTENER:
258                         mControl.setOnChangedListener(BrightnessController.this);
259                         break;
260                     case MSG_DETACH_LISTENER:
261                         mControl.setOnChangedListener(null);
262                         break;
263                     case MSG_VR_MODE_CHANGED:
264                         updateVrMode(msg.arg1 != 0);
265                         break;
266                     default:
267                         super.handleMessage(msg);
268                 }
269             } finally {
270                 mExternalChange = false;
271             }
272         }
273     };
274
275     public BrightnessController(Context context, ImageView icon, ToggleSlider control) {
276         mContext = context;
277         mIcon = icon;
278         mControl = control;
279         mBackgroundHandler = new Handler(Looper.getMainLooper());
280         mUserTracker = new CurrentUserTracker(mContext) {
281             @Override
282             public void onUserSwitched(int newUserId) {
283                 mBackgroundHandler.post(mUpdateModeRunnable);
284                 mBackgroundHandler.post(mUpdateSliderRunnable);
285             }
286         };
287         mBrightnessObserver = new BrightnessObserver(mHandler);
288
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();
294
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"));
299     }
300
301     public void setBackgroundLooper(Looper backgroundLooper) {
302         mBackgroundHandler = new Handler(backgroundLooper);
303     }
304
305     public void addStateChangedCallback(BrightnessStateChangeCallback cb) {
306         mChangeCallbacks.add(cb);
307     }
308
309     public boolean removeStateChangedCallback(BrightnessStateChangeCallback cb) {
310         return mChangeCallbacks.remove(cb);
311     }
312
313     @Override
314     public void onInit(ToggleSlider control) {
315         // Do nothing
316     }
317
318     public void registerCallbacks() {
319         if (mListening) {
320             return;
321         }
322
323         if (mVrManager != null) {
324             try {
325                 mVrManager.registerListener(mVrStateCallbacks);
326                 mIsVrModeEnabled = mVrManager.getVrModeState();
327             } catch (RemoteException e) {
328                 Log.e(TAG, "Failed to register VR mode state listener: ", e);
329             }
330         }
331
332         mBackgroundHandler.post(mStartListeningRunnable);
333         mListening = true;
334     }
335
336     /** Unregister all call backs, both to and from the controller */
337     public void unregisterCallbacks() {
338         if (!mListening) {
339             return;
340         }
341
342         if (mVrManager != null) {
343             try {
344                 mVrManager.unregisterListener(mVrStateCallbacks);
345             } catch (RemoteException e) {
346                 Log.e(TAG, "Failed to unregister VR mode state listener: ", e);
347             }
348         }
349
350         mBackgroundHandler.post(mStopListeningRunnable);
351         mListening = false;
352     }
353
354     @Override
355     public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value,
356             boolean stopTracking) {
357         updateIcon(mAutomatic);
358         if (mExternalChange) return;
359
360         if (mIsVrModeEnabled) {
361             final int val = value + mMinimumBacklightForVr;
362             if (stopTracking) {
363                 MetricsLogger.action(mContext, MetricsEvent.ACTION_BRIGHTNESS_FOR_VR, val);
364             }
365             setBrightness(val);
366             if (!tracking) {
367                 AsyncTask.execute(new Runnable() {
368                         public void run() {
369                             Settings.System.putIntForUser(mContext.getContentResolver(),
370                                     Settings.System.SCREEN_BRIGHTNESS_FOR_VR, val,
371                                     UserHandle.USER_CURRENT);
372                         }
373                     });
374             }
375         } else if (!mAutomatic) {
376             final int val = value + mMinimumBacklight;
377             if (stopTracking) {
378                 MetricsLogger.action(mContext, MetricsEvent.ACTION_BRIGHTNESS, val);
379             }
380             setBrightness(val);
381             if (!tracking) {
382                 AsyncTask.execute(new Runnable() {
383                         public void run() {
384                             Settings.System.putIntForUser(mContext.getContentResolver(),
385                                     Settings.System.SCREEN_BRIGHTNESS, val,
386                                     UserHandle.USER_CURRENT);
387                         }
388                     });
389             }
390         } else {
391             final float adj = value / (BRIGHTNESS_ADJ_RESOLUTION / 2f) - 1;
392             if (stopTracking) {
393                 MetricsLogger.action(mContext, MetricsEvent.ACTION_BRIGHTNESS_AUTO, value);
394             }
395             setBrightnessAdj(adj);
396             if (!tracking) {
397                 AsyncTask.execute(new Runnable() {
398                     public void run() {
399                         Settings.System.putFloatForUser(mContext.getContentResolver(),
400                                 Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, adj,
401                                 UserHandle.USER_CURRENT);
402                     }
403                 });
404             }
405         }
406
407         for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
408             cb.onBrightnessLevelChanged();
409         }
410     }
411
412     private void setMode(int mode) {
413         Settings.System.putIntForUser(mContext.getContentResolver(),
414                 Settings.System.SCREEN_BRIGHTNESS_MODE, mode,
415                 mUserTracker.getCurrentUserId());
416     }
417
418     private void setBrightness(int brightness) {
419         try {
420             mPower.setTemporaryScreenBrightnessSettingOverride(brightness);
421         } catch (RemoteException ex) {
422         }
423     }
424
425     private void setBrightnessAdj(float adj) {
426         try {
427             mPower.setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(adj);
428         } catch (RemoteException ex) {
429         }
430     }
431
432     private void updateIcon(boolean automatic) {
433         if (mIcon != null) {
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);
437         }
438     }
439
440     private void updateVrMode(boolean isEnabled) {
441         if (mIsVrModeEnabled != isEnabled) {
442             mIsVrModeEnabled = isEnabled;
443             mBackgroundHandler.post(mUpdateSliderRunnable);
444         }
445     }
446 }