1/*
2 * Copyright (C) 2011 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.Parcel;
25import android.os.Parcelable;
26import android.os.RemoteException;
27import android.os.ServiceManager;
28import android.preference.SeekBarDialogPreference;
29import android.provider.Settings;
30import android.provider.Settings.SettingNotFoundException;
31import android.util.AttributeSet;
32import android.view.IWindowManager;
33import android.view.View;
34import android.widget.SeekBar;
35
36public class PointerSpeedPreference extends SeekBarDialogPreference implements
37        SeekBar.OnSeekBarChangeListener {
38    private SeekBar mSeekBar;
39
40    private int mOldSpeed;
41    private boolean mRestoredOldState;
42
43    private boolean mTouchInProgress;
44
45    private static final int MIN_SPEED = -7;
46    private static final int MAX_SPEED = 7;
47
48    private ContentObserver mSpeedObserver = new ContentObserver(new Handler()) {
49        @Override
50        public void onChange(boolean selfChange) {
51            onSpeedChanged();
52        }
53    };
54
55    public PointerSpeedPreference(Context context, AttributeSet attrs) {
56        super(context, attrs);
57    }
58
59    @Override
60    protected void showDialog(Bundle state) {
61        super.showDialog(state);
62
63        getContext().getContentResolver().registerContentObserver(
64                Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
65                mSpeedObserver);
66
67        mRestoredOldState = false;
68    }
69
70    @Override
71    protected void onBindDialogView(View view) {
72        super.onBindDialogView(view);
73
74        mSeekBar = getSeekBar(view);
75        mSeekBar.setMax(MAX_SPEED - MIN_SPEED);
76        mOldSpeed = getSpeed(0);
77        mSeekBar.setProgress(mOldSpeed - MIN_SPEED);
78        mSeekBar.setOnSeekBarChangeListener(this);
79    }
80
81    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
82        if (!mTouchInProgress) {
83            setSpeed(progress + MIN_SPEED);
84        }
85    }
86
87    public void onStartTrackingTouch(SeekBar seekBar) {
88        mTouchInProgress = true;
89    }
90
91    public void onStopTrackingTouch(SeekBar seekBar) {
92        mTouchInProgress = false;
93        setSpeed(seekBar.getProgress() + MIN_SPEED);
94    }
95
96    private int getSpeed(int defaultValue) {
97        int speed = defaultValue;
98        try {
99            speed = Settings.System.getInt(getContext().getContentResolver(),
100                    Settings.System.POINTER_SPEED);
101        } catch (SettingNotFoundException snfe) {
102        }
103        return speed;
104    }
105
106    private void onSpeedChanged() {
107        int speed = getSpeed(0);
108        mSeekBar.setProgress(speed - MIN_SPEED);
109    }
110
111    @Override
112    protected void onDialogClosed(boolean positiveResult) {
113        super.onDialogClosed(positiveResult);
114
115        final ContentResolver resolver = getContext().getContentResolver();
116
117        if (positiveResult) {
118            Settings.System.putInt(resolver, Settings.System.POINTER_SPEED,
119                    mSeekBar.getProgress() + MIN_SPEED);
120        } else {
121            restoreOldState();
122        }
123
124        resolver.unregisterContentObserver(mSpeedObserver);
125    }
126
127    private void restoreOldState() {
128        if (mRestoredOldState) return;
129
130        setSpeed(mOldSpeed);
131        mRestoredOldState = true;
132    }
133
134    private void setSpeed(int speed) {
135        try {
136            IWindowManager wm = IWindowManager.Stub.asInterface(
137                    ServiceManager.getService("window"));
138            if (wm != null) {
139                wm.setPointerSpeed(speed);
140            }
141        } catch (RemoteException e) {
142        }
143    }
144
145    @Override
146    protected Parcelable onSaveInstanceState() {
147        final Parcelable superState = super.onSaveInstanceState();
148        if (getDialog() == null || !getDialog().isShowing()) return superState;
149
150        // Save the dialog state
151        final SavedState myState = new SavedState(superState);
152        myState.progress = mSeekBar.getProgress();
153        myState.oldSpeed = mOldSpeed;
154
155        // Restore the old state when the activity or dialog is being paused
156        restoreOldState();
157        return myState;
158    }
159
160    @Override
161    protected void onRestoreInstanceState(Parcelable state) {
162        if (state == null || !state.getClass().equals(SavedState.class)) {
163            // Didn't save state for us in onSaveInstanceState
164            super.onRestoreInstanceState(state);
165            return;
166        }
167
168        SavedState myState = (SavedState) state;
169        super.onRestoreInstanceState(myState.getSuperState());
170        mOldSpeed = myState.oldSpeed;
171        mSeekBar.setProgress(myState.progress);
172        setSpeed(myState.progress + MIN_SPEED);
173    }
174
175    private static class SavedState extends BaseSavedState {
176        int progress;
177        int oldSpeed;
178
179        public SavedState(Parcel source) {
180            super(source);
181            progress = source.readInt();
182            oldSpeed = source.readInt();
183        }
184
185        @Override
186        public void writeToParcel(Parcel dest, int flags) {
187            super.writeToParcel(dest, flags);
188            dest.writeInt(progress);
189            dest.writeInt(oldSpeed);
190        }
191
192        public SavedState(Parcelable superState) {
193            super(superState);
194        }
195
196        public static final Parcelable.Creator<SavedState> CREATOR =
197                new Parcelable.Creator<SavedState>() {
198
199            public SavedState createFromParcel(Parcel in) {
200                return new SavedState(in);
201            }
202
203            public SavedState[] newArray(int size) {
204                return new SavedState[size];
205            }
206        };
207    }
208}
209
210