19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 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.media;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkeyimport static android.Manifest.permission.REMOTE_AUDIO_PLAYBACK;
20c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasaniimport static android.media.AudioManager.RINGER_MODE_NORMAL;
21c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasaniimport static android.media.AudioManager.RINGER_MODE_SILENT;
22c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasaniimport static android.media.AudioManager.RINGER_MODE_VIBRATE;
23c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani
24c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Triviimport android.app.Activity;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.ActivityManagerNative;
266243edd818b84adfbe712d5d233d6414b33653acAmith Yamasaniimport android.app.KeyguardManager;
27f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Triviimport android.app.PendingIntent;
28f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Triviimport android.app.PendingIntent.CanceledException;
29c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Triviimport android.app.PendingIntent.OnFinished;
3082aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothA2dp;
3182aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothAdapter;
3282aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothClass;
3382aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothDevice;
3482aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothHeadset;
3582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothProfile;
364294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Triviimport android.content.ActivityNotFoundException;
37bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.content.BroadcastReceiver;
38d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Triviimport android.content.ComponentName;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
42a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurentimport android.content.IntentFilter;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager;
44f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Triviimport android.content.res.Configuration;
45b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekhimport android.database.ContentObserver;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.MediaPlayer.OnCompletionListener;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.MediaPlayer.OnErrorListener;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
49f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Triviimport android.os.Bundle;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Environment;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IBinder;
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Looper;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
55c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Triviimport android.os.PowerManager;
56632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.RemoteCallbackList;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.ServiceManager;
5982aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.os.SystemProperties;
60bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurentimport android.os.Vibrator;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings.System;
633c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Triviimport android.speech.RecognizerIntent;
64b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Triviimport android.telephony.PhoneStateListener;
65b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Triviimport android.telephony.TelephonyManager;
66632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.text.TextUtils;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
68d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Triviimport android.view.KeyEvent;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.VolumePanel;
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.telephony.ITelephony;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
73d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Triviimport java.io.FileDescriptor;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
75d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Triviimport java.io.PrintWriter;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
773172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurentimport java.util.concurrent.ConcurrentHashMap;
78c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.HashMap;
79c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Iterator;
805a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganeshimport java.util.List;
81c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Map;
8282aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport java.util.NoSuchElementException;
83c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Set;
84d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Triviimport java.util.Stack;
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The implementation of the volume manager service.
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This implementation focuses on delivering a responsive UI. Most methods are
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * asynchronous to external calls. For example, the task of setting a volume
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will update our internal state, but in a separate thread will set the system
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * volume and later persist to the database. Similarly, setting the ringer mode
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will update the state and broadcast a change and in a separate thread later
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * persist the ringer mode.
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
98c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivipublic class AudioService extends IAudioService.Stub implements OnFinished {
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "AudioService";
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi    /** Debug remote control client/display feature */
1037ff866e8cf43afc64111e98863dab549b57447b4Jean-Michel Trivi    protected static final boolean DEBUG_RC = false;
1043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /** Debug volumes */
1053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    protected static final boolean DEBUG_VOL = false;
10618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** How long to delay before persisting a change in volume/ringer mode. */
10845edba1b8b0377dfe70a4f2b0afb0f04dd8e1ee9RoboErik    private static final int PERSIST_DELAY = 500;
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Context mContext;
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ContentResolver mContentResolver;
112c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato    private boolean mVoiceCapable;
113d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** The UI */
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private VolumePanel mVolumePanel;
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // sendMsg() flags
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** If the msg is already queued, replace it with this one. */
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int SENDMSG_REPLACE = 0;
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** If the msg is already queued, ignore this one and leave the old. */
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int SENDMSG_NOOP = 1;
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** If the msg is already queued, queue this one and leave the old. */
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int SENDMSG_QUEUE = 2;
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // AudioHandler messages
1269bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    private static final int MSG_SET_DEVICE_VOLUME = 0;
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MSG_PERSIST_VOLUME = 1;
1285c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood    private static final int MSG_PERSIST_MASTER_VOLUME = 2;
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MSG_PERSIST_RINGER_MODE = 3;
130bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_MEDIA_SERVER_DIED = 4;
131bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_MEDIA_SERVER_STARTED = 5;
132bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_PLAY_SOUND_EFFECT = 6;
133bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_BTA2DP_DOCK_TIMEOUT = 7;
134bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_LOAD_SOUND_EFFECTS = 8;
135bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_SET_FORCE_USE = 9;
136bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 10;
137bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_BT_HEADSET_CNCT_FAILED = 11;
138bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_RCDISPLAY_CLEAR = 12;
139bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_RCDISPLAY_UPDATE = 13;
140bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_SET_ALL_VOLUMES = 14;
141bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 15;
142632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    private static final int MSG_REPORT_NEW_ROUTES = 16;
1433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private static final int MSG_REEVALUATE_REMOTE = 17;
144f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi    private static final int MSG_RCC_NEW_PLAYBACK_INFO = 18;
145f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi    private static final int MSG_RCC_NEW_VOLUME_OBS = 19;
1463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // start of messages handled under wakelock
1473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
148e12c39bb9cedb8b363658979872694eb55b1386eJean-Michel Trivi    //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
149f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi    private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 20;
150f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi    private static final int MSG_SET_A2DP_CONNECTION_STATE = 21;
1513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // end of messages handled under wakelock
152afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent
153afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent    // flags for MSG_PERSIST_VOLUME indicating if current and/or last audible volume should be
154afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent    // persisted
155afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent    private static final int PERSIST_CURRENT = 0x1;
156afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent    private static final int PERSIST_LAST_AUDIBLE = 0x2;
157afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent
1584c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
159dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // Timeout for connection to bluetooth headset service
160dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
161dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioSystemThread */
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private AudioSystemThread mAudioSystemThread;
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioHandler */
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private AudioHandler mAudioHandler;
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see VolumeStreamState */
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private VolumeStreamState[] mStreamStates;
168b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    private SettingsObserver mSettingsObserver;
169a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mMode;
171ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    // protects mRingerMode
172ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    private final Object mSettingsLock = new Object();
17345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mMediaServerOk;
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private SoundPool mSoundPool;
17730c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final Object mSoundEffectsLock = new Object();
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int NUM_SOUNDPOOL_CHANNELS = 4;
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1804767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    // Internally master volume is a float in the 0.0 - 1.0 range,
1814767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    // but to support integer based AudioManager API we translate it to 0 - 100
1824767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    private static final int MAX_MASTER_VOLUME = 100;
1834767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood
1846c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    // Maximum volume adjust steps allowed in a single batch call.
1856c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
1866c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Sound effect file names  */
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String[] SOUND_EFFECT_FILES = new String[] {
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Effect_Tick.ogg",
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "KeypressStandard.ogg",
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "KeypressSpacebar.ogg",
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "KeypressDelete.ogg",
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "KeypressReturn.ogg"
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * uses soundpool (second column) */
20030c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final int[][] SOUND_EFFECT_FILES_MAP = new int[][] {
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        {0, -1},  // FX_KEY_CLICK
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        {0, -1},  // FX_FOCUS_NAVIGATION_UP
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        {0, -1},  // FX_FOCUS_NAVIGATION_DOWN
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        {0, -1},  // FX_FOCUS_NAVIGATION_LEFT
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        {0, -1},  // FX_FOCUS_NAVIGATION_RIGHT
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        {1, -1},  // FX_KEYPRESS_STANDARD
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        {2, -1},  // FX_KEYPRESS_SPACEBAR
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        {3, -1},  // FX_FOCUS_DELETE
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        {4, -1}   // FX_FOCUS_RETURN
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2125982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles   /** @hide Maximum volume index values for audio streams */
21330c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final int[] MAX_STREAM_VOLUME = new int[] {
2146ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        5,  // STREAM_VOICE_CALL
2156ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_SYSTEM
2166ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_RING
2176ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15, // STREAM_MUSIC
2186ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_ALARM
2196ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_NOTIFICATION
2206ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15, // STREAM_BLUETOOTH_SCO
2216ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_SYSTEM_ENFORCED
2226ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15, // STREAM_DTMF
2236ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15  // STREAM_TTS
2245982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles    };
2256d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
226a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     * of another stream: This avoids multiplying the volume settings for hidden
227a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     * stream types that follow other stream behavior for volume settings
2286d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     * NOTE: do not create loops in aliases!
2296d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     * Some streams alias to different streams according to device category (phone or tablet) or
2306d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     * use case (in call s off call...).See updateStreamVolumeAlias() for more details
2316d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     *  mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and
2326d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     *  STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/
23330c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final int[] STREAM_VOLUME_ALIAS = new int[] {
2346d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
2356d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_SYSTEM
2366d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_RING
2376d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
2386d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
2396d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
2406d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
2416d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
2426d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_DTMF
2436d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC            // STREAM_TTS
244a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    };
2456d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] {
2466d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
2476d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_SYSTEM
2486d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_RING
2496d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
2506d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
2516d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
2526d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
2536d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_SYSTEM_ENFORCED
2546d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_DTMF
2556d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC            // STREAM_TTS
2566d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    };
2576d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private int[] mStreamVolumeAlias;
258a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
259bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    // stream names used by dumpStreamStates()
260bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private final String[] STREAM_NAMES = new String[] {
261bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_VOICE_CALL",
262bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_SYSTEM",
263bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_RING",
264bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_MUSIC",
265bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_ALARM",
266bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_NOTIFICATION",
267bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_BLUETOOTH_SCO",
268bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_SYSTEM_ENFORCED",
269bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_DTMF",
270bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_TTS"
271bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    };
272bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
27330c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onError(int error) {
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (error) {
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioSystem.AUDIO_STATUS_SERVER_DIED:
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mMediaServerOk) {
278afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            null, 1500);
28089e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                    mMediaServerOk = false;
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioSystem.AUDIO_STATUS_OK:
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!mMediaServerOk) {
285afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    sendMsg(mAudioHandler, MSG_MEDIA_SERVER_STARTED, SENDMSG_NOOP, 0, 0,
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            null, 0);
28789e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                    mMediaServerOk = true;
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project       }
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link AudioManager#RINGER_MODE_SILENT}, or
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link AudioManager#RINGER_MODE_VIBRATE}.
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
301ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    // protected by mSettingsLock
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mRingerMode;
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3049bcf401d13d47416043a704430388abd59aef7cdEric Laurent    /** @see System#MODE_RINGER_STREAMS_AFFECTED */
3059bcf401d13d47416043a704430388abd59aef7cdEric Laurent    private int mRingerModeAffectedStreams;
3069bcf401d13d47416043a704430388abd59aef7cdEric Laurent
3075b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    // Streams currently muted by ringer mode
3085b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    private int mRingerModeMutedStreams;
3095b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see System#MUTE_STREAMS_AFFECTED */
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mMuteAffectedStreams;
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
314bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent     * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
315bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent     * mVibrateSetting is just maintained during deprecation period but vibration policy is
316bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent     * now only controlled by mHasVibrator and mRingerMode
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mVibrateSetting;
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
320bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    // Is there a vibrator
321bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private final boolean mHasVibrator;
322bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
323a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    // Broadcast receiver for device connections intent broadcasts
324a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
325a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
326e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi    // Used to alter media button redirection when the phone is ringing.
327e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi    private boolean mIsRinging = false;
328e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi
329c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    // Devices currently connected
33030c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
331c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
332c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    // Forced device usage for communications
333c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    private int mForcedUseForComm;
334c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
3350dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    // True if we have master volume support
3360dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    private final boolean mUseMasterVolume;
3370dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
3389760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood    private final int[] mMasterVolumeRamp;
3399760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood
3409272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    // List of binder death handlers for setMode() client processes.
3419272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    // The last process to have called setMode() is at the top of the list.
34230c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
343eb14a783be073b5fd6e8c8c9bc87d2d1919f2c9eEric Laurent
3443def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    // List of clients having issued a SCO start request
34530c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
3463def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
3473def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    // BluetoothHeadset API to control SCO connection
3483def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    private BluetoothHeadset mBluetoothHeadset;
3493def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
35082aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh    // Bluetooth headset device
35182aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh    private BluetoothDevice mBluetoothHeadsetDevice;
3523def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
35362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // Indicate if SCO audio connection is currently active and if the initiator is
35462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // audio service (internal) or bluetooth headset (external)
35562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private int mScoAudioState;
35662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // SCO audio state is not active
35762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private static final int SCO_STATE_INACTIVE = 0;
358dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // SCO audio activation request waiting for headset service to connect
359dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_ACTIVATE_REQ = 1;
36062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // SCO audio state is active or starting due to a local request to start a virtual call
361dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
362dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // SCO audio deactivation request waiting for headset service to connect
363dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_DEACTIVATE_REQ = 5;
364dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
36562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // SCO audio state is active due to an action in BT handsfree (either voice recognition or
36662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // in call audio)
36762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
368dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // Deactivation request for all SCO connections (initiated by audio mode change)
369dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // waiting for headset service to connect
370dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
371dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
372dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // Current connection state indicated by bluetooth headset
373dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private int mScoConnectionState;
37462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent
375a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // true if boot sequence has been completed
376a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private boolean mBootCompleted;
377a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // listener for SoundPool sample load completion indication
378a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private SoundPoolCallback mSoundPoolCallBack;
379a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // thread for SoundPool listener
380a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private SoundPoolListenerThread mSoundPoolListenerThread;
381a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // message looper for SoundPool listener
382a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private Looper mSoundPoolLooper = null;
383c55b393efd462490cd5e27fc373bceafdd25662eJean-Michel Trivi    // volume applied to sound played with playSoundEffect()
384c55b393efd462490cd5e27fc373bceafdd25662eJean-Michel Trivi    private static int SOUND_EFFECT_VOLUME_DB;
38525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    // getActiveStreamType() will return STREAM_NOTIFICATION during this period after a notification
38625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    // stopped
38725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    private static final int NOTIFICATION_VOLUME_DELAY_MS = 5000;
38825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    // previous volume adjustment direction received by checkForRingerModeChange()
38925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    private int mPrevVolDirection = AudioManager.ADJUST_SAME;
3906243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani    // Keyguard manager proxy
3916243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani    private KeyguardManager mKeyguardManager;
39245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
39345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // is controlled by Vol keys.
39445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private int  mVolumeControlStream = -1;
39545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private final Object mForceControlStreamLock = new Object();
39645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
39745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // server process so in theory it is not necessary to monitor the client death.
39845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // However it is good to be ready for future evolutions.
39945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private ForceControlStreamClient mForceControlStreamClient = null;
400098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    // Used to play ringtones outside system_server
401098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    private volatile IRingtonePlayer mRingtonePlayer;
4029bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
403f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
404f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
4057847211fb4699bf6018e29d214a918ed6657319bEric Laurent    // Request to override default use of A2DP for media.
4067847211fb4699bf6018e29d214a918ed6657319bEric Laurent    private boolean mBluetoothA2dpEnabled;
4077847211fb4699bf6018e29d214a918ed6657319bEric Laurent    private final Object mBluetoothA2dpEnabledLock = new Object();
4087847211fb4699bf6018e29d214a918ed6657319bEric Laurent
409632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    // Monitoring of audio routes.  Protected by mCurAudioRoutes.
410632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
411632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
412632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            = new RemoteCallbackList<IAudioRoutesObserver>();
413632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
4143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
4153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * A fake stream type to match the notion of remote media playback
4163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
4173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int STREAM_REMOTE_MUSIC = -200;
4183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Construction
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @hide */
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public AudioService(Context context) {
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContentResolver = context.getContentResolver();
427c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato        mVoiceCapable = mContext.getResources().getBoolean(
428c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato                com.android.internal.R.bool.config_voice_capable);
4295982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles
430c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
4312d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi        mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
432c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
433bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
434bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
435bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
4365982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles       // Intialized volume
4375982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles        MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt(
4385982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles            "ro.config.vc_call_vol_steps",
4395982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles           MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
4405982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles
441c55b393efd462490cd5e27fc373bceafdd25662eJean-Michel Trivi        SOUND_EFFECT_VOLUME_DB = context.getResources().getInteger(
442c55b393efd462490cd5e27fc373bceafdd25662eJean-Michel Trivi                com.android.internal.R.integer.config_soundEffectVolumeDb);
44325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVolumePanel = new VolumePanel(context, this);
4456d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        mMode = AudioSystem.MODE_NORMAL;
446c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent        mForcedUseForComm = AudioSystem.FORCE_NONE;
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        createAudioSystemThread();
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        readPersistedSettings();
449c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent        mSettingsObserver = new SettingsObserver();
4506d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        updateStreamVolumeAlias(false /*updateVolumes*/);
451a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        createStreamStates();
4529f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mMediaServerOk = true;
4543891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent
4553891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        // Call setRingerModeInt() to apply correct mute
4563891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        // state on streams affected by ringer mode.
4573891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        mRingerModeMutedStreams = 0;
4583891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        setRingerModeInt(getRingerMode(), false);
4593891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        AudioSystem.setErrorCallback(mAudioSystemCallback);
461a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
462a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        // Register for device connection intent broadcasts.
463a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        IntentFilter intentFilter =
464b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
46582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
46682aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
46759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
46859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
46962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent        intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
470950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
471950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
472f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
473f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        // Register a configuration change listener only if requested by system properties
474f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        // to monitor orientation changes (off by default)
475f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        if (SystemProperties.getBoolean("ro.audio.monitorOrientation", false)) {
476f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            Log.v(TAG, "monitoring device orientation");
477f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
478f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            // initialize orientation in AudioSystem
479f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            setOrientationForAudioSystem();
480f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        }
481f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
482a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        context.registerReceiver(mReceiver, intentFilter);
4835982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles
484d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        // Register for package removal intent broadcasts for media button receiver persistence
485d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        IntentFilter pkgFilter = new IntentFilter();
486d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
487d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        pkgFilter.addDataScheme("package");
488d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        context.registerReceiver(mReceiver, pkgFilter);
489d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
490b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi        // Register for phone state monitoring
491b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi        TelephonyManager tmgr = (TelephonyManager)
492b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi                context.getSystemService(Context.TELEPHONY_SERVICE);
493b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi        tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
4948517e46f3d3c2ce11de09aa849a8533ffc1a2026Mike Lockwood
4950dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        mUseMasterVolume = context.getResources().getBoolean(
4960dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood                com.android.internal.R.bool.config_useMasterVolume);
4979063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood        restoreMasterVolume();
4989760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood
4999760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        mMasterVolumeRamp = context.getResources().getIntArray(
5009760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood                com.android.internal.R.array.config_masterVolumeRamp);
5017847211fb4699bf6018e29d214a918ed6657319bEric Laurent
5023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        mMainRemote = new RemotePlaybackState(-1, MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC],
5033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC]);
5043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        mHasRemotePlayback = false;
5053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        mMainRemoteIsActive = false;
5063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        postReevaluateRemote();
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void createAudioSystemThread() {
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAudioSystemThread = new AudioSystemThread();
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAudioSystemThread.start();
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        waitForAudioHandlerCreation();
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Waits for the volume handler to be created by the other thread. */
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void waitForAudioHandlerCreation() {
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized(this) {
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (mAudioHandler == null) {
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Wait for mAudioHandler to be set by the other thread
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    wait();
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (InterruptedException e) {
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.e(TAG, "Interrupted while waiting on volume handler.");
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
529244820185269991186d07068b92985624cede4a5Eric Laurent    private void checkAllAliasStreamVolumes() {
530244820185269991186d07068b92985624cede4a5Eric Laurent        int numStreamTypes = AudioSystem.getNumStreamTypes();
531244820185269991186d07068b92985624cede4a5Eric Laurent        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
532244820185269991186d07068b92985624cede4a5Eric Laurent            if (streamType != mStreamVolumeAlias[streamType]) {
533244820185269991186d07068b92985624cede4a5Eric Laurent                mStreamStates[streamType].
534244820185269991186d07068b92985624cede4a5Eric Laurent                                    setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]],
535244820185269991186d07068b92985624cede4a5Eric Laurent                                                  false /*lastAudible*/);
536244820185269991186d07068b92985624cede4a5Eric Laurent                mStreamStates[streamType].
537244820185269991186d07068b92985624cede4a5Eric Laurent                                    setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]],
538244820185269991186d07068b92985624cede4a5Eric Laurent                                                  true /*lastAudible*/);
539244820185269991186d07068b92985624cede4a5Eric Laurent            }
540244820185269991186d07068b92985624cede4a5Eric Laurent            // apply stream volume
541244820185269991186d07068b92985624cede4a5Eric Laurent            if (mStreamStates[streamType].muteCount() == 0) {
542244820185269991186d07068b92985624cede4a5Eric Laurent                mStreamStates[streamType].applyAllVolumes();
543244820185269991186d07068b92985624cede4a5Eric Laurent            }
544244820185269991186d07068b92985624cede4a5Eric Laurent        }
545244820185269991186d07068b92985624cede4a5Eric Laurent    }
546244820185269991186d07068b92985624cede4a5Eric Laurent
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void createStreamStates() {
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int numStreamTypes = AudioSystem.getNumStreamTypes();
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < numStreamTypes; i++) {
5526d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
555244820185269991186d07068b92985624cede4a5Eric Laurent        checkAllAliasStreamVolumes();
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
558bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private void dumpStreamStates(PrintWriter pw) {
559bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        pw.println("\nStream volumes (device: index)");
560bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        int numStreamTypes = AudioSystem.getNumStreamTypes();
561bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        for (int i = 0; i < numStreamTypes; i++) {
562bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.println("- "+STREAM_NAMES[i]+":");
563bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            mStreamStates[i].dump(pw);
564bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.println("");
565bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
566bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    }
567bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
5686d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
5696d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private void updateStreamVolumeAlias(boolean updateVolumes) {
5706d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        int dtmfStreamAlias;
5716d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (mVoiceCapable) {
5726d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            mStreamVolumeAlias = STREAM_VOLUME_ALIAS;
5736d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            dtmfStreamAlias = AudioSystem.STREAM_RING;
5746d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        } else {
5756d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE;
5766d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
5776d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
5786d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (isInCommunication()) {
5796d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
5806d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
5816d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
5826d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (updateVolumes) {
5836d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
5846d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                                                                 false /*lastAudible*/);
5856d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
5866d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                                                                 true /*lastAudible*/);
5876d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            sendMsg(mAudioHandler,
5886d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    MSG_SET_ALL_VOLUMES,
5896d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    SENDMSG_QUEUE,
5906d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    0,
5916d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    0,
5926d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    mStreamStates[AudioSystem.STREAM_DTMF], 0);
5936d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
5946d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    }
5956d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void readPersistedSettings() {
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ContentResolver cr = mContentResolver;
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
599bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        int ringerModeFromSettings =
600bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                System.getInt(cr, System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
601bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        int ringerMode = ringerModeFromSettings;
60272668b2c040b581b298b069f3b5af5ed7f212d89Eric Laurent        // sanity check in case the settings are restored from a device with incompatible
60372668b2c040b581b298b069f3b5af5ed7f212d89Eric Laurent        // ringer modes
604ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        if (!AudioManager.isValidRingerMode(ringerMode)) {
605ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            ringerMode = AudioManager.RINGER_MODE_NORMAL;
606bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
607bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
608bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            ringerMode = AudioManager.RINGER_MODE_SILENT;
609bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
610bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (ringerMode != ringerModeFromSettings) {
611ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            System.putInt(cr, System.MODE_RINGER, ringerMode);
612ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
613ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        synchronized(mSettingsLock) {
614ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            mRingerMode = ringerMode;
61572668b2c040b581b298b069f3b5af5ed7f212d89Eric Laurent        }
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
617bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
618bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        // are still needed while setVibrateSetting() and getVibrateSetting() are being deprecated.
619bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        mVibrateSetting = getValueForVibrateSetting(0,
620bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                        AudioManager.VIBRATE_TYPE_NOTIFICATION,
621bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                        mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
622bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                                        : AudioManager.VIBRATE_SETTING_OFF);
623bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
624bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                        AudioManager.VIBRATE_TYPE_RINGER,
625bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                        mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
626bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                                        : AudioManager.VIBRATE_SETTING_OFF);
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
628c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent        // make sure settings for ringer mode are consistent with device type: non voice capable
629c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent        // devices (tablets) include media stream in silent mode whereas phones don't.
6309bcf401d13d47416043a704430388abd59aef7cdEric Laurent        mRingerModeAffectedStreams = Settings.System.getInt(cr,
6319bcf401d13d47416043a704430388abd59aef7cdEric Laurent                Settings.System.MODE_RINGER_STREAMS_AFFECTED,
632a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
633c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent                 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)));
634c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent        if (mVoiceCapable) {
635c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent            mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
636c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent        } else {
637402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent            mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
638402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        }
639c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent        Settings.System.putInt(cr,
640c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent                Settings.System.MODE_RINGER_STREAMS_AFFECTED, mRingerModeAffectedStreams);
641c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mMuteAffectedStreams = System.getInt(cr,
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                System.MUTE_STREAMS_AFFECTED,
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM)));
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
64657978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        boolean masterMute = System.getInt(cr, System.VOLUME_MASTER_MUTE, 0) == 1;
64757978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        AudioSystem.setMasterMute(masterMute);
64857978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        broadcastMasterMuteStatus(masterMute);
64957978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Each stream will read its own persisted settings
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Broadcast the sticky intent
653ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        broadcastRingerMode(ringerMode);
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Broadcast vibrate settings
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
658d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
659d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        // Restore the default media button receiver from the system settings
660d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        restoreMediaButtonReceiver();
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
663a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    private int rescaleIndex(int index, int srcStream, int dstStream) {
664a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
665a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    }
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // IPC methods
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#adjustVolume(int, int) */
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void adjustVolume(int direction, int flags) {
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags);
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6763114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /** @see AudioManager#adjustLocalOrRemoteStreamVolume(int, int) with current assumption
6773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *  on streamType: fixed to STREAM_MUSIC */
6783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public void adjustLocalOrRemoteStreamVolume(int streamType, int direction) {
6793114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (DEBUG_VOL) Log.d(TAG, "adjustLocalOrRemoteStreamVolume(dir="+direction+")");
6803114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
6813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, 0);
6823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
6833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            adjustStreamVolume(AudioSystem.STREAM_MUSIC, direction, 0);
6843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
6853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
6863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#adjustVolume(int, int, int) */
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
6893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType);
690402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        int streamType;
69145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        if (mVolumeControlStream != -1) {
69245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            streamType = mVolumeControlStream;
693402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        } else {
694402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent            streamType = getActiveStreamType(suggestedStreamType);
695402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        }
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6976243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani        // Play sounds on STREAM_RING only and if lock screen is not on.
6983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if ((streamType != STREAM_REMOTE_MUSIC) &&
6993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                (flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
7006d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                ((mStreamVolumeAlias[streamType] != AudioSystem.STREAM_RING)
7016243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani                 || (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) {
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flags &= ~AudioManager.FLAG_PLAY_SOUND;
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (streamType == STREAM_REMOTE_MUSIC) {
7063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            // don't play sounds for remote
7073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            flags &= ~AudioManager.FLAG_PLAY_SOUND;
7083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            //if (DEBUG_VOL) Log.i(TAG, "Need to adjust remote volume: calling adjustRemoteVolume()");
7093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, flags);
7103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        } else {
7113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            adjustStreamVolume(streamType, direction, flags);
7123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#adjustStreamVolume(int, int, int) */
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void adjustStreamVolume(int streamType, int direction, int flags) {
7173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction);
7183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidDirection(direction);
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
72296a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent        // use stream type alias here so that streams with same alias have the same behavior,
72396a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent        // including with regard to silent mode control (e.g the use of STREAM_RING below and in
72496a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent        // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
7256d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        int streamTypeAlias = mStreamVolumeAlias[streamType];
726b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
7279bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
7289bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        final int device = getDeviceForStream(streamTypeAlias);
7299bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        // get last audible index if stream is muted, current index otherwise
730244820185269991186d07068b92985624cede4a5Eric Laurent        final int aliasIndex = streamState.getIndex(device,
7319bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                                  (streamState.muteCount() != 0) /* lastAudible */);
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean adjustVolume = true;
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
734244820185269991186d07068b92985624cede4a5Eric Laurent        // convert one UI step (+/-1) into a number of internal units on the stream alias
735244820185269991186d07068b92985624cede4a5Eric Laurent        int step = rescaleIndex(10, streamType, streamTypeAlias);
736244820185269991186d07068b92985624cede4a5Eric Laurent
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // If either the client forces allowing ringer modes for this adjustment,
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // or the stream type is one that is affected by ringer modes
73925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
740bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                (streamTypeAlias == getMasterStreamType())) {
741ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            int ringerMode = getRingerMode();
742c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            // do not vibrate if already in vibrate mode
743ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
744cc11b1b8bb47aa6be23ff5c4caf683ff90074121Eric Laurent                flags &= ~AudioManager.FLAG_VIBRATE;
745cc11b1b8bb47aa6be23ff5c4caf683ff90074121Eric Laurent            }
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Check if the ringer mode changes with this volume adjustment. If
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // it does, it will handle adjusting the volume, so we won't below
748244820185269991186d07068b92985624cede4a5Eric Laurent            adjustVolume = checkForRingerModeChange(aliasIndex, direction, step);
7498c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent            if ((streamTypeAlias == getMasterStreamType()) &&
7508c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent                    (mRingerMode == AudioManager.RINGER_MODE_SILENT)) {
7518c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent                streamState.setLastAudibleIndex(0, device);
7528c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent            }
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7555b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // If stream is muted, adjust last audible index only
7565b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        int index;
757244820185269991186d07068b92985624cede4a5Eric Laurent        final int oldIndex = mStreamStates[streamType].getIndex(device,
758244820185269991186d07068b92985624cede4a5Eric Laurent                (mStreamStates[streamType].muteCount() != 0) /* lastAudible */);
759244820185269991186d07068b92985624cede4a5Eric Laurent
7605b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        if (streamState.muteCount() != 0) {
7615b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent            if (adjustVolume) {
762244820185269991186d07068b92985624cede4a5Eric Laurent                // Post a persist volume msg
763244820185269991186d07068b92985624cede4a5Eric Laurent                // no need to persist volume on all streams sharing the same alias
764244820185269991186d07068b92985624cede4a5Eric Laurent                streamState.adjustLastAudibleIndex(direction * step, device);
765244820185269991186d07068b92985624cede4a5Eric Laurent                sendMsg(mAudioHandler,
766244820185269991186d07068b92985624cede4a5Eric Laurent                        MSG_PERSIST_VOLUME,
767244820185269991186d07068b92985624cede4a5Eric Laurent                        SENDMSG_QUEUE,
768244820185269991186d07068b92985624cede4a5Eric Laurent                        PERSIST_LAST_AUDIBLE,
769244820185269991186d07068b92985624cede4a5Eric Laurent                        device,
770244820185269991186d07068b92985624cede4a5Eric Laurent                        streamState,
771244820185269991186d07068b92985624cede4a5Eric Laurent                        PERSIST_DELAY);
7725b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent            }
773244820185269991186d07068b92985624cede4a5Eric Laurent            index = mStreamStates[streamType].getIndex(device, true  /* lastAudible */);
7745b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        } else {
775244820185269991186d07068b92985624cede4a5Eric Laurent            if (adjustVolume && streamState.adjustIndex(direction * step, device)) {
7765b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                // Post message to set system volume (it in turn will post a message
7775b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                // to persist). Do not change volume if stream is muted.
778afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                sendMsg(mAudioHandler,
7799bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        MSG_SET_DEVICE_VOLUME,
78098ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent                        SENDMSG_QUEUE,
7819bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        device,
782afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        0,
783afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        streamState,
784afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        0);
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
786244820185269991186d07068b92985624cede4a5Eric Laurent            index = mStreamStates[streamType].getIndex(device, false  /* lastAudible */);
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
78825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
78925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        sendVolumeUpdate(streamType, oldIndex, index, flags);
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
792cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood    /** @see AudioManager#adjustMasterVolume(int) */
7936c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    public void adjustMasterVolume(int steps, int flags) {
7946c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        ensureValidSteps(steps);
7959760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
7969760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        int delta = 0;
7976c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        int numSteps = Math.abs(steps);
7986c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
7996c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        for (int i = 0; i < numSteps; ++i) {
8006c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            delta = findVolumeDelta(direction, volume);
8016c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            volume += delta;
802cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood        }
80324b082f87e96c00d5c17d60c735423900be40e70RoboErik
8046c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
8056c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        setMasterVolume(volume, flags);
806cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood    }
807cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setStreamVolume(int, int, int) */
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setStreamVolume(int streamType, int index, int flags) {
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
8116d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        VolumeStreamState streamState = mStreamStates[mStreamVolumeAlias[streamType]];
8129ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent
8139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        final int device = getDeviceForStream(streamType);
8149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        // get last audible index if stream is muted, current index otherwise
8159bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        final int oldIndex = streamState.getIndex(device,
8169bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                                  (streamState.muteCount() != 0) /* lastAudible */);
8179ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent
818244820185269991186d07068b92985624cede4a5Eric Laurent        index = rescaleIndex(index * 10, streamType, mStreamVolumeAlias[streamType]);
819244820185269991186d07068b92985624cede4a5Eric Laurent
820f740664cd808bebfc35ded46da6002bdc97a1a16Eric Laurent        // setting volume on master stream type also controls silent mode
821f740664cd808bebfc35ded46da6002bdc97a1a16Eric Laurent        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
822f740664cd808bebfc35ded46da6002bdc97a1a16Eric Laurent                (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
823ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            int newRingerMode;
824b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent            if (index == 0) {
825bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
826bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                              : AudioManager.RINGER_MODE_SILENT;
8276d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                setStreamVolumeInt(mStreamVolumeAlias[streamType],
8289bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                   index,
8299bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                   device,
8309bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                   false,
8319bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                   true);
832b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent            } else {
833b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                newRingerMode = AudioManager.RINGER_MODE_NORMAL;
834b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent            }
835ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            setRingerMode(newRingerMode);
836b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent        }
837b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent
8386d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false, true);
8399bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        // get last audible index if stream is muted, current index otherwise
840244820185269991186d07068b92985624cede4a5Eric Laurent        index = mStreamStates[streamType].getIndex(device,
841244820185269991186d07068b92985624cede4a5Eric Laurent                                 (mStreamStates[streamType].muteCount() != 0) /* lastAudible */);
8425b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
84325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        sendVolumeUpdate(streamType, oldIndex, index, flags);
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
84645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    /** @see AudioManager#forceVolumeControlStream(int) */
84745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    public void forceVolumeControlStream(int streamType, IBinder cb) {
84845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        synchronized(mForceControlStreamLock) {
84945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            mVolumeControlStream = streamType;
85045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            if (mVolumeControlStream == -1) {
85145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                if (mForceControlStreamClient != null) {
85245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mForceControlStreamClient.release();
85345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mForceControlStreamClient = null;
85445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                }
85545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            } else {
85645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                mForceControlStreamClient = new ForceControlStreamClient(cb);
85745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
85845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
85945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    }
86045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
86145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private class ForceControlStreamClient implements IBinder.DeathRecipient {
86245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        private IBinder mCb; // To be notified of client's death
86345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
86445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        ForceControlStreamClient(IBinder cb) {
86545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            if (cb != null) {
86645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                try {
86745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    cb.linkToDeath(this, 0);
86845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                } catch (RemoteException e) {
86945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    // Client has died!
87045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
87145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    cb = null;
87245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                }
87345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
87445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            mCb = cb;
87545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
87645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
87745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        public void binderDied() {
87845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            synchronized(mForceControlStreamLock) {
87945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                Log.w(TAG, "SCO client died");
88045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                if (mForceControlStreamClient != this) {
88145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    Log.w(TAG, "unregistered control stream client died");
88245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                } else {
88345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mForceControlStreamClient = null;
88445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mVolumeControlStream = -1;
88545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                }
88645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
88745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
88845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
88945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        public void release() {
89045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            if (mCb != null) {
89145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                mCb.unlinkToDeath(this, 0);
89245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                mCb = null;
89345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
89445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
89545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    }
89645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
8976c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    private int findVolumeDelta(int direction, int volume) {
8986c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        int delta = 0;
8996c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        if (direction == AudioManager.ADJUST_RAISE) {
9006c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            if (volume == MAX_MASTER_VOLUME) {
9016c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                return 0;
9026c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
9036c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // This is the default value if we make it to the end
9046c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            delta = mMasterVolumeRamp[1];
9056c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // If we're raising the volume move down the ramp array until we
9066c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // find the volume we're above and use that groups delta.
9076c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
9086c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                if (volume >= mMasterVolumeRamp[i - 1]) {
9096c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    delta = mMasterVolumeRamp[i];
9106c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    break;
9116c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                }
9126c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
9136c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        } else if (direction == AudioManager.ADJUST_LOWER){
9146c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            if (volume == 0) {
9156c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                return 0;
9166c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
9176c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            int length = mMasterVolumeRamp.length;
9186c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // This is the default value if we make it to the end
9196c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            delta = -mMasterVolumeRamp[length - 1];
9206c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // If we're lowering the volume move up the ramp array until we
9216c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // find the volume we're below and use the group below it's delta
9226c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            for (int i = 2; i < length; i += 2) {
9236c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                if (volume <= mMasterVolumeRamp[i]) {
9246c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    delta = -mMasterVolumeRamp[i - 1];
9256c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    break;
9266c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                }
9276c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
9286c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        }
9296c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        return delta;
9306c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    }
9316c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang
93225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    // UI update and Broadcast Intent
93325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
93425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) {
93525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            streamType = AudioSystem.STREAM_NOTIFICATION;
93625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        }
93725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
93825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        mVolumePanel.postVolumeChanged(streamType, flags);
93925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
9409ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent        oldIndex = (oldIndex + 5) / 10;
9419ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent        index = (index + 5) / 10;
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
9449ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent        intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
9459ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent        intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
9469ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent        mContext.sendBroadcast(intent);
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9490dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    // UI update and Broadcast Intent
9500dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
9510dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        mVolumePanel.postMasterVolumeChanged(flags);
9520dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
9530dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
9540dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
9550dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
9560dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        mContext.sendBroadcast(intent);
9570dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    }
9580dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
9590dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    // UI update and Broadcast Intent
9600dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    private void sendMasterMuteUpdate(boolean muted, int flags) {
9610dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        mVolumePanel.postMasterMuteChanged(flags);
96257978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        broadcastMasterMuteStatus(muted);
96357978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh    }
9640dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
96557978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh    private void broadcastMasterMuteStatus(boolean muted) {
9660dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
9670dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
96857978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
96957978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
9700dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        long origCallerIdentityToken = Binder.clearCallingIdentity();
9710dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        mContext.sendStickyBroadcast(intent);
9720dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        Binder.restoreCallingIdentity(origCallerIdentityToken);
9730dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    }
9740dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the stream state's index, and posts a message to set system volume.
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This will not call out to the UI. Assumes a valid stream type.
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param streamType Type of the stream
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param index Desired volume index of the stream
9819bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent     * @param device the device whose volume must be changed
9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param force If true, set the volume even if the desired volume is same
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * as the current volume.
9849bcf401d13d47416043a704430388abd59aef7cdEric Laurent     * @param lastAudible If true, stores new index as last audible one
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9869bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    private void setStreamVolumeInt(int streamType,
9879bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    int index,
9889bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    int device,
9899bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    boolean force,
9909bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    boolean lastAudible) {
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        VolumeStreamState streamState = mStreamStates[streamType];
9925b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
9935b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // If stream is muted, set last audible index only
9945b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        if (streamState.muteCount() != 0) {
995758dd527f64f1e827adfe09f0141ab213733ca22Eric Laurent            // Do not allow last audible index to be 0
996758dd527f64f1e827adfe09f0141ab213733ca22Eric Laurent            if (index != 0) {
9979bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                streamState.setLastAudibleIndex(index, device);
998758dd527f64f1e827adfe09f0141ab213733ca22Eric Laurent                // Post a persist volume msg
999afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                sendMsg(mAudioHandler,
1000afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        MSG_PERSIST_VOLUME,
100198ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent                        SENDMSG_QUEUE,
1002afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        PERSIST_LAST_AUDIBLE,
10039bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        device,
1004afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        streamState,
1005afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        PERSIST_DELAY);
1006758dd527f64f1e827adfe09f0141ab213733ca22Eric Laurent            }
10075b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        } else {
10089bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if (streamState.setIndex(index, device, lastAudible) || force) {
10095b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                // Post message to set system volume (it in turn will post a message
10105b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                // to persist).
1011afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                sendMsg(mAudioHandler,
10129bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        MSG_SET_DEVICE_VOLUME,
101398ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent                        SENDMSG_QUEUE,
10149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        device,
1015afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        0,
1016afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        streamState,
1017afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        0);
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setStreamSolo(int, boolean) */
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setStreamSolo(int streamType, boolean state, IBinder cb) {
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int stream = 0; stream < mStreamStates.length; stream++) {
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!isStreamAffectedByMute(stream) || stream == streamType) continue;
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Bring back last audible volume
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStreamStates[stream].mute(cb, state);
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         }
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setStreamMute(int, boolean) */
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setStreamMute(int streamType, boolean state, IBinder cb) {
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (isStreamAffectedByMute(streamType)) {
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStreamStates[streamType].mute(cb, state);
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
103825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    /** get stream mute state. */
103925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    public boolean isStreamMute(int streamType) {
104025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        return (mStreamStates[streamType].muteCount() != 0);
104125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    }
104225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
1043ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    /** @see AudioManager#setMasterMute(boolean, IBinder) */
10440273af55cf68d54d26d154b44d105d40fed79701Justin Koh    public void setMasterMute(boolean state, int flags, IBinder cb) {
10451ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons        if (state != AudioSystem.getMasterMute()) {
10461ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons            AudioSystem.setMasterMute(state);
104757978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh            // Post a persist master volume msg
104875cf9e19a575c28c200c02c0ab6f83bb79f5c50dJustin Koh            sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
104957978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                    : 0, 0, null, PERSIST_DELAY);
10500273af55cf68d54d26d154b44d105d40fed79701Justin Koh            sendMasterMuteUpdate(state, flags);
10511ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons        }
1052ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1053ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
1054ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    /** get master mute state. */
1055ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    public boolean isMasterMute() {
10563194ea94348bce8e7ee9f803698d877f46f8279aMike Lockwood        return AudioSystem.getMasterMute();
1057ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1058ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getStreamVolume(int) */
10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStreamVolume(int streamType) {
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
10629bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = getDeviceForStream(streamType);
10639bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        return (mStreamStates[streamType].getIndex(device, false  /* lastAudible */) + 5) / 10;
10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10664767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    public int getMasterVolume() {
1067ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        if (isMasterMute()) return 0;
1068ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        return getLastAudibleMasterVolume();
10698dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    }
10708dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood
10714767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    public void setMasterVolume(int volume, int flags) {
10729760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        if (volume < 0) {
10739760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood            volume = 0;
10749760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        } else if (volume > MAX_MASTER_VOLUME) {
10759760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood            volume = MAX_MASTER_VOLUME;
10769760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        }
10775c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
10785c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood    }
10795c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
10805c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood    private void doSetMasterVolume(float volume, int flags) {
10815c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        // don't allow changing master volume when muted
10825c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        if (!AudioSystem.getMasterMute()) {
10835c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            int oldVolume = getMasterVolume();
10845c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            AudioSystem.setMasterVolume(volume);
10855c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
10865c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            int newVolume = getMasterVolume();
10875c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            if (newVolume != oldVolume) {
10885c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                // Post a persist master volume msg
10895c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
10905c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                        Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
10915c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            }
10923caba517253d1703fc29b50740c4567b932279fbJustin Koh            // Send the volume update regardless whether there was a change.
10933caba517253d1703fc29b50740c4567b932279fbJustin Koh            sendMasterVolumeUpdate(flags, oldVolume, newVolume);
10945c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        }
10958dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    }
10968dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood
10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getStreamMaxVolume(int) */
10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStreamMaxVolume(int streamType) {
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
1100a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11034767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    public int getMasterMaxVolume() {
11044767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood        return MAX_MASTER_VOLUME;
11054767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    }
110625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
110725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    /** Get last audible volume before stream was muted. */
110825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    public int getLastAudibleStreamVolume(int streamType) {
110925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        ensureValidStreamType(streamType);
11109bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = getDeviceForStream(streamType);
11119bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        return (mStreamStates[streamType].getIndex(device, true  /* lastAudible */) + 5) / 10;
111225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    }
111325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
1114ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    /** Get last audible master volume before it was muted. */
1115ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    public int getLastAudibleMasterVolume() {
1116ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1117ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1118ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
11196d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    /** @see AudioManager#getMasterStreamType(int) */
11206d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    public int getMasterStreamType() {
11216d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (mVoiceCapable) {
11226d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            return AudioSystem.STREAM_RING;
11236d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        } else {
11246d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            return AudioSystem.STREAM_MUSIC;
11256d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
11266d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    }
11276d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getRingerMode() */
11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getRingerMode() {
1130ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        synchronized(mSettingsLock) {
1131ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            return mRingerMode;
1132ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
1133ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    }
1134ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten
1135ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    private void ensureValidRingerMode(int ringerMode) {
1136ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        if (!AudioManager.isValidRingerMode(ringerMode)) {
1137ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1138ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setRingerMode(int) */
11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setRingerMode(int ringerMode) {
1143244820185269991186d07068b92985624cede4a5Eric Laurent        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1144244820185269991186d07068b92985624cede4a5Eric Laurent            ringerMode = AudioManager.RINGER_MODE_SILENT;
1145244820185269991186d07068b92985624cede4a5Eric Laurent        }
1146ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        if (ringerMode != getRingerMode()) {
1147ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            setRingerModeInt(ringerMode, true);
1148ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            // Send sticky broadcast
1149ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            broadcastRingerMode(ringerMode);
1150b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
1151b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    }
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11534050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    private void setRingerModeInt(int ringerMode, boolean persist) {
1154ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        synchronized(mSettingsLock) {
1155ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            mRingerMode = ringerMode;
1156ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
1157b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh
11585b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // Mute stream if not previously muted by ringer mode and ringer mode
11595b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
11605b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // Unmute stream if previously muted by ringer mode and ringer mode
11615b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
1162b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        int numStreamTypes = AudioSystem.getNumStreamTypes();
11635b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
11645b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent            if (isStreamMutedByRingerMode(streamType)) {
11655b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                if (!isStreamAffectedByRingerMode(streamType) ||
1166ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    ringerMode == AudioManager.RINGER_MODE_NORMAL) {
1167b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    // ring and notifications volume should never be 0 when not silenced
1168b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    // on voice capable devices
1169b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    if (mVoiceCapable &&
11706d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                            mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
11713172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        synchronized (mStreamStates[streamType]) {
11723172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            Set set = mStreamStates[streamType].mLastAudibleIndex.entrySet();
11733172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            Iterator i = set.iterator();
11743172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            while (i.hasNext()) {
11753172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                Map.Entry entry = (Map.Entry)i.next();
11763172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                if ((Integer)entry.getValue() == 0) {
11773172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                    entry.setValue(10);
11783172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                }
11799bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                            }
11809bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        }
1181b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    }
11825b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                    mStreamStates[streamType].mute(null, false);
11835b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                    mRingerModeMutedStreams &= ~(1 << streamType);
11849bcf401d13d47416043a704430388abd59aef7cdEric Laurent                }
11855b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent            } else {
11865b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                if (isStreamAffectedByRingerMode(streamType) &&
1187ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    ringerMode != AudioManager.RINGER_MODE_NORMAL) {
11885b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                   mStreamStates[streamType].mute(null, true);
11895b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                   mRingerModeMutedStreams |= (1 << streamType);
11905b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent               }
1191b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            }
11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1193a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
1194b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        // Post a persist ringer mode msg
11954050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        if (persist) {
1196afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
11974050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent                    SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
11984050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        }
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12019063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood    private void restoreMasterVolume() {
12029063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood        if (mUseMasterVolume) {
12039063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood            float volume = Settings.System.getFloat(mContentResolver,
12049063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                    Settings.System.VOLUME_MASTER, -1.0f);
12059063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood            if (volume >= 0.0f) {
12069063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                AudioSystem.setMasterVolume(volume);
12079063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood            }
12089063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood        }
12099063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood    }
12109063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood
12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#shouldVibrate(int) */
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean shouldVibrate(int vibrateType) {
1213bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return false;
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (getVibrateSetting(vibrateType)) {
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_ON:
1218ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                return getRingerMode() != AudioManager.RINGER_MODE_SILENT;
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
1221ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE;
12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_OFF:
1224bcac496076ef6f439147e7a2be71e8a2b76ddedeDaniel Sandler                // return false, even for incoming calls
1225bcac496076ef6f439147e7a2be71e8a2b76ddedeDaniel Sandler                return false;
12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getVibrateSetting(int) */
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getVibrateSetting(int vibrateType) {
1234bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mVibrateSetting >> (vibrateType * 2)) & 3;
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setVibrateSetting(int, int) */
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setVibrateSetting(int vibrateType, int vibrateSetting) {
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1241bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return;
1242bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Broadcast change
12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        broadcastVibrateSetting(vibrateType);
12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #setVibrateSetting(int, int)
12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static int getValueForVibrateSetting(int existingValue, int vibrateType,
12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int vibrateSetting) {
12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // First clear the existing setting. Each vibrate type has two bits in
12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // the value. Note '3' is '11' in binary.
12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        existingValue &= ~(3 << (vibrateType * 2));
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Set into the old value
12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return existingValue;
12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12669272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    private class SetModeDeathHandler implements IBinder.DeathRecipient {
12679272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        private IBinder mCb; // To be notified of client's death
1268f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        private int mPid;
12699272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
12709272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
12719f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        SetModeDeathHandler(IBinder cb, int pid) {
12729272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            mCb = cb;
12739f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            mPid = pid;
12749272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
12759272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
12769272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public void binderDied() {
1277d7454be47f4111c0478a502353e11dea401378bdEric Laurent            int newModeOwnerPid = 0;
12789272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            synchronized(mSetModeDeathHandlers) {
12799272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                Log.w(TAG, "setMode() client died");
12809272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                int index = mSetModeDeathHandlers.indexOf(this);
12819272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                if (index < 0) {
12829272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                    Log.w(TAG, "unregistered setMode() client died");
12839272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                } else {
1284d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
12859272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                }
12869272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            }
12879f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
12889f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            // SCO connections not started by the application changing the mode
1289d7454be47f4111c0478a502353e11dea401378bdEric Laurent            if (newModeOwnerPid != 0) {
1290d7454be47f4111c0478a502353e11dea401378bdEric Laurent                 disconnectBluetoothSco(newModeOwnerPid);
12919f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
12929272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
12939272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
1294f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        public int getPid() {
1295f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen            return mPid;
1296f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        }
1297f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen
12989272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public void setMode(int mode) {
12999272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            mMode = mode;
13009272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
13019272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
13029272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public int getMode() {
13039272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            return mMode;
13049272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
13059272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
13069272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public IBinder getBinder() {
13079272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            return mCb;
13089272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
13099272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    }
13109272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setMode(int) */
13129272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    public void setMode(int mode, IBinder cb) {
13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!checkAudioSettingsPermission("setMode()")) {
13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1316a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
13178f677d66d9c3ba34c97e69b2bb9e161f129af0eeJean-Michel Trivi        if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
1318a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            return;
1319a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        }
1320a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
1321d7454be47f4111c0478a502353e11dea401378bdEric Laurent        int newModeOwnerPid = 0;
13229f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        synchronized(mSetModeDeathHandlers) {
1323a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            if (mode == AudioSystem.MODE_CURRENT) {
1324a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                mode = mMode;
1325a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
1326d7454be47f4111c0478a502353e11dea401378bdEric Laurent            newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
13279f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
13289f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
13299f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        // SCO connections not started by the application changing the mode
1330d7454be47f4111c0478a502353e11dea401378bdEric Laurent        if (newModeOwnerPid != 0) {
1331d7454be47f4111c0478a502353e11dea401378bdEric Laurent             disconnectBluetoothSco(newModeOwnerPid);
13329f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
13339f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    }
13342ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi
13359f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    // must be called synchronized on mSetModeDeathHandlers
1336d7454be47f4111c0478a502353e11dea401378bdEric Laurent    // setModeInt() returns a valid PID if the audio mode was successfully set to
13379f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    // any mode other than NORMAL.
1338d7454be47f4111c0478a502353e11dea401378bdEric Laurent    int setModeInt(int mode, IBinder cb, int pid) {
1339d7454be47f4111c0478a502353e11dea401378bdEric Laurent        int newModeOwnerPid = 0;
13409f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        if (cb == null) {
13419f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            Log.e(TAG, "setModeInt() called with null binder");
1342d7454be47f4111c0478a502353e11dea401378bdEric Laurent            return newModeOwnerPid;
13439f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
13442ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi
13459f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        SetModeDeathHandler hdlr = null;
13469f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        Iterator iter = mSetModeDeathHandlers.iterator();
13479f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        while (iter.hasNext()) {
13489f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
13499f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (h.getPid() == pid) {
13509f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr = h;
13519f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Remove from client list so that it is re-inserted at top of list
13529f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                iter.remove();
13539f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr.getBinder().unlinkToDeath(hdlr, 0);
13549f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                break;
13559f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
13569f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
13579f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        int status = AudioSystem.AUDIO_STATUS_OK;
13589f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        do {
13599f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode == AudioSystem.MODE_NORMAL) {
13609f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // get new mode from client at top the list if any
13619f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (!mSetModeDeathHandlers.isEmpty()) {
13629f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    hdlr = mSetModeDeathHandlers.get(0);
13639f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    cb = hdlr.getBinder();
13649f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mode = hdlr.getMode();
13659f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
13669f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            } else {
13679f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (hdlr == null) {
13689f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    hdlr = new SetModeDeathHandler(cb, pid);
13699f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
13709f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Register for client death notification
13719f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                try {
13729f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    cb.linkToDeath(hdlr, 0);
13739f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                } catch (RemoteException e) {
13749f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    // Client has died!
13759f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    Log.w(TAG, "setMode() could not link to "+cb+" binder death");
13769f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
13779272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
13789f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Last client to call setMode() is always at top of client list
13799f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // as required by SetModeDeathHandler.binderDied()
13809f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                mSetModeDeathHandlers.add(0, hdlr);
13819f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr.setMode(mode);
13829f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
13833def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
13849f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode != mMode) {
13859f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                status = AudioSystem.setPhoneState(mode);
13869f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (status == AudioSystem.AUDIO_STATUS_OK) {
13879f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mMode = mode;
13889f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                } else {
13899f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    if (hdlr != null) {
13909f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        mSetModeDeathHandlers.remove(hdlr);
13919f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        cb.unlinkToDeath(hdlr, 0);
13923def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
13939f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    // force reading new top of mSetModeDeathHandlers stack
13949f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mode = AudioSystem.MODE_NORMAL;
1395b9c9d260f21b321527c4622a123af9767630d94dEric Laurent                }
13969f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            } else {
13979f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                status = AudioSystem.AUDIO_STATUS_OK;
13989f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
13999f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
14009f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent
14019f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        if (status == AudioSystem.AUDIO_STATUS_OK) {
14029f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode != AudioSystem.MODE_NORMAL) {
1403d7454be47f4111c0478a502353e11dea401378bdEric Laurent                if (mSetModeDeathHandlers.isEmpty()) {
1404d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
1405d7454be47f4111c0478a502353e11dea401378bdEric Laurent                } else {
1406d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
1407d7454be47f4111c0478a502353e11dea401378bdEric Laurent                }
14089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
14103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            if (streamType == STREAM_REMOTE_MUSIC) {
14113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                // here handle remote media playback the same way as local playback
14123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                streamType = AudioManager.STREAM_MUSIC;
14133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
14149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            int device = getDeviceForStream(streamType);
14156d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device, false);
14166d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, false);
14176d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
14186d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            updateStreamVolumeAlias(true /*updateVolumes*/);
14199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1420d7454be47f4111c0478a502353e11dea401378bdEric Laurent        return newModeOwnerPid;
14219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getMode() */
14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getMode() {
14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mMode;
14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#playSoundEffect(int) */
14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void playSoundEffect(int effectType) {
1430afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_NOOP,
1431a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                effectType, -1, null, 0);
14329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#playSoundEffect(int, float) */
14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void playSoundEffectVolume(int effectType, float volume) {
1436a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent        loadSoundEffects();
1437afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_NOOP,
14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                effectType, (int) (volume * 1000), null, 0);
14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Loads samples into the soundpool.
14435c17a820f9e46e0756c11795b3e6f89105f2f539Glenn Kasten     * This method must be called at first when sound effects are enabled
14449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
14459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean loadSoundEffects() {
1446a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        int status;
1447a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
14489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mSoundEffectsLock) {
1449a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            if (!mBootCompleted) {
1450a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                Log.w(TAG, "loadSoundEffects() called before boot complete");
1451a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                return false;
1452a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
1453a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1454a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent            if (mSoundPool != null) {
1455a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                return true;
1456a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent            }
14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0);
1458a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1459a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            try {
1460a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundPoolCallBack = null;
1461a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundPoolListenerThread = new SoundPoolListenerThread();
1462a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundPoolListenerThread.start();
1463a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                // Wait for mSoundPoolCallBack to be set by the other thread
1464a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundEffectsLock.wait();
1465a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            } catch (InterruptedException e) {
1466a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
1467a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
1468a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1469a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            if (mSoundPoolCallBack == null) {
1470a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                Log.w(TAG, "loadSoundEffects() could not create SoundPool listener or thread");
1471a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                if (mSoundPoolLooper != null) {
1472a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundPoolLooper.quit();
1473a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundPoolLooper = null;
1474a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
1475a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundPoolListenerThread = null;
1476a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundPool.release();
1477a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundPool = null;
14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * poolId table: The value -1 in this table indicates that corresponding
14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Once loaded, the value in poolId is the sample ID and the same
14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * sample can be reused for another effect using the same file.
14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int[] poolId = new int[SOUND_EFFECT_FILES.length];
14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) {
14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                poolId[fileIdx] = -1;
14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * this indicates we have a valid sample loaded for this effect.
14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
1495a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1496117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent            int lastSample = 0;
14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Do not load sample if this effect uses the MediaPlayer
14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    continue;
15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
1503a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    String filePath = Environment.getRootDirectory()
1504a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                            + SOUND_EFFECTS_PATH
1505a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                            + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effect][0]];
15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int sampleId = mSoundPool.load(filePath, 0);
15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (sampleId <= 0) {
15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Log.w(TAG, "Soundpool could not load file: "+filePath);
1509117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    } else {
1510117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                        SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
1511117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                        poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
1512117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                        lastSample = sampleId;
15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    SOUND_EFFECT_FILES_MAP[effect][1] = poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1518a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            // wait for all samples to be loaded
1519117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent            if (lastSample != 0) {
1520117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                mSoundPoolCallBack.setLastSample(lastSample);
1521117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent
1522117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                try {
1523117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    mSoundEffectsLock.wait();
1524117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    status = mSoundPoolCallBack.status();
1525117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                } catch (java.lang.InterruptedException e) {
1526117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    Log.w(TAG, "Interrupted while waiting sound pool callback.");
1527117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    status = -1;
1528117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                }
1529117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent            } else {
1530a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                status = -1;
1531a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
1532117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent
1533a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            if (mSoundPoolLooper != null) {
1534a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundPoolLooper.quit();
1535a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundPoolLooper = null;
1536a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
1537a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            mSoundPoolListenerThread = null;
1538a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            if (status != 0) {
1539a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                Log.w(TAG,
1540a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                        "loadSoundEffects(), Error "
1541117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                                + ((lastSample != 0) ? mSoundPoolCallBack.status() : -1)
1542a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                                + " while loading samples");
1543117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
1544117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
1545117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                        SOUND_EFFECT_FILES_MAP[effect][1] = -1;
1546117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    }
1547117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                }
1548117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent
1549a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundPool.release();
1550a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundPool = null;
1551a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1553a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        return (status == 0);
15549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  Unloads samples from the sound pool.
15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  This method can be called to free some memory when
15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  sound effects are disabled.
15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
15619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void unloadSoundEffects() {
15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mSoundEffectsLock) {
15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mSoundPool == null) {
15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1566a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1567117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent            mAudioHandler.removeMessages(MSG_LOAD_SOUND_EFFECTS);
1568a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            mAudioHandler.removeMessages(MSG_PLAY_SOUND_EFFECT);
1569a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
15709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int[] poolId = new int[SOUND_EFFECT_FILES.length];
15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) {
15729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                poolId[fileIdx] = 0;
15739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
15769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
15779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    continue;
15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    SOUND_EFFECT_FILES_MAP[effect][1] = -1;
15829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
15839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1585a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            mSoundPool.release();
15869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSoundPool = null;
15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1590a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    class SoundPoolListenerThread extends Thread {
1591a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public SoundPoolListenerThread() {
1592a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            super("SoundPoolListenerThread");
1593a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1594a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1595a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        @Override
1596a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public void run() {
1597a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1598a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            Looper.prepare();
1599a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            mSoundPoolLooper = Looper.myLooper();
1600a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1601a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            synchronized (mSoundEffectsLock) {
1602a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                if (mSoundPool != null) {
1603a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundPoolCallBack = new SoundPoolCallback();
1604a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
1605a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
1606a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundEffectsLock.notify();
1607a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
1608a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            Looper.loop();
1609a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1610a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    }
1611a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1612a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private final class SoundPoolCallback implements
1613a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            android.media.SoundPool.OnLoadCompleteListener {
1614a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1615a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        int mStatus;
1616a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        int mLastSample;
1617a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1618a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public int status() {
1619a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            return mStatus;
1620a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1621a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1622a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public void setLastSample(int sample) {
1623a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            mLastSample = sample;
1624a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1625a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1626a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
1627a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            synchronized (mSoundEffectsLock) {
1628a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                if (status != 0) {
1629a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mStatus = status;
1630a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
1631a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                if (sampleId == mLastSample) {
1632a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundEffectsLock.notify();
1633a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
1634a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
1635a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1636a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    }
1637a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
16384050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    /** @see AudioManager#reloadAudioSettings() */
16394050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    public void reloadAudioSettings() {
16404050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
16414050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        readPersistedSettings();
16424050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
16434050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        // restore volume settings
16444050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        int numStreamTypes = AudioSystem.getNumStreamTypes();
16454050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
16464050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent            VolumeStreamState streamState = mStreamStates[streamType];
16474050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
16483172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            synchronized (streamState) {
16493172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                streamState.readSettings();
1650a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
16513172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                // unmute stream that was muted but is not affect by mute anymore
16523172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) {
16533172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    int size = streamState.mDeathHandlers.size();
16543172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    for (int i = 0; i < size; i++) {
16553172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        streamState.mDeathHandlers.get(i).mMuteCount = 1;
16563172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        streamState.mDeathHandlers.get(i).mute(false);
16573172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    }
16583172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                }
16594050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent            }
16604050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        }
16614050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
1662244820185269991186d07068b92985624cede4a5Eric Laurent        checkAllAliasStreamVolumes();
1663244820185269991186d07068b92985624cede4a5Eric Laurent
16644050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        // apply new ringer mode
16654050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        setRingerModeInt(getRingerMode(), false);
16664050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    }
16674050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
1668c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    /** @see AudioManager#setSpeakerphoneOn() */
1669c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public void setSpeakerphoneOn(boolean on){
1670dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
1671dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent            return;
1672dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        }
1673fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        mForcedUseForComm = on ? AudioSystem.FORCE_SPEAKER : AudioSystem.FORCE_NONE;
1674fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
1675afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
1676fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
1677c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
1678c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
1679c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    /** @see AudioManager#isSpeakerphoneOn() */
1680c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public boolean isSpeakerphoneOn() {
1681fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
1682c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
1683c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
1684c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    /** @see AudioManager#setBluetoothScoOn() */
1685c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public void setBluetoothScoOn(boolean on){
1686dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
1687dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent            return;
1688dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        }
1689fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        mForcedUseForComm = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE;
1690fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
1691afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
1692fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
1693afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
1694fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
1695c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
1696c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
1697c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    /** @see AudioManager#isBluetoothScoOn() */
1698c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public boolean isBluetoothScoOn() {
1699fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
1700c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
1701c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
17027847211fb4699bf6018e29d214a918ed6657319bEric Laurent    /** @see AudioManager#setBluetoothA2dpOn() */
17037847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public void setBluetoothA2dpOn(boolean on) {
17047847211fb4699bf6018e29d214a918ed6657319bEric Laurent        setBluetoothA2dpOnInt(on);
17057847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
17067847211fb4699bf6018e29d214a918ed6657319bEric Laurent
17077847211fb4699bf6018e29d214a918ed6657319bEric Laurent    /** @see AudioManager#isBluetoothA2dpOn() */
17087847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public boolean isBluetoothA2dpOn() {
17097847211fb4699bf6018e29d214a918ed6657319bEric Laurent        synchronized (mBluetoothA2dpEnabledLock) {
17107847211fb4699bf6018e29d214a918ed6657319bEric Laurent            return mBluetoothA2dpEnabled;
17117847211fb4699bf6018e29d214a918ed6657319bEric Laurent        }
17127847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
17137847211fb4699bf6018e29d214a918ed6657319bEric Laurent
17143def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    /** @see AudioManager#startBluetoothSco() */
17153def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    public void startBluetoothSco(IBinder cb){
1716dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (!checkAudioSettingsPermission("startBluetoothSco()") ||
1717dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                !mBootCompleted) {
17183def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return;
17193def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
1720854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        ScoClient client = getScoClient(cb, true);
17213def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        client.incCount();
17223def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
17233def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
17243def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    /** @see AudioManager#stopBluetoothSco() */
17253def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    public void stopBluetoothSco(IBinder cb){
1726dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
1727dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                !mBootCompleted) {
17283def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return;
17293def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
1730854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        ScoClient client = getScoClient(cb, false);
1731854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        if (client != null) {
1732854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            client.decCount();
1733854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        }
17343def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
17353def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
17367847211fb4699bf6018e29d214a918ed6657319bEric Laurent
17373def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    private class ScoClient implements IBinder.DeathRecipient {
17383def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        private IBinder mCb; // To be notified of client's death
1739f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        private int mCreatorPid;
17403def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        private int mStartcount; // number of SCO connections started by this client
17413def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
17423def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        ScoClient(IBinder cb) {
17433def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            mCb = cb;
1744f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen            mCreatorPid = Binder.getCallingPid();
17453def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            mStartcount = 0;
17463def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
17473def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
17483def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void binderDied() {
17493def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
17503def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                Log.w(TAG, "SCO client died");
17513def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int index = mScoClients.indexOf(this);
17523def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (index < 0) {
17533def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    Log.w(TAG, "unregistered SCO client died");
17543def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                } else {
17553def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    clearCount(true);
17563def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    mScoClients.remove(this);
17573def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
17583def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
17593def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
17603def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
17613def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void incCount() {
17623def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
176382aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh                requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED);
17643def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (mStartcount == 0) {
17653def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    try {
17663def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        mCb.linkToDeath(this, 0);
17673def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    } catch (RemoteException e) {
17683def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        // client has already died!
17693def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        Log.w(TAG, "ScoClient  incCount() could not link to "+mCb+" binder death");
17703def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
17713def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
17723def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                mStartcount++;
17733def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
17743def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
17753def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
17763def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void decCount() {
17773def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
17783def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (mStartcount == 0) {
17793def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    Log.w(TAG, "ScoClient.decCount() already 0");
17803def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                } else {
17813def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    mStartcount--;
17823def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    if (mStartcount == 0) {
1783e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        try {
1784e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                            mCb.unlinkToDeath(this, 0);
1785e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        } catch (NoSuchElementException e) {
1786e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                            Log.w(TAG, "decCount() going to 0 but not registered to binder");
1787e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        }
17883def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
178982aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
17903def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
17913def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
17923def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
17933def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
17943def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void clearCount(boolean stopSco) {
17953def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
1796e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                if (mStartcount != 0) {
1797e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    try {
1798e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        mCb.unlinkToDeath(this, 0);
1799e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    } catch (NoSuchElementException e) {
1800e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
1801e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    }
1802e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                }
18033def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                mStartcount = 0;
18043def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (stopSco) {
180582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
18063def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
18073def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
18083def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
18093def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
18103def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public int getCount() {
18113def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return mStartcount;
18123def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
18133def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
18143def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public IBinder getBinder() {
18153def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return mCb;
18163def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
18173def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
1818d7454be47f4111c0478a502353e11dea401378bdEric Laurent        public int getPid() {
1819d7454be47f4111c0478a502353e11dea401378bdEric Laurent            return mCreatorPid;
1820d7454be47f4111c0478a502353e11dea401378bdEric Laurent        }
1821d7454be47f4111c0478a502353e11dea401378bdEric Laurent
18223def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public int totalCount() {
18233def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
18243def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int count = 0;
18253def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int size = mScoClients.size();
18263def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                for (int i = 0; i < size; i++) {
18273def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    count += mScoClients.get(i).getCount();
18283def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
18293def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                return count;
18303def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
18313def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
18323def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
18333def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        private void requestScoState(int state) {
183462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent            checkScoAudioState();
1835dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            if (totalCount() == 0) {
1836dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
1837dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // Make sure that the state transitions to CONNECTING even if we cannot initiate
1838dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // the connection.
1839dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
1840dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // Accept SCO audio activation only in NORMAL audio mode or if the mode is
1841f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen                    // currently controlled by the same client process.
18429f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    synchronized(mSetModeDeathHandlers) {
18439f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        if ((mSetModeDeathHandlers.isEmpty() ||
18449f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
18459f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                (mScoAudioState == SCO_STATE_INACTIVE ||
18469f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
18479f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            if (mScoAudioState == SCO_STATE_INACTIVE) {
18489f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
18499f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    if (mBluetoothHeadset.startScoUsingVirtualVoiceCall(
18509f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                            mBluetoothHeadsetDevice)) {
18519f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                        mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
18529f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    } else {
18539f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                        broadcastScoConnectionState(
18549f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
18559f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    }
18569f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                } else if (getBluetoothHeadset()) {
18579f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    mScoAudioState = SCO_STATE_ACTIVATE_REQ;
1858dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                }
18599f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            } else {
18609f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
18619f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
1862dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            }
1863dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        } else {
18649f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
1865dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
1866dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
186762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
1868dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                              (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
1869dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                               mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
1870dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
1871671db6f3ba1fdb3c907e0735fe6d0d284f5c34deMarco Nelissen                        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
1872dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            if (!mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
1873dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                    mBluetoothHeadsetDevice)) {
1874dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                mScoAudioState = SCO_STATE_INACTIVE;
1875dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                broadcastScoConnectionState(
1876dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
1877dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            }
1878dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        } else if (getBluetoothHeadset()) {
1879dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
1880dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
1881dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    } else {
1882dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        mScoAudioState = SCO_STATE_INACTIVE;
1883dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
1884dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
18853def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
18863def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
18873def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
18883def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
18893def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
189062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private void checkScoAudioState() {
189162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
1892dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                mScoAudioState == SCO_STATE_INACTIVE &&
189362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
189462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
189562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
189662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent        }
189762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    }
189862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent
1899854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent    private ScoClient getScoClient(IBinder cb, boolean create) {
19003def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        synchronized(mScoClients) {
1901854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            ScoClient client = null;
19023def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            int size = mScoClients.size();
19033def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            for (int i = 0; i < size; i++) {
19043def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                client = mScoClients.get(i);
19053def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (client.getBinder() == cb)
19063def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    return client;
19073def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
1908854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            if (create) {
1909854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                client = new ScoClient(cb);
1910854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                mScoClients.add(client);
1911854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            }
19123def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return client;
19133def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
19143def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
19153def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
1916d7454be47f4111c0478a502353e11dea401378bdEric Laurent    public void clearAllScoClients(int exceptPid, boolean stopSco) {
19173def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        synchronized(mScoClients) {
1918854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            ScoClient savedClient = null;
19193def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            int size = mScoClients.size();
19203def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            for (int i = 0; i < size; i++) {
1921854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                ScoClient cl = mScoClients.get(i);
1922d7454be47f4111c0478a502353e11dea401378bdEric Laurent                if (cl.getPid() != exceptPid) {
1923854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                    cl.clearCount(stopSco);
1924854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                } else {
1925854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                    savedClient = cl;
1926854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                }
1927854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            }
1928854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            mScoClients.clear();
1929854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            if (savedClient != null) {
1930854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                mScoClients.add(savedClient);
19313def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
19323def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
19333def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
19343def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
1935dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private boolean getBluetoothHeadset() {
1936dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        boolean result = false;
1937dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
1938dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (adapter != null) {
1939dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
1940dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                    BluetoothProfile.HEADSET);
1941dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
1942dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // If we could not get a bluetooth headset proxy, send a failure message
1943dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // without delay to reset the SCO audio state and clear SCO clients.
1944dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // If we could get a proxy, send a delayed failure message that will reset our state
1945dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // in case we don't receive onServiceConnected().
1946afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
1947dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
1948dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        return result;
1949dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
1950dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
1951d7454be47f4111c0478a502353e11dea401378bdEric Laurent    private void disconnectBluetoothSco(int exceptPid) {
1952dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        synchronized(mScoClients) {
1953dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            checkScoAudioState();
1954dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
1955dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
1956dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                if (mBluetoothHeadsetDevice != null) {
1957dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (mBluetoothHeadset != null) {
1958dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (!mBluetoothHeadset.stopVoiceRecognition(
1959b06ac839dd2d0437fc8314f6deb7233af5af521eEric Laurent                                mBluetoothHeadsetDevice)) {
1960afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
1961dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                    SENDMSG_REPLACE, 0, 0, null, 0);
1962dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
1963dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
1964dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            getBluetoothHeadset()) {
1965dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
1966dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
1967dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                }
1968dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            } else {
1969d7454be47f4111c0478a502353e11dea401378bdEric Laurent                clearAllScoClients(exceptPid, true);
1970dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            }
1971dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
1972dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
1973dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
1974dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private void resetBluetoothSco() {
1975dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        synchronized(mScoClients) {
1976d7454be47f4111c0478a502353e11dea401378bdEric Laurent            clearAllScoClients(0, false);
1977dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            mScoAudioState = SCO_STATE_INACTIVE;
1978dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
1979dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
1980dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
1981dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
1982dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private void broadcastScoConnectionState(int state) {
1983dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (state != mScoConnectionState) {
1984dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
1985dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
1986dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
1987dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    mScoConnectionState);
1988dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            mContext.sendStickyBroadcast(newIntent);
1989dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            mScoConnectionState = state;
1990dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
1991dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
1992dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
199382aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
199482aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        new BluetoothProfile.ServiceListener() {
199582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        public void onServiceConnected(int profile, BluetoothProfile proxy) {
19966bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            BluetoothDevice btDevice;
19976bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            List<BluetoothDevice> deviceList;
19986bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            switch(profile) {
19996bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.A2DP:
20006bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                BluetoothA2dp a2dp = (BluetoothA2dp) proxy;
20016bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                deviceList = a2dp.getConnectedDevices();
200262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                if (deviceList.size() > 0) {
20036bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    btDevice = deviceList.get(0);
2004b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    synchronized (mConnectedDevices) {
2005b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                        int state = a2dp.getConnectionState(btDevice);
2006b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                        int delay = checkSendBecomingNoisyIntent(
2007b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                                                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2008b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
2009e12c39bb9cedb8b363658979872694eb55b1386eJean-Michel Trivi                        queueMsgUnderWakeLock(mAudioHandler,
2010b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                                MSG_SET_A2DP_CONNECTION_STATE,
2011b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                                state,
2012b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                                0,
2013b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                                btDevice,
2014b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                                delay);
2015b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    }
20166bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
20176bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
20186bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
20196bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.HEADSET:
20206bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                synchronized (mScoClients) {
20216bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Discard timeout message
20226bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
20236bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mBluetoothHeadset = (BluetoothHeadset) proxy;
20246bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    deviceList = mBluetoothHeadset.getConnectedDevices();
20256bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (deviceList.size() > 0) {
20266bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        mBluetoothHeadsetDevice = deviceList.get(0);
20276bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    } else {
20286bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        mBluetoothHeadsetDevice = null;
2029dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
20306bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Refresh SCO audio state
20316bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    checkScoAudioState();
20326bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Continue pending action if any
20336bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
20346bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
20356bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
20366bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        boolean status = false;
20376bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        if (mBluetoothHeadsetDevice != null) {
20386bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            switch (mScoAudioState) {
20396bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_ACTIVATE_REQ:
20406bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
20416bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
20426bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                        mBluetoothHeadsetDevice);
20436bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                break;
20446bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_DEACTIVATE_REQ:
20456bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
20466bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                        mBluetoothHeadsetDevice);
20476bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                break;
20486bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_DEACTIVATE_EXT_REQ:
20496bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                status = mBluetoothHeadset.stopVoiceRecognition(
20506bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                        mBluetoothHeadsetDevice);
20516bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            }
20526bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
20536bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        if (!status) {
2054afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
20556bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                    SENDMSG_REPLACE, 0, 0, null, 0);
20566bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
2057dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
2058dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                }
20596bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
20606bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
20616bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            default:
20626bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
20633def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
20643def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
206582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        public void onServiceDisconnected(int profile) {
20666bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            switch(profile) {
20676bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.A2DP:
20686bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                synchronized (mConnectedDevices) {
20696bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
20706bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableNow(
20716bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
20726bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
20736bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
20746bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
20756bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
20766bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.HEADSET:
20776bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                synchronized (mScoClients) {
20786bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mBluetoothHeadset = null;
20796bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
20806bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
20816bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
20826bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            default:
20836bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
20843def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
20853def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
20863def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    };
2087d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
20889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
20899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Internal methods
20909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
20919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
20939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Checks if the adjustment should change ringer mode instead of just
20949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * adjusting volume. If so, this will set the proper ringer mode and volume
20959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * indices on the stream states.
20969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2097244820185269991186d07068b92985624cede4a5Eric Laurent    private boolean checkForRingerModeChange(int oldIndex, int direction,  int step) {
20989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean adjustVolumeIndex = true;
2099ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        int ringerMode = getRingerMode();
2100bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
2101bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        switch (ringerMode) {
2102bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_NORMAL:
2103bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            if (direction == AudioManager.ADJUST_LOWER) {
2104bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                if (mHasVibrator) {
2105244820185269991186d07068b92985624cede4a5Eric Laurent                    // "step" is the delta in internal index units corresponding to a
2106244820185269991186d07068b92985624cede4a5Eric Laurent                    // change of 1 in UI index units.
2107244820185269991186d07068b92985624cede4a5Eric Laurent                    // Because of rounding when rescaling from one stream index range to its alias
2108244820185269991186d07068b92985624cede4a5Eric Laurent                    // index range, we cannot simply test oldIndex == step:
2109244820185269991186d07068b92985624cede4a5Eric Laurent                    //   (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
2110244820185269991186d07068b92985624cede4a5Eric Laurent                    if (step <= oldIndex && oldIndex < 2 * step) {
2111bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        ringerMode = RINGER_MODE_VIBRATE;
2112bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    }
2113bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                } else {
2114244820185269991186d07068b92985624cede4a5Eric Laurent                    // (oldIndex < step) is equivalent to (old UI index == 0)
2115244820185269991186d07068b92985624cede4a5Eric Laurent                    if ((oldIndex < step) && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
2116bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        ringerMode = RINGER_MODE_SILENT;
2117bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    }
21183d4c06f90726a85e89dab13c41ddc15b9c912a3fEric Laurent                }
21196329bf7b1e2217c6c9477bd57349a1edade18417Daniel Sandler            }
2120bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
2121bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_VIBRATE:
2122bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            if (!mHasVibrator) {
2123bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
2124bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        "but no vibrator is present");
2125bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                break;
2126bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            }
2127c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            if ((direction == AudioManager.ADJUST_LOWER)) {
2128c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani                if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
2129bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    ringerMode = RINGER_MODE_SILENT;
2130c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani                }
2131c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            } else if (direction == AudioManager.ADJUST_RAISE) {
2132bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                ringerMode = RINGER_MODE_NORMAL;
2133c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            }
2134c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            adjustVolumeIndex = false;
2135bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
2136bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_SILENT:
21379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (direction == AudioManager.ADJUST_RAISE) {
2138bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                if (mHasVibrator) {
2139bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    ringerMode = RINGER_MODE_VIBRATE;
2140bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                } else {
2141bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    ringerMode = RINGER_MODE_NORMAL;
2142bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                }
21439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2144b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent            adjustVolumeIndex = false;
2145bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
2146bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        default:
2147bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
2148bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
21499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2151bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        setRingerMode(ringerMode);
21529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
215325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        mPrevVolDirection = direction;
215425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
21559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return adjustVolumeIndex;
21569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isStreamAffectedByRingerMode(int streamType) {
21599bcf401d13d47416043a704430388abd59aef7cdEric Laurent        return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
21609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21625b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    private boolean isStreamMutedByRingerMode(int streamType) {
21635b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        return (mRingerModeMutedStreams & (1 << streamType)) != 0;
21645b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    }
21655b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
21669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isStreamAffectedByMute(int streamType) {
21679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mMuteAffectedStreams & (1 << streamType)) != 0;
21689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void ensureValidDirection(int direction) {
21719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
21729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("Bad direction " + direction);
21739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21766c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    private void ensureValidSteps(int steps) {
21776c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
21786c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            throw new IllegalArgumentException("Bad volume adjust steps " + steps);
21796c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        }
21806c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    }
21816c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang
21829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void ensureValidStreamType(int streamType) {
21839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (streamType < 0 || streamType >= mStreamStates.length) {
21849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("Bad stream type " + streamType);
21859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21886d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private boolean isInCommunication() {
21896d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        boolean isOffhook = false;
219025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
219125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        if (mVoiceCapable) {
219225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            try {
219325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
219425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                if (phone != null) isOffhook = phone.isOffhook();
219525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            } catch (RemoteException e) {
219625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                Log.w(TAG, "Couldn't connect to phone service", e);
219725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            }
21986d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
21996d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        return (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION);
22006d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    }
220125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
22026d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private int getActiveStreamType(int suggestedStreamType) {
22036d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (mVoiceCapable) {
22046d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            if (isInCommunication()) {
220525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
220625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                        == AudioSystem.FORCE_BT_SCO) {
220725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
220825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_BLUETOOTH_SCO;
220925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                } else {
221025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
221125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_VOICE_CALL;
221225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                }
22133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
22143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control
22153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                // volume can have priority over STREAM_MUSIC
22163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
22173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL)
22183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
22193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return STREAM_REMOTE_MUSIC;
22203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
22213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL)
22223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
22233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return AudioSystem.STREAM_MUSIC;
22243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                } else {
22253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL)
22263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
22273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return AudioSystem.STREAM_RING;
22283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
222925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
22303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL)
22313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
223225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return AudioSystem.STREAM_MUSIC;
2233c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato            } else {
22343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
22353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        + suggestedStreamType);
223625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return suggestedStreamType;
223725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            }
223825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        } else {
22396d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            if (isInCommunication()) {
224025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
224125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                        == AudioSystem.FORCE_BT_SCO) {
22423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
224325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_BLUETOOTH_SCO;
224425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                } else {
22453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL)  Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
224625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_VOICE_CALL;
224725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                }
224825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
22493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    NOTIFICATION_VOLUME_DELAY_MS) ||
22503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
225125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                            NOTIFICATION_VOLUME_DELAY_MS)) {
22523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
225325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return AudioSystem.STREAM_NOTIFICATION;
22543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
22553114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
22563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control
22573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    // volume can have priority over STREAM_MUSIC
22583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
22593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return STREAM_REMOTE_MUSIC;
22603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                } else {
22613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL)
22623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default");
22633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return AudioSystem.STREAM_MUSIC;
22643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
226525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            } else {
22663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
22673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        + suggestedStreamType);
226825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return suggestedStreamType;
2269c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato            }
22709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2273ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    private void broadcastRingerMode(int ringerMode) {
22749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Send sticky broadcast
22751c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn        Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION);
2276ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
22771c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn        broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
22781c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
22791c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn        long origCallerIdentityToken = Binder.clearCallingIdentity();
22801c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn        mContext.sendStickyBroadcast(broadcast);
22811c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn        Binder.restoreCallingIdentity(origCallerIdentityToken);
22829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void broadcastVibrateSetting(int vibrateType) {
22859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Send broadcast
22869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (ActivityManagerNative.isSystemReady()) {
22879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
22889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
22899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
22909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.sendBroadcast(broadcast);
22919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Message helper methods
22952d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    /**
22962d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     * Queue a message on the given handler's message queue, after acquiring the service wake lock.
22972d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     * Note that the wake lock needs to be released after the message has been handled.
22982d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     */
22992d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    private void queueMsgUnderWakeLock(Handler handler, int msg,
23002d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            int arg1, int arg2, Object obj, int delay) {
23012d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi        mMediaEventWakeLock.acquire();
23022d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi        sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
23032d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    }
23049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2305afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent    private static void sendMsg(Handler handler, int msg,
23069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
23079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (existingMsgPolicy == SENDMSG_REPLACE) {
23099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handler.removeMessages(msg);
23109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
23119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
23129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2314afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
23159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
23169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean checkAudioSettingsPermission(String method) {
23189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS")
23199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                == PackageManager.PERMISSION_GRANTED) {
23209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
23219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String msg = "Audio Settings Permission Denial: " + method + " from pid="
23239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + Binder.getCallingPid()
23249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + ", uid=" + Binder.getCallingUid();
23259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.w(TAG, msg);
23269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
23279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
23289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23299bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    private int getDeviceForStream(int stream) {
23309bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = AudioSystem.getDevicesForStream(stream);
23319bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        if ((device & (device - 1)) != 0) {
23329bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Multiple device selection is either:
23339bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            //  - speaker + one other device: give priority to speaker in this case.
23349bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            //  - one A2DP device + another device: happens with duplicated output. In this case
23359bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // retain the device on the A2DP output as the other must not correspond to an active
23369bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // selection if not the speaker.
23379bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
23389bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                device = AudioSystem.DEVICE_OUT_SPEAKER;
23399bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            } else {
23409bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
23419bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
23429bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
23439bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        return device;
23449bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    }
23459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2346b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    public void setWiredDeviceConnectionState(int device, int state, String name) {
2347b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
2348b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            int delay = checkSendBecomingNoisyIntent(device, state);
23492d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            queueMsgUnderWakeLock(mAudioHandler,
2350b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
2351b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    device,
2352b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    state,
2353b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    name,
2354b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    delay);
2355b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
2356b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
2357b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
2358b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state)
2359b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
2360b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        int delay;
2361b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
2362b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2363b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                                            (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
23642d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            queueMsgUnderWakeLock(mAudioHandler,
2365b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    MSG_SET_A2DP_CONNECTION_STATE,
2366b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    state,
2367b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    0,
2368b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    device,
2369b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    delay);
2370b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
2371b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        return delay;
2372b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
2373b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
23749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
23759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Inner classes
23769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
23779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public class VolumeStreamState {
23799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final int mStreamType;
23809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
238111a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi        private String mVolumeIndexSettingName;
238211a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi        private String mLastAudibleVolumeIndexSettingName;
2383a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        private int mIndexMax;
23843172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        private final ConcurrentHashMap<Integer, Integer> mIndex =
23853172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                            new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
23863172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        private final ConcurrentHashMap<Integer, Integer> mLastAudibleIndex =
23873172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                            new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
23889bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
23899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2390a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        private VolumeStreamState(String settingName, int streamType) {
23919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23929bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            mVolumeIndexSettingName = settingName;
23939bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE;
23949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStreamType = streamType;
23965982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles            mIndexMax = MAX_STREAM_VOLUME[streamType];
2397a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
2398a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            mIndexMax *= 10;
23999bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
24009bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            readSettings();
24019bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
24029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDeathHandlers = new ArrayList<VolumeDeathHandler>();
24039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
24049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24059bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        public String getSettingNameForDevice(boolean lastAudible, int device) {
24069bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            String name = lastAudible ?
24079bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                            mLastAudibleVolumeIndexSettingName :
24089bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                            mVolumeIndexSettingName;
24099bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            String suffix = AudioSystem.getDeviceName(device);
24109bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if (suffix.isEmpty()) {
24119bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                return name;
24129bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
24139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            return name + "_" + suffix;
24149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
24159bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
24163172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public synchronized void readSettings() {
24179bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
24189ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent
24199bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            for (int i = 0; remainingDevices != 0; i++) {
24209bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                int device = (1 << i);
24219bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                if ((device & remainingDevices) == 0) {
24229bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    continue;
24239bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                }
24249bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                remainingDevices &= ~device;
24259bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
24269bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                // retrieve current volume for device
24279ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                String name = getSettingNameForDevice(false /* lastAudible */, device);
24289ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                // if no volume stored for current stream and device, use default volume if default
24299ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                // device, continue otherwise
24309ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
24319ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                                        AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
24329ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                int index = Settings.System.getInt(mContentResolver, name, defaultIndex);
24339bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                if (index == -1) {
24349bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    continue;
24359bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                }
24369bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
24379bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                // retrieve last audible volume for device
24389ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                name = getSettingNameForDevice(true  /* lastAudible */, device);
24399ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                // use stored last audible index if present, otherwise use current index if not 0
24409ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                // or default index
24419ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                defaultIndex = (index > 0) ?
24429ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                                    index : AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
24439ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                int lastAudibleIndex = Settings.System.getInt(mContentResolver, name, defaultIndex);
24449ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent
2445bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                // a last audible index of 0 should never be stored for ring and notification
2446bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                // streams on phones (voice capable devices).
2447bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                // same for system stream on phones and tablets
24489ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                if ((lastAudibleIndex == 0) &&
2449bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        ((mVoiceCapable &&
2450bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_RING)) ||
2451bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                         (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_SYSTEM))) {
24529ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                    lastAudibleIndex = AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
24539ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                    // Correct the data base
24549ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                    sendMsg(mAudioHandler,
24559ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            MSG_PERSIST_VOLUME,
24569ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            SENDMSG_QUEUE,
24579ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            PERSIST_LAST_AUDIBLE,
24589ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            device,
24599ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            this,
24609ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            PERSIST_DELAY);
24619ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                }
24629ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                mLastAudibleIndex.put(device, getValidIndex(10 * lastAudibleIndex));
2463bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                // the initial index should never be 0 for ring and notification streams on phones
2464bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                // (voice capable devices) if not in silent or vibrate mode.
2465bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                // same for system stream on phones and tablets
2466bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                if ((index == 0) && (mRingerMode == AudioManager.RINGER_MODE_NORMAL) &&
2467bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        ((mVoiceCapable &&
2468bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_RING)) ||
2469bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                         (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_SYSTEM))) {
24709ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                    index = lastAudibleIndex;
24719ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                    // Correct the data base
24729ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                    sendMsg(mAudioHandler,
24739ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            MSG_PERSIST_VOLUME,
24749ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            SENDMSG_QUEUE,
24759ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            PERSIST_CURRENT,
24769ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            device,
24779ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            this,
24789ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            PERSIST_DELAY);
24799ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                }
24809ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                mIndex.put(device, getValidIndex(10 * index));
24819bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
24829bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
24839bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
24849bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        public void applyDeviceVolume(int device) {
24859bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            AudioSystem.setStreamVolumeIndex(mStreamType,
24869bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                             (getIndex(device, false  /* lastAudible */) + 5)/10,
24879bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                             device);
24889bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
24899bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
24903172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public synchronized void applyAllVolumes() {
24919bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // apply default volume first: by convention this will reset all
24929bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // devices volumes in audio policy manager to the supplied value
24939bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            AudioSystem.setStreamVolumeIndex(mStreamType,
24949bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    (getIndex(AudioSystem.DEVICE_OUT_DEFAULT, false /* lastAudible */) + 5)/10,
24959bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    AudioSystem.DEVICE_OUT_DEFAULT);
24969bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // then apply device specific volumes
24979bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            Set set = mIndex.entrySet();
24989bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            Iterator i = set.iterator();
24999bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            while (i.hasNext()) {
25009bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                Map.Entry entry = (Map.Entry)i.next();
25019bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                int device = ((Integer)entry.getKey()).intValue();
25029bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
25039bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    AudioSystem.setStreamVolumeIndex(mStreamType,
25049bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                                     ((Integer)entry.getValue() + 5)/10,
25059bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                                     device);
25069bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                }
25079bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
250811a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi        }
250911a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi
25109bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        public boolean adjustIndex(int deltaIndex, int device) {
25119bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            return setIndex(getIndex(device,
2512244820185269991186d07068b92985624cede4a5Eric Laurent                                     false  /* lastAudible */) + deltaIndex,
25139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                            device,
25149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                            true  /* lastAudible */);
25159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
25169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25173172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public synchronized boolean setIndex(int index, int device, boolean lastAudible) {
25189bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            int oldIndex = getIndex(device, false  /* lastAudible */);
25199bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            index = getValidIndex(index);
25209bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            mIndex.put(device, getValidIndex(index));
25219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25229bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if (oldIndex != index) {
25239bcf401d13d47416043a704430388abd59aef7cdEric Laurent                if (lastAudible) {
25249bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    mLastAudibleIndex.put(device, index);
25259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2526a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                // Apply change to all streams using this one as alias
2527bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                // if changing volume of current device, also change volume of current
2528bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                // device on aliased stream
2529bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                boolean currentDevice = (device == getDeviceForStream(mStreamType));
2530a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                int numStreamTypes = AudioSystem.getNumStreamTypes();
2531a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
2532bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    if (streamType != mStreamType &&
2533bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                            mStreamVolumeAlias[streamType] == mStreamType) {
2534bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        int scaledIndex = rescaleIndex(index, mStreamType, streamType);
2535bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        mStreamStates[streamType].setIndex(scaledIndex,
2536bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                                           device,
25379bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                                           lastAudible);
2538bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        if (currentDevice) {
2539bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                            mStreamStates[streamType].setIndex(scaledIndex,
2540bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                                               getDeviceForStream(streamType),
2541bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                                               lastAudible);
2542bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        }
2543a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    }
2544a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
25459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
25469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
25479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
25489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
25499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
25509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25513172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public synchronized int getIndex(int device, boolean lastAudible) {
25523172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            ConcurrentHashMap <Integer, Integer> indexes;
25539bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if (lastAudible) {
25549bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                indexes = mLastAudibleIndex;
25559bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            } else {
25569bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                indexes = mIndex;
25579bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
25589bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            Integer index = indexes.get(device);
25599bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if (index == null) {
25609bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
25619bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                index = indexes.get(AudioSystem.DEVICE_OUT_DEFAULT);
25629bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
25639bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            return index.intValue();
25649bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
25659bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
25663172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public synchronized void setLastAudibleIndex(int index, int device) {
2567244820185269991186d07068b92985624cede4a5Eric Laurent            // Apply change to all streams using this one as alias
2568244820185269991186d07068b92985624cede4a5Eric Laurent            // if changing volume of current device, also change volume of current
2569244820185269991186d07068b92985624cede4a5Eric Laurent            // device on aliased stream
2570244820185269991186d07068b92985624cede4a5Eric Laurent            boolean currentDevice = (device == getDeviceForStream(mStreamType));
2571244820185269991186d07068b92985624cede4a5Eric Laurent            int numStreamTypes = AudioSystem.getNumStreamTypes();
2572244820185269991186d07068b92985624cede4a5Eric Laurent            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
2573244820185269991186d07068b92985624cede4a5Eric Laurent                if (streamType != mStreamType &&
2574244820185269991186d07068b92985624cede4a5Eric Laurent                        mStreamVolumeAlias[streamType] == mStreamType) {
2575244820185269991186d07068b92985624cede4a5Eric Laurent                    int scaledIndex = rescaleIndex(index, mStreamType, streamType);
2576244820185269991186d07068b92985624cede4a5Eric Laurent                    mStreamStates[streamType].setLastAudibleIndex(scaledIndex, device);
2577244820185269991186d07068b92985624cede4a5Eric Laurent                    if (currentDevice) {
2578244820185269991186d07068b92985624cede4a5Eric Laurent                        mStreamStates[streamType].setLastAudibleIndex(scaledIndex,
2579244820185269991186d07068b92985624cede4a5Eric Laurent                                                                   getDeviceForStream(streamType));
2580244820185269991186d07068b92985624cede4a5Eric Laurent                    }
2581244820185269991186d07068b92985624cede4a5Eric Laurent                }
2582244820185269991186d07068b92985624cede4a5Eric Laurent            }
25839bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            mLastAudibleIndex.put(device, getValidIndex(index));
25845b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        }
25855b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
25863172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public synchronized void adjustLastAudibleIndex(int deltaIndex, int device) {
25879bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            setLastAudibleIndex(getIndex(device,
2588244820185269991186d07068b92985624cede4a5Eric Laurent                                         true  /* lastAudible */) + deltaIndex,
25899bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                device);
25905b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        }
25915b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
25929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getMaxIndex() {
2593a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            return mIndexMax;
25949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
25959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25963172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        // only called by setAllIndexes() which is already synchronized
25973172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public ConcurrentHashMap <Integer, Integer> getAllIndexes(boolean lastAudible) {
25986d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            if (lastAudible) {
25996d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                return mLastAudibleIndex;
26006d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            } else {
26016d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                return mIndex;
26026d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            }
26036d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
26046d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
26053172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public synchronized void setAllIndexes(VolumeStreamState srcStream, boolean lastAudible) {
26063172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            ConcurrentHashMap <Integer, Integer> indexes = srcStream.getAllIndexes(lastAudible);
26076d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            Set set = indexes.entrySet();
26086d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            Iterator i = set.iterator();
26096d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            while (i.hasNext()) {
26106d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                Map.Entry entry = (Map.Entry)i.next();
26116d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                int device = ((Integer)entry.getKey()).intValue();
26126d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                int index = ((Integer)entry.getValue()).intValue();
26136d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                index = rescaleIndex(index, srcStream.getStreamType(), mStreamType);
26146d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                setIndex(index, device, lastAudible);
26156d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            }
26166d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
26176d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
26183172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public synchronized void mute(IBinder cb, boolean state) {
26199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            VolumeDeathHandler handler = getDeathHandler(cb, state);
26209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (handler == null) {
26219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
26229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
26239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
26249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handler.mute(state);
26259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
26269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26276d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        public int getStreamType() {
26286d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            return mStreamType;
26296d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
26306d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
26319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int getValidIndex(int index) {
26329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (index < 0) {
26339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
2634a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            } else if (index > mIndexMax) {
2635a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                return mIndexMax;
26369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
26379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return index;
26399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
26409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private class VolumeDeathHandler implements IBinder.DeathRecipient {
26429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            private IBinder mICallback; // To be notified of client's death
26439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            private int mMuteCount; // Number of active mutes for this client
26449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            VolumeDeathHandler(IBinder cb) {
26469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mICallback = cb;
26479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
26489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26493172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            // must be called while synchronized on parent VolumeStreamState
26509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void mute(boolean state) {
26513172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                if (state) {
26523172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    if (mMuteCount == 0) {
26533172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        // Register for client death notification
26543172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        try {
26553172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // mICallback can be 0 if muted by AudioService
26563172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            if (mICallback != null) {
26573172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                mICallback.linkToDeath(this, 0);
26583172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
26593172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            mDeathHandlers.add(this);
26603172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // If the stream is not yet muted by any client, set level to 0
26613172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            if (muteCount() == 0) {
26623172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                Set set = mIndex.entrySet();
26633172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                Iterator i = set.iterator();
26643172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                while (i.hasNext()) {
26653172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                    Map.Entry entry = (Map.Entry)i.next();
26663172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                    int device = ((Integer)entry.getKey()).intValue();
26673172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                    setIndex(0, device, false /* lastAudible */);
26685b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                                }
26693172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                sendMsg(mAudioHandler,
26703172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                        MSG_SET_ALL_VOLUMES,
26713172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                        SENDMSG_QUEUE,
26723172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                        0,
26733172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                        0,
26743172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                        VolumeStreamState.this, 0);
26753172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
26763172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        } catch (RemoteException e) {
26773172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // Client has died!
26783172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            binderDied();
26793172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            return;
26803172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        }
26813172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    } else {
26823172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
26833172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    }
26843172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    mMuteCount++;
26853172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                } else {
26863172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    if (mMuteCount == 0) {
26873172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
26883172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    } else {
26893172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        mMuteCount--;
26903172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        if (mMuteCount == 0) {
26913172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // Unregister from client death notification
26923172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            mDeathHandlers.remove(this);
26933172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // mICallback can be 0 if muted by AudioService
26943172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            if (mICallback != null) {
26953172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                mICallback.unlinkToDeath(this, 0);
26963172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
26973172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            if (muteCount() == 0) {
26983172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                // If the stream is not muted any more, restore its volume if
26993172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                // ringer mode allows it
27003172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                if (!isStreamAffectedByRingerMode(mStreamType) ||
27013172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                        mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
27029bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    Set set = mIndex.entrySet();
27039bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    Iterator i = set.iterator();
27049bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    while (i.hasNext()) {
27059bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                        Map.Entry entry = (Map.Entry)i.next();
27069bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                        int device = ((Integer)entry.getKey()).intValue();
27073172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                        setIndex(getIndex(device,
27083172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                                          true  /* lastAudible */),
27093172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                                 device,
27103172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                                 false  /* lastAudible */);
27119bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    }
27129bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    sendMsg(mAudioHandler,
27139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                            MSG_SET_ALL_VOLUMES,
271498ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent                                            SENDMSG_QUEUE,
27159bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                            0,
27169bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                            0,
27179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                            VolumeStreamState.this, 0);
27189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                }
27199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
27209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
27219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
27229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
27239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
27249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void binderDied() {
27269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.w(TAG, "Volume service client died for stream: "+mStreamType);
27279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mMuteCount != 0) {
27289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Reset all active mute requests from this client.
27299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mMuteCount = 1;
27309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mute(false);
27319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
27329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
27339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27353172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        private synchronized int muteCount() {
27369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int count = 0;
27379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int size = mDeathHandlers.size();
27389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < size; i++) {
27399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                count += mDeathHandlers.get(i).mMuteCount;
27409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
27419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return count;
27429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27443172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        // only called by mute() which is already synchronized
27459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
27463172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            VolumeDeathHandler handler;
27473172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            int size = mDeathHandlers.size();
27483172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            for (int i = 0; i < size; i++) {
27493172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = mDeathHandlers.get(i);
27503172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                if (cb == handler.mICallback) {
27513172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    return handler;
2752ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood                }
2753ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood            }
27543172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            // If this is the first mute request for this client, create a new
27553172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            // client death handler. Otherwise, it is an out of sequence unmute request.
27563172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            if (state) {
27573172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = new VolumeDeathHandler(cb);
27583172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            } else {
27593172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                Log.w(TAG, "stream was not muted by this client");
27603172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = null;
27613172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            }
27623172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            return handler;
2763ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        }
2764bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
2765bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        private void dump(PrintWriter pw) {
2766bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.print("   Current: ");
2767bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Set set = mIndex.entrySet();
2768bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Iterator i = set.iterator();
2769bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            while (i.hasNext()) {
2770bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                Map.Entry entry = (Map.Entry)i.next();
2771bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue())
2772bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                             + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", ");
2773bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            }
2774bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.print("\n   Last audible: ");
2775bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            set = mLastAudibleIndex.entrySet();
2776bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            i = set.iterator();
2777bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            while (i.hasNext()) {
2778bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                Map.Entry entry = (Map.Entry)i.next();
2779bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue())
2780bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                             + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", ");
2781bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            }
2782bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
2783ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
2784ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
27859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Thread that handles native AudioSystem control. */
27869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class AudioSystemThread extends Thread {
27879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        AudioSystemThread() {
27889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super("AudioService");
27899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
27929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
27939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Set this thread up so the handler will work on it
27949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Looper.prepare();
27959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized(AudioService.this) {
27979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAudioHandler = new AudioHandler();
27989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Notify that the handler has been created
28009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                AudioService.this.notify();
28019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
28029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Listen for volume change requests that are set by VolumePanel
28049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Looper.loop();
28059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
28069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
28079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Handles internal volume messages in separate volume thread. */
28099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class AudioHandler extends Handler {
28109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28119bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private void setDeviceVolume(VolumeStreamState streamState, int device) {
28129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Apply volume
28149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            streamState.applyDeviceVolume(device);
2815a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
2816a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            // Apply change to all streams using this one as alias
2817a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            int numStreamTypes = AudioSystem.getNumStreamTypes();
2818a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
2819a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                if (streamType != streamState.mStreamType &&
28206d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
28216d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    mStreamStates[streamType].applyDeviceVolume(getDeviceForStream(streamType));
2822a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
2823a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
28249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Post a persist volume msg
2826afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            sendMsg(mAudioHandler,
2827afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    MSG_PERSIST_VOLUME,
282898ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent                    SENDMSG_QUEUE,
2829afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    PERSIST_CURRENT|PERSIST_LAST_AUDIBLE,
28309bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    device,
2831afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    streamState,
2832afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    PERSIST_DELAY);
2833afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent
28349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
28359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28369bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private void setAllVolumes(VolumeStreamState streamState) {
28379bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
28389bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Apply volume
28399bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            streamState.applyAllVolumes();
28409bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
28419bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Apply change to all streams using this one as alias
28429bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            int numStreamTypes = AudioSystem.getNumStreamTypes();
28439bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
28449bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                if (streamType != streamState.mStreamType &&
28456d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
28469bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    mStreamStates[streamType].applyAllVolumes();
28479bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                }
28489bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
28499bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
28509bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
2851afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        private void persistVolume(VolumeStreamState streamState,
28529bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                   int persistType,
28539bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                   int device) {
2854afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            if ((persistType & PERSIST_CURRENT) != 0) {
28559bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                System.putInt(mContentResolver,
28569bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                          streamState.getSettingNameForDevice(false /* lastAudible */, device),
28579bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                          (streamState.getIndex(device, false /* lastAudible */) + 5)/ 10);
285831951ca52aa007891b0be975318199e207c70e02Eric Laurent            }
2859afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            if ((persistType & PERSIST_LAST_AUDIBLE) != 0) {
28609bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                System.putInt(mContentResolver,
28619bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        streamState.getSettingNameForDevice(true /* lastAudible */, device),
28629bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        (streamState.getIndex(device, true  /* lastAudible */) + 5) / 10);
286331951ca52aa007891b0be975318199e207c70e02Eric Laurent            }
28649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
28659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2866ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        private void persistRingerMode(int ringerMode) {
2867ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            System.putInt(mContentResolver, System.MODE_RINGER, ringerMode);
28689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
28699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private void playSoundEffect(int effectType, int volume) {
28719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mSoundEffectsLock) {
28729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSoundPool == null) {
28739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return;
28749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2875a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                float volFloat;
287625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                // use default if volume is not specified by caller
2877a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                if (volume < 0) {
287825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    volFloat = (float)Math.pow(10, SOUND_EFFECT_VOLUME_DB/20);
2879a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                } else {
2880a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                    volFloat = (float) volume / 1000.0f;
2881a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                }
28829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
2884a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], volFloat, volFloat, 0, 0, 1.0f);
28859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
28869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MediaPlayer mediaPlayer = new MediaPlayer();
288762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    try {
288862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effectType][0]];
288962b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setDataSource(filePath);
289062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
289162b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.prepare();
289262b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setVolume(volFloat, volFloat);
289362b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
289462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            public void onCompletion(MediaPlayer mp) {
289562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                cleanupPlayer(mp);
289662b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            }
289762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        });
289862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setOnErrorListener(new OnErrorListener() {
289962b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            public boolean onError(MediaPlayer mp, int what, int extra) {
290062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                cleanupPlayer(mp);
290162b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                return true;
290262b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            }
290362b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        });
290462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.start();
290562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IOException ex) {
290662b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IOException: "+ex);
290762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IllegalArgumentException ex) {
290862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
290962b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IllegalStateException ex) {
291062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
29119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
29129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
29139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
29149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
29159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2916f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        private void onHandlePersistMediaButtonReceiver(ComponentName receiver) {
2917d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi            Settings.System.putString(mContentResolver, Settings.System.MEDIA_BUTTON_RECEIVER,
2918d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    receiver == null ? "" : receiver.flattenToString());
2919d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        }
2920d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
29219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private void cleanupPlayer(MediaPlayer mp) {
29229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mp != null) {
29239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
29249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mp.stop();
29259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mp.release();
29269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (IllegalStateException ex) {
29279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
29289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
29299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
29309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
29319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2932fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        private void setForceUse(int usage, int config) {
2933fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent            AudioSystem.setForceUse(usage, config);
2934fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        }
2935fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
29369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
29379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
29389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2939afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            switch (msg.what) {
29409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29419bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                case MSG_SET_DEVICE_VOLUME:
29429bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
29439bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    break;
29449bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
29459bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                case MSG_SET_ALL_VOLUMES:
29469bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    setAllVolumes((VolumeStreamState) msg.obj);
29479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
29489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PERSIST_VOLUME:
29509bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    persistVolume((VolumeStreamState) msg.obj, msg.arg1, msg.arg2);
29519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
29529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29535c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                case MSG_PERSIST_MASTER_VOLUME:
29545c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                    Settings.System.putFloat(mContentResolver, Settings.System.VOLUME_MASTER,
29555c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                            (float)msg.arg1 / (float)1000.0);
29565c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                    break;
29575c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
295857978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                case MSG_PERSIST_MASTER_VOLUME_MUTE:
295957978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                    Settings.System.putInt(mContentResolver, Settings.System.VOLUME_MASTER_MUTE,
296057978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                            msg.arg1);
296157978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                    break;
296257978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh
29639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PERSIST_RINGER_MODE:
2964ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    // note that the value persisted is the current ringer mode, not the
2965ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    // value of ringer mode as of the time the request was made to persist
2966ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    persistRingerMode(getRingerMode());
29679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
29689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_MEDIA_SERVER_DIED:
297089e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                    if (!mMediaServerOk) {
297189e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                        Log.e(TAG, "Media server died.");
2972a25c5d88d17f251262307ce31e799c9cf361d145Eric Laurent                        // Force creation of new IAudioFlinger interface so that we are notified
2973a25c5d88d17f251262307ce31e799c9cf361d145Eric Laurent                        // when new media_server process is back to life.
2974a25c5d88d17f251262307ce31e799c9cf361d145Eric Laurent                        AudioSystem.setErrorCallback(mAudioSystemCallback);
2975afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
297689e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                                null, 500);
297789e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                    }
29789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
29799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_MEDIA_SERVER_STARTED:
29819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.e(TAG, "Media server started.");
29823c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // indicate to audio HAL that we start the reconfiguration phase after a media
29833c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // server crash
29843c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // Note that MSG_MEDIA_SERVER_STARTED message is only received when the media server
29853c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // process restarts after a crash, not the first time it is started.
29863c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    AudioSystem.setParameters("restarting=true");
29873c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent
2988c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore device connection states
29896bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mConnectedDevices) {
29906bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        Set set = mConnectedDevices.entrySet();
29916bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        Iterator i = set.iterator();
29929bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        while (i.hasNext()) {
29936bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            Map.Entry device = (Map.Entry)i.next();
29946bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            AudioSystem.setDeviceConnectionState(
29956bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            ((Integer)device.getKey()).intValue(),
29966bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            AudioSystem.DEVICE_STATE_AVAILABLE,
29976bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            (String)device.getValue());
29986bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
2999c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    }
3000c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore call state
3001c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    AudioSystem.setPhoneState(mMode);
3002c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
3003d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    // Restore forced usage for communcations and record
3004c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
3005d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
3006c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
3007a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    // Restore stream volumes
30089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int numStreamTypes = AudioSystem.getNumStreamTypes();
30099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
30109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        VolumeStreamState streamState = mStreamStates[streamType];
3011c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                        AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
30129bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
30139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        streamState.applyAllVolumes();
30149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
3015c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
3016c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore ringer mode
3017c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    setRingerModeInt(getRingerMode(), false);
30183c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent
30199063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                    // Restore master volume
30209063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                    restoreMasterVolume();
30219063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood
3022f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                    // Reset device orientation (if monitored for this device)
3023f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                    if (SystemProperties.getBoolean("ro.audio.monitorOrientation", false)) {
3024f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                        setOrientationForAudioSystem();
3025f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                    }
3026f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
30277847211fb4699bf6018e29d214a918ed6657319bEric Laurent                    synchronized (mBluetoothA2dpEnabledLock) {
30287847211fb4699bf6018e29d214a918ed6657319bEric Laurent                        AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
30297847211fb4699bf6018e29d214a918ed6657319bEric Laurent                                mBluetoothA2dpEnabled ?
30307847211fb4699bf6018e29d214a918ed6657319bEric Laurent                                        AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
30317847211fb4699bf6018e29d214a918ed6657319bEric Laurent                    }
30323c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // indicate the end of reconfiguration phase to audio HAL
30333c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    AudioSystem.setParameters("restarting=false");
30349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
30359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3036117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                case MSG_LOAD_SOUND_EFFECTS:
3037117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    loadSoundEffects();
3038117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    break;
3039117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent
30409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PLAY_SOUND_EFFECT:
30419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    playSoundEffect(msg.arg1, msg.arg2);
30429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
30434c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
30444c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                case MSG_BTA2DP_DOCK_TIMEOUT:
30454c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                    // msg.obj  == address of BTA2DP device
30466bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mConnectedDevices) {
30476bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableNow( (String) msg.obj );
30486bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
30494c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                    break;
3050fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
3051fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                case MSG_SET_FORCE_USE:
3052fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                    setForceUse(msg.arg1, msg.arg2);
3053fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                    break;
3054d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
3055d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                case MSG_PERSIST_MEDIABUTTONRECEIVER:
3056f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                    onHandlePersistMediaButtonReceiver( (ComponentName) msg.obj );
3057d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    break;
3058dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
30598f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                case MSG_RCDISPLAY_CLEAR:
30604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    onRcDisplayClear();
30618f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                    break;
30628f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
30638f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                case MSG_RCDISPLAY_UPDATE:
30644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    // msg.obj is guaranteed to be non null
30654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    onRcDisplayUpdate( (RemoteControlStackEntry) msg.obj, msg.arg1);
30668f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                    break;
30678f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
3068dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                case MSG_BT_HEADSET_CNCT_FAILED:
3069dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    resetBluetoothSco();
3070dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    break;
3071b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3072b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
3073b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
30742d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi                    mMediaEventWakeLock.release();
3075b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    break;
3076b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3077b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                case MSG_SET_A2DP_CONNECTION_STATE:
3078b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    onSetA2dpConnectionState((BluetoothDevice)msg.obj, msg.arg1);
30792d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi                    mMediaEventWakeLock.release();
3080b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    break;
3081632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
3082632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                case MSG_REPORT_NEW_ROUTES: {
3083632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    int N = mRoutesObservers.beginBroadcast();
3084632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (N > 0) {
3085632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        AudioRoutesInfo routes;
3086632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        synchronized (mCurAudioRoutes) {
3087632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            routes = new AudioRoutesInfo(mCurAudioRoutes);
3088632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        }
3089632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        while (N > 0) {
3090632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            N--;
3091632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
3092632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            try {
3093632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                obs.dispatchAudioRoutesChanged(routes);
3094632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            } catch (RemoteException e) {
3095632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            }
3096632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        }
3097632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
3098632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    mRoutesObservers.finishBroadcast();
3099632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    break;
3100632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
31013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
31023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case MSG_REEVALUATE_REMOTE:
31033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    onReevaluateRemote();
31043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
3105f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi
3106f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                case MSG_RCC_NEW_PLAYBACK_INFO:
3107f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                    onNewPlaybackInfoForRcc(msg.arg1 /* rccId */, msg.arg2 /* key */,
3108f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                            ((Integer)msg.obj).intValue() /* value */);
3109f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                    break;
3110f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                case MSG_RCC_NEW_VOLUME_OBS:
3111f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                    onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */,
3112f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                            (IRemoteVolumeObserver)msg.obj /* rvo */);
3113f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                    break;
31149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
31159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
31169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
31179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3118b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    private class SettingsObserver extends ContentObserver {
3119a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
3120b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        SettingsObserver() {
3121b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            super(new Handler());
3122b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            mContentResolver.registerContentObserver(Settings.System.getUriFor(
3123b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh                Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
3124b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
3125b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh
3126b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        @Override
3127b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        public void onChange(boolean selfChange) {
3128b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            super.onChange(selfChange);
3129ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
3130ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       However there appear to be some missing locks around mRingerModeMutedStreams
3131ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       and mRingerModeAffectedStreams, so will leave this synchronized for now.
3132ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
3133a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            synchronized (mSettingsLock) {
3134a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                int ringerModeAffectedStreams = Settings.System.getInt(mContentResolver,
3135c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent                       Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3136c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent                       ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
3137c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent                       (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)));
3138c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent                if (mVoiceCapable) {
3139c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent                    ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
3140c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent                } else {
3141402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent                    ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
3142402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent                }
3143a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3144a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    /*
3145a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     * Ensure all stream types that should be affected by ringer mode
3146a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     * are in the proper state.
3147a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     */
3148a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    mRingerModeAffectedStreams = ringerModeAffectedStreams;
3149a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    setRingerModeInt(getRingerMode(), false);
3150a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
3151a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
3152b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
3153b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    }
3154a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
31556bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
31564c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceAvailable(String address) {
31577847211fb4699bf6018e29d214a918ed6657319bEric Laurent        // enable A2DP before notifying A2DP connection to avoid unecessary processing in
31587847211fb4699bf6018e29d214a918ed6657319bEric Laurent        // audio policy manager
31597847211fb4699bf6018e29d214a918ed6657319bEric Laurent        setBluetoothA2dpOnInt(true);
31604c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
31614c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                AudioSystem.DEVICE_STATE_AVAILABLE,
31624c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
31634c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // Reset A2DP suspend state each time a new sink is connected
31644c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setParameters("A2dpSuspended=false");
31654c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
31664c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
31674c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
31684c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
31699841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood    private void sendBecomingNoisyIntent() {
31709841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood        mContext.sendBroadcast(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
31719841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood    }
31729841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood
31736bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
31744c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceUnavailableNow(String address) {
31754c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
31764c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                AudioSystem.DEVICE_STATE_UNAVAILABLE,
31774c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
31784c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
31794c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
31804c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
31816bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
31824c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceUnavailableLater(String address) {
31833b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        // prevent any activity on the A2DP audio output to avoid unwanted
31843b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        // reconnection of the sink.
31853b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        AudioSystem.setParameters("A2dpSuspended=true");
31864c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // the device will be made unavailable later, so consider it disconnected right away
31874c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
31884c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // send the delayed message to make the device unavailable later
31894c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
31904c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
31914c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
31924c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
31934c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
31946bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
3195a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private void cancelA2dpDeviceTimeout() {
31964c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
31974c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
31984c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
31996bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
3200a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private boolean hasScheduledA2dpDockTimeout() {
3201a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi        return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
3202a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    }
3203a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi
3204b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private void onSetA2dpConnectionState(BluetoothDevice btDevice, int state)
32056bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    {
32066bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        if (btDevice == null) {
32076bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            return;
32086bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
32096bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        String address = btDevice.getAddress();
32106bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
32116bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            address = "";
32126bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
32136bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        synchronized (mConnectedDevices) {
32146bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            boolean isConnected =
32156bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
32166bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
32176bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
32186bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
32196bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                if (btDevice.isBluetoothDock()) {
32206bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (state == BluetoothProfile.STATE_DISCONNECTED) {
32216bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // introduction of a delay for transient disconnections of docks when
32226bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // power is rapidly turned off/on, this message will be canceled if
32236bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // we reconnect the dock under a preset delay
32246bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableLater(address);
32256bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // the next time isConnected is evaluated, it will be false for the dock
32266bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
32276bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                } else {
32286bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    makeA2dpDeviceUnavailableNow(address);
32296bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
3230632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                synchronized (mCurAudioRoutes) {
3231632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (mCurAudioRoutes.mBluetoothName != null) {
3232632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        mCurAudioRoutes.mBluetoothName = null;
3233632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3234632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                SENDMSG_NOOP, 0, 0, null, 0);
3235632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
3236632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
32376bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
32386bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                if (btDevice.isBluetoothDock()) {
32396bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // this could be a reconnection after a transient disconnection
32406bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    cancelA2dpDeviceTimeout();
32416bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mDockAddress = address;
32426bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                } else {
32436bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // this could be a connection of another A2DP device before the timeout of
32446bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // a dock: cancel the dock timeout, and make the dock unavailable now
32456bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if(hasScheduledA2dpDockTimeout()) {
32466bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        cancelA2dpDeviceTimeout();
32476bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableNow(mDockAddress);
32486bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
32496bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
32506bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                makeA2dpDeviceAvailable(address);
3251632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                synchronized (mCurAudioRoutes) {
3252632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    String name = btDevice.getAliasName();
3253632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
3254632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        mCurAudioRoutes.mBluetoothName = name;
3255632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3256632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                SENDMSG_NOOP, 0, 0, null, 0);
3257632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
3258632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
32596bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            }
32606bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
32616bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    }
32626bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
326359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent    private boolean handleDeviceConnection(boolean connected, int device, String params) {
326459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        synchronized (mConnectedDevices) {
326559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            boolean isConnected = (mConnectedDevices.containsKey(device) &&
32669841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                    (params.isEmpty() || mConnectedDevices.get(device).equals(params)));
326759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent
326859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            if (isConnected && !connected) {
326959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                AudioSystem.setDeviceConnectionState(device,
327059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                              AudioSystem.DEVICE_STATE_UNAVAILABLE,
32719841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                                              mConnectedDevices.get(device));
327259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 mConnectedDevices.remove(device);
327359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 return true;
327459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            } else if (!isConnected && connected) {
327559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 AudioSystem.setDeviceConnectionState(device,
327659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                                      AudioSystem.DEVICE_STATE_AVAILABLE,
327759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                                      params);
327859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 mConnectedDevices.put(new Integer(device), params);
327959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 return true;
328059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            }
328159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        }
328259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        return false;
328359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent    }
328459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent
3285b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
3286b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // sent if none of these devices is connected.
3287b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    int mBecomingNoisyIntentDevices =
3288b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
3289b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            AudioSystem.DEVICE_OUT_ALL_A2DP;
3290b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3291b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // must be called before removing the device from mConnectedDevices
3292b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private int checkSendBecomingNoisyIntent(int device, int state) {
3293b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        int delay = 0;
3294b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
3295b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            int devices = 0;
3296b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            for (int dev : mConnectedDevices.keySet()) {
3297b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                if ((dev & mBecomingNoisyIntentDevices) != 0) {
3298b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                   devices |= dev;
3299b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                }
3300b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
3301b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            if (devices == device) {
3302b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                delay = 1000;
3303b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                sendBecomingNoisyIntent();
3304b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
3305b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
3306b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3307b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        if (mAudioHandler.hasMessages(MSG_SET_A2DP_CONNECTION_STATE) ||
3308b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
3309b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            delay = 1000;
3310b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
3311b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        return delay;
3312b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
3313b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3314b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private void sendDeviceConnectionIntent(int device, int state, String name)
3315b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
3316b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        Intent intent = new Intent();
3317b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3318b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.putExtra("state", state);
3319b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.putExtra("name", name);
3320b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
3321b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3322632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        int connType = 0;
3323632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
3324b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
3325632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HEADSET;
3326b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_HEADSET_PLUG);
3327b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.putExtra("microphone", 1);
3328b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) {
3329632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HEADPHONES;
3330b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_HEADSET_PLUG);
3331b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.putExtra("microphone", 0);
3332b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
3333632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
3334b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
3335b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
3336632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
3337b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
3338b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_AUX_DIGITAL) {
3339632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HDMI;
3340b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);
3341b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
3342b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3343632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        synchronized (mCurAudioRoutes) {
3344632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            if (connType != 0) {
3345632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                int newConn = mCurAudioRoutes.mMainType;
3346632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                if (state != 0) {
3347632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    newConn |= connType;
3348632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                } else {
3349632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    newConn &= ~connType;
3350632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
3351632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                if (newConn != mCurAudioRoutes.mMainType) {
3352632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    mCurAudioRoutes.mMainType = newConn;
3353632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3354632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            SENDMSG_NOOP, 0, 0, null, 0);
3355632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
3356632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            }
3357632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        }
3358632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
3359b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        ActivityManagerNative.broadcastStickyIntent(intent, null);
3360b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
3361b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3362b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private void onSetWiredDeviceConnectionState(int device, int state, String name)
3363b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
3364b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
3365b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
3366b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) {
3367b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                setBluetoothA2dpOnInt(true);
3368b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
3369b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            handleDeviceConnection((state == 1), device, "");
3370b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            if ((state != 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
3371b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) {
3372b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                setBluetoothA2dpOnInt(false);
3373b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
3374b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            sendDeviceConnectionIntent(device, state, name);
3375b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
3376b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
3377b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3378a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    /* cache of the address of the last dock the device was connected to */
3379a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private String mDockAddress;
3380a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi
3381a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    /**
3382a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     * Receiver for misc intent broadcasts the Phone app cares about.
3383a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     */
3384a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
3385a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        @Override
3386a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        public void onReceive(Context context, Intent intent) {
3387a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            String action = intent.getAction();
338859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            int device;
338959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            int state;
3390a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
3391758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi            if (action.equals(Intent.ACTION_DOCK_EVENT)) {
3392758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
3393758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
3394758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                int config;
3395758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                switch (dockState) {
3396758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_DESK:
3397758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_BT_DESK_DOCK;
3398758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        break;
3399758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_CAR:
3400758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_BT_CAR_DOCK;
3401758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        break;
340221e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                    case Intent.EXTRA_DOCK_STATE_LE_DESK:
340321e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        config = AudioSystem.FORCE_ANALOG_DOCK;
340421e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        break;
340521e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                    case Intent.EXTRA_DOCK_STATE_HE_DESK:
340621e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        config = AudioSystem.FORCE_DIGITAL_DOCK;
340721e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        break;
3408758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_UNDOCKED:
3409758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    default:
3410758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_NONE;
3411758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                }
3412758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
341382aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh            } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
341459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
341582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh                                               BluetoothProfile.STATE_DISCONNECTED);
341659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
3417a56d1c72190462aa9e377906583eceb58e0efcddNick Pelly                String address = null;
3418dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent
3419dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
3420dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (btDevice == null) {
3421dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    return;
3422dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                }
3423dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent
3424dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                address = btDevice.getAddress();
3425dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                BluetoothClass btClass = btDevice.getBluetoothClass();
3426dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (btClass != null) {
3427dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    switch (btClass.getDeviceClass()) {
3428dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
3429dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
3430dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                        device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
3431dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                        break;
3432dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
3433dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                        device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
3434dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                        break;
3435d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    }
3436d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                }
3437d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent
3438dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (!BluetoothAdapter.checkBluetoothAddress(address)) {
3439dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    address = "";
3440dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                }
3441d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent
344259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
344359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                if (handleDeviceConnection(connected, device, address)) {
34446bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mScoClients) {
344559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        if (connected) {
344659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                            mBluetoothHeadsetDevice = btDevice;
344759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        } else {
34486bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mBluetoothHeadsetDevice = null;
34496bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            resetBluetoothSco();
34506bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
345162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    }
3452a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
345359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ||
345459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                           action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
345559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                state = intent.getIntExtra("state", 0);
345659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int alsaCard = intent.getIntExtra("card", -1);
345759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int alsaDevice = intent.getIntExtra("device", -1);
34589841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
34599841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                                    : "card=" + alsaCard + ";device=" + alsaDevice);
346059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                device = action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
346159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE;
346259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                Log.v(TAG, "Broadcast Receiver: Got "
346359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        + (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
346459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                              "ACTION_USB_AUDIO_ACCESSORY_PLUG" : "ACTION_USB_AUDIO_DEVICE_PLUG")
346559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        + ", state = " + state + ", card: " + alsaCard + ", device: " + alsaDevice);
346659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                handleDeviceConnection((state == 1), device, params);
34673def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
346862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                boolean broadcast = false;
346959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
34703def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                synchronized (mScoClients) {
347162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
3472dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // broadcast intent if the connection was initated by AudioService
3473dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (!mScoClients.isEmpty() &&
3474dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
3475dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                             mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
3476dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                             mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
347762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        broadcast = true;
347862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    }
347962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    switch (btState) {
348062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_CONNECTED:
348159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
3482dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
3483dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
3484dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
348562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
34863def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        }
348762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
348862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
348959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
349062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        mScoAudioState = SCO_STATE_INACTIVE;
3491d7454be47f4111c0478a502353e11dea401378bdEric Laurent                        clearAllScoClients(0, false);
349262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
349362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_CONNECTING:
3494dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
3495dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
3496dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
349762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
34983def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        }
349962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    default:
350062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        // do not broadcast CONNECTING or invalid state
350162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        broadcast = false;
350262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
35033def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
35043def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
350562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                if (broadcast) {
350659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                    broadcastScoConnectionState(scoAudioState);
3507dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    //FIXME: this is to maintain compatibility with deprecated intent
3508dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
350962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
351059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                    newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
351162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    mContext.sendStickyBroadcast(newIntent);
351262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                }
351362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent            } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
3514a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mBootCompleted = true;
3515afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_NOOP,
3516117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                        0, 0, null, 0);
3517dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
35186243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani                mKeyguardManager =
35196243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani                        (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
3520dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
3521dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                resetBluetoothSco();
3522dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                getBluetoothHeadset();
3523dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                //FIXME: this is to maintain compatibility with deprecated intent
3524dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
352562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
352662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
352762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
352862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                mContext.sendStickyBroadcast(newIntent);
35296bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
35306bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
35316bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                if (adapter != null) {
35326bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
35336bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                            BluetoothProfile.A2DP);
35346bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
3535d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi            } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
3536d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
3537d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    // a package is being removed, not replaced
3538d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    String packageName = intent.getData().getSchemeSpecificPart();
3539d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    if (packageName != null) {
3540d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                        removeMediaButtonReceiverForPackage(packageName);
3541d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    }
3542d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                }
3543950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent            } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
3544950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent                AudioSystem.setParameters("screen_state=on");
3545950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
3546950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent                AudioSystem.setParameters("screen_state=off");
3547f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            } else if (action.equalsIgnoreCase(Intent.ACTION_CONFIGURATION_CHANGED)) {
3548f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                handleConfigurationChanged(context);
3549a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
3550a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        }
3551a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    }
3552d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3553d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    //==========================================================================================
3554d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    // AudioFocus
3555d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    //==========================================================================================
3556b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi
3557b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi    /* constant to identify focus stack entry that is used to hold the focus while the phone
35584dd3674e517051f130fef36d2eb201c68ff61094Jean-Michel Trivi     * is ringing or during a call. Used by com.android.internal.telephony.CallManager when
35594dd3674e517051f130fef36d2eb201c68ff61094Jean-Michel Trivi     * entering and exiting calls.
3560e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi     */
35614dd3674e517051f130fef36d2eb201c68ff61094Jean-Michel Trivi    public final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";
3562e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi
3563392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi    private final static Object mAudioFocusLock = new Object();
3564392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi
3565e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi    private final static Object mRingingLock = new Object();
3566e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi
3567b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
3568b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi        @Override
3569b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi        public void onCallStateChanged(int state, String incomingNumber) {
3570b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi            if (state == TelephonyManager.CALL_STATE_RINGING) {
3571b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi                //Log.v(TAG, " CALL_STATE_RINGING");
3572e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi                synchronized(mRingingLock) {
3573e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi                    mIsRinging = true;
3574e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi                }
35752ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi            } else if ((state == TelephonyManager.CALL_STATE_OFFHOOK)
35762ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi                    || (state == TelephonyManager.CALL_STATE_IDLE)) {
3577e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi                synchronized(mRingingLock) {
3578e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi                    mIsRinging = false;
3579e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi                }
3580e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi            }
3581e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi        }
3582b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi    };
3583e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi
3584e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi    private void notifyTopOfAudioFocusStack() {
3585e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi        // notify the top of the stack it gained focus
3586e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi        if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
3587e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi            if (canReassignAudioFocus()) {
3588e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                try {
3589e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                    mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange(
3590e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                            AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId);
3591e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                } catch (RemoteException e) {
3592e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                    Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e);
3593e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                    e.printStackTrace();
3594e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                }
3595e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi            }
3596e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi        }
3597e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi    }
3598e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi
3599d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    private static class FocusStackEntry {
3600d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        public int mStreamType = -1;// no stream type
3601d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        public IAudioFocusDispatcher mFocusDispatcher = null;
3602d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        public IBinder mSourceRef = null;
3603d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        public String mClientId;
3604078fd47e91d495175927d1a4a8b9aad039a7ba4eJean-Michel Trivi        public int mFocusChangeType;
3605061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi        public AudioFocusDeathHandler mHandler;
36068f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        public String mPackageName;
36078f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        public int mCallingUid;
3608d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3609d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        public FocusStackEntry() {
3610d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        }
3611d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
36128f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        public FocusStackEntry(int streamType, int duration,
3613061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi                IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr,
3614061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi                String pn, int uid) {
3615d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            mStreamType = streamType;
3616d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            mFocusDispatcher = afl;
3617d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            mSourceRef = source;
3618d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            mClientId = id;
3619078fd47e91d495175927d1a4a8b9aad039a7ba4eJean-Michel Trivi            mFocusChangeType = duration;
3620061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi            mHandler = hdlr;
36218f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            mPackageName = pn;
36228f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            mCallingUid = uid;
3623d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        }
3624061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi
3625e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi        public void unlinkToDeath() {
3626e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi            try {
3627e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi                if (mSourceRef != null && mHandler != null) {
3628e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi                    mSourceRef.unlinkToDeath(mHandler, 0);
3629e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi                    mHandler = null;
3630e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi                }
3631e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi            } catch (java.util.NoSuchElementException e) {
3632e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi                Log.e(TAG, "Encountered " + e + " in FocusStackEntry.unlinkToDeath()");
3633061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi            }
3634061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi        }
3635de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi
3636de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi        @Override
3637de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi        protected void finalize() throws Throwable {
3638e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi            unlinkToDeath(); // unlink exception handled inside method
3639e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi            super.finalize();
3640de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi        }
3641d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
3642d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
364330c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>();
3644d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3645d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    /**
3646d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * Helper function:
3647d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * Display in the log the current entries in the audio focus stack
3648d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     */
3649d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    private void dumpFocusStack(PrintWriter pw) {
3650b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi        pw.println("\nAudio Focus stack entries:");
3651392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi        synchronized(mAudioFocusLock) {
3652d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
3653d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            while(stackIterator.hasNext()) {
3654d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                FocusStackEntry fse = stackIterator.next();
3655d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                pw.println("     source:" + fse.mSourceRef + " -- client: " + fse.mClientId
36568f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        + " -- duration: " + fse.mFocusChangeType
36578f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        + " -- uid: " + fse.mCallingUid);
3658d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            }
3659d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        }
3660d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
3661d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3662d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    /**
3663d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * Helper function:
36648f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Called synchronized on mAudioFocusLock
3665d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * Remove a focus listener from the focus stack.
3666d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * @param focusListenerToRemove the focus listener
3667d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding
3668d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     *   focus, notify the next item in the stack it gained focus.
3669d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     */
3670d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    private void removeFocusStackEntry(String clientToRemove, boolean signal) {
3671e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi        // is the current top of the focus stack abandoning focus? (because of request, not death)
3672d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientToRemove))
3673d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        {
3674d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            //Log.i(TAG, "   removeFocusStackEntry() removing top of stack");
3675e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi            FocusStackEntry fse = mFocusStack.pop();
3676e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi            fse.unlinkToDeath();
3677d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            if (signal) {
3678d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                // notify the new top of the stack it gained focus
3679e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                notifyTopOfAudioFocusStack();
36808f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                // there's a new top of the stack, let the remote control know
36818f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                synchronized(mRCStack) {
3682b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
36838f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                }
3684d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            }
3685d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        } else {
3686d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            // focus is abandoned by a client that's not at the top of the stack,
3687d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            // no need to update focus.
3688d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
3689d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            while(stackIterator.hasNext()) {
3690d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
3691d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                if(fse.mClientId.equals(clientToRemove)) {
3692d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                    Log.i(TAG, " AudioFocus  abandonAudioFocus(): removing entry for "
3693d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                            + fse.mClientId);
369472843377d50a8f95cceaf33d316ab68d9b47f2ebJean-Michel Trivi                    stackIterator.remove();
3695e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi                    fse.unlinkToDeath();
3696d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                }
3697d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            }
3698d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        }
3699d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
3700d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3701d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    /**
3702d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * Helper function:
37038f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Called synchronized on mAudioFocusLock
3704e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi     * Remove focus listeners from the focus stack for a particular client when it has died.
3705d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     */
3706d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    private void removeFocusStackEntryForClient(IBinder cb) {
3707e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi        // is the owner of the audio focus part of the client to remove?
3708e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi        boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() &&
3709e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                mFocusStack.peek().mSourceRef.equals(cb);
3710d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
3711d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        while(stackIterator.hasNext()) {
3712d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
3713d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            if(fse.mSourceRef.equals(cb)) {
3714d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                Log.i(TAG, " AudioFocus  abandonAudioFocus(): removing entry for "
3715d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                        + fse.mClientId);
371672843377d50a8f95cceaf33d316ab68d9b47f2ebJean-Michel Trivi                stackIterator.remove();
3717e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi                // the client just died, no need to unlink to its death
3718d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            }
3719d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        }
3720e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi        if (isTopOfStackForClientToRemove) {
3721e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi            // we removed an entry at the top of the stack:
3722e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi            //  notify the new top of the stack it gained focus.
3723e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi            notifyTopOfAudioFocusStack();
37248f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            // there's a new top of the stack, let the remote control know
37258f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            synchronized(mRCStack) {
3726b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
37278f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            }
3728e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi        }
3729d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
3730d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3731d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    /**
3732d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * Helper function:
3733d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * Returns true if the system is in a state where the focus can be reevaluated, false otherwise.
3734d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     */
3735d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    private boolean canReassignAudioFocus() {
3736b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi        // focus requests are rejected during a phone call or when the phone is ringing
3737b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi        // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
3738b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi        if (!mFocusStack.isEmpty() && IN_VOICE_COMM_FOCUS_ID.equals(mFocusStack.peek().mClientId)) {
3739d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            return false;
3740d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        }
3741d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        return true;
3742d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
3743d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3744d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    /**
3745d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * Inner class to monitor audio focus client deaths, and remove them from the audio focus
3746d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * stack if necessary.
3747d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     */
3748d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    private class AudioFocusDeathHandler implements IBinder.DeathRecipient {
3749d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        private IBinder mCb; // To be notified of client's death
3750d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3751d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        AudioFocusDeathHandler(IBinder cb) {
3752d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            mCb = cb;
3753d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        }
3754d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3755d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        public void binderDied() {
3756392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            synchronized(mAudioFocusLock) {
3757d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                Log.w(TAG, "  AudioFocus   audio focus client died");
3758d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                removeFocusStackEntryForClient(mCb);
3759d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            }
3760d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        }
3761d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3762d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        public IBinder getBinder() {
3763d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            return mCb;
3764d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        }
3765d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
3766d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3767d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3768d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    /** @see AudioManager#requestAudioFocus(IAudioFocusDispatcher, int, int) */
3769078fd47e91d495175927d1a4a8b9aad039a7ba4eJean-Michel Trivi    public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb,
37708f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
3771d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        Log.i(TAG, " AudioFocus  requestAudioFocus() from " + clientId);
3772d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        // the main stream type for the audio focus request is currently not used. It may
3773d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        // potentially be used to handle multiple stream type-dependent audio focuses.
3774d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3775382f4e6ea4dcf39105b36364582ed01642daa93cJean-Michel Trivi        // we need a valid binder callback for clients
3776382f4e6ea4dcf39105b36364582ed01642daa93cJean-Michel Trivi        if (!cb.pingBinder()) {
3777382f4e6ea4dcf39105b36364582ed01642daa93cJean-Michel Trivi            Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
3778d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
3779d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        }
3780d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3781392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi        synchronized(mAudioFocusLock) {
3782392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            if (!canReassignAudioFocus()) {
3783392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
3784392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            }
3785d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3786baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi            // handle the potential premature death of the new holder of the focus
3787baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi            // (premature death == death before abandoning focus)
3788baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi            // Register for client death notification
3789baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi            AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
3790baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi            try {
3791baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi                cb.linkToDeath(afdh, 0);
3792baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi            } catch (RemoteException e) {
3793baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi                // client has already died!
3794baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi                Log.w(TAG, "AudioFocus  requestAudioFocus() could not link to "+cb+" binder death");
3795baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
3796baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi            }
3797baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi
3798d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) {
3799e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                // if focus is already owned by this client and the reason for acquiring the focus
3800e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                // hasn't changed, don't do anything
3801e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                if (mFocusStack.peek().mFocusChangeType == focusChangeHint) {
3802de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi                    // unlink death handler so it can be gc'ed.
3803de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi                    // linkToDeath() creates a JNI global reference preventing collection.
3804de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi                    cb.unlinkToDeath(afdh, 0);
3805e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                    return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
3806e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                }
3807e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                // the reason for the audio focus request has changed: remove the current top of
3808e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                // stack and respond as if we had a new focus owner
3809e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi                FocusStackEntry fse = mFocusStack.pop();
3810e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi                fse.unlinkToDeath();
3811d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            }
3812d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3813d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            // notify current top of stack it is losing focus
3814d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
3815d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                try {
3816d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                    mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange(
3817078fd47e91d495175927d1a4a8b9aad039a7ba4eJean-Michel Trivi                            -1 * focusChangeHint, // loss and gain codes are inverse of each other
3818d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                            mFocusStack.peek().mClientId);
3819d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                } catch (RemoteException e) {
3820d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                    Log.e(TAG, " Failure to signal loss of focus due to "+ e);
3821d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                    e.printStackTrace();
3822d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                }
3823d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            }
3824d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
382555d1bb3483e17a11d122e68044e552d96ab55ff4Jean-Michel Trivi            // focus requester might already be somewhere below in the stack, remove it
3826baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi            removeFocusStackEntry(clientId, false /* signal */);
3827061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi
3828d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            // push focus requester at the top of the audio focus stack
38298f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, fd, cb,
3830061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi                    clientId, afdh, callingPackageName, Binder.getCallingUid()));
38318f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
38328f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            // there's a new top of the stack, let the remote control know
38338f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            synchronized(mRCStack) {
3834b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
38358f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            }
3836392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi        }//synchronized(mAudioFocusLock)
3837d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3838d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
3839d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
3840d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3841d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    /** @see AudioManager#abandonAudioFocus(IAudioFocusDispatcher) */
3842d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    public int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) {
3843d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        Log.i(TAG, " AudioFocus  abandonAudioFocus() from " + clientId);
3844392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi        try {
3845392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            // this will take care of notifying the new focus owner if needed
3846392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            synchronized(mAudioFocusLock) {
3847392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi                removeFocusStackEntry(clientId, true);
3848392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            }
3849392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi        } catch (java.util.ConcurrentModificationException cme) {
3850392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            // Catching this exception here is temporary. It is here just to prevent
3851392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            // a crash seen when the "Silent" notification is played. This is believed to be fixed
3852392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            // but this try catch block is left just to be safe.
3853392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            Log.e(TAG, "FATAL EXCEPTION AudioFocus  abandonAudioFocus() caused " + cme);
3854392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            cme.printStackTrace();
38552930bb2d47be279dd228ba8c749c1e39e5da8be1Jean-Michel Trivi        }
3856d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3857d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
3858d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
3859d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3860d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3861d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    public void unregisterAudioFocusClient(String clientId) {
3862392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi        synchronized(mAudioFocusLock) {
38632930bb2d47be279dd228ba8c749c1e39e5da8be1Jean-Michel Trivi            removeFocusStackEntry(clientId, false);
38642930bb2d47be279dd228ba8c749c1e39e5da8be1Jean-Michel Trivi        }
3865d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
3866d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3867d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3868d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    //==========================================================================================
3869d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    // RemoteControl
3870d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    //==========================================================================================
3871c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
38724294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        filterMediaKeyEvent(keyEvent, false /*needWakeLock*/);
3873c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    }
3874c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
3875c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
38764294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        filterMediaKeyEvent(keyEvent, true /*needWakeLock*/);
3877c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    }
3878c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
38794294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    private void filterMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
3880c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        // sanity check on the incoming key event
3881c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        if (!isValidMediaKeyEvent(keyEvent)) {
3882c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            Log.e(TAG, "not dispatching invalid media key event " + keyEvent);
3883c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            return;
3884c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        }
3885722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        // event filtering for telephony
3886c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        synchronized(mRingingLock) {
3887722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi            synchronized(mRCStack) {
3888722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi                if ((mMediaReceiverForCalls != null) &&
3889722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi                        (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL))) {
3890722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi                    dispatchMediaKeyEventForCalls(keyEvent, needWakeLock);
3891722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi                    return;
3892722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi                }
3893d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi            }
3894c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        }
38954294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        // event filtering based on voice-based interactions
38964294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        if (isValidVoiceInputKeyCode(keyEvent.getKeyCode())) {
38974294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            filterVoiceInputKeyEvent(keyEvent, needWakeLock);
38984294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        } else {
38994294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            dispatchMediaKeyEvent(keyEvent, needWakeLock);
39004294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        }
39014294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    }
39024294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
39034294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    /**
3904722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     * Handles the dispatching of the media button events to the telephony package.
3905722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     * Precondition: mMediaReceiverForCalls != null
3906722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
3907722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
3908722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     *     is dispatched.
3909722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     */
3910722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    private void dispatchMediaKeyEventForCalls(KeyEvent keyEvent, boolean needWakeLock) {
3911722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
3912722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
3913722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        keyIntent.setPackage(mMediaReceiverForCalls.getPackageName());
3914722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        if (needWakeLock) {
3915722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi            mMediaEventWakeLock.acquire();
3916722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi            keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
3917722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        }
3918722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        mContext.sendOrderedBroadcast(keyIntent, null, mKeyEventDone,
3919722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi                mAudioHandler, Activity.RESULT_OK, null, null);
3920722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    }
3921722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi
3922722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    /**
39234294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * Handles the dispatching of the media button events to one of the registered listeners,
39244294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * or if there was none, broadcast an ACTION_MEDIA_BUTTON intent to the rest of the system.
39254294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
39264294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
39274294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     *     is dispatched.
39284294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     */
39294294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
3930c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        if (needWakeLock) {
3931c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            mMediaEventWakeLock.acquire();
3932c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        }
3933c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
3934c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
3935c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        synchronized(mRCStack) {
3936c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            if (!mRCStack.empty()) {
3937c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                // send the intent that was registered by the client
3938c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                try {
3939c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                    mRCStack.peek().mMediaIntent.send(mContext,
3940c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                            needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/,
3941c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                            keyIntent, AudioService.this, mAudioHandler);
3942c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                } catch (CanceledException e) {
3943c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                    Log.e(TAG, "Error sending pending intent " + mRCStack.peek());
3944c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                    e.printStackTrace();
3945d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi                }
3946c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            } else {
3947c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                // legacy behavior when nobody registered their media button event receiver
3948c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                //    through AudioManager
3949c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                if (needWakeLock) {
3950c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                    keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
3951d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi                }
3952c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                mContext.sendOrderedBroadcast(keyIntent, null, mKeyEventDone,
3953c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                        mAudioHandler, Activity.RESULT_OK, null, null);
3954d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi            }
3955d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        }
3956d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    }
3957d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
39584294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    /**
3959ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown     * The different actions performed in response to a voice button key event.
39604294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     */
39614294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    private final static int VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS = 1;
39624294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    private final static int VOICEBUTTON_ACTION_START_VOICE_INPUT = 2;
39634294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    private final static int VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS = 3;
39644294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
39654294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    private final Object mVoiceEventLock = new Object();
3966ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown    private boolean mVoiceButtonDown;
3967ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown    private boolean mVoiceButtonHandled;
39684294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
39694294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    /**
39704294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * Filter key events that may be used for voice-based interactions
39714294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * @param keyEvent a non-null KeyEvent whose key code is that of one of the supported
39724294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     *    media buttons that can be used to trigger voice-based interactions.
39734294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
39744294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     *     is dispatched.
39754294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     */
39764294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    private void filterVoiceInputKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
3977ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown        if (DEBUG_RC) {
3978ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown            Log.v(TAG, "voice input key event: " + keyEvent + ", needWakeLock=" + needWakeLock);
3979ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown        }
3980ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown
39814294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        int voiceButtonAction = VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS;
39824294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        int keyAction = keyEvent.getAction();
39834294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        synchronized (mVoiceEventLock) {
3984ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown            if (keyAction == KeyEvent.ACTION_DOWN) {
3985ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                if (keyEvent.getRepeatCount() == 0) {
3986ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                    // initial down
3987ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                    mVoiceButtonDown = true;
3988ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                    mVoiceButtonHandled = false;
3989ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                } else if (mVoiceButtonDown && !mVoiceButtonHandled
3990ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                        && (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
3991ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                    // long-press, start voice-based interactions
3992ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                    mVoiceButtonHandled = true;
3993ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                    voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT;
3994ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                }
3995ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown            } else if (keyAction == KeyEvent.ACTION_UP) {
3996ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                if (mVoiceButtonDown) {
3997ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                    // voice button up
3998ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                    mVoiceButtonDown = false;
3999ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                    if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
4000ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                        voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS;
40014294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                    }
4002ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                }
40034294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            }
40044294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        }//synchronized (mVoiceEventLock)
40054294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
40064294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        // take action after media button event filtering for voice-based interactions
40074294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        switch (voiceButtonAction) {
40084294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            case VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS:
40094294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                if (DEBUG_RC) Log.v(TAG, "   ignore key event");
40104294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                break;
40114294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            case VOICEBUTTON_ACTION_START_VOICE_INPUT:
40124294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                if (DEBUG_RC) Log.v(TAG, "   start voice-based interactions");
40134294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                // then start the voice-based interactions
40144294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                startVoiceBasedInteractions(needWakeLock);
40154294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                break;
40164294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            case VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS:
40174294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                if (DEBUG_RC) Log.v(TAG, "   send simulated key event");
40184294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                sendSimulatedMediaButtonEvent(keyEvent, needWakeLock);
40194294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                break;
40204294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        }
40214294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    }
40224294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
40234294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    private void sendSimulatedMediaButtonEvent(KeyEvent originalKeyEvent, boolean needWakeLock) {
40244294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        // send DOWN event
40254294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        KeyEvent keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_DOWN);
40264294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        dispatchMediaKeyEvent(keyEvent, needWakeLock);
40274294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        // send UP event
40284294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_UP);
40294294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        dispatchMediaKeyEvent(keyEvent, needWakeLock);
40304294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
40314294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    }
40324294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
40334294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
4034c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
4035c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        if (keyEvent == null) {
4036c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            return false;
4037c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        }
4038c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        final int keyCode = keyEvent.getKeyCode();
4039c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        switch (keyCode) {
4040c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MUTE:
4041c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_HEADSETHOOK:
4042c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_PLAY:
4043c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_PAUSE:
4044c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
4045c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_STOP:
4046c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_NEXT:
4047c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
4048c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_REWIND:
4049c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_RECORD:
4050c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
4051c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_CLOSE:
4052c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_EJECT:
4053c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                break;
4054c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            default:
4055c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                return false;
4056c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        }
4057c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        return true;
4058c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    }
4059c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
40604294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    /**
40614294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * Checks whether the given key code is one that can trigger the launch of voice-based
40624294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     *   interactions.
40634294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * @param keyCode the key code associated with the key event
40644294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * @return true if the key is one of the supported voice-based interaction triggers
40654294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     */
40664294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    private static boolean isValidVoiceInputKeyCode(int keyCode) {
40674294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK) {
40684294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            return true;
40694294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        } else {
40704294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            return false;
40714294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        }
40724294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    }
40734294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
40744294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    /**
40754294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * Tell the system to start voice-based interactions / voice commands
40764294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     */
40774294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    private void startVoiceBasedInteractions(boolean needWakeLock) {
40783c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        Intent voiceIntent = null;
40793c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        // select which type of search to launch:
40803c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        // - screen on and device unlocked: action is ACTION_WEB_SEARCH
40813c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        // - device locked or screen off: action is ACTION_VOICE_SEARCH_HANDS_FREE
40823c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        //    with EXTRA_SECURE set to true if the device is securely locked
40833c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
40843c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
40853c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        if (!isLocked && pm.isScreenOn()) {
40863c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi            voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
40873c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        } else {
40883c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi            voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
40893c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi            voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE,
40903c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi                    isLocked && mKeyguardManager.isKeyguardSecure());
40913c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        }
40923c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        // start the search activity
40934294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        if (needWakeLock) {
40944294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            mMediaEventWakeLock.acquire();
40954294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        }
40964294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        try {
40973c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi            if (voiceIntent != null) {
40983c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi                voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
40993c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
41003c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi                mContext.startActivity(voiceIntent);
41014294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            }
41024294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        } catch (ActivityNotFoundException e) {
41033c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi            Log.w(TAG, "No activity for search: " + e);
41044294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        } finally {
41054294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            if (needWakeLock) {
41064294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                mMediaEventWakeLock.release();
41074294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            }
41084294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        }
41094294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    }
41104294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
4111c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    private PowerManager.WakeLock mMediaEventWakeLock;
4112c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
4113c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number
4114c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
4115c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    // only set when wakelock was acquired, no need to check value when received
4116c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    private static final String EXTRA_WAKELOCK_ACQUIRED =
4117c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            "android.media.AudioService.WAKELOCK_ACQUIRED";
4118c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
4119c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    public void onSendFinished(PendingIntent pendingIntent, Intent intent,
4120c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            int resultCode, String resultData, Bundle resultExtras) {
4121c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        if (resultCode == WAKELOCK_RELEASE_ON_FINISHED) {
4122c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            mMediaEventWakeLock.release();
4123c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        }
4124c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    }
4125c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
4126c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
4127c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        public void onReceive(Context context, Intent intent) {
41284294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            if (intent == null) {
41294294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                return;
41304294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            }
41314294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            Bundle extras = intent.getExtras();
41324294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            if (extras == null) {
41334294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                return;
41344294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            }
41354294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)) {
4136c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                mMediaEventWakeLock.release();
4137c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            }
4138c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        }
4139c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    };
4140c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
4141ced110ec5970c632f523dfc0350b6071461ea9bcNeel Parekh    private final Object mCurrentRcLock = new Object();
41428f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    /**
41434426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * The one remote control client which will receive a request for display information.
414417da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi     * This object may be null.
41458f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Access protected by mCurrentRcLock.
41468f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     */
41474426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private IRemoteControlClient mCurrentRcClient = null;
41488f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
41497b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi    private final static int RC_INFO_NONE = 0;
41507b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi    private final static int RC_INFO_ALL =
41514426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        RemoteControlClient.FLAG_INFORMATION_REQUEST_ALBUM_ART |
41524426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        RemoteControlClient.FLAG_INFORMATION_REQUEST_KEY_MEDIA |
41534426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        RemoteControlClient.FLAG_INFORMATION_REQUEST_METADATA |
41544426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        RemoteControlClient.FLAG_INFORMATION_REQUEST_PLAYSTATE;
41557b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi
41567b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi    /**
415717da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi     * A monotonically increasing generation counter for mCurrentRcClient.
41588f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Only accessed with a lock on mCurrentRcLock.
415917da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi     * No value wrap-around issues as we only act on equal values.
41608f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     */
4161ced110ec5970c632f523dfc0350b6071461ea9bcNeel Parekh    private int mCurrentRcClientGen = 0;
41628f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
41638f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    /**
41648f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Inner class to monitor remote control client deaths, and remove the client for the
41658f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * remote control stack if necessary.
41668f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     */
41678f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    private class RcClientDeathHandler implements IBinder.DeathRecipient {
41688f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        private IBinder mCb; // To be notified of client's death
4169f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        private PendingIntent mMediaIntent;
41708f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
4171f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        RcClientDeathHandler(IBinder cb, PendingIntent pi) {
41728f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            mCb = cb;
4173f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            mMediaIntent = pi;
41748f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
41758f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
41768f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        public void binderDied() {
41778f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            Log.w(TAG, "  RemoteControlClient died");
41788f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            // remote control client died, make sure the displays don't use it anymore
41798f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            //  by setting its remote control client to null
418026b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi            registerRemoteControlClient(mMediaIntent, null/*rcClient*/, null/*ignored*/);
41813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            // the dead client was maybe handling remote playback, reevaluate
41823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            postReevaluateRemote();
41838f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
41848f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
41858f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        public IBinder getBinder() {
41868f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            return mCb;
41878f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
41888f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    }
41898f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
41903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
41913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * A global counter for RemoteControlClient identifiers
41923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
41933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private static int sLastRccId = 0;
41943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
41953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private class RemotePlaybackState {
41963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        int mRccId;
41973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        int mVolume;
41983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        int mVolumeMax;
41993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        int mVolumeHandling;
42003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
42013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        private RemotePlaybackState(int id, int vol, int volMax) {
42023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mRccId = id;
42033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mVolume = vol;
42043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mVolumeMax = volMax;
42053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
42063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
42073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
42083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
42093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
42103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Internal cache for the playback information of the RemoteControlClient whose volume gets to
42113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * be controlled by the volume keys ("main"), so we don't have to iterate over the RC stack
42123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * every time we need this info.
42133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
42143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private RemotePlaybackState mMainRemote;
42153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
42163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Indicates whether the "main" RemoteControlClient is considered active.
42173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Use synchronized on mMainRemote.
42183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
42193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private boolean mMainRemoteIsActive;
42203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
42213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Indicates whether there is remote playback going on. True even if there is no "active"
42223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * remote playback (mMainRemoteIsActive is false), but a RemoteControlClient has declared it
42233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * handles remote playback.
42243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Use synchronized on mMainRemote.
42253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
42263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private boolean mHasRemotePlayback;
42273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
4228d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    private static class RemoteControlStackEntry {
42293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        public int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
4230f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        /**
4231f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi         * The target for the ACTION_MEDIA_BUTTON events.
4232f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi         * Always non null.
4233f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi         */
4234f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        public PendingIntent mMediaIntent;
4235f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        /**
4236f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi         * The registered media button event receiver.
4237f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi         * Always non null.
4238f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi         */
4239f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        public ComponentName mReceiverComponent;
42408f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        public String mCallingPackageName;
42418f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        public int mCallingUid;
4242f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        /**
4243f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi         * Provides access to the information to display on the remote control.
4244f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi         * May be null (when a media button event receiver is registered,
4245f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi         *     but no remote control client has been registered) */
42464426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        public IRemoteControlClient mRcClient;
42478f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        public RcClientDeathHandler mRcClientDeathHandler;
42483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        /**
42493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi         * Information only used for non-local playback
42503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi         */
42513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        public int mPlaybackType;
42523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        public int mPlaybackVolume;
42533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        public int mPlaybackVolumeMax;
42543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        public int mPlaybackVolumeHandling;
42553114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        public int mPlaybackStream;
42563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        public int mPlaybackState;
42571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi        public IRemoteVolumeObserver mRemoteVolumeObs;
42583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
42593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        public void resetPlaybackInfo() {
42603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mPlaybackType = RemoteControlClient.PLAYBACK_TYPE_LOCAL;
42613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mPlaybackVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
42623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mPlaybackVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
42633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mPlaybackVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
42643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mPlaybackStream = AudioManager.STREAM_MUSIC;
42653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mPlaybackState = RemoteControlClient.PLAYSTATE_STOPPED;
42661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi            mRemoteVolumeObs = null;
42673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
4268d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
4269f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        /** precondition: mediaIntent != null, eventReceiver != null */
4270f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        public RemoteControlStackEntry(PendingIntent mediaIntent, ComponentName eventReceiver) {
4271f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            mMediaIntent = mediaIntent;
4272f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            mReceiverComponent = eventReceiver;
42738f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            mCallingUid = -1;
427417da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi            mRcClient = null;
42753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mRccId = ++sLastRccId;
42763114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
42773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            resetPlaybackInfo();
42788f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
42798f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
42808f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        public void unlinkToRcClientDeath() {
42818f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) {
42828f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                try {
42838f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                    mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0);
4284a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi                    mRcClientDeathHandler = null;
42858f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                } catch (java.util.NoSuchElementException e) {
42868f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                    // not much we can do here
42878f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                    Log.e(TAG, "Encountered " + e + " in unlinkToRcClientDeath()");
42888f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                    e.printStackTrace();
42898f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                }
42908f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            }
4291d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        }
4292a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi
4293a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi        @Override
4294a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi        protected void finalize() throws Throwable {
4295a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi            unlinkToRcClientDeath();// unlink exception handled inside method
4296a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi            super.finalize();
4297a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi        }
4298d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    }
4299d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
43008f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    /**
43018f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     *  The stack of remote control event receivers.
43028f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     *  Code sections and methods that modify the remote control event receiver stack are
43038f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     *  synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either
43048f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     *  stack, audio focus or RC, can lead to a change in the remote control display
43058f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     */
430630c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>();
4307d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
4308d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    /**
4309722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     * The component the telephony package can register so telephony calls have priority to
4310722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     * handle media button events
4311722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     */
4312722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    private ComponentName mMediaReceiverForCalls = null;
4313722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi
4314722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    /**
4315d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi     * Helper function:
4316d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi     * Display in the log the current entries in the remote control focus stack
4317d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi     */
4318d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    private void dumpRCStack(PrintWriter pw) {
4319b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi        pw.println("\nRemote Control stack entries:");
4320d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        synchronized(mRCStack) {
4321d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
4322d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi            while(stackIterator.hasNext()) {
43238f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
4324f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                pw.println("  pi: " + rcse.mMediaIntent +
4325f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                        "  -- ercvr: " + rcse.mReceiverComponent +
432617da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi                        "  -- client: " + rcse.mRcClient +
43273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        "  -- uid: " + rcse.mCallingUid +
43283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        "  -- type: " + rcse.mPlaybackType +
43293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        "  state: " + rcse.mPlaybackState);
43303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
43313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
43323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
43333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
43343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
43353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Helper function:
43363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Display in the log the current entries in the remote control stack, focusing
43373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * on RemoteControlClient data
43383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
43393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private void dumpRCCStack(PrintWriter pw) {
43403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        pw.println("\nRemote Control Client stack entries:");
43413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized(mRCStack) {
43423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
43433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            while(stackIterator.hasNext()) {
43443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
43453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                pw.println("  uid: " + rcse.mCallingUid +
43463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        "  -- id: " + rcse.mRccId +
43473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        "  -- type: " + rcse.mPlaybackType +
43483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        "  -- state: " + rcse.mPlaybackState +
43493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        "  -- vol handling: " + rcse.mPlaybackVolumeHandling +
43503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        "  -- vol: " + rcse.mPlaybackVolume +
43511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                        "  -- volMax: " + rcse.mPlaybackVolumeMax +
43521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                        "  -- volObs: " + rcse.mRemoteVolumeObs);
43531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi
4354d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi            }
4355d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        }
43563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (mMainRemote) {
43573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            pw.println("\nRemote Volume State:");
43583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            pw.println("  has remote: " + mHasRemotePlayback);
43593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            pw.println("  is remote active: " + mMainRemoteIsActive);
43603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            pw.println("  rccId: " + mMainRemote.mRccId);
43613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            pw.println("  volume handling: "
43623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    + ((mMainRemote.mVolumeHandling == RemoteControlClient.PLAYBACK_VOLUME_FIXED) ?
43633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            "PLAYBACK_VOLUME_FIXED(0)" : "PLAYBACK_VOLUME_VARIABLE(1)"));
43643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            pw.println("  volume: " + mMainRemote.mVolume);
43653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            pw.println("  volume steps: " + mMainRemote.mVolumeMax);
43663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
4367d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    }
4368d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
4369d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    /**
4370d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi     * Helper function:
4371d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi     * Remove any entry in the remote control stack that has the same package name as packageName
4372d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi     * Pre-condition: packageName != null
4373d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi     */
4374d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi    private void removeMediaButtonReceiverForPackage(String packageName) {
4375d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        synchronized(mRCStack) {
4376d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi            if (mRCStack.empty()) {
4377d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                return;
4378d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi            } else {
4379d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                RemoteControlStackEntry oldTop = mRCStack.peek();
4380d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
4381d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                // iterate over the stack entries
4382d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                while(stackIterator.hasNext()) {
4383d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
4384d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    if (packageName.equalsIgnoreCase(rcse.mReceiverComponent.getPackageName())) {
4385d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                        // a stack entry is from the package being removed, remove it from the stack
4386d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                        stackIterator.remove();
4387a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi                        rcse.unlinkToRcClientDeath();
4388d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    }
4389d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                }
4390d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                if (mRCStack.empty()) {
4391d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    // no saved media button receiver
4392d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    mAudioHandler.sendMessage(
4393d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                            mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
4394d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                                    null));
4395d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                } else if (oldTop != mRCStack.peek()) {
4396d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    // the top of the stack has changed, save it in the system settings
4397d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    // by posting a message to persist it
4398d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    mAudioHandler.sendMessage(
4399d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                            mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
4400d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                                    mRCStack.peek().mReceiverComponent));
4401d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                }
4402d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi            }
4403d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        }
4404d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi    }
4405d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
4406d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi    /**
4407d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi     * Helper function:
4408f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * Restore remote control receiver from the system settings.
4409d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi     */
4410d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi    private void restoreMediaButtonReceiver() {
4411d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        String receiverName = Settings.System.getString(mContentResolver,
4412d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                Settings.System.MEDIA_BUTTON_RECEIVER);
4413d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        if ((null != receiverName) && !receiverName.isEmpty()) {
4414f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName);
4415f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            // construct a PendingIntent targeted to the restored component name
4416f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            // for the media button and register it
4417f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4418f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            //     the associated intent will be handled by the component being registered
4419f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            mediaButtonIntent.setComponent(eventReceiver);
4420f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            PendingIntent pi = PendingIntent.getBroadcast(mContext,
4421f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                    0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
4422f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            registerMediaButtonIntent(pi, eventReceiver);
4423d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        }
4424d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi    }
4425d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
4426d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi    /**
4427d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi     * Helper function:
4428f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * Set the new remote control receiver at the top of the RC focus stack.
4429f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * precondition: mediaIntent != null, target != null
4430d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi     */
4431f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    private void pushMediaButtonReceiver(PendingIntent mediaIntent, ComponentName target) {
4432d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        // already at top of stack?
4433f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) {
4434d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi            return;
4435d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        }
4436d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
44378f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        RemoteControlStackEntry rcse = null;
44388f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        boolean wasInsideStack = false;
4439d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        while(stackIterator.hasNext()) {
44408f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            rcse = (RemoteControlStackEntry)stackIterator.next();
4441f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            if(rcse.mMediaIntent.equals(mediaIntent)) {
44428f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                wasInsideStack = true;
444372843377d50a8f95cceaf33d316ab68d9b47f2ebJean-Michel Trivi                stackIterator.remove();
4444d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi                break;
4445d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi            }
4446d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        }
44478f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        if (!wasInsideStack) {
4448f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            rcse = new RemoteControlStackEntry(mediaIntent, target);
44498f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
44508f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        mRCStack.push(rcse);
4451d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
4452d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        // post message to persist the default media button receiver
4453d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        mAudioHandler.sendMessage( mAudioHandler.obtainMessage(
4454f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) );
4455d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    }
4456d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
4457d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    /**
4458d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi     * Helper function:
4459f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * Remove the remote control receiver from the RC focus stack.
4460f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * precondition: pi != null
4461d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi     */
4462f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    private void removeMediaButtonReceiver(PendingIntent pi) {
4463d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
4464d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        while(stackIterator.hasNext()) {
4465d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi            RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
4466f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            if(rcse.mMediaIntent.equals(pi)) {
446772843377d50a8f95cceaf33d316ab68d9b47f2ebJean-Michel Trivi                stackIterator.remove();
4468a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi                rcse.unlinkToRcClientDeath();
4469d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi                break;
4470d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi            }
4471d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        }
4472d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    }
4473d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
44748f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    /**
44758f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Helper function:
44768f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Called synchronized on mRCStack
44778f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     */
4478f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    private boolean isCurrentRcController(PendingIntent pi) {
4479f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(pi)) {
44808f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            return true;
44818f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
44828f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        return false;
44838f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    }
44848f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
44854426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    //==========================================================================================
44864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    // Remote control display / client
44874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    //==========================================================================================
44884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
44894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Update the remote control displays with the new "focused" client generation
44904426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
449118e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi    private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration,
4492f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            PendingIntent newMediaIntent, boolean clearing) {
44934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        // NOTE: Only one IRemoteControlDisplay supported in this implementation
44944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        if (mRcDisplay != null) {
44954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            try {
44964b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                mRcDisplay.setCurrentClientId(
4497f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                        newClientGeneration, newMediaIntent, clearing);
44984426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            } catch (RemoteException e) {
4499db8a361629f06f62b9e1c40d4413b3b5099bd124Jean-Michel Trivi                Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc() "+e);
45004426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                // if we had a display before, stop monitoring its death
45014426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                rcDisplay_stopDeathMonitor_syncRcStack();
45024426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mRcDisplay = null;
45034426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
45044426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
45054426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
45064426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
45074426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
45084426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Update the remote control clients with the new "focused" client generation
45094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
451018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi    private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) {
45114426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
45124426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        while(stackIterator.hasNext()) {
45134426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            RemoteControlStackEntry se = stackIterator.next();
45144426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            if ((se != null) && (se.mRcClient != null)) {
45154426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                try {
45164426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    se.mRcClient.setCurrentClientGenerationId(newClientGeneration);
45174426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                } catch (RemoteException e) {
4518db8a361629f06f62b9e1c40d4413b3b5099bd124Jean-Michel Trivi                    Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()"+e);
45194426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    stackIterator.remove();
45204426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    se.unlinkToRcClientDeath();
45214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                }
45224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
45234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
45244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
45254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
45264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
45274b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi     * Update the displays and clients with the new "focused" client generation and name
45284b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi     * @param newClientGeneration the new generation value matching a client update
45294b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi     * @param newClientEventReceiver the media button event receiver associated with the client.
45304b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi     *    May be null, which implies there is no registered media button event receiver.
45314b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi     * @param clearing true if the new client generation value maps to a remote control update
45324b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi     *    where the display should be cleared.
45334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
453418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi    private void setNewRcClient_syncRcsCurrc(int newClientGeneration,
4535f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            PendingIntent newMediaIntent, boolean clearing) {
45363094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi        // send the new valid client generation ID to all displays
4537f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newMediaIntent, clearing);
45383094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi        // send the new valid client generation ID to all clients
453918e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi        setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration);
45404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
45414426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
45424426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
45434426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Called when processing MSG_RCDISPLAY_CLEAR event
45444426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
45454426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void onRcDisplayClear() {
454618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi        if (DEBUG_RC) Log.i(TAG, "Clear remote control display");
45474426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
45483094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi        synchronized(mRCStack) {
45493094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi            synchronized(mCurrentRcLock) {
45503094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                mCurrentRcClientGen++;
45513094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                // synchronously update the displays and clients with the new client generation
455218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi                setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
4553f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                        null /*newMediaIntent*/, true /*clearing*/);
45543094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi            }
45554426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
45564426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
45574426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
45584426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
45594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Called when processing MSG_RCDISPLAY_UPDATE event
45604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
45614426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void onRcDisplayUpdate(RemoteControlStackEntry rcse, int flags /* USED ?*/) {
45623094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi        synchronized(mRCStack) {
45633094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi            synchronized(mCurrentRcLock) {
45643094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) {
456518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi                    if (DEBUG_RC) Log.i(TAG, "Display/update remote control ");
45663094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi
45673094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                    mCurrentRcClientGen++;
45683094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                    // synchronously update the displays and clients with
45693094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                    //      the new client generation
457018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi                    setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
4571f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                            rcse.mMediaIntent /*newMediaIntent*/,
45723094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                            false /*clearing*/);
45733094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi
4574db8a361629f06f62b9e1c40d4413b3b5099bd124Jean-Michel Trivi                    // tell the current client that it needs to send info
45753094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                    try {
45763094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                        mCurrentRcClient.onInformationRequested(mCurrentRcClientGen,
45773094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                                flags, mArtworkExpectedWidth, mArtworkExpectedHeight);
45783094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                    } catch (RemoteException e) {
45793094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                        Log.e(TAG, "Current valid remote client is dead: "+e);
45803094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                        mCurrentRcClient = null;
45813094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                    }
45823094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                } else {
45833094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                    // the remote control display owner has changed between the
45843094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                    // the message to update the display was sent, and the time it
45853094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                    // gets to be processed (now)
45864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                }
45874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
45884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
45894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
45904426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
45914426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
45928f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    /**
45938f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Helper function:
45948f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Called synchronized on mRCStack
45958f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     */
4596b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi    private void clearRemoteControlDisplay_syncAfRcs() {
45978f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        synchronized(mCurrentRcLock) {
459817da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi            mCurrentRcClient = null;
45998f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
46004426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        // will cause onRcDisplayClear() to be called in AudioService's handler thread
46018f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) );
46028f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    }
46038f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
46048f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    /**
4605b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi     * Helper function for code readability: only to be called from
4606b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi     *    checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for
4607b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi     *    this method.
4608b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi     * Preconditions:
4609b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi     *    - called synchronized mAudioFocusLock then on mRCStack
4610b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi     *    - mRCStack.isEmpty() is false
46118f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     */
4612b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi    private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
46138f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        RemoteControlStackEntry rcse = mRCStack.peek();
4614b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi        int infoFlagsAboutToBeUsed = infoChangedFlags;
46158f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        // this is where we enforce opt-in for information display on the remote controls
46168f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        //   with the new AudioManager.registerRemoteControlClient() API
461717da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi        if (rcse.mRcClient == null) {
461817da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi            //Log.w(TAG, "Can't update remote control display with null remote control client");
4619b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi            clearRemoteControlDisplay_syncAfRcs();
46208f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            return;
46218f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
46228f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        synchronized(mCurrentRcLock) {
462317da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi            if (!rcse.mRcClient.equals(mCurrentRcClient)) {
46247b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi                // new RC client, assume every type of information shall be queried
4625b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi                infoFlagsAboutToBeUsed = RC_INFO_ALL;
46267b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi            }
462717da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi            mCurrentRcClient = rcse.mRcClient;
46288f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
46294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        // will cause onRcDisplayUpdate() to be called in AudioService's handler thread
4630b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi        mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_UPDATE,
46310a9faa8cf934ef38319cd945b600825c6bb88b9cJean-Michel Trivi                infoFlagsAboutToBeUsed /* arg1 */, 0, rcse /* obj, != null */) );
46328f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    }
46338f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
46348f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    /**
46358f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Helper function:
4636b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi     * Called synchronized on mAudioFocusLock, then mRCStack
46378f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Check whether the remote control display should be updated, triggers the update if required
4638b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi     * @param infoChangedFlags the flags corresponding to the remote control client information
4639b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi     *     that has changed, if applicable (checking for the update conditions might trigger a
4640b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi     *     clear, rather than an update event).
46418f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     */
4642b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi    private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
46438f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        // determine whether the remote control display should be refreshed
46448f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        // if either stack is empty, there is a mismatch, so clear the RC display
46458f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        if (mRCStack.isEmpty() || mFocusStack.isEmpty()) {
4646b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi            clearRemoteControlDisplay_syncAfRcs();
46478f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            return;
46488f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
46498f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        // if the top of the two stacks belong to different packages, there is a mismatch, clear
46508f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        if ((mRCStack.peek().mCallingPackageName != null)
46518f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                && (mFocusStack.peek().mPackageName != null)
46528f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                && !(mRCStack.peek().mCallingPackageName.compareTo(
46538f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        mFocusStack.peek().mPackageName) == 0)) {
4654b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi            clearRemoteControlDisplay_syncAfRcs();
46558f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            return;
46568f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
46578f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        // if the audio focus didn't originate from the same Uid as the one in which the remote
46588f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        //   control information will be retrieved, clear
46598f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        if (mRCStack.peek().mCallingUid != mFocusStack.peek().mCallingUid) {
4660b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi            clearRemoteControlDisplay_syncAfRcs();
46618f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            return;
46628f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
46638f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        // refresh conditions were verified: update the remote controls
4664b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi        // ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty
4665b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi        updateRemoteControlDisplay_syncAfRcs(infoChangedFlags);
46668f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    }
4667d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
46686bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    /**
4669f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c)
4670f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * precondition: mediaIntent != null, target != null
4671f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     */
4672f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    public void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver) {
4673f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        Log.i(TAG, "  Remote Control   registerMediaButtonIntent() for " + mediaIntent);
4674d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
46758f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        synchronized(mAudioFocusLock) {
46768f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            synchronized(mRCStack) {
4677f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                pushMediaButtonReceiver(mediaIntent, eventReceiver);
4678b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi                // new RC client, assume every type of information shall be queried
4679b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
46808f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            }
4681d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        }
4682d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    }
4683d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
46846bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    /**
4685f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent)
4686f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * precondition: mediaIntent != null, eventReceiver != null
4687f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     */
4688f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    public void unregisterMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver)
4689f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    {
4690f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        Log.i(TAG, "  Remote Control   unregisterMediaButtonIntent() for " + mediaIntent);
4691d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
46928f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        synchronized(mAudioFocusLock) {
46938f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            synchronized(mRCStack) {
4694f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                boolean topOfStackWillChange = isCurrentRcController(mediaIntent);
4695f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                removeMediaButtonReceiver(mediaIntent);
46968f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                if (topOfStackWillChange) {
4697b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi                    // current RC client will change, assume every type of info needs to be queried
4698b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
46998f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                }
47008f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            }
4701d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        }
4702d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    }
4703d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
470426b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi    /**
4705722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     * see AudioManager.registerMediaButtonEventReceiverForCalls(ComponentName c)
4706722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     * precondition: c != null
4707722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     */
4708722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    public void registerMediaButtonEventReceiverForCalls(ComponentName c) {
4709722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
4710722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi                != PackageManager.PERMISSION_GRANTED) {
4711722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi            Log.e(TAG, "Invalid permissions to register media button receiver for calls");
4712722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi            return;
4713722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        }
4714722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        synchronized(mRCStack) {
4715722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi            mMediaReceiverForCalls = c;
4716722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        }
4717722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    }
4718722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi
4719722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    /**
4720722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     * see AudioManager.unregisterMediaButtonEventReceiverForCalls()
4721722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     */
4722722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    public void unregisterMediaButtonEventReceiverForCalls() {
4723722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
4724722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi                != PackageManager.PERMISSION_GRANTED) {
4725722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi            Log.e(TAG, "Invalid permissions to unregister media button receiver for calls");
4726722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi            return;
4727722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        }
4728722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        synchronized(mRCStack) {
4729722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi            mMediaReceiverForCalls = null;
4730722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        }
4731722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    }
4732722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi
4733722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    /**
473426b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi     * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...)
47353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @return the unique ID of the RemoteControlStackEntry associated with the RemoteControlClient
473626b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi     * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient
473726b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi     *     without modifying the RC stack, but while still causing the display to refresh (will
473826b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi     *     become blank as a result of this)
473926b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi     */
47403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public int registerRemoteControlClient(PendingIntent mediaIntent,
4741f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            IRemoteControlClient rcClient, String callingPackageName) {
4742b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi        if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient);
47433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
47448f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        synchronized(mAudioFocusLock) {
47458f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            synchronized(mRCStack) {
47468f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                // store the new display information
47478f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
47488f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                while(stackIterator.hasNext()) {
47498f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                    RemoteControlStackEntry rcse = stackIterator.next();
4750f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                    if(rcse.mMediaIntent.equals(mediaIntent)) {
47518f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        // already had a remote control client?
47528f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        if (rcse.mRcClientDeathHandler != null) {
47538f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                            // stop monitoring the old client's death
47548f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                            rcse.unlinkToRcClientDeath();
47558f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        }
47568f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        // save the new remote control client
475717da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi                        rcse.mRcClient = rcClient;
475826b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi                        rcse.mCallingPackageName = callingPackageName;
475926b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi                        rcse.mCallingUid = Binder.getCallingUid();
476026b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi                        if (rcClient == null) {
4761a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi                            // here rcse.mRcClientDeathHandler is null;
47623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            rcse.resetPlaybackInfo();
476326b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi                            break;
476426b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi                        }
47653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        rccId = rcse.mRccId;
476626b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi
476726b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi                        // there is a new (non-null) client:
476826b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi                        // 1/ give the new client the current display (if any)
47694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        if (mRcDisplay != null) {
47704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                            try {
47714426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                                rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay);
47724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                            } catch (RemoteException e) {
47734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                                Log.e(TAG, "Error connecting remote control display to client: "+e);
47744426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                                e.printStackTrace();
47754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                            }
47764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        }
477726b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi                        // 2/ monitor the new client's death
477826b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi                        IBinder b = rcse.mRcClient.asBinder();
47798f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        RcClientDeathHandler rcdh =
4780f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                                new RcClientDeathHandler(b, rcse.mMediaIntent);
47818f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        try {
47828f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                            b.linkToDeath(rcdh, 0);
47838f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        } catch (RemoteException e) {
47848f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                            // remote control client is DOA, disqualify it
47858f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                            Log.w(TAG, "registerRemoteControlClient() has a dead client " + b);
478617da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi                            rcse.mRcClient = null;
47878f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        }
47888f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        rcse.mRcClientDeathHandler = rcdh;
47898f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        break;
47908f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                    }
47918f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                }
47928f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                // if the eventReceiver is at the top of the stack
47938f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                // then check for potential refresh of the remote controls
4794f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                if (isCurrentRcController(mediaIntent)) {
4795b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
47968f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                }
47978f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            }
47988f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
47993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        return rccId;
48008f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    }
48018f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
48024b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi    /**
4803f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * see AudioManager.unregisterRemoteControlClient(PendingIntent pi, ...)
48044b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi     * rcClient is guaranteed non-null
48054b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi     */
4806f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    public void unregisterRemoteControlClient(PendingIntent mediaIntent,
48074426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            IRemoteControlClient rcClient) {
48084b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi        synchronized(mAudioFocusLock) {
48094b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi            synchronized(mRCStack) {
48104b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
48114b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                while(stackIterator.hasNext()) {
48124b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                    RemoteControlStackEntry rcse = stackIterator.next();
4813f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                    if ((rcse.mMediaIntent.equals(mediaIntent))
48144b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                            && rcClient.equals(rcse.mRcClient)) {
48154b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                        // we found the IRemoteControlClient to unregister
48164b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                        // stop monitoring its death
48174b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                        rcse.unlinkToRcClientDeath();
48184b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                        // reset the client-related fields
48194b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                        rcse.mRcClient = null;
48204b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                        rcse.mCallingPackageName = null;
48214b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                    }
48224b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                }
48234b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi            }
48244b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi        }
48254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
48264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
48274426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
48284426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * The remote control displays.
48294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Access synchronized on mRCStack
48304426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * NOTE: Only one IRemoteControlDisplay supported in this implementation
48314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
48324426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private IRemoteControlDisplay mRcDisplay;
48334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private RcDisplayDeathHandler mRcDisplayDeathHandler;
48344426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mArtworkExpectedWidth = -1;
48354426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mArtworkExpectedHeight = -1;
48364426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
48374426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Inner class to monitor remote control display deaths, and unregister them from the list
48384426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * of displays if necessary.
48394426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
48404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private class RcDisplayDeathHandler implements IBinder.DeathRecipient {
484118e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi        private IBinder mCb; // To be notified of client's death
484218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi
484318e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi        public RcDisplayDeathHandler(IBinder b) {
484418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi            if (DEBUG_RC) Log.i(TAG, "new RcDisplayDeathHandler for "+b);
484518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi            mCb = b;
484618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi        }
484718e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi
48484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        public void binderDied() {
48498f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            synchronized(mRCStack) {
485018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi                Log.w(TAG, "RemoteControl: display died");
48514426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mRcDisplay = null;
48524426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
48534426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
48544426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
485518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi        public void unlinkToRcDisplayDeath() {
485618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi            if (DEBUG_RC) Log.i(TAG, "unlinkToRcDisplayDeath for "+mCb);
48574426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            try {
485818e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi                mCb.unlinkToDeath(this, 0);
48594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            } catch (java.util.NoSuchElementException e) {
486018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi                // not much we can do here, the display was being unregistered anyway
486118e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi                Log.e(TAG, "Encountered " + e + " in unlinkToRcDisplayDeath()");
48624426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                e.printStackTrace();
48634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
48644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
486518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi
486618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi    }
486718e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi
486818e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi    private void rcDisplay_stopDeathMonitor_syncRcStack() {
486918e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi        if (mRcDisplay != null) { // implies (mRcDisplayDeathHandler != null)
487018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi            // we had a display before, stop monitoring its death
487118e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi            mRcDisplayDeathHandler.unlinkToRcDisplayDeath();
487218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi        }
48734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
48744426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
48754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void rcDisplay_startDeathMonitor_syncRcStack() {
48764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        if (mRcDisplay != null) {
48774426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // new non-null display, monitor its death
48784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            IBinder b = mRcDisplay.asBinder();
487918e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi            mRcDisplayDeathHandler = new RcDisplayDeathHandler(b);
48804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            try {
48814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                b.linkToDeath(mRcDisplayDeathHandler, 0);
48824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            } catch (RemoteException e) {
48834426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                // remote control display is DOA, disqualify it
48844426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + b);
48854426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mRcDisplay = null;
48864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
48874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
48884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
48894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
489018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi    /**
4891958bba6862c9540c528263686b0de044b4a7a5f6Jean-Michel Trivi     * Register an IRemoteControlDisplay.
4892958bba6862c9540c528263686b0de044b4a7a5f6Jean-Michel Trivi     * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient
4893958bba6862c9540c528263686b0de044b4a7a5f6Jean-Michel Trivi     * at the top of the stack to update the new display with its information.
489418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi     * Since only one IRemoteControlDisplay is supported, this will unregister the previous display.
489518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi     * @param rcd the IRemoteControlDisplay to register. No effect if null.
489618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi     */
48974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) {
489818e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi        if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")");
4899b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi        synchronized(mAudioFocusLock) {
4900b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi            synchronized(mRCStack) {
4901b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                if ((mRcDisplay == rcd) || (rcd == null)) {
4902b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                    return;
4903b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                }
4904b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                // if we had a display before, stop monitoring its death
4905b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                rcDisplay_stopDeathMonitor_syncRcStack();
4906b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                mRcDisplay = rcd;
4907b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                // new display, start monitoring its death
4908b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                rcDisplay_startDeathMonitor_syncRcStack();
49094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
4910b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                // let all the remote control clients there is a new display
4911b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                // no need to unplug the previous because we only support one display
4912b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                // and the clients don't track the death of the display
4913b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
4914b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                while(stackIterator.hasNext()) {
4915b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                    RemoteControlStackEntry rcse = stackIterator.next();
4916b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                    if(rcse.mRcClient != null) {
4917b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                        try {
4918b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                            rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay);
4919b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                        } catch (RemoteException e) {
4920b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                            Log.e(TAG, "Error connecting remote control display to client: " + e);
4921b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                            e.printStackTrace();
4922b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                        }
49234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    }
49248f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                }
4925db8a361629f06f62b9e1c40d4413b3b5099bd124Jean-Michel Trivi
4926338794576667745b060ac269b2c2b36e0c6964f2Jean-Michel Trivi                // we have a new display, of which all the clients are now aware: have it be updated
4927b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
4928338794576667745b060ac269b2c2b36e0c6964f2Jean-Michel Trivi            }
49298f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
49308f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    }
4931d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
493218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi    /**
493318e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi     * Unregister an IRemoteControlDisplay.
493418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi     * Since only one IRemoteControlDisplay is supported, this has no effect if the one to
493518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi     *    unregister is not the current one.
493618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi     * @param rcd the IRemoteControlDisplay to unregister. No effect if null.
493718e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi     */
49384426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
493918e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi        if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")");
49404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized(mRCStack) {
494118e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi            // only one display here, so you can only unregister the current display
494218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi            if ((rcd == null) || (rcd != mRcDisplay)) {
494318e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi                if (DEBUG_RC) Log.w(TAG, "    trying to unregister unregistered RCD");
494418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi                return;
494518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi            }
49464426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // if we had a display before, stop monitoring its death
49474426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            rcDisplay_stopDeathMonitor_syncRcStack();
49484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            mRcDisplay = null;
49494426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
49504426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // disconnect this remote control display from all the clients
49514426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
49524426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            while(stackIterator.hasNext()) {
49534426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
49544426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                if(rcse.mRcClient != null) {
49554426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    try {
49564426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        rcse.mRcClient.unplugRemoteControlDisplay(rcd);
49574426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    } catch (RemoteException e) {
49584426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        Log.e(TAG, "Error disconnecting remote control display to client: " + e);
49594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        e.printStackTrace();
49604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    }
49614426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                }
49624426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
49634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
49644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
49654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
49664426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
49674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized(mRCStack) {
49684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // NOTE: Only one IRemoteControlDisplay supported in this implementation
49694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            mArtworkExpectedWidth = w;
49704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            mArtworkExpectedHeight = h;
49714426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
49724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
49734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
49743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public void setPlaybackInfoForRcc(int rccId, int what, int value) {
4975f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi        sendMsg(mAudioHandler, MSG_RCC_NEW_PLAYBACK_INFO, SENDMSG_QUEUE,
4976f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                rccId /* arg1 */, what /* arg2 */, Integer.valueOf(value) /* obj */, 0 /* delay */);
4977f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi    }
4978f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi
4979f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi    // handler for MSG_RCC_NEW_PLAYBACK_INFO
4980f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi    private void onNewPlaybackInfoForRcc(int rccId, int key, int value) {
4981f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi        if(DEBUG_RC) Log.d(TAG, "onNewPlaybackInfoForRcc(id=" + rccId +
4982f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                ", what=" + key + ",val=" + value + ")");
49833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized(mRCStack) {
49843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
49853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            while(stackIterator.hasNext()) {
49863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
49873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (rcse.mRccId == rccId) {
4988f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                    switch (key) {
49893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        case RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE:
49903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            rcse.mPlaybackType = value;
49913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            postReevaluateRemote();
49923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            break;
49933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        case RemoteControlClient.PLAYBACKINFO_VOLUME:
49943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            rcse.mPlaybackVolume = value;
49953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            synchronized (mMainRemote) {
49963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                if (rccId == mMainRemote.mRccId) {
49973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                    mMainRemote.mVolume = value;
49983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                    mVolumePanel.postHasNewRemotePlaybackInfo();
49993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                }
50003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            }
50013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            break;
50023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        case RemoteControlClient.PLAYBACKINFO_VOLUME_MAX:
50033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            rcse.mPlaybackVolumeMax = value;
50043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            synchronized (mMainRemote) {
50053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                if (rccId == mMainRemote.mRccId) {
50063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                    mMainRemote.mVolumeMax = value;
50073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                    mVolumePanel.postHasNewRemotePlaybackInfo();
50083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                }
50093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            }
50103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            break;
50113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        case RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING:
50123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            rcse.mPlaybackVolumeHandling = value;
50133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            synchronized (mMainRemote) {
50143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                if (rccId == mMainRemote.mRccId) {
50153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                    mMainRemote.mVolumeHandling = value;
50163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                    mVolumePanel.postHasNewRemotePlaybackInfo();
50173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                }
50183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            }
50193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            break;
50203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        case RemoteControlClient.PLAYBACKINFO_USES_STREAM:
50213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            rcse.mPlaybackStream = value;
50223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            break;
50233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        case RemoteControlClient.PLAYBACKINFO_PLAYSTATE:
50243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            rcse.mPlaybackState = value;
50253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            synchronized (mMainRemote) {
50263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                if (rccId == mMainRemote.mRccId) {
50273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                    mMainRemoteIsActive = isPlaystateActive(value);
50283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                    postReevaluateRemote();
50293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                }
50303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            }
50313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            break;
50323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        default:
5033f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                            Log.e(TAG, "unhandled key " + key + " for RCC " + rccId);
50343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            break;
50353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    }
50363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return;
50373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
50383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
50393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
50403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
50413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
50421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi    public void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
5043f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi        sendMsg(mAudioHandler, MSG_RCC_NEW_VOLUME_OBS, SENDMSG_QUEUE,
5044f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                rccId /* arg1 */, 0, rvo /* obj */, 0 /* delay */);
5045f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi    }
5046f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi
5047f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi    // handler for MSG_RCC_NEW_VOLUME_OBS
5048f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi    private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
50491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi        synchronized(mRCStack) {
50501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
50511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi            while(stackIterator.hasNext()) {
50521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
50531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                if (rcse.mRccId == rccId) {
50541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                    rcse.mRemoteVolumeObs = rvo;
50551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                    break;
50561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                }
50571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi            }
50581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi        }
50591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi    }
50601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi
50613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
50623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Checks if a remote client is active on the supplied stream type. Update the remote stream
50633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * volume state if found and playing
50643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @param streamType
50653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @return false if no remote playing is currently playing
50663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
50673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private boolean checkUpdateRemoteStateIfActive(int streamType) {
50683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized(mRCStack) {
50693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
50703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            while(stackIterator.hasNext()) {
50713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
50723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if ((rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE)
50733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        && isPlaystateActive(rcse.mPlaybackState)
50743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        && (rcse.mPlaybackStream == streamType)) {
50753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_RC) Log.d(TAG, "remote playback active on stream " + streamType
50763114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            + ", vol =" + rcse.mPlaybackVolume);
50773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    synchronized (mMainRemote) {
50783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        mMainRemote.mRccId = rcse.mRccId;
50793114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        mMainRemote.mVolume = rcse.mPlaybackVolume;
50803114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        mMainRemote.mVolumeMax = rcse.mPlaybackVolumeMax;
50813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        mMainRemote.mVolumeHandling = rcse.mPlaybackVolumeHandling;
50823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        mMainRemoteIsActive = true;
50833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    }
50843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return true;
50853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
50863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
50873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
50883114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (mMainRemote) {
50893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mMainRemoteIsActive = false;
50903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
50913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        return false;
50923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
50933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
50943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
50953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Returns true if the given playback state is considered "active", i.e. it describes a state
50963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * where playback is happening, or about to
50973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @param playState the playback state to evaluate
50983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @return true if active, false otherwise (inactive or unknown)
50993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
51003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private static boolean isPlaystateActive(int playState) {
51013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        switch (playState) {
51023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_PLAYING:
51033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_BUFFERING:
51043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
51053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_REWINDING:
51063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
51073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
51083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                return true;
51093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            default:
51103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                return false;
51113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
51123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
51133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
51143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private void adjustRemoteVolume(int streamType, int direction, int flags) {
51153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
51163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        boolean volFixed = false;
51173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (mMainRemote) {
51183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            if (!mMainRemoteIsActive) {
51193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL) Log.w(TAG, "adjustRemoteVolume didn't find an active client");
51203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                return;
51213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
51223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            rccId = mMainRemote.mRccId;
51233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            volFixed = (mMainRemote.mVolumeHandling ==
51243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    RemoteControlClient.PLAYBACK_VOLUME_FIXED);
51253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
51263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        // unlike "local" stream volumes, we can't compute the new volume based on the direction,
51273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        // we can only notify the remote that volume needs to be updated, and we'll get an async'
51283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        // update through setPlaybackInfoForRcc()
51293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (!volFixed) {
51303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            sendVolumeUpdateToRemote(rccId, direction);
51313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
51323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
51333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        // fire up the UI
51343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        mVolumePanel.postRemoteVolumeChanged(streamType, flags);
51353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
51363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
51373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private void sendVolumeUpdateToRemote(int rccId, int direction) {
51383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (DEBUG_VOL) { Log.d(TAG, "sendVolumeUpdateToRemote(rccId="+rccId+" , dir="+direction); }
51393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (direction == 0) {
51403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            // only handling discrete events
51413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            return;
51423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
51431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi        IRemoteVolumeObserver rvo = null;
51443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (mRCStack) {
51453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
51463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            while(stackIterator.hasNext()) {
51473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
51483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
51493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (rcse.mRccId == rccId) {
51501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                    rvo = rcse.mRemoteVolumeObs;
51513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
51523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
51533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
51543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
51551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi        if (rvo != null) {
51561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi            try {
51571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                rvo.dispatchRemoteVolumeUpdate(direction, -1);
51581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi            } catch (RemoteException e) {
51591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                Log.e(TAG, "Error dispatching relative volume update", e);
51601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi            }
51613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
51623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
51633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
51643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public int getRemoteStreamMaxVolume() {
51653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (mMainRemote) {
51663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
51673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                return 0;
51683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
51693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            return mMainRemote.mVolumeMax;
51703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
51713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
51723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
51733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public int getRemoteStreamVolume() {
51743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (mMainRemote) {
51753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
51763114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                return 0;
51773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
51783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            return mMainRemote.mVolume;
51793114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
51803114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
51813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
51823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public void setRemoteStreamVolume(int vol) {
51833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (DEBUG_VOL) { Log.d(TAG, "setRemoteStreamVolume(vol="+vol+")"); }
51843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
51853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (mMainRemote) {
51863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
51873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                return;
51883114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
51893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            rccId = mMainRemote.mRccId;
51903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
51911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi        IRemoteVolumeObserver rvo = null;
51923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (mRCStack) {
51933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
51943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            while(stackIterator.hasNext()) {
51953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
51963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (rcse.mRccId == rccId) {
51973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
51981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                    rvo = rcse.mRemoteVolumeObs;
51993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
52003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
52013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
52023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
52031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi        if (rvo != null) {
52041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi            try {
52051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                rvo.dispatchRemoteVolumeUpdate(0, vol);
52061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi            } catch (RemoteException e) {
52071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                Log.e(TAG, "Error dispatching absolute volume update", e);
52081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi            }
52093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
52103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
52113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
52123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
52133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Call to make AudioService reevaluate whether it's in a mode where remote players should
52143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * have their volume controlled. In this implementation this is only to reset whether
52153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * VolumePanel should display remote volumes
52163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
52173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private void postReevaluateRemote() {
52183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        sendMsg(mAudioHandler, MSG_REEVALUATE_REMOTE, SENDMSG_QUEUE, 0, 0, null, 0);
52193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
52203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
52213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private void onReevaluateRemote() {
52223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (DEBUG_VOL) { Log.w(TAG, "onReevaluateRemote()"); }
52233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        // is there a registered RemoteControlClient that is handling remote playback
52243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        boolean hasRemotePlayback = false;
52253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (mRCStack) {
52263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
52273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            while(stackIterator.hasNext()) {
52283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
52293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) {
52303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    hasRemotePlayback = true;
52313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
52323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
52333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
52343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
52353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (mMainRemote) {
52363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            if (mHasRemotePlayback != hasRemotePlayback) {
52373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                mHasRemotePlayback = hasRemotePlayback;
52383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                mVolumePanel.postRemoteSliderVisibility(hasRemotePlayback);
52393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
52403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
52413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
52423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
5243f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    //==========================================================================================
5244f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    // Device orientation
5245f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    //==========================================================================================
5246f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    /**
5247f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi     * Handles device configuration changes that may map to a change in the orientation.
5248f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi     * This feature is optional, and is defined by the definition and value of the
5249f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi     * "ro.audio.monitorOrientation" system property.
5250f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi     */
5251f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    private void handleConfigurationChanged(Context context) {
5252f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        try {
5253f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            // reading new orientation "safely" (i.e. under try catch) in case anything
5254f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            // goes wrong when obtaining resources and configuration
5255f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            int newOrientation = context.getResources().getConfiguration().orientation;
5256f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            if (newOrientation != mDeviceOrientation) {
5257f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                mDeviceOrientation = newOrientation;
5258f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                setOrientationForAudioSystem();
5259f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            }
5260f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        } catch (Exception e) {
5261f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            Log.e(TAG, "Error retrieving device orientation: " + e);
5262f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        }
5263f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    }
5264f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
5265f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    private void setOrientationForAudioSystem() {
5266f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        switch (mDeviceOrientation) {
5267f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_LANDSCAPE:
5268f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is landscape");
5269f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=landscape");
5270f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
5271f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_PORTRAIT:
5272f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is portrait");
5273f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=portrait");
5274f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
5275f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_SQUARE:
5276f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is square");
5277f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=square");
5278f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
5279f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_UNDEFINED:
5280f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is undefined");
5281f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=undefined");
5282f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
5283f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            default:
5284f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                Log.e(TAG, "Unknown orientation");
5285f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        }
5286f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    }
5287f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
5288f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
52897847211fb4699bf6018e29d214a918ed6657319bEric Laurent    // Handles request to override default use of A2DP for media.
52907847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public void setBluetoothA2dpOnInt(boolean on) {
52917847211fb4699bf6018e29d214a918ed6657319bEric Laurent        synchronized (mBluetoothA2dpEnabledLock) {
52927847211fb4699bf6018e29d214a918ed6657319bEric Laurent            mBluetoothA2dpEnabled = on;
52937847211fb4699bf6018e29d214a918ed6657319bEric Laurent            sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
52947847211fb4699bf6018e29d214a918ed6657319bEric Laurent                    AudioSystem.FOR_MEDIA,
52957847211fb4699bf6018e29d214a918ed6657319bEric Laurent                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
52967847211fb4699bf6018e29d214a918ed6657319bEric Laurent                    null, 0);
52977847211fb4699bf6018e29d214a918ed6657319bEric Laurent        }
52987847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
52997847211fb4699bf6018e29d214a918ed6657319bEric Laurent
5300d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    @Override
5301098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    public void setRingtonePlayer(IRingtonePlayer player) {
5302098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5303098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        mRingtonePlayer = player;
5304098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    }
5305098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
5306098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    @Override
5307098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    public IRingtonePlayer getRingtonePlayer() {
5308098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        return mRingtonePlayer;
5309098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    }
5310098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
5311098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    @Override
5312632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5313632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        synchronized (mCurAudioRoutes) {
5314632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5315632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            mRoutesObservers.register(observer);
5316632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            return routes;
5317632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        }
5318632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    }
5319632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
5320632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    @Override
5321d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
5322eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5323eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey
5324d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        dumpFocusStack(pw);
5325d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        dumpRCStack(pw);
53263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        dumpRCCStack(pw);
5327bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        dumpStreamStates(pw);
5328632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.println("\nAudio routes:");
5329632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
5330632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
5331d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
53329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5333