1d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown/*
2d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown * Copyright (C) 2011 The Android Open Source Project
3d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown *
4d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
5d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown * you may not use this file except in compliance with the License.
6d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown * You may obtain a copy of the License at
7d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown *
8d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
9d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown *
10d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown * Unless required by applicable law or agreed to in writing, software
11d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
12d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown * See the License for the specific language governing permissions and
14d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown * limitations under the License.
15d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown */
16d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
17d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brownpackage com.android.settings;
18d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
19d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brownimport android.content.ContentResolver;
20d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brownimport android.content.Context;
21d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brownimport android.database.ContentObserver;
22b4765ac70d4ebf7ce0e3bbcbc2697cb242ed176dJeff Brownimport android.hardware.input.InputManager;
23d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brownimport android.os.Handler;
24d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brownimport android.os.Parcel;
25d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brownimport android.os.Parcelable;
26d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brownimport android.provider.Settings;
27d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brownimport android.util.AttributeSet;
28d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brownimport android.view.View;
29d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brownimport android.widget.SeekBar;
30d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
31c2ad2e4ce56317ad0335c8065b2ae0c276d0c880John Reckpublic class PointerSpeedPreference extends SeekBarDialogPreference implements
32d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        SeekBar.OnSeekBarChangeListener {
33b4765ac70d4ebf7ce0e3bbcbc2697cb242ed176dJeff Brown    private final InputManager mIm;
34d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    private SeekBar mSeekBar;
35d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
36d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    private int mOldSpeed;
37d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    private boolean mRestoredOldState;
38d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
39d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    private boolean mTouchInProgress;
40d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
41d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    private ContentObserver mSpeedObserver = new ContentObserver(new Handler()) {
42d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        @Override
43d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        public void onChange(boolean selfChange) {
44d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown            onSpeedChanged();
45d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        }
46d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    };
47d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
48d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    public PointerSpeedPreference(Context context, AttributeSet attrs) {
49d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        super(context, attrs);
50b4765ac70d4ebf7ce0e3bbcbc2697cb242ed176dJeff Brown        mIm = (InputManager)getContext().getSystemService(Context.INPUT_SERVICE);
51d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    }
52d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
53d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    @Override
54783718fffee2a7b6e05cc337d0f45bc94f89f76dJason Monk    protected void onClick() {
55783718fffee2a7b6e05cc337d0f45bc94f89f76dJason Monk        super.onClick();
56d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
57d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        getContext().getContentResolver().registerContentObserver(
58d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown                Settings.System.getUriFor(Settings.System.POINTER_SPEED), true,
59d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown                mSpeedObserver);
60d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
61d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        mRestoredOldState = false;
62d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    }
63d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
64d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    @Override
65d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    protected void onBindDialogView(View view) {
66d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        super.onBindDialogView(view);
67d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
68d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        mSeekBar = getSeekBar(view);
69b4765ac70d4ebf7ce0e3bbcbc2697cb242ed176dJeff Brown        mSeekBar.setMax(InputManager.MAX_POINTER_SPEED - InputManager.MIN_POINTER_SPEED);
704397f406a3c9e09ca2d5174ba46328345faa504eJeff Brown        mOldSpeed = mIm.getPointerSpeed(getContext());
71b4765ac70d4ebf7ce0e3bbcbc2697cb242ed176dJeff Brown        mSeekBar.setProgress(mOldSpeed - InputManager.MIN_POINTER_SPEED);
72d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        mSeekBar.setOnSeekBarChangeListener(this);
73d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    }
74d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
75d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
76d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        if (!mTouchInProgress) {
77b4765ac70d4ebf7ce0e3bbcbc2697cb242ed176dJeff Brown            mIm.tryPointerSpeed(progress + InputManager.MIN_POINTER_SPEED);
78d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        }
79d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    }
80d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
81d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    public void onStartTrackingTouch(SeekBar seekBar) {
82d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        mTouchInProgress = true;
83d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    }
84d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
85d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    public void onStopTrackingTouch(SeekBar seekBar) {
86d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        mTouchInProgress = false;
87b4765ac70d4ebf7ce0e3bbcbc2697cb242ed176dJeff Brown        mIm.tryPointerSpeed(seekBar.getProgress() + InputManager.MIN_POINTER_SPEED);
88d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    }
89d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
90d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    private void onSpeedChanged() {
914397f406a3c9e09ca2d5174ba46328345faa504eJeff Brown        int speed = mIm.getPointerSpeed(getContext());
92b4765ac70d4ebf7ce0e3bbcbc2697cb242ed176dJeff Brown        mSeekBar.setProgress(speed - InputManager.MIN_POINTER_SPEED);
93d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    }
94d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
95d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    @Override
96d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    protected void onDialogClosed(boolean positiveResult) {
97d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        super.onDialogClosed(positiveResult);
98d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
99d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        final ContentResolver resolver = getContext().getContentResolver();
100d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
101d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        if (positiveResult) {
1024397f406a3c9e09ca2d5174ba46328345faa504eJeff Brown            mIm.setPointerSpeed(getContext(),
1034397f406a3c9e09ca2d5174ba46328345faa504eJeff Brown                    mSeekBar.getProgress() + InputManager.MIN_POINTER_SPEED);
104d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        } else {
105d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown            restoreOldState();
106d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        }
107d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
108d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        resolver.unregisterContentObserver(mSpeedObserver);
109d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    }
110d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
111d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    private void restoreOldState() {
112d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        if (mRestoredOldState) return;
113d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
114b4765ac70d4ebf7ce0e3bbcbc2697cb242ed176dJeff Brown        mIm.tryPointerSpeed(mOldSpeed);
115d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        mRestoredOldState = true;
116d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    }
117d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
118d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    @Override
119d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    protected Parcelable onSaveInstanceState() {
120d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        final Parcelable superState = super.onSaveInstanceState();
121d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        if (getDialog() == null || !getDialog().isShowing()) return superState;
122d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
123d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        // Save the dialog state
124d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        final SavedState myState = new SavedState(superState);
125d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        myState.progress = mSeekBar.getProgress();
126d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        myState.oldSpeed = mOldSpeed;
127d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
128d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        // Restore the old state when the activity or dialog is being paused
129d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        restoreOldState();
130d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        return myState;
131d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    }
132d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
133d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    @Override
134d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    protected void onRestoreInstanceState(Parcelable state) {
135d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        if (state == null || !state.getClass().equals(SavedState.class)) {
136d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown            // Didn't save state for us in onSaveInstanceState
137d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown            super.onRestoreInstanceState(state);
138d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown            return;
139d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        }
140d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
141d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        SavedState myState = (SavedState) state;
142d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        super.onRestoreInstanceState(myState.getSuperState());
143d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        mOldSpeed = myState.oldSpeed;
144b4765ac70d4ebf7ce0e3bbcbc2697cb242ed176dJeff Brown        mIm.tryPointerSpeed(myState.progress + InputManager.MIN_POINTER_SPEED);
145d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    }
146d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
147d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    private static class SavedState extends BaseSavedState {
148d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        int progress;
149d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        int oldSpeed;
150d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
151d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        public SavedState(Parcel source) {
152d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown            super(source);
153d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown            progress = source.readInt();
154d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown            oldSpeed = source.readInt();
155d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        }
156d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
157d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        @Override
158d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        public void writeToParcel(Parcel dest, int flags) {
159d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown            super.writeToParcel(dest, flags);
160d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown            dest.writeInt(progress);
161d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown            dest.writeInt(oldSpeed);
162d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        }
163d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
164d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        public SavedState(Parcelable superState) {
165d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown            super(superState);
166d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        }
167d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
168d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        public static final Parcelable.Creator<SavedState> CREATOR =
169d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown                new Parcelable.Creator<SavedState>() {
170d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
171d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown            public SavedState createFromParcel(Parcel in) {
172d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown                return new SavedState(in);
173d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown            }
174d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
175d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown            public SavedState[] newArray(int size) {
176d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown                return new SavedState[size];
177d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown            }
178d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown        };
179d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown    }
180d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown}
181d82487b0ffc8c67fdca9d5a7e12151719c93c58dJeff Brown
182