VolumePreference.java revision ba87e3e6c985e7175152993b5efcc7dd2f0e1c93
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.content.Context;
20import android.content.res.TypedArray;
21import android.database.ContentObserver;
22import android.media.Ringtone;
23import android.media.RingtoneManager;
24import android.media.AudioManager;
25import android.os.Handler;
26import android.preference.PreferenceManager;
27import android.provider.Settings;
28import android.provider.Settings.System;
29import android.util.AttributeSet;
30import android.view.View;
31import android.widget.SeekBar;
32import android.widget.SeekBar.OnSeekBarChangeListener;
33
34/**
35 * @hide
36 */
37public class VolumePreference extends SeekBarPreference implements
38        PreferenceManager.OnActivityStopListener {
39
40    private static final String TAG = "VolumePreference";
41
42    private int mStreamType;
43
44    /** May be null if the dialog isn't visible. */
45    private SeekBarVolumizer mSeekBarVolumizer;
46
47    public VolumePreference(Context context, AttributeSet attrs) {
48        super(context, attrs);
49
50        TypedArray a = context.obtainStyledAttributes(attrs,
51                com.android.internal.R.styleable.VolumePreference, 0, 0);
52        mStreamType = a.getInt(android.R.styleable.VolumePreference_streamType, 0);
53        a.recycle();
54    }
55
56    public void setStreamType(int streamType) {
57        mStreamType = streamType;
58    }
59
60    @Override
61    protected void onBindDialogView(View view) {
62        super.onBindDialogView(view);
63
64        final SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar);
65        mSeekBarVolumizer = new SeekBarVolumizer(getContext(), seekBar, mStreamType);
66
67        getPreferenceManager().registerOnActivityStopListener(this);
68    }
69
70    @Override
71    protected void onDialogClosed(boolean positiveResult) {
72        super.onDialogClosed(positiveResult);
73
74        if (!positiveResult && mSeekBarVolumizer != null) {
75            mSeekBarVolumizer.revertVolume();
76        }
77
78        cleanup();
79    }
80
81    public void onActivityStop() {
82        cleanup();
83    }
84
85    /**
86     * Do clean up.  This can be called multiple times!
87     */
88    private void cleanup() {
89       getPreferenceManager().unregisterOnActivityStopListener(this);
90
91       if (mSeekBarVolumizer != null) {
92           mSeekBarVolumizer.stop();
93           mSeekBarVolumizer = null;
94       }
95    }
96
97    protected void onSampleStarting(SeekBarVolumizer volumizer) {
98        if (mSeekBarVolumizer != null && volumizer != mSeekBarVolumizer) {
99            mSeekBarVolumizer.stopSample();
100        }
101    }
102
103    /**
104     * Turns a {@link SeekBar} into a volume control.
105     */
106    public class SeekBarVolumizer implements OnSeekBarChangeListener, Runnable {
107
108        private Context mContext;
109        private Handler mHandler = new Handler();
110
111        private AudioManager mAudioManager;
112        private int mStreamType;
113        private int mOriginalStreamVolume;
114        private Ringtone mRingtone;
115
116        private int mLastProgress;
117        private SeekBar mSeekBar;
118
119        private ContentObserver mVolumeObserver = new ContentObserver(mHandler) {
120            @Override
121            public void onChange(boolean selfChange) {
122                super.onChange(selfChange);
123
124                if (mSeekBar != null) {
125                    mSeekBar.setProgress(System.getInt(mContext.getContentResolver(),
126                            System.VOLUME_SETTINGS[mStreamType], 0));
127                }
128            }
129        };
130
131        public SeekBarVolumizer(Context context, SeekBar seekBar, int streamType) {
132            mContext = context;
133            mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
134            mStreamType = streamType;
135            mSeekBar = seekBar;
136
137            initSeekBar(seekBar);
138        }
139
140        private void initSeekBar(SeekBar seekBar) {
141            seekBar.setMax(mAudioManager.getStreamMaxVolume(mStreamType));
142            mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType);
143            seekBar.setProgress(mOriginalStreamVolume);
144            seekBar.setOnSeekBarChangeListener(this);
145
146            mContext.getContentResolver().registerContentObserver(
147                    System.getUriFor(System.VOLUME_SETTINGS[mStreamType]),
148                    false, mVolumeObserver);
149
150            mRingtone = RingtoneManager.getRingtone(mContext,
151                    mStreamType == AudioManager.STREAM_NOTIFICATION
152                            ? Settings.System.DEFAULT_NOTIFICATION_URI
153                            : Settings.System.DEFAULT_RINGTONE_URI);
154            mRingtone.setStreamType(mStreamType);
155        }
156
157        public void stop() {
158            stopSample();
159            mContext.getContentResolver().unregisterContentObserver(mVolumeObserver);
160            mSeekBar.setOnSeekBarChangeListener(null);
161        }
162
163        public void revertVolume() {
164            mAudioManager.setStreamVolume(mStreamType, mOriginalStreamVolume, 0);
165        }
166
167        public void onProgressChanged(SeekBar seekBar, int progress,
168                boolean fromTouch) {
169            if (!fromTouch) {
170                return;
171            }
172
173            postSetVolume(progress);
174        }
175
176        private void postSetVolume(int progress) {
177            // Do the volume changing separately to give responsive UI
178            mLastProgress = progress;
179            mHandler.removeCallbacks(this);
180            mHandler.post(this);
181        }
182
183        public void onStartTrackingTouch(SeekBar seekBar) {
184        }
185
186        public void onStopTrackingTouch(SeekBar seekBar) {
187            if (mRingtone != null && !mRingtone.isPlaying()) {
188                sample();
189            }
190        }
191
192        public void run() {
193            mAudioManager.setStreamVolume(mStreamType, mLastProgress, 0);
194        }
195
196        private void sample() {
197            onSampleStarting(this);
198            mRingtone.play();
199        }
200
201        public void stopSample() {
202            if (mRingtone != null) {
203                mRingtone.stop();
204            }
205        }
206
207        public SeekBar getSeekBar() {
208            return mSeekBar;
209        }
210
211    }
212}
213