VolumePreference.java revision 0e588ea8e1746f3335b2b5c8a51fdd9a96167b59
1/*
2 * Copyright (C) 2007 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 android.preference;
18
19import android.app.Dialog;
20import android.content.Context;
21import android.content.res.TypedArray;
22import android.os.Parcel;
23import android.os.Parcelable;
24import android.util.AttributeSet;
25import android.view.KeyEvent;
26import android.view.View;
27import android.widget.SeekBar;
28
29/**
30 * @hide
31 */
32public class VolumePreference extends SeekBarDialogPreference implements
33        PreferenceManager.OnActivityStopListener, View.OnKeyListener, SeekBarVolumizer.Callback {
34
35    static final String TAG = "VolumePreference";
36
37    private int mStreamType;
38
39    /** May be null if the dialog isn't visible. */
40    private SeekBarVolumizer mSeekBarVolumizer;
41
42    public VolumePreference(
43            Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
44        super(context, attrs, defStyleAttr, defStyleRes);
45
46        final TypedArray a = context.obtainStyledAttributes(attrs,
47                com.android.internal.R.styleable.VolumePreference, defStyleAttr, defStyleRes);
48        mStreamType = a.getInt(android.R.styleable.VolumePreference_streamType, 0);
49        a.recycle();
50    }
51
52    public VolumePreference(Context context, AttributeSet attrs, int defStyleAttr) {
53        this(context, attrs, defStyleAttr, 0);
54    }
55
56    public VolumePreference(Context context, AttributeSet attrs) {
57        this(context, attrs, com.android.internal.R.attr.dialogPreferenceStyle);
58    }
59
60    public void setStreamType(int streamType) {
61        mStreamType = streamType;
62    }
63
64    @Override
65    protected void onBindDialogView(View view) {
66        super.onBindDialogView(view);
67
68        final SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
69        mSeekBarVolumizer = new SeekBarVolumizer(getContext(), mStreamType, null, this);
70        mSeekBarVolumizer.start();
71        mSeekBarVolumizer.setSeekBar(seekBar);
72
73        getPreferenceManager().registerOnActivityStopListener(this);
74
75        // grab focus and key events so that pressing the volume buttons in the
76        // dialog doesn't also show the normal volume adjust toast.
77        view.setOnKeyListener(this);
78        view.setFocusableInTouchMode(true);
79        view.requestFocus();
80    }
81
82    public boolean onKey(View v, int keyCode, KeyEvent event) {
83        // If key arrives immediately after the activity has been cleaned up.
84        if (mSeekBarVolumizer == null) return true;
85        boolean isdown = (event.getAction() == KeyEvent.ACTION_DOWN);
86        switch (keyCode) {
87            case KeyEvent.KEYCODE_VOLUME_DOWN:
88                if (isdown) {
89                    mSeekBarVolumizer.changeVolumeBy(-1);
90                }
91                return true;
92            case KeyEvent.KEYCODE_VOLUME_UP:
93                if (isdown) {
94                    mSeekBarVolumizer.changeVolumeBy(1);
95                }
96                return true;
97            case KeyEvent.KEYCODE_VOLUME_MUTE:
98                if (isdown) {
99                    mSeekBarVolumizer.muteVolume();
100                }
101                return true;
102            default:
103                return false;
104        }
105    }
106
107    @Override
108    protected void onDialogClosed(boolean positiveResult) {
109        super.onDialogClosed(positiveResult);
110
111        if (!positiveResult && mSeekBarVolumizer != null) {
112            mSeekBarVolumizer.revertVolume();
113        }
114
115        cleanup();
116    }
117
118    public void onActivityStop() {
119        if (mSeekBarVolumizer != null) {
120            mSeekBarVolumizer.postStopSample();
121        }
122    }
123
124    /**
125     * Do clean up.  This can be called multiple times!
126     */
127    private void cleanup() {
128       getPreferenceManager().unregisterOnActivityStopListener(this);
129
130       if (mSeekBarVolumizer != null) {
131           Dialog dialog = getDialog();
132           if (dialog != null && dialog.isShowing()) {
133               View view = dialog.getWindow().getDecorView()
134                       .findViewById(com.android.internal.R.id.seekbar);
135               if (view != null) view.setOnKeyListener(null);
136               // Stopped while dialog was showing, revert changes
137               mSeekBarVolumizer.revertVolume();
138           }
139           mSeekBarVolumizer.stop();
140           mSeekBarVolumizer = null;
141       }
142
143    }
144
145    @Override
146    public void onSampleStarting(SeekBarVolumizer volumizer) {
147        if (mSeekBarVolumizer != null && volumizer != mSeekBarVolumizer) {
148            mSeekBarVolumizer.stopSample();
149        }
150    }
151
152    @Override
153    protected Parcelable onSaveInstanceState() {
154        final Parcelable superState = super.onSaveInstanceState();
155        if (isPersistent()) {
156            // No need to save instance state since it's persistent
157            return superState;
158        }
159
160        final SavedState myState = new SavedState(superState);
161        if (mSeekBarVolumizer != null) {
162            mSeekBarVolumizer.onSaveInstanceState(myState.getVolumeStore());
163        }
164        return myState;
165    }
166
167    @Override
168    protected void onRestoreInstanceState(Parcelable state) {
169        if (state == null || !state.getClass().equals(SavedState.class)) {
170            // Didn't save state for us in onSaveInstanceState
171            super.onRestoreInstanceState(state);
172            return;
173        }
174
175        SavedState myState = (SavedState) state;
176        super.onRestoreInstanceState(myState.getSuperState());
177        if (mSeekBarVolumizer != null) {
178            mSeekBarVolumizer.onRestoreInstanceState(myState.getVolumeStore());
179        }
180    }
181
182    public static class VolumeStore {
183        public int volume = -1;
184        public int originalVolume = -1;
185    }
186
187    private static class SavedState extends BaseSavedState {
188        VolumeStore mVolumeStore = new VolumeStore();
189
190        public SavedState(Parcel source) {
191            super(source);
192            mVolumeStore.volume = source.readInt();
193            mVolumeStore.originalVolume = source.readInt();
194        }
195
196        @Override
197        public void writeToParcel(Parcel dest, int flags) {
198            super.writeToParcel(dest, flags);
199            dest.writeInt(mVolumeStore.volume);
200            dest.writeInt(mVolumeStore.originalVolume);
201        }
202
203        VolumeStore getVolumeStore() {
204            return mVolumeStore;
205        }
206
207        public SavedState(Parcelable superState) {
208            super(superState);
209        }
210
211        public static final Parcelable.Creator<SavedState> CREATOR =
212                new Parcelable.Creator<SavedState>() {
213            public SavedState createFromParcel(Parcel in) {
214                return new SavedState(in);
215            }
216
217            public SavedState[] newArray(int size) {
218                return new SavedState[size];
219            }
220        };
221    }
222}
223