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