Home | History | Annotate | Download | only in preference
      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