VolumePreference.java revision 9066cfe9886ac131c34d59ed0e2d287b0e3c0087
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 198 // Only play a preview sample when controlling the ringer stream 199 if (mStreamType != AudioManager.STREAM_RING 200 && mStreamType != AudioManager.STREAM_NOTIFICATION) { 201 return; 202 } 203 204 onSampleStarting(this); 205 mRingtone.play(); 206 } 207 208 public void stopSample() { 209 if (mRingtone != null) { 210 mRingtone.stop(); 211 } 212 } 213 214 public SeekBar getSeekBar() { 215 return mSeekBar; 216 } 217 218 } 219} 220