BrightnessController.java revision 97b87a99297144e9c3e4a57a444fe1402dee7e4f
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 com.android.internal.logging.MetricsLogger;
34
35import java.util.ArrayList;
36
37public 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 {
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
80        public BrightnessObserver(Handler handler) {
81            super(handler);
82        }
83
84        @Override
85        public void onChange(boolean selfChange) {
86            onChange(selfChange, null);
87        }
88
89        @Override
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
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
127        public void stopObserving() {
128            final ContentResolver cr = mContext.getContentResolver();
129            cr.unregisterContentObserver(this);
130        }
131
132    }
133
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
157    public void addStateChangedCallback(BrightnessStateChangeCallback cb) {
158        mChangeCallbacks.add(cb);
159    }
160
161    public boolean removeStateChangedCallback(BrightnessStateChangeCallback cb) {
162        return mChangeCallbacks.remove(cb);
163    }
164
165    @Override
166    public void onInit(ToggleSlider control) {
167        // Do nothing
168    }
169
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 */
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
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
242    private void setMode(int mode) {
243        Settings.System.putIntForUser(mContext.getContentResolver(),
244                Settings.System.SCREEN_BRIGHTNESS_MODE, mode,
245                mUserTracker.getCurrentUserId());
246    }
247
248    private void setBrightness(int brightness) {
249        try {
250            mPower.setTemporaryScreenBrightnessSettingOverride(brightness);
251        } catch (RemoteException ex) {
252        }
253    }
254
255    private void setBrightnessAdj(float adj) {
256        try {
257            mPower.setTemporaryScreenAutoBrightnessAdjustmentSettingOverride(adj);
258        } catch (RemoteException ex) {
259        }
260    }
261
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 */
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 */
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