RingerVolumePreference.java revision 88ea1164afb52327b4ae2d5c695700b12fff1134
1/*
2 * Copyright (C) 2008 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 com.android.settings;
18
19import android.app.Dialog;
20import android.content.Context;
21import android.media.AudioManager;
22import android.os.Parcel;
23import android.os.Parcelable;
24import android.preference.VolumePreference;
25import android.provider.Settings;
26import android.util.AttributeSet;
27import android.view.View;
28import android.widget.CheckBox;
29import android.widget.CompoundButton;
30import android.widget.SeekBar;
31import android.widget.TextView;
32
33/**
34 * Special preference type that allows configuration of both the ring volume and
35 * notification volume.
36 */
37public class RingerVolumePreference extends VolumePreference implements
38        CheckBox.OnCheckedChangeListener {
39    private static final String TAG = "RingerVolumePreference";
40
41    private CheckBox mNotificationsUseRingVolumeCheckbox;
42    private SeekBarVolumizer [] mSeekBarVolumizer;
43    private static final int[] SEEKBAR_ID = new int[] {
44        R.id.notification_volume_seekbar,
45        R.id.media_volume_seekbar,
46        R.id.alarm_volume_seekbar
47    };
48    private static final int[] SEEKBAR_TYPE = new int[] {
49        AudioManager.STREAM_NOTIFICATION,
50        AudioManager.STREAM_MUSIC,
51        AudioManager.STREAM_ALARM
52    };
53    //private SeekBarVolumizer mNotificationSeekBarVolumizer;
54    private TextView mNotificationVolumeTitle;
55
56    public RingerVolumePreference(Context context, AttributeSet attrs) {
57        super(context, attrs);
58
59        // The always visible seekbar is for ring volume
60        setStreamType(AudioManager.STREAM_RING);
61
62        setDialogLayoutResource(R.layout.preference_dialog_ringervolume);
63        setDialogIcon(R.drawable.ic_settings_sound);
64
65        mSeekBarVolumizer = new SeekBarVolumizer[SEEKBAR_ID.length];
66    }
67
68    @Override
69    protected void onBindDialogView(View view) {
70        super.onBindDialogView(view);
71
72        for (int i = 0; i < SEEKBAR_ID.length; i++) {
73            SeekBar seekBar = (SeekBar) view.findViewById(SEEKBAR_ID[i]);
74            mSeekBarVolumizer[i] = new SeekBarVolumizer(getContext(), seekBar,
75                SEEKBAR_TYPE[i]);
76        }
77
78        mNotificationVolumeTitle = (TextView) view.findViewById(R.id.notification_volume_title);
79        mNotificationsUseRingVolumeCheckbox =
80                (CheckBox) view.findViewById(R.id.same_notification_volume);
81        mNotificationsUseRingVolumeCheckbox.setOnCheckedChangeListener(this);
82        mNotificationsUseRingVolumeCheckbox.setChecked(Settings.System.getInt(
83                getContext().getContentResolver(),
84                Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1) == 1);
85        setNotificationVolumeVisibility(!mNotificationsUseRingVolumeCheckbox.isChecked());
86    }
87
88    @Override
89    protected void onDialogClosed(boolean positiveResult) {
90        super.onDialogClosed(positiveResult);
91
92        if (!positiveResult) {
93            for (SeekBarVolumizer vol : mSeekBarVolumizer) {
94                if (vol != null) vol.revertVolume();
95            }
96        }
97        cleanup();
98    }
99
100    @Override
101    public void onActivityStop() {
102        super.onActivityStop();
103        cleanup();
104    }
105
106    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
107        setNotificationVolumeVisibility(!isChecked);
108
109        Settings.System.putInt(getContext().getContentResolver(),
110                Settings.System.NOTIFICATIONS_USE_RING_VOLUME, isChecked ? 1 : 0);
111
112        if (isChecked) {
113            // The user wants the notification to be same as ring, so do a
114            // one-time sync right now
115            AudioManager audioManager = (AudioManager) getContext()
116                    .getSystemService(Context.AUDIO_SERVICE);
117            audioManager.setStreamVolume(AudioManager.STREAM_NOTIFICATION,
118                    audioManager.getStreamVolume(AudioManager.STREAM_RING), 0);
119        }
120    }
121
122    @Override
123    protected void onSampleStarting(SeekBarVolumizer volumizer) {
124        super.onSampleStarting(volumizer);
125        for (SeekBarVolumizer vol : mSeekBarVolumizer) {
126            if (vol != null && vol != volumizer) vol.stopSample();
127        }
128    }
129
130    private void setNotificationVolumeVisibility(boolean visible) {
131        if (mSeekBarVolumizer[0] != null) {
132            mSeekBarVolumizer[0].getSeekBar().setVisibility(
133                    visible ? View.VISIBLE : View.GONE);
134        }
135        mNotificationVolumeTitle.setVisibility(visible ? View.VISIBLE : View.GONE);
136    }
137
138    private void cleanup() {
139        for (int i = 0; i < SEEKBAR_ID.length; i++) {
140            if (mSeekBarVolumizer[i] != null) {
141                Dialog dialog = getDialog();
142                if (dialog != null && dialog.isShowing()) {
143                    // Stopped while dialog was showing, revert changes
144                    mSeekBarVolumizer[i].revertVolume();
145                }
146                mSeekBarVolumizer[i].stop();
147                mSeekBarVolumizer[i] = null;
148            }
149        }
150    }
151
152    @Override
153    protected Parcelable onSaveInstanceState() {
154        final Parcelable superState = super.onSaveInstanceState();
155        if (isPersistent()) {
156            // No need to save instance state since it's persistent
157            return superState;
158        }
159
160        final SavedState myState = new SavedState(superState);
161        VolumeStore[] volumeStore = myState.getVolumeStore(SEEKBAR_ID.length);
162        for (int i = 0; i < SEEKBAR_ID.length; i++) {
163            SeekBarVolumizer vol = mSeekBarVolumizer[i];
164            if (vol != null) {
165                vol.onSaveInstanceState(volumeStore[i]);
166            }
167        }
168        return myState;
169    }
170
171    @Override
172    protected void onRestoreInstanceState(Parcelable state) {
173        if (state == null || !state.getClass().equals(SavedState.class)) {
174            // Didn't save state for us in onSaveInstanceState
175            super.onRestoreInstanceState(state);
176            return;
177        }
178
179        SavedState myState = (SavedState) state;
180        super.onRestoreInstanceState(myState.getSuperState());
181        VolumeStore[] volumeStore = myState.getVolumeStore(SEEKBAR_ID.length);
182        for (int i = 0; i < SEEKBAR_ID.length; i++) {
183            SeekBarVolumizer vol = mSeekBarVolumizer[i];
184            if (vol != null) {
185                vol.onRestoreInstanceState(volumeStore[i]);
186            }
187        }
188    }
189
190    private static class SavedState extends BaseSavedState {
191        VolumeStore [] mVolumeStore;
192
193        public SavedState(Parcel source) {
194            super(source);
195            mVolumeStore = new VolumeStore[SEEKBAR_ID.length];
196            for (int i = 0; i < SEEKBAR_ID.length; i++) {
197                mVolumeStore[i] = new VolumeStore();
198                mVolumeStore[i].volume = source.readInt();
199                mVolumeStore[i].originalVolume = source.readInt();
200            }
201        }
202
203        @Override
204        public void writeToParcel(Parcel dest, int flags) {
205            super.writeToParcel(dest, flags);
206            for (int i = 0; i < SEEKBAR_ID.length; i++) {
207                dest.writeInt(mVolumeStore[i].volume);
208                dest.writeInt(mVolumeStore[i].originalVolume);
209            }
210        }
211
212        VolumeStore[] getVolumeStore(int count) {
213            if (mVolumeStore == null || mVolumeStore.length != count) {
214                mVolumeStore = new VolumeStore[count];
215                for (int i = 0; i < count; i++) {
216                    mVolumeStore[i] = new VolumeStore();
217                }
218            }
219            return mVolumeStore;
220        }
221
222        public SavedState(Parcelable superState) {
223            super(superState);
224        }
225
226        public static final Parcelable.Creator<SavedState> CREATOR =
227                new Parcelable.Creator<SavedState>() {
228            public SavedState createFromParcel(Parcel in) {
229                return new SavedState(in);
230            }
231
232            public SavedState[] newArray(int size) {
233                return new SavedState[size];
234            }
235        };
236    }
237}
238