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