1/*
2 * Copyright (C) 2008 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.settings;
18
19import android.content.ContentResolver;
20import android.content.Context;
21import android.database.ContentObserver;
22import android.os.Bundle;
23import android.os.Handler;
24import android.os.IPowerManager;
25import android.os.Parcel;
26import android.os.Parcelable;
27import android.os.RemoteException;
28import android.os.ServiceManager;
29import android.preference.SeekBarDialogPreference;
30import android.provider.Settings;
31import android.provider.Settings.SettingNotFoundException;
32import android.util.AttributeSet;
33import android.view.View;
34import android.widget.CheckBox;
35import android.widget.CompoundButton;
36import android.widget.SeekBar;
37
38public class BrightnessPreference extends SeekBarDialogPreference implements
39        SeekBar.OnSeekBarChangeListener, CheckBox.OnCheckedChangeListener {
40
41    private SeekBar mSeekBar;
42    private CheckBox mCheckBox;
43
44    private int mOldBrightness;
45    private int mOldAutomatic;
46
47    private boolean mAutomaticAvailable;
48
49    private boolean mRestoredOldState;
50
51    // Backlight range is from 0 - 255. Need to make sure that user
52    // doesn't set the backlight to 0 and get stuck
53    private int mScreenBrightnessDim =
54	    getContext().getResources().getInteger(com.android.internal.R.integer.config_screenBrightnessDim);
55    private static final int MAXIMUM_BACKLIGHT = android.os.Power.BRIGHTNESS_ON;
56
57    private ContentObserver mBrightnessObserver = new ContentObserver(new Handler()) {
58        @Override
59        public void onChange(boolean selfChange) {
60            onBrightnessChanged();
61        }
62    };
63
64    private ContentObserver mBrightnessModeObserver = new ContentObserver(new Handler()) {
65        @Override
66        public void onChange(boolean selfChange) {
67            onBrightnessModeChanged();
68        }
69    };
70
71    public BrightnessPreference(Context context, AttributeSet attrs) {
72        super(context, attrs);
73
74        mAutomaticAvailable = context.getResources().getBoolean(
75                com.android.internal.R.bool.config_automatic_brightness_available);
76
77        setDialogLayoutResource(R.layout.preference_dialog_brightness);
78        setDialogIcon(R.drawable.ic_settings_display);
79    }
80
81    @Override
82    protected void showDialog(Bundle state) {
83        super.showDialog(state);
84
85        getContext().getContentResolver().registerContentObserver(
86                Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS), true,
87                mBrightnessObserver);
88
89        getContext().getContentResolver().registerContentObserver(
90                Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_MODE), true,
91                mBrightnessModeObserver);
92        mRestoredOldState = false;
93    }
94
95    @Override
96    protected void onBindDialogView(View view) {
97        super.onBindDialogView(view);
98
99        mSeekBar = getSeekBar(view);
100        mSeekBar.setMax(MAXIMUM_BACKLIGHT - mScreenBrightnessDim);
101        mOldBrightness = getBrightness(0);
102        mSeekBar.setProgress(mOldBrightness - mScreenBrightnessDim);
103
104        mCheckBox = (CheckBox)view.findViewById(R.id.automatic_mode);
105        if (mAutomaticAvailable) {
106            mCheckBox.setOnCheckedChangeListener(this);
107            mOldAutomatic = getBrightnessMode(0);
108            mCheckBox.setChecked(mOldAutomatic != 0);
109        } else {
110            mCheckBox.setVisibility(View.GONE);
111        }
112        mSeekBar.setOnSeekBarChangeListener(this);
113    }
114
115    public void onProgressChanged(SeekBar seekBar, int progress,
116            boolean fromTouch) {
117        setBrightness(progress + mScreenBrightnessDim);
118    }
119
120    public void onStartTrackingTouch(SeekBar seekBar) {
121        // NA
122    }
123
124    public void onStopTrackingTouch(SeekBar seekBar) {
125        // NA
126    }
127
128    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
129        setMode(isChecked ? Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC
130                : Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
131        if (!isChecked) {
132            setBrightness(mSeekBar.getProgress() + mScreenBrightnessDim);
133        }
134    }
135
136    private int getBrightness(int defaultValue) {
137        int brightness = defaultValue;
138        try {
139            brightness = Settings.System.getInt(getContext().getContentResolver(),
140                    Settings.System.SCREEN_BRIGHTNESS);
141        } catch (SettingNotFoundException snfe) {
142        }
143        return brightness;
144    }
145
146    private int getBrightnessMode(int defaultValue) {
147        int brightnessMode = defaultValue;
148        try {
149            brightnessMode = Settings.System.getInt(getContext().getContentResolver(),
150                    Settings.System.SCREEN_BRIGHTNESS_MODE);
151        } catch (SettingNotFoundException snfe) {
152        }
153        return brightnessMode;
154    }
155
156    private void onBrightnessChanged() {
157        int brightness = getBrightness(MAXIMUM_BACKLIGHT);
158        mSeekBar.setProgress(brightness - mScreenBrightnessDim);
159    }
160
161    private void onBrightnessModeChanged() {
162        boolean checked = getBrightnessMode(0) != 0;
163        mCheckBox.setChecked(checked);
164    }
165
166    @Override
167    protected void onDialogClosed(boolean positiveResult) {
168        super.onDialogClosed(positiveResult);
169
170        final ContentResolver resolver = getContext().getContentResolver();
171
172        if (positiveResult) {
173            Settings.System.putInt(resolver,
174                    Settings.System.SCREEN_BRIGHTNESS,
175                    mSeekBar.getProgress() + mScreenBrightnessDim);
176        } else {
177            restoreOldState();
178        }
179
180        resolver.unregisterContentObserver(mBrightnessObserver);
181        resolver.unregisterContentObserver(mBrightnessModeObserver);
182    }
183
184    private void restoreOldState() {
185        if (mRestoredOldState) return;
186
187        if (mAutomaticAvailable) {
188            setMode(mOldAutomatic);
189        }
190        if (!mAutomaticAvailable || mOldAutomatic == 0) {
191            setBrightness(mOldBrightness);
192        }
193        mRestoredOldState = true;
194    }
195
196    private void setBrightness(int brightness) {
197        try {
198            IPowerManager power = IPowerManager.Stub.asInterface(
199                    ServiceManager.getService("power"));
200            if (power != null) {
201                power.setBacklightBrightness(brightness);
202            }
203        } catch (RemoteException doe) {
204
205        }
206    }
207
208    private void setMode(int mode) {
209        if (mode == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) {
210            mSeekBar.setVisibility(View.GONE);
211        } else {
212            mSeekBar.setVisibility(View.VISIBLE);
213        }
214        Settings.System.putInt(getContext().getContentResolver(),
215                Settings.System.SCREEN_BRIGHTNESS_MODE, mode);
216    }
217
218    @Override
219    protected Parcelable onSaveInstanceState() {
220        final Parcelable superState = super.onSaveInstanceState();
221        if (getDialog() == null || !getDialog().isShowing()) return superState;
222
223        // Save the dialog state
224        final SavedState myState = new SavedState(superState);
225        myState.automatic = mCheckBox.isChecked();
226        myState.progress = mSeekBar.getProgress();
227        myState.oldAutomatic = mOldAutomatic == 1;
228        myState.oldProgress = mOldBrightness;
229
230        // Restore the old state when the activity or dialog is being paused
231        restoreOldState();
232        return myState;
233    }
234
235    @Override
236    protected void onRestoreInstanceState(Parcelable state) {
237        if (state == null || !state.getClass().equals(SavedState.class)) {
238            // Didn't save state for us in onSaveInstanceState
239            super.onRestoreInstanceState(state);
240            return;
241        }
242
243        SavedState myState = (SavedState) state;
244        super.onRestoreInstanceState(myState.getSuperState());
245        mOldBrightness = myState.oldProgress;
246        mOldAutomatic = myState.oldAutomatic ? 1 : 0;
247        setMode(myState.automatic ? 1 : 0);
248        setBrightness(myState.progress + mScreenBrightnessDim);
249    }
250
251    private static class SavedState extends BaseSavedState {
252
253        boolean automatic;
254        boolean oldAutomatic;
255        int progress;
256        int oldProgress;
257
258        public SavedState(Parcel source) {
259            super(source);
260            automatic = source.readInt() == 1;
261            progress = source.readInt();
262            oldAutomatic = source.readInt() == 1;
263            oldProgress = source.readInt();
264        }
265
266        @Override
267        public void writeToParcel(Parcel dest, int flags) {
268            super.writeToParcel(dest, flags);
269            dest.writeInt(automatic ? 1 : 0);
270            dest.writeInt(progress);
271            dest.writeInt(oldAutomatic ? 1 : 0);
272            dest.writeInt(oldProgress);
273        }
274
275        public SavedState(Parcelable superState) {
276            super(superState);
277        }
278
279        public static final Parcelable.Creator<SavedState> CREATOR =
280                new Parcelable.Creator<SavedState>() {
281
282            public SavedState createFromParcel(Parcel in) {
283                return new SavedState(in);
284            }
285
286            public SavedState[] newArray(int size) {
287                return new SavedState[size];
288            }
289        };
290    }
291}
292
293