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.provider.Settings.SettingNotFoundException;
32import android.widget.ImageView;
33
34import java.util.ArrayList;
35
36public class BrightnessController implements ToggleSlider.Listener {
37    private static final String TAG = "StatusBar.BrightnessController";
38
39    private final int mMinimumBacklight;
40    private final int mMaximumBacklight;
41
42    private final Context mContext;
43    private final ImageView mIcon;
44    private final ToggleSlider mControl;
45    private final boolean mAutomaticAvailable;
46    private final IPowerManager mPower;
47    private final CurrentUserTracker mUserTracker;
48    private final Handler mHandler;
49    private final BrightnessObserver mBrightnessObserver;
50
51    private ArrayList<BrightnessStateChangeCallback> mChangeCallbacks =
52            new ArrayList<BrightnessStateChangeCallback>();
53
54    public interface BrightnessStateChangeCallback {
55        public void onBrightnessLevelChanged();
56    }
57
58    /** ContentObserver to watch brightness **/
59    private class BrightnessObserver extends ContentObserver {
60
61        private final Uri BRIGHTNESS_MODE_URI =
62                Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE);
63        private final Uri BRIGHTNESS_URI =
64                Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS);
65
66        public BrightnessObserver(Handler handler) {
67            super(handler);
68        }
69
70        @Override
71        public void onChange(boolean selfChange) {
72            onChange(selfChange, null);
73        }
74
75        @Override
76        public void onChange(boolean selfChange, Uri uri) {
77            if (selfChange) return;
78            if (BRIGHTNESS_MODE_URI.equals(uri)) {
79                updateMode();
80            } else if (BRIGHTNESS_URI.equals(uri)) {
81                updateSlider();
82            } else {
83                updateMode();
84                updateSlider();
85            }
86            for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
87                cb.onBrightnessLevelChanged();
88            }
89        }
90
91        public void startObserving() {
92            final ContentResolver cr = mContext.getContentResolver();
93            cr.unregisterContentObserver(this);
94            cr.registerContentObserver(
95                    BRIGHTNESS_MODE_URI,
96                    false, this, UserHandle.USER_ALL);
97            cr.registerContentObserver(
98                    BRIGHTNESS_URI,
99                    false, this, UserHandle.USER_ALL);
100        }
101
102        public void stopObserving() {
103            final ContentResolver cr = mContext.getContentResolver();
104            cr.unregisterContentObserver(this);
105        }
106
107    }
108
109    public BrightnessController(Context context, ImageView icon, ToggleSlider control) {
110        mContext = context;
111        mIcon = icon;
112        mControl = control;
113        mHandler = new Handler();
114        mUserTracker = new CurrentUserTracker(mContext) {
115            @Override
116            public void onUserSwitched(int newUserId) {
117                updateMode();
118                updateSlider();
119            }
120        };
121        mBrightnessObserver = new BrightnessObserver(mHandler);
122        mBrightnessObserver.startObserving();
123
124        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
125        mMinimumBacklight = pm.getMinimumScreenBrightnessSetting();
126        mMaximumBacklight = pm.getMaximumScreenBrightnessSetting();
127
128        mAutomaticAvailable = context.getResources().getBoolean(
129                com.android.internal.R.bool.config_automatic_brightness_available);
130        mPower = IPowerManager.Stub.asInterface(ServiceManager.getService("power"));
131
132        // Update the slider and mode before attaching the listener so we don't receive the
133        // onChanged notifications for the initial values.
134        updateMode();
135        updateSlider();
136
137        control.setOnChangedListener(this);
138    }
139
140    public void addStateChangedCallback(BrightnessStateChangeCallback cb) {
141        mChangeCallbacks.add(cb);
142    }
143
144    public boolean removeStateChangedCallback(BrightnessStateChangeCallback cb) {
145        return mChangeCallbacks.remove(cb);
146    }
147
148    @Override
149    public void onInit(ToggleSlider control) {
150        // Do nothing
151    }
152
153    /** Unregister all call backs, both to and from the controller */
154    public void unregisterCallbacks() {
155        mBrightnessObserver.stopObserving();
156        mChangeCallbacks.clear();
157        mUserTracker.stopTracking();
158    }
159
160    public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value) {
161        setMode(automatic ? Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC
162                : Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
163        updateIcon(automatic);
164        if (!automatic) {
165            final int val = value + mMinimumBacklight;
166            setBrightness(val);
167            if (!tracking) {
168                AsyncTask.execute(new Runnable() {
169                        public void run() {
170                            Settings.System.putIntForUser(mContext.getContentResolver(),
171                                    Settings.System.SCREEN_BRIGHTNESS, val,
172                                    UserHandle.USER_CURRENT);
173                        }
174                    });
175            }
176        }
177
178        for (BrightnessStateChangeCallback cb : mChangeCallbacks) {
179            cb.onBrightnessLevelChanged();
180        }
181    }
182
183    private void setMode(int mode) {
184        Settings.System.putIntForUser(mContext.getContentResolver(),
185                Settings.System.SCREEN_BRIGHTNESS_MODE, mode,
186                mUserTracker.getCurrentUserId());
187    }
188
189    private void setBrightness(int brightness) {
190        try {
191            mPower.setTemporaryScreenBrightnessSettingOverride(brightness);
192        } catch (RemoteException ex) {
193        }
194    }
195
196    private void updateIcon(boolean automatic) {
197        if (mIcon != null) {
198            mIcon.setImageResource(automatic ?
199                    com.android.systemui.R.drawable.ic_qs_brightness_auto_on :
200                    com.android.systemui.R.drawable.ic_qs_brightness_auto_off);
201        }
202    }
203
204    /** Fetch the brightness mode from the system settings and update the icon */
205    private void updateMode() {
206        if (mAutomaticAvailable) {
207            int automatic;
208            try {
209                automatic = Settings.System.getIntForUser(mContext.getContentResolver(),
210                        Settings.System.SCREEN_BRIGHTNESS_MODE,
211                        UserHandle.USER_CURRENT);
212            } catch (SettingNotFoundException snfe) {
213                automatic = 0;
214            }
215            mControl.setChecked(automatic != 0);
216            updateIcon(automatic != 0);
217        } else {
218            mControl.setChecked(false);
219            updateIcon(false /*automatic*/);
220        }
221    }
222
223    /** Fetch the brightness from the system settings and update the slider */
224    private void updateSlider() {
225        int value;
226        try {
227            value = Settings.System.getIntForUser(mContext.getContentResolver(),
228                    Settings.System.SCREEN_BRIGHTNESS,
229                    UserHandle.USER_CURRENT);
230        } catch (SettingNotFoundException ex) {
231            value = mMaximumBacklight;
232        }
233        mControl.setMax(mMaximumBacklight - mMinimumBacklight);
234        mControl.setValue(value - mMinimumBacklight);
235    }
236
237}
238