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