19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.view;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
192bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasaniimport com.android.internal.R;
202bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
21c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurentimport android.app.AlertDialog;
222bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasaniimport android.app.Dialog;
232bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasaniimport android.content.DialogInterface.OnDismissListener;
242bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasaniimport android.content.BroadcastReceiver;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
262bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasaniimport android.content.DialogInterface;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
282bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasaniimport android.content.IntentFilter;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.AudioManager;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.AudioService;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.AudioSystem;
3369f593ccb7414ee98991b1da1a4bfbd9951e3570Marco Nelissenimport android.media.RingtoneManager;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.ToneGenerator;
3569f593ccb7414ee98991b1da1a4bfbd9951e3570Marco Nelissenimport android.net.Uri;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Vibrator;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
40284e630a9b7f126ffb83cee4a1c4fe5134190cabAmith Yamasaniimport android.view.WindowManager.LayoutParams;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.ImageView;
422bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasaniimport android.widget.SeekBar;
432bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasaniimport android.widget.SeekBar.OnSeekBarChangeListener;
442bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
452bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasaniimport java.util.HashMap;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Handle the volume up and down keys.
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This code really should be moved elsewhere.
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
52e8ecde10b33b1d050d2b63b3f4cd20e8bb7c96d4Dianne Hackborn * Seriously, it really really should be moved elsewhere.  This is used by
53e8ecde10b33b1d050d2b63b3f4cd20e8bb7c96d4Dianne Hackborn * android.media.AudioService, which actually runs in the system process, to
54e8ecde10b33b1d050d2b63b3f4cd20e8bb7c96d4Dianne Hackborn * show the volume dialog when the user changes the volume.  What a mess.
55e8ecde10b33b1d050d2b63b3f4cd20e8bb7c96d4Dianne Hackborn *
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
582bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasanipublic class VolumePanel extends Handler implements OnSeekBarChangeListener, View.OnClickListener
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project{
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "VolumePanel";
6169f593ccb7414ee98991b1da1a4bfbd9951e3570Marco Nelissen    private static boolean LOGD = false;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The delay before playing a sound. This small period exists so the user
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * can press another key (non-volume keys, too) to have it NOT be audible.
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * PhoneWindow will implement this part.
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int PLAY_SOUND_DELAY = 300;
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The delay before vibrating. This small period exists so if the user is
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * moving to silent mode, it will not emit a short vibrate (it normally
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * would since vibrate is between normal mode and silent mode using hardware
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * keys).
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static final int VIBRATE_DELAY = 300;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int VIBRATE_DURATION = 300;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int BEEP_DURATION = 150;
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MAX_VOLUME = 100;
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int FREE_DELAY = 10000;
832bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private static final int TIMEOUT_DELAY = 3000;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MSG_VOLUME_CHANGED = 0;
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MSG_FREE_RESOURCES = 1;
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MSG_PLAY_SOUND = 2;
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MSG_STOP_SOUNDS = 3;
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MSG_VIBRATE = 4;
902bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private static final int MSG_TIMEOUT = 5;
912bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private static final int MSG_RINGER_MODE_CHANGED = 6;
92ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    private static final int MSG_MUTE_CHANGED = 7;
933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private static final int MSG_REMOTE_VOLUME_CHANGED = 8;
943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private static final int MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN = 9;
953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private static final int MSG_SLIDER_VISIBILITY_CHANGED = 10;
96c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private static final int MSG_DISPLAY_SAFE_VOLUME_WARNING = 11;
972bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
988dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    // Pseudo stream type for master volume
994767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    private static final int STREAM_MASTER = -100;
1003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // Pseudo stream type for remote volume is defined in AudioService.STREAM_REMOTE_MUSIC
1018dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected Context mContext;
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private AudioManager mAudioManager;
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected AudioService mAudioService;
10569f593ccb7414ee98991b1da1a4bfbd9951e3570Marco Nelissen    private boolean mRingIsSilent;
10642722bfa136f5616872a2c4e199813e804621c81Amith Yamasani    private boolean mShowCombinedVolumes;
10771def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani    private boolean mVoiceCapable;
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
109c4b78d206ffcdccac01e3436a4a3462bef9672edChristopher Tate    // True if we want to play tones on the system stream when the master stream is specified.
110c4b78d206ffcdccac01e3436a4a3462bef9672edChristopher Tate    private final boolean mPlayMasterStreamTones;
111c4b78d206ffcdccac01e3436a4a3462bef9672edChristopher Tate
1122bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    /** Dialog containing all the sliders */
1132bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private final Dialog mDialog;
1142bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    /** Dialog's content view */
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final View mView;
1162bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
117baf6dbfa9340f3266e41841ebd51f21effc583eeAmith Yamasani    /** The visible portion of the volume overlay */
118baf6dbfa9340f3266e41841ebd51f21effc583eeAmith Yamasani    private final ViewGroup mPanel;
1192bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    /** Contains the sliders and their touchable icons */
1202bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private final ViewGroup mSliderGroup;
1212bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    /** The button that expands the dialog to show all sliders */
1222bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private final View mMoreButton;
1232bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    /** Dummy divider icon that needs to vanish with the more button */
1242bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private final View mDivider;
1252bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
1262bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    /** Currently active stream that shows up at the top of the list of sliders */
1272bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private int mActiveStreamType = -1;
1282bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    /** All the slider controls mapped by stream type */
1292bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private HashMap<Integer,StreamControl> mStreamControls;
1302bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
13171def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani    private enum StreamResources {
13271def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        BluetoothSCOStream(AudioManager.STREAM_BLUETOOTH_SCO,
13371def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani                R.string.volume_icon_description_bluetooth,
13471def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani                R.drawable.ic_audio_bt,
13571def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani                R.drawable.ic_audio_bt,
13671def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani                false),
13771def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        RingerStream(AudioManager.STREAM_RING,
13871def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani                R.string.volume_icon_description_ringer,
13971def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani                R.drawable.ic_audio_ring_notif,
14071def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani                R.drawable.ic_audio_ring_notif_mute,
14171def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani                false),
14271def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        VoiceStream(AudioManager.STREAM_VOICE_CALL,
14371def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani                R.string.volume_icon_description_incall,
14471def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani                R.drawable.ic_audio_phone,
14571def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani                R.drawable.ic_audio_phone,
14671def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani                false),
14792e1b2d37be8d3d76a55d0242b3cfab7fd8e449aAmith Yamasani        AlarmStream(AudioManager.STREAM_ALARM,
14892e1b2d37be8d3d76a55d0242b3cfab7fd8e449aAmith Yamasani                R.string.volume_alarm,
14992e1b2d37be8d3d76a55d0242b3cfab7fd8e449aAmith Yamasani                R.drawable.ic_audio_alarm,
15092e1b2d37be8d3d76a55d0242b3cfab7fd8e449aAmith Yamasani                R.drawable.ic_audio_alarm_mute,
15192e1b2d37be8d3d76a55d0242b3cfab7fd8e449aAmith Yamasani                false),
15271def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        MediaStream(AudioManager.STREAM_MUSIC,
15371def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani                R.string.volume_icon_description_media,
15471def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani                R.drawable.ic_audio_vol,
15571def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani                R.drawable.ic_audio_vol_mute,
15671def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani                true),
15771def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        NotificationStream(AudioManager.STREAM_NOTIFICATION,
15871def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani                R.string.volume_icon_description_notification,
15971def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani                R.drawable.ic_audio_notification,
16071def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani                R.drawable.ic_audio_notification_mute,
1618dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood                true),
1628dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        // for now, use media resources for master volume
1638dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        MasterStream(STREAM_MASTER,
1643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                R.string.volume_icon_description_media, //FIXME should have its own description
1658dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood                R.drawable.ic_audio_vol,
1668dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood                R.drawable.ic_audio_vol_mute,
1673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                false),
1683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        RemoteStream(AudioService.STREAM_REMOTE_MUSIC,
1693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                R.string.volume_icon_description_media, //FIXME should have its own description
1703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                R.drawable.ic_media_route_on_holo_dark,
1713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                R.drawable.ic_media_route_disabled_holo_dark,
1723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                false);// will be dynamically updated
1732bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
17471def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        int streamType;
17571def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        int descRes;
17671def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        int iconRes;
17771def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        int iconMuteRes;
17871def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        // RING, VOICE_CALL & BLUETOOTH_SCO are hidden unless explicitly requested
17971def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        boolean show;
18071def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani
18171def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        StreamResources(int streamType, int descRes, int iconRes, int iconMuteRes, boolean show) {
18271def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani            this.streamType = streamType;
18371def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani            this.descRes = descRes;
18471def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani            this.iconRes = iconRes;
18571def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani            this.iconMuteRes = iconMuteRes;
18671def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani            this.show = show;
18771def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        }
1882bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    };
1892bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
19071def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani    // List of stream types and their order
19171def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani    private static final StreamResources[] STREAMS = {
19271def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        StreamResources.BluetoothSCOStream,
19371def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        StreamResources.RingerStream,
19471def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        StreamResources.VoiceStream,
19571def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        StreamResources.MediaStream,
19692e1b2d37be8d3d76a55d0242b3cfab7fd8e449aAmith Yamasani        StreamResources.NotificationStream,
1978dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        StreamResources.AlarmStream,
1983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        StreamResources.MasterStream,
1993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        StreamResources.RemoteStream
2002bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    };
2012bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
2022bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    /** Object that contains data for each slider */
2032bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private class StreamControl {
2042bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        int streamType;
2052bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        ViewGroup group;
2062bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        ImageView icon;
2072bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        SeekBar seekbarView;
2082bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        int iconRes;
2092bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        int iconMuteRes;
2102bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    }
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Synchronize when accessing this
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ToneGenerator mToneGenerators[];
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Vibrator mVibrator;
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
216c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private static AlertDialog sConfirmSafeVolumeDialog;
2170516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent    private static Object sConfirmSafeVolumeLock = new Object();
218c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
219c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private static class WarningDialogReceiver extends BroadcastReceiver
220c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            implements DialogInterface.OnDismissListener {
221c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        private Context mContext;
222c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        private Dialog mDialog;
223c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
224c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        WarningDialogReceiver(Context context, Dialog dialog) {
225c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            mContext = context;
226c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            mDialog = dialog;
227c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
228c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            context.registerReceiver(this, filter);
229c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
230c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
231c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        @Override
232c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        public void onReceive(Context context, Intent intent) {
233c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            mDialog.cancel();
2340516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent            synchronized (sConfirmSafeVolumeLock) {
2350516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent                sConfirmSafeVolumeDialog = null;
2360516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent            }
237c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
238c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
239c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        public void onDismiss(DialogInterface unused) {
240c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            mContext.unregisterReceiver(this);
2410516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent            synchronized (sConfirmSafeVolumeLock) {
2420516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent                sConfirmSafeVolumeDialog = null;
2430516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent            }
244c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
245c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
246c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
247c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
2482bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    public VolumePanel(final Context context, AudioService volumeService) {
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAudioService = volumeService;
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2538dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        // For now, only show master volume if master volume is supported
2548dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        boolean useMasterVolume = context.getResources().getBoolean(
2558dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood                com.android.internal.R.bool.config_useMasterVolume);
2568dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        if (useMasterVolume) {
2578dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood            for (int i = 0; i < STREAMS.length; i++) {
2588dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood                StreamResources streamRes = STREAMS[i];
2598dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood                streamRes.show = (streamRes.streamType == STREAM_MASTER);
2608dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood            }
2618dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        }
2628dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        LayoutInflater inflater = (LayoutInflater) context
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
2652bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        View view = mView = inflater.inflate(R.layout.volume_adjust, null);
2662bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        mView.setOnTouchListener(new View.OnTouchListener() {
2672bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            public boolean onTouch(View v, MotionEvent event) {
2682bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                resetTimeout();
269284e630a9b7f126ffb83cee4a1c4fe5134190cabAmith Yamasani                return false;
2702bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            }
2712bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        });
272baf6dbfa9340f3266e41841ebd51f21effc583eeAmith Yamasani        mPanel = (ViewGroup) mView.findViewById(R.id.visible_panel);
2732bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        mSliderGroup = (ViewGroup) mView.findViewById(R.id.slider_group);
2742bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        mMoreButton = (ImageView) mView.findViewById(R.id.expand_button);
2752bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        mDivider = (ImageView) mView.findViewById(R.id.expand_button_divider);
2762bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
277284e630a9b7f126ffb83cee4a1c4fe5134190cabAmith Yamasani        mDialog = new Dialog(context, R.style.Theme_Panel_Volume) {
278284e630a9b7f126ffb83cee4a1c4fe5134190cabAmith Yamasani            public boolean onTouchEvent(MotionEvent event) {
279284e630a9b7f126ffb83cee4a1c4fe5134190cabAmith Yamasani                if (isShowing() && event.getAction() == MotionEvent.ACTION_OUTSIDE) {
280284e630a9b7f126ffb83cee4a1c4fe5134190cabAmith Yamasani                    forceTimeout();
281284e630a9b7f126ffb83cee4a1c4fe5134190cabAmith Yamasani                    return true;
282284e630a9b7f126ffb83cee4a1c4fe5134190cabAmith Yamasani                }
283284e630a9b7f126ffb83cee4a1c4fe5134190cabAmith Yamasani                return false;
284284e630a9b7f126ffb83cee4a1c4fe5134190cabAmith Yamasani            }
285284e630a9b7f126ffb83cee4a1c4fe5134190cabAmith Yamasani        };
2862bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        mDialog.setTitle("Volume control"); // No need to localize
2872bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        mDialog.setContentView(mView);
2882bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        mDialog.setOnDismissListener(new OnDismissListener() {
2892bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            public void onDismiss(DialogInterface dialog) {
2902bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                mActiveStreamType = -1;
291402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent                mAudioManager.forceVolumeControlStream(mActiveStreamType);
2922bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            }
2932bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        });
2942bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        // Change some window properties
2952bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        Window window = mDialog.getWindow();
2962bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        window.setGravity(Gravity.TOP);
297284e630a9b7f126ffb83cee4a1c4fe5134190cabAmith Yamasani        LayoutParams lp = window.getAttributes();
2982bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        lp.token = null;
299284e630a9b7f126ffb83cee4a1c4fe5134190cabAmith Yamasani        // Offset from the top
300284e630a9b7f126ffb83cee4a1c4fe5134190cabAmith Yamasani        lp.y = mContext.getResources().getDimensionPixelOffset(
301284e630a9b7f126ffb83cee4a1c4fe5134190cabAmith Yamasani                com.android.internal.R.dimen.volume_panel_top);
302284e630a9b7f126ffb83cee4a1c4fe5134190cabAmith Yamasani        lp.type = LayoutParams.TYPE_VOLUME_OVERLAY;
303284e630a9b7f126ffb83cee4a1c4fe5134190cabAmith Yamasani        lp.width = LayoutParams.WRAP_CONTENT;
304284e630a9b7f126ffb83cee4a1c4fe5134190cabAmith Yamasani        lp.height = LayoutParams.WRAP_CONTENT;
3052bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        window.setAttributes(lp);
306284e630a9b7f126ffb83cee4a1c4fe5134190cabAmith Yamasani        window.addFlags(LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCH_MODAL
307284e630a9b7f126ffb83cee4a1c4fe5134190cabAmith Yamasani                | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
3082bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mToneGenerators = new ToneGenerator[AudioSystem.getNumStreamTypes()];
310c2346134bb519a54d50655cbef940fc3fdec60a9Jeff Brown        mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
3112bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
31271def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
3138dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        mShowCombinedVolumes = !mVoiceCapable && !useMasterVolume;
31442722bfa136f5616872a2c4e199813e804621c81Amith Yamasani        // If we don't want to show multiple volumes, hide the settings button and divider
31542722bfa136f5616872a2c4e199813e804621c81Amith Yamasani        if (!mShowCombinedVolumes) {
31642722bfa136f5616872a2c4e199813e804621c81Amith Yamasani            mMoreButton.setVisibility(View.GONE);
31742722bfa136f5616872a2c4e199813e804621c81Amith Yamasani            mDivider.setVisibility(View.GONE);
31842722bfa136f5616872a2c4e199813e804621c81Amith Yamasani        } else {
31942722bfa136f5616872a2c4e199813e804621c81Amith Yamasani            mMoreButton.setOnClickListener(this);
32042722bfa136f5616872a2c4e199813e804621c81Amith Yamasani        }
32142722bfa136f5616872a2c4e199813e804621c81Amith Yamasani
322c4b78d206ffcdccac01e3436a4a3462bef9672edChristopher Tate        boolean masterVolumeOnly = context.getResources().getBoolean(
323c4b78d206ffcdccac01e3436a4a3462bef9672edChristopher Tate                com.android.internal.R.bool.config_useMasterVolume);
324c4b78d206ffcdccac01e3436a4a3462bef9672edChristopher Tate        boolean masterVolumeKeySounds = mContext.getResources().getBoolean(
325c4b78d206ffcdccac01e3436a4a3462bef9672edChristopher Tate                com.android.internal.R.bool.config_useVolumeKeySounds);
326c4b78d206ffcdccac01e3436a4a3462bef9672edChristopher Tate
327c4b78d206ffcdccac01e3436a4a3462bef9672edChristopher Tate        mPlayMasterStreamTones = masterVolumeOnly && masterVolumeKeySounds;
328c4b78d206ffcdccac01e3436a4a3462bef9672edChristopher Tate
3292bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        listenToRingerMode();
3302bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    }
3312bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
3322bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private void listenToRingerMode() {
3332bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        final IntentFilter filter = new IntentFilter();
3342bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
3352bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        mContext.registerReceiver(new BroadcastReceiver() {
3362bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
3372bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            public void onReceive(Context context, Intent intent) {
3382bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                final String action = intent.getAction();
3392bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
3402bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) {
3412bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                    removeMessages(MSG_RINGER_MODE_CHANGED);
3422bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                    sendMessage(obtainMessage(MSG_RINGER_MODE_CHANGED));
3432bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                }
3442bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            }
3452bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        }, filter);
3462bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    }
3472bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
3482bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private boolean isMuted(int streamType) {
3498dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        if (streamType == STREAM_MASTER) {
3508c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent            return mAudioManager.isMasterMute();
3513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) {
3523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            return (mAudioService.getRemoteStreamVolume() <= 0);
3538dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        } else {
3548c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent            return mAudioManager.isStreamMute(streamType);
3558dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        }
3568dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    }
3578dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood
3588dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    private int getStreamMaxVolume(int streamType) {
3598dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        if (streamType == STREAM_MASTER) {
3608c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent            return mAudioManager.getMasterMaxVolume();
3613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) {
3623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            return mAudioService.getRemoteStreamMaxVolume();
3638dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        } else {
3648c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent            return mAudioManager.getStreamMaxVolume(streamType);
3658dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        }
3668dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    }
3678dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood
3688dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    private int getStreamVolume(int streamType) {
3698dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        if (streamType == STREAM_MASTER) {
3708c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent            return mAudioManager.getMasterVolume();
3713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) {
3723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            return mAudioService.getRemoteStreamVolume();
3738dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        } else {
3748c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent            return mAudioManager.getStreamVolume(streamType);
3758dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        }
3768dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    }
3778dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood
3788dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    private void setStreamVolume(int streamType, int index, int flags) {
3798dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        if (streamType == STREAM_MASTER) {
3808c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent            mAudioManager.setMasterVolume(index, flags);
3813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) {
3823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mAudioService.setRemoteStreamVolume(index);
3838dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        } else {
3848c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent            mAudioManager.setStreamVolume(streamType, index, flags);
3858dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        }
3862bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    }
3872bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
3882bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private void createSliders() {
3892bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        LayoutInflater inflater = (LayoutInflater) mContext
3902bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
39171def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        mStreamControls = new HashMap<Integer, StreamControl>(STREAMS.length);
39242722bfa136f5616872a2c4e199813e804621c81Amith Yamasani        Resources res = mContext.getResources();
39371def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        for (int i = 0; i < STREAMS.length; i++) {
39471def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani            StreamResources streamRes = STREAMS[i];
39571def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani            int streamType = streamRes.streamType;
39671def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani            if (mVoiceCapable && streamRes == StreamResources.NotificationStream) {
39771def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani                streamRes = StreamResources.RingerStream;
39871def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani            }
3992bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            StreamControl sc = new StreamControl();
400d47a3aee7ad7d8ef66ee279ab64b64a0f7918e90Amith Yamasani            sc.streamType = streamType;
4012bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            sc.group = (ViewGroup) inflater.inflate(R.layout.volume_adjust_item, null);
4022bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            sc.group.setTag(sc);
4032bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            sc.icon = (ImageView) sc.group.findViewById(R.id.stream_icon);
4042bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            sc.icon.setTag(sc);
40571def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani            sc.icon.setContentDescription(res.getString(streamRes.descRes));
40671def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani            sc.iconRes = streamRes.iconRes;
40771def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani            sc.iconMuteRes = streamRes.iconMuteRes;
4082bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            sc.icon.setImageResource(sc.iconRes);
4092bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            sc.seekbarView = (SeekBar) sc.group.findViewById(R.id.seekbar);
410d47a3aee7ad7d8ef66ee279ab64b64a0f7918e90Amith Yamasani            int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO ||
411d47a3aee7ad7d8ef66ee279ab64b64a0f7918e90Amith Yamasani                    streamType == AudioSystem.STREAM_VOICE_CALL) ? 1 : 0;
4128dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood            sc.seekbarView.setMax(getStreamMaxVolume(streamType) + plusOne);
4132bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            sc.seekbarView.setOnSeekBarChangeListener(this);
4142bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            sc.seekbarView.setTag(sc);
415d47a3aee7ad7d8ef66ee279ab64b64a0f7918e90Amith Yamasani            mStreamControls.put(streamType, sc);
4162bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        }
4172bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    }
4182bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
4192bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private void reorderSliders(int activeStreamType) {
4202bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        mSliderGroup.removeAllViews();
4212bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
4222bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        StreamControl active = mStreamControls.get(activeStreamType);
4232bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        if (active == null) {
4242bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            Log.e("VolumePanel", "Missing stream type! - " + activeStreamType);
4252bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            mActiveStreamType = -1;
4262bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        } else {
4272bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            mSliderGroup.addView(active.group);
4282bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            mActiveStreamType = activeStreamType;
4292bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            active.group.setVisibility(View.VISIBLE);
4302bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            updateSlider(active);
4312bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        }
4322bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
43342722bfa136f5616872a2c4e199813e804621c81Amith Yamasani        addOtherVolumes();
43442722bfa136f5616872a2c4e199813e804621c81Amith Yamasani    }
43542722bfa136f5616872a2c4e199813e804621c81Amith Yamasani
43642722bfa136f5616872a2c4e199813e804621c81Amith Yamasani    private void addOtherVolumes() {
43742722bfa136f5616872a2c4e199813e804621c81Amith Yamasani        if (!mShowCombinedVolumes) return;
43842722bfa136f5616872a2c4e199813e804621c81Amith Yamasani
43971def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani        for (int i = 0; i < STREAMS.length; i++) {
4402bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            // Skip the phone specific ones and the active one
44171def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani            final int streamType = STREAMS[i].streamType;
44271def77a2811ce99ee50f09bc933ff380ce85055Amith Yamasani            if (!STREAMS[i].show || streamType == mActiveStreamType) {
4432bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                continue;
4442bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            }
4452bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            StreamControl sc = mStreamControls.get(streamType);
4462bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            mSliderGroup.addView(sc.group);
4472bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            updateSlider(sc);
4482bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        }
4492bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    }
4502bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
4512bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    /** Update the mute and progress state of a slider */
4522bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private void updateSlider(StreamControl sc) {
4538c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent        sc.seekbarView.setProgress(getStreamVolume(sc.streamType));
4542bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        final boolean muted = isMuted(sc.streamType);
4552bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        sc.icon.setImageResource(muted ? sc.iconMuteRes : sc.iconRes);
4568c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent        if (sc.streamType == AudioManager.STREAM_RING &&
4578c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent                mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) {
458c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            sc.icon.setImageResource(R.drawable.ic_audio_ring_notif_vibrate);
459c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani        }
4603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (sc.streamType == AudioService.STREAM_REMOTE_MUSIC) {
4613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            // never disable touch interactions for remote playback, the muting is not tied to
4623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            // the state of the phone.
4633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            sc.seekbarView.setEnabled(true);
4643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        } else if (sc.streamType != mAudioManager.getMasterStreamType() && muted) {
4658c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent            sc.seekbarView.setEnabled(false);
4668c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent        } else {
4678c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent            sc.seekbarView.setEnabled(true);
4688c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent        }
4692bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    }
4702bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
4712bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private boolean isExpanded() {
4722bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        return mMoreButton.getVisibility() != View.VISIBLE;
4732bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    }
4742bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
4752bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private void expand() {
4762bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        final int count = mSliderGroup.getChildCount();
4772bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        for (int i = 0; i < count; i++) {
4782bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            mSliderGroup.getChildAt(i).setVisibility(View.VISIBLE);
4792bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        }
4802bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        mMoreButton.setVisibility(View.INVISIBLE);
4812bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        mDivider.setVisibility(View.INVISIBLE);
4822bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    }
4832bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
4842bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private void collapse() {
4852bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        mMoreButton.setVisibility(View.VISIBLE);
4862bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        mDivider.setVisibility(View.VISIBLE);
4872bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        final int count = mSliderGroup.getChildCount();
4882bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        for (int i = 1; i < count; i++) {
4892bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            mSliderGroup.getChildAt(i).setVisibility(View.GONE);
4902bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        }
4912bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    }
4922bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
4932bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private void updateStates() {
4942bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        final int count = mSliderGroup.getChildCount();
4952bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        for (int i = 0; i < count; i++) {
4962bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            StreamControl sc = (StreamControl) mSliderGroup.getChildAt(i).getTag();
4972bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            updateSlider(sc);
4982bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        }
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void postVolumeChanged(int streamType, int flags) {
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (hasMessages(MSG_VOLUME_CHANGED)) return;
503a654986978c870ed33af2ad696cd6e61d9fed489Amith Yamasani        synchronized (this) {
504a654986978c870ed33af2ad696cd6e61d9fed489Amith Yamasani            if (mStreamControls == null) {
505a654986978c870ed33af2ad696cd6e61d9fed489Amith Yamasani                createSliders();
506a654986978c870ed33af2ad696cd6e61d9fed489Amith Yamasani            }
5072bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        }
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        removeMessages(MSG_FREE_RESOURCES);
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        obtainMessage(MSG_VOLUME_CHANGED, streamType, flags).sendToTarget();
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public void postRemoteVolumeChanged(int streamType, int flags) {
5133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (hasMessages(MSG_REMOTE_VOLUME_CHANGED)) return;
5143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (this) {
5153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            if (mStreamControls == null) {
5163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                createSliders();
5173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
5183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
5193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        removeMessages(MSG_FREE_RESOURCES);
5203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        obtainMessage(MSG_REMOTE_VOLUME_CHANGED, streamType, flags).sendToTarget();
5213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
5223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
5233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public void postRemoteSliderVisibility(boolean visible) {
5243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        obtainMessage(MSG_SLIDER_VISIBILITY_CHANGED,
5253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                AudioService.STREAM_REMOTE_MUSIC, visible ? 1 : 0).sendToTarget();
5263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
5273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
5283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
5293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Called by AudioService when it has received new remote playback information that
5303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * would affect the VolumePanel display (mainly volumes). The difference with
5313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * {@link #postRemoteVolumeChanged(int, int)} is that the handling of the posted message
5323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * (MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN) will only update the volume slider if it is being
5333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * displayed.
5343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * This special code path is due to the fact that remote volume updates arrive to AudioService
5353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * asynchronously. So after AudioService has sent the volume update (which should be treated
5363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * as a request to update the volume), the application will likely set a new volume. If the UI
5373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * is still up, we need to refresh the display to show this new value.
5383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
5393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public void postHasNewRemotePlaybackInfo() {
5403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (hasMessages(MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN)) return;
5413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        // don't create or prevent resources to be freed, if they disappear, this update came too
5423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        //   late and shouldn't warrant the panel to be displayed longer
5433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        obtainMessage(MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN).sendToTarget();
5443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
5453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
5468dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    public void postMasterVolumeChanged(int flags) {
5478dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        postVolumeChanged(STREAM_MASTER, flags);
5488dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    }
5498dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood
550ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    public void postMuteChanged(int streamType, int flags) {
551ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        if (hasMessages(MSG_VOLUME_CHANGED)) return;
552a654986978c870ed33af2ad696cd6e61d9fed489Amith Yamasani        synchronized (this) {
553a654986978c870ed33af2ad696cd6e61d9fed489Amith Yamasani            if (mStreamControls == null) {
554a654986978c870ed33af2ad696cd6e61d9fed489Amith Yamasani                createSliders();
555a654986978c870ed33af2ad696cd6e61d9fed489Amith Yamasani            }
556ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        }
557ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        removeMessages(MSG_FREE_RESOURCES);
558ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        obtainMessage(MSG_MUTE_CHANGED, streamType, flags).sendToTarget();
559ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
560ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
561ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    public void postMasterMuteChanged(int flags) {
562ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        postMuteChanged(STREAM_MASTER, flags);
563ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
564ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
565c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    public void postDisplaySafeVolumeWarning() {
5660516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent        if (hasMessages(MSG_DISPLAY_SAFE_VOLUME_WARNING)) return;
567c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        obtainMessage(MSG_DISPLAY_SAFE_VOLUME_WARNING, 0, 0).sendToTarget();
568c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
569c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Override this if you have other work to do when the volume changes (for
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * example, vibrating, playing a sound, etc.). Make sure to call through to
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the superclass implementation.
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onVolumeChanged(int streamType, int flags) {
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (LOGD) Log.d(TAG, "onVolumeChanged(streamType: " + streamType + ", flags: " + flags + ")");
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
580a654986978c870ed33af2ad696cd6e61d9fed489Amith Yamasani            synchronized (this) {
581a654986978c870ed33af2ad696cd6e61d9fed489Amith Yamasani                if (mActiveStreamType != streamType) {
582a654986978c870ed33af2ad696cd6e61d9fed489Amith Yamasani                    reorderSliders(streamType);
583a654986978c870ed33af2ad696cd6e61d9fed489Amith Yamasani                }
584a654986978c870ed33af2ad696cd6e61d9fed489Amith Yamasani                onShowVolumeChanged(streamType, flags);
585e3361b8d0889de6489eb61c6d9ca05885cf4bf31Amith Yamasani            }
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
58869f593ccb7414ee98991b1da1a4bfbd9951e3570Marco Nelissen        if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && ! mRingIsSilent) {
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            removeMessages(MSG_PLAY_SOUND);
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sendMessageDelayed(obtainMessage(MSG_PLAY_SOUND, streamType, flags), PLAY_SOUND_DELAY);
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((flags & AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE) != 0) {
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            removeMessages(MSG_PLAY_SOUND);
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            removeMessages(MSG_VIBRATE);
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            onStopSounds();
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        removeMessages(MSG_FREE_RESOURCES);
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sendMessageDelayed(obtainMessage(MSG_FREE_RESOURCES), FREE_DELAY);
6012bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
6022bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        resetTimeout();
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
605ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    protected void onMuteChanged(int streamType, int flags) {
606ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
607ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        if (LOGD) Log.d(TAG, "onMuteChanged(streamType: " + streamType + ", flags: " + flags + ")");
608ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
609ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        StreamControl sc = mStreamControls.get(streamType);
610ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        if (sc != null) {
611ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood            sc.icon.setImageResource(isMuted(sc.streamType) ? sc.iconMuteRes : sc.iconRes);
612ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        }
613ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
614ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        onVolumeChanged(streamType, flags);
615ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
616ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onShowVolumeChanged(int streamType, int flags) {
6188c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent        int index = getStreamVolume(streamType);
619d72d51c77a43d75c098afb55c3939210739510f9Eric Laurent
62069f593ccb7414ee98991b1da1a4bfbd9951e3570Marco Nelissen        mRingIsSilent = false;
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (LOGD) {
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.d(TAG, "onShowVolumeChanged(streamType: " + streamType
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + ", flags: " + flags + "), index: " + index);
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // get max volume for progress bar
6282bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
6298dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood        int max = getStreamMaxVolume(streamType);
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (streamType) {
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.STREAM_RING: {
6342bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani//                setRingerIcon();
63569f593ccb7414ee98991b1da1a4bfbd9951e3570Marco Nelissen                Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri(
63669f593ccb7414ee98991b1da1a4bfbd9951e3570Marco Nelissen                        mContext, RingtoneManager.TYPE_RINGTONE);
63769f593ccb7414ee98991b1da1a4bfbd9951e3570Marco Nelissen                if (ringuri == null) {
63869f593ccb7414ee98991b1da1a4bfbd9951e3570Marco Nelissen                    mRingIsSilent = true;
63969f593ccb7414ee98991b1da1a4bfbd9951e3570Marco Nelissen                }
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.STREAM_MUSIC: {
6442bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                // Special case for when Bluetooth is active for music
6458b4b97a14ad9b5b982d8fe92755efabec8ad0076Glenn Kasten                if ((mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC) &
6468b4b97a14ad9b5b982d8fe92755efabec8ad0076Glenn Kasten                        (AudioManager.DEVICE_OUT_BLUETOOTH_A2DP |
6478b4b97a14ad9b5b982d8fe92755efabec8ad0076Glenn Kasten                        AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
6488b4b97a14ad9b5b982d8fe92755efabec8ad0076Glenn Kasten                        AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) != 0) {
6492bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                    setMusicIcon(R.drawable.ic_audio_bt, R.drawable.ic_audio_bt_mute);
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
6512bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                    setMusicIcon(R.drawable.ic_audio_vol, R.drawable.ic_audio_vol_mute);
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.STREAM_VOICE_CALL: {
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                /*
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * For in-call voice call volume, there is no inaudible volume.
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * Rescale the UI control so the progress bar doesn't go all
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * the way to zero and don't show the mute icon.
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 */
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                index++;
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                max++;
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.STREAM_ALARM: {
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.STREAM_NOTIFICATION: {
67269f593ccb7414ee98991b1da1a4bfbd9951e3570Marco Nelissen                Uri ringuri = RingtoneManager.getActualDefaultRingtoneUri(
67369f593ccb7414ee98991b1da1a4bfbd9951e3570Marco Nelissen                        mContext, RingtoneManager.TYPE_NOTIFICATION);
67469f593ccb7414ee98991b1da1a4bfbd9951e3570Marco Nelissen                if (ringuri == null) {
67569f593ccb7414ee98991b1da1a4bfbd9951e3570Marco Nelissen                    mRingIsSilent = true;
67669f593ccb7414ee98991b1da1a4bfbd9951e3570Marco Nelissen                }
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.STREAM_BLUETOOTH_SCO: {
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                /*
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * For in-call voice call volume, there is no inaudible volume.
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * Rescale the UI control so the progress bar doesn't go all
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * the way to zero and don't show the mute icon.
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 */
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                index++;
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                max++;
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
6913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            case AudioService.STREAM_REMOTE_MUSIC: {
6923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (LOGD) { Log.d(TAG, "showing remote volume "+index+" over "+ max); }
6933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                break;
6943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6972bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        StreamControl sc = mStreamControls.get(streamType);
6982bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        if (sc != null) {
699d47a3aee7ad7d8ef66ee279ab64b64a0f7918e90Amith Yamasani            if (sc.seekbarView.getMax() != max) {
700d47a3aee7ad7d8ef66ee279ab64b64a0f7918e90Amith Yamasani                sc.seekbarView.setMax(max);
701d47a3aee7ad7d8ef66ee279ab64b64a0f7918e90Amith Yamasani            }
7024bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent
7032bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            sc.seekbarView.setProgress(index);
7044bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            if (((flags & AudioManager.FLAG_FIXED_VOLUME) != 0) ||
7054bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent                    (streamType != mAudioManager.getMasterStreamType() &&
7064bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent                     streamType != AudioService.STREAM_REMOTE_MUSIC &&
7074bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent                     isMuted(streamType))) {
7088c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent                sc.seekbarView.setEnabled(false);
7098c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent            } else {
7108c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent                sc.seekbarView.setEnabled(true);
7118c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent            }
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7142bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        if (!mDialog.isShowing()) {
7153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            int stream = (streamType == AudioService.STREAM_REMOTE_MUSIC) ? -1 : streamType;
7163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            // when the stream is for remote playback, use -1 to reset the stream type evaluation
7173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mAudioManager.forceVolumeControlStream(stream);
7182bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            mDialog.setContentView(mView);
7192bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            // Showing dialog - use collapsed state
72042722bfa136f5616872a2c4e199813e804621c81Amith Yamasani            if (mShowCombinedVolumes) {
72142722bfa136f5616872a2c4e199813e804621c81Amith Yamasani                collapse();
72242722bfa136f5616872a2c4e199813e804621c81Amith Yamasani            }
7232bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            mDialog.show();
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Do a little vibrate if applicable (only when going into vibrate mode)
7273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if ((streamType != AudioService.STREAM_REMOTE_MUSIC) &&
7283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                ((flags & AudioManager.FLAG_VIBRATE) != 0) &&
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAudioService.isStreamAffectedByRingerMode(streamType) &&
7308c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent                mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) {
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sendMessageDelayed(obtainMessage(MSG_VIBRATE), VIBRATE_DELAY);
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onPlaySound(int streamType, int flags) {
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (hasMessages(MSG_STOP_SOUNDS)) {
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            removeMessages(MSG_STOP_SOUNDS);
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Force stop right now
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            onStopSounds();
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (this) {
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ToneGenerator toneGen = getOrCreateToneGenerator(streamType);
745733a42b24b91ce2881e2e4457a1ee06f12bb127aEric Laurent            if (toneGen != null) {
746733a42b24b91ce2881e2e4457a1ee06f12bb127aEric Laurent                toneGen.startTone(ToneGenerator.TONE_PROP_BEEP);
747733a42b24b91ce2881e2e4457a1ee06f12bb127aEric Laurent                sendMessageDelayed(obtainMessage(MSG_STOP_SOUNDS), BEEP_DURATION);
748733a42b24b91ce2881e2e4457a1ee06f12bb127aEric Laurent            }
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onStopSounds() {
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (this) {
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int numStreamTypes = AudioSystem.getNumStreamTypes();
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = numStreamTypes - 1; i >= 0; i--) {
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ToneGenerator toneGen = mToneGenerators[i];
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (toneGen != null) {
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    toneGen.stopTone();
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onVibrate() {
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Make sure we ended up in vibrate ringer mode
7688c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent        if (mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_VIBRATE) {
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVibrator.vibrate(VIBRATE_DURATION);
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    protected void onRemoteVolumeChanged(int streamType, int flags) {
7763114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        // streamType is the real stream type being affected, but for the UI sliders, we
7773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        // refer to AudioService.STREAM_REMOTE_MUSIC. We still play the beeps on the real
7783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        // stream type.
7793114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (LOGD) Log.d(TAG, "onRemoteVolumeChanged(stream:"+streamType+", flags: " + flags + ")");
7803114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
7813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (((flags & AudioManager.FLAG_SHOW_UI) != 0) || mDialog.isShowing()) {
7823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            synchronized (this) {
7833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (mActiveStreamType != AudioService.STREAM_REMOTE_MUSIC) {
7843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    reorderSliders(AudioService.STREAM_REMOTE_MUSIC);
7853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
7863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                onShowVolumeChanged(AudioService.STREAM_REMOTE_MUSIC, flags);
7873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
7883114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        } else {
7893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            if (LOGD) Log.d(TAG, "not calling onShowVolumeChanged(), no FLAG_SHOW_UI or no UI");
7903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
7913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
7923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 && ! mRingIsSilent) {
7933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            removeMessages(MSG_PLAY_SOUND);
7943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            sendMessageDelayed(obtainMessage(MSG_PLAY_SOUND, streamType, flags), PLAY_SOUND_DELAY);
7953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
7963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
7973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if ((flags & AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE) != 0) {
7983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            removeMessages(MSG_PLAY_SOUND);
7993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            removeMessages(MSG_VIBRATE);
8003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            onStopSounds();
8013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
8023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
8033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        removeMessages(MSG_FREE_RESOURCES);
8043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        sendMessageDelayed(obtainMessage(MSG_FREE_RESOURCES), FREE_DELAY);
8053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
8063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        resetTimeout();
8073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
8083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
8093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    protected void onRemoteVolumeUpdateIfShown() {
8103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (LOGD) Log.d(TAG, "onRemoteVolumeUpdateIfShown()");
8113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (mDialog.isShowing()
8123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                && (mActiveStreamType == AudioService.STREAM_REMOTE_MUSIC)
8133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                && (mStreamControls != null)) {
8143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            onShowVolumeChanged(AudioService.STREAM_REMOTE_MUSIC, 0);
8153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
8163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
8173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
8183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
8193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
8203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Handler for MSG_SLIDER_VISIBILITY_CHANGED
8213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Hide or show a slider
8223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @param streamType can be a valid stream type value, or VolumePanel.STREAM_MASTER,
8233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *                   or AudioService.STREAM_REMOTE_MUSIC
8243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @param visible
8253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
8263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    synchronized protected void onSliderVisibilityChanged(int streamType, int visible) {
8273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (LOGD) Log.d(TAG, "onSliderVisibilityChanged(stream="+streamType+", visi="+visible+")");
8283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        boolean isVisible = (visible == 1);
8293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        for (int i = STREAMS.length - 1 ; i >= 0 ; i--) {
8303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            StreamResources streamRes = STREAMS[i];
8313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            if (streamRes.streamType == streamType) {
8323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                streamRes.show = isVisible;
8333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (!isVisible && (mActiveStreamType == streamType)) {
8343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    mActiveStreamType = -1;
8353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
8363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                break;
8373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
8383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
8393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
8403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
841c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    protected void onDisplaySafeVolumeWarning() {
8420516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent        synchronized (sConfirmSafeVolumeLock) {
8430516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent            if (sConfirmSafeVolumeDialog != null) {
8440516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent                return;
8450516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent            }
8460516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent            sConfirmSafeVolumeDialog = new AlertDialog.Builder(mContext)
8470516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent                    .setMessage(com.android.internal.R.string.safe_media_volume_warning)
8480516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent                    .setPositiveButton(com.android.internal.R.string.yes,
8490516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent                                        new DialogInterface.OnClickListener() {
8500516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent                        public void onClick(DialogInterface dialog, int which) {
8510516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent                            mAudioService.disableSafeMediaVolume();
8520516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent                        }
8530516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent                    })
8540516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent                    .setNegativeButton(com.android.internal.R.string.no, null)
8550516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent                    .setIconAttribute(android.R.attr.alertDialogIcon)
8560516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent                    .create();
8570516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent            final WarningDialogReceiver warning = new WarningDialogReceiver(mContext,
8580516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent                    sConfirmSafeVolumeDialog);
8590516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent
8600516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent            sConfirmSafeVolumeDialog.setOnDismissListener(warning);
8610516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent            sConfirmSafeVolumeDialog.getWindow().setType(
8620516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent                                                    WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
8630516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent            sConfirmSafeVolumeDialog.show();
8640516a9ecb0d4d76acd2f1c4c2521f44c696789a8Eric Laurent        }
865c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
866c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Lock on this VolumePanel instance as long as you use the returned ToneGenerator.
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ToneGenerator getOrCreateToneGenerator(int streamType) {
871c4b78d206ffcdccac01e3436a4a3462bef9672edChristopher Tate        if (streamType == STREAM_MASTER) {
872c4b78d206ffcdccac01e3436a4a3462bef9672edChristopher Tate            // For devices that use the master volume setting only but still want to
873c4b78d206ffcdccac01e3436a4a3462bef9672edChristopher Tate            // play a volume-changed tone, direct the master volume pseudostream to
874c4b78d206ffcdccac01e3436a4a3462bef9672edChristopher Tate            // the system stream's tone generator.
875c4b78d206ffcdccac01e3436a4a3462bef9672edChristopher Tate            if (mPlayMasterStreamTones) {
876c4b78d206ffcdccac01e3436a4a3462bef9672edChristopher Tate                streamType = AudioManager.STREAM_SYSTEM;
877c4b78d206ffcdccac01e3436a4a3462bef9672edChristopher Tate            } else {
878c4b78d206ffcdccac01e3436a4a3462bef9672edChristopher Tate                return null;
879c4b78d206ffcdccac01e3436a4a3462bef9672edChristopher Tate            }
880c4b78d206ffcdccac01e3436a4a3462bef9672edChristopher Tate        }
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (this) {
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mToneGenerators[streamType] == null) {
883733a42b24b91ce2881e2e4457a1ee06f12bb127aEric Laurent                try {
884733a42b24b91ce2881e2e4457a1ee06f12bb127aEric Laurent                    mToneGenerators[streamType] = new ToneGenerator(streamType, MAX_VOLUME);
885733a42b24b91ce2881e2e4457a1ee06f12bb127aEric Laurent                } catch (RuntimeException e) {
886733a42b24b91ce2881e2e4457a1ee06f12bb127aEric Laurent                    if (LOGD) {
887733a42b24b91ce2881e2e4457a1ee06f12bb127aEric Laurent                        Log.d(TAG, "ToneGenerator constructor failed with "
888733a42b24b91ce2881e2e4457a1ee06f12bb127aEric Laurent                                + "RuntimeException: " + e);
889733a42b24b91ce2881e2e4457a1ee06f12bb127aEric Laurent                    }
890733a42b24b91ce2881e2e4457a1ee06f12bb127aEric Laurent                }
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
892733a42b24b91ce2881e2e4457a1ee06f12bb127aEric Laurent            return mToneGenerators[streamType];
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8982bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani     * Switch between icons because Bluetooth music is same as music volume, but with
8992bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani     * different icons.
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9012bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private void setMusicIcon(int resId, int resMuteId) {
9022bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        StreamControl sc = mStreamControls.get(AudioManager.STREAM_MUSIC);
9032bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        if (sc != null) {
9042bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            sc.iconRes = resId;
9052bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            sc.iconMuteRes = resMuteId;
9062bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            sc.icon.setImageResource(isMuted(sc.streamType) ? sc.iconMuteRes : sc.iconRes);
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void onFreeResources() {
9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (this) {
9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = mToneGenerators.length - 1; i >= 0; i--) {
9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mToneGenerators[i] != null) {
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mToneGenerators[i].release();
9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mToneGenerators[i] = null;
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void handleMessage(Message msg) {
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (msg.what) {
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_VOLUME_CHANGED: {
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                onVolumeChanged(msg.arg1, msg.arg2);
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
930ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood            case MSG_MUTE_CHANGED: {
931ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood                onMuteChanged(msg.arg1, msg.arg2);
932ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood                break;
933ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood            }
934ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_FREE_RESOURCES: {
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                onFreeResources();
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_STOP_SOUNDS: {
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                onStopSounds();
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_PLAY_SOUND: {
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                onPlaySound(msg.arg1, msg.arg2);
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case MSG_VIBRATE: {
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                onVibrate();
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9552bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            case MSG_TIMEOUT: {
9562bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                if (mDialog.isShowing()) {
9572bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                    mDialog.dismiss();
9582bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                    mActiveStreamType = -1;
9592bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                }
9602bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                break;
9612bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            }
9622bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            case MSG_RINGER_MODE_CHANGED: {
9632bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                if (mDialog.isShowing()) {
9642bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                    updateStates();
9652bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                }
9662bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani                break;
9672bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            }
9683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
9693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            case MSG_REMOTE_VOLUME_CHANGED: {
9703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                onRemoteVolumeChanged(msg.arg1, msg.arg2);
9713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                break;
9723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
9733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
9743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            case MSG_REMOTE_VOLUME_UPDATE_IF_SHOWN:
9753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                onRemoteVolumeUpdateIfShown();
9763114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                break;
9773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
9783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            case MSG_SLIDER_VISIBILITY_CHANGED:
9793114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                onSliderVisibilityChanged(msg.arg1, msg.arg2);
9803114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                break;
981c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
982c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            case MSG_DISPLAY_SAFE_VOLUME_WARNING:
983c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                onDisplaySafeVolumeWarning();
984c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                break;
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9882bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    private void resetTimeout() {
9892bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        removeMessages(MSG_TIMEOUT);
9902bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        sendMessageDelayed(obtainMessage(MSG_TIMEOUT), TIMEOUT_DELAY);
9912bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    }
9922bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
993baf6dbfa9340f3266e41841ebd51f21effc583eeAmith Yamasani    private void forceTimeout() {
994baf6dbfa9340f3266e41841ebd51f21effc583eeAmith Yamasani        removeMessages(MSG_TIMEOUT);
995baf6dbfa9340f3266e41841ebd51f21effc583eeAmith Yamasani        sendMessage(obtainMessage(MSG_TIMEOUT));
996baf6dbfa9340f3266e41841ebd51f21effc583eeAmith Yamasani    }
997baf6dbfa9340f3266e41841ebd51f21effc583eeAmith Yamasani
9982bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    public void onProgressChanged(SeekBar seekBar, int progress,
9992bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            boolean fromUser) {
10002bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        final Object tag = seekBar.getTag();
10012bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        if (fromUser && tag instanceof StreamControl) {
10022bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            StreamControl sc = (StreamControl) tag;
10038dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood            if (getStreamVolume(sc.streamType) != progress) {
10048dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood                setStreamVolume(sc.streamType, progress, 0);
10052bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            }
10062bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        }
10072bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        resetTimeout();
10082bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    }
10092bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
10102bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    public void onStartTrackingTouch(SeekBar seekBar) {
10112bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    }
10122bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
10132bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    public void onStopTrackingTouch(SeekBar seekBar) {
10143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        final Object tag = seekBar.getTag();
10153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (tag instanceof StreamControl) {
10163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            StreamControl sc = (StreamControl) tag;
10173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            // because remote volume updates are asynchronous, AudioService might have received
10183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            // a new remote volume value since the finger adjusted the slider. So when the
10193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            // progress of the slider isn't being tracked anymore, adjust the slider to the last
10203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            // "published" remote volume value, so the UI reflects the actual volume.
10213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            if (sc.streamType == AudioService.STREAM_REMOTE_MUSIC) {
10223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                seekBar.setProgress(getStreamVolume(AudioService.STREAM_REMOTE_MUSIC));
10233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
10243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
10252bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    }
10262bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani
10272bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    public void onClick(View v) {
10282bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        if (v == mMoreButton) {
10292bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani            expand();
10302bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        }
10312bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani        resetTimeout();
10322bbdd77ab20788e901a410f299edef028b66bb6eAmith Yamasani    }
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1034