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 17 package android.preference; 18 19 import android.app.Dialog; 20 import android.content.Context; 21 import android.content.res.TypedArray; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 import android.util.AttributeSet; 25 import android.view.KeyEvent; 26 import android.view.View; 27 import android.widget.SeekBar; 28 29 /** 30 * @hide 31 */ 32 public 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.stopSample(); 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 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) { 154 // noop 155 } 156 157 @Override 158 public void onMuted(boolean muted) { 159 // noop 160 } 161 162 @Override 163 protected Parcelable onSaveInstanceState() { 164 final Parcelable superState = super.onSaveInstanceState(); 165 if (isPersistent()) { 166 // No need to save instance state since it's persistent 167 return superState; 168 } 169 170 final SavedState myState = new SavedState(superState); 171 if (mSeekBarVolumizer != null) { 172 mSeekBarVolumizer.onSaveInstanceState(myState.getVolumeStore()); 173 } 174 return myState; 175 } 176 177 @Override 178 protected void onRestoreInstanceState(Parcelable state) { 179 if (state == null || !state.getClass().equals(SavedState.class)) { 180 // Didn't save state for us in onSaveInstanceState 181 super.onRestoreInstanceState(state); 182 return; 183 } 184 185 SavedState myState = (SavedState) state; 186 super.onRestoreInstanceState(myState.getSuperState()); 187 if (mSeekBarVolumizer != null) { 188 mSeekBarVolumizer.onRestoreInstanceState(myState.getVolumeStore()); 189 } 190 } 191 192 public static class VolumeStore { 193 public int volume = -1; 194 public int originalVolume = -1; 195 } 196 197 private static class SavedState extends BaseSavedState { 198 VolumeStore mVolumeStore = new VolumeStore(); 199 200 public SavedState(Parcel source) { 201 super(source); 202 mVolumeStore.volume = source.readInt(); 203 mVolumeStore.originalVolume = source.readInt(); 204 } 205 206 @Override 207 public void writeToParcel(Parcel dest, int flags) { 208 super.writeToParcel(dest, flags); 209 dest.writeInt(mVolumeStore.volume); 210 dest.writeInt(mVolumeStore.originalVolume); 211 } 212 213 VolumeStore getVolumeStore() { 214 return mVolumeStore; 215 } 216 217 public SavedState(Parcelable superState) { 218 super(superState); 219 } 220 221 public static final Parcelable.Creator<SavedState> CREATOR = 222 new Parcelable.Creator<SavedState>() { 223 public SavedState createFromParcel(Parcel in) { 224 return new SavedState(in); 225 } 226 227 public SavedState[] newArray(int size) { 228 return new SavedState[size]; 229 } 230 }; 231 } 232 } 233