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;
25fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kastenimport android.app.ActivityManager;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.ActivityManagerNative;
27ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackbornimport android.app.AppOpsManager;
286243edd818b84adfbe712d5d233d6414b33653acAmith Yamasaniimport android.app.KeyguardManager;
29f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Triviimport android.app.PendingIntent;
30f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Triviimport android.app.PendingIntent.CanceledException;
3182aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothA2dp;
3282aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothAdapter;
3382aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothClass;
3482aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothDevice;
3582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothHeadset;
3682aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothProfile;
374294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Triviimport android.content.ActivityNotFoundException;
38bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.content.BroadcastReceiver;
39d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Triviimport android.content.ComponentName;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
43a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurentimport android.content.IntentFilter;
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager;
45f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Triviimport android.content.res.Configuration;
46e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurentimport android.content.res.Resources;
47e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurentimport android.content.res.XmlResourceParser;
48b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekhimport android.database.ContentObserver;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.MediaPlayer.OnCompletionListener;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.MediaPlayer.OnErrorListener;
51f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Triviimport android.net.Uri;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
53c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurentimport android.os.Build;
54f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Triviimport android.os.Bundle;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Environment;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IBinder;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Looper;
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
60c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Triviimport android.os.PowerManager;
61632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.RemoteCallbackList;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.ServiceManager;
6482aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.os.SystemProperties;
655ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackbornimport android.os.UserHandle;
66bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurentimport android.os.Vibrator;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings.System;
693c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Triviimport android.speech.RecognizerIntent;
70b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Triviimport android.telephony.PhoneStateListener;
71b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Triviimport android.telephony.TelephonyManager;
72632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.text.TextUtils;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
74d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Triviimport android.view.KeyEvent;
75bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Triviimport android.view.Surface;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.VolumePanel;
77bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Triviimport android.view.WindowManager;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.telephony.ITelephony;
80e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurentimport com.android.internal.util.XmlUtils;
81e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
82e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurentimport org.xmlpull.v1.XmlPullParserException;
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
84d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Triviimport java.io.FileDescriptor;
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
86d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Triviimport java.io.PrintWriter;
87e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurentimport java.lang.reflect.Field;
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
893172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurentimport java.util.concurrent.ConcurrentHashMap;
90c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.HashMap;
91f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Triviimport java.util.HashSet;
92c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Iterator;
935a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganeshimport java.util.List;
94c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Map;
9582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport java.util.NoSuchElementException;
96c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Set;
97d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Triviimport java.util.Stack;
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The implementation of the volume manager service.
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This implementation focuses on delivering a responsive UI. Most methods are
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * asynchronous to external calls. For example, the task of setting a volume
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will update our internal state, but in a separate thread will set the system
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * volume and later persist to the database. Similarly, setting the ringer mode
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will update the state and broadcast a change and in a separate thread later
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * persist the ringer mode.
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
111fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivipublic class AudioService extends IAudioService.Stub {
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "AudioService";
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi    /** Debug remote control client/display feature */
1167ff866e8cf43afc64111e98863dab549b57447b4Jean-Michel Trivi    protected static final boolean DEBUG_RC = false;
1173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /** Debug volumes */
1183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    protected static final boolean DEBUG_VOL = false;
11918e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** How long to delay before persisting a change in volume/ringer mode. */
12145edba1b8b0377dfe70a4f2b0afb0f04dd8e1ee9RoboErik    private static final int PERSIST_DELAY = 500;
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
123ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    private final Context mContext;
124ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    private final ContentResolver mContentResolver;
125ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    private final AppOpsManager mAppOps;
126ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    private final boolean mVoiceCapable;
127d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** The UI */
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private VolumePanel mVolumePanel;
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // sendMsg() flags
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** If the msg is already queued, replace it with this one. */
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int SENDMSG_REPLACE = 0;
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** If the msg is already queued, ignore this one and leave the old. */
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int SENDMSG_NOOP = 1;
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** If the msg is already queued, queue this one and leave the old. */
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int SENDMSG_QUEUE = 2;
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // AudioHandler messages
1409bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    private static final int MSG_SET_DEVICE_VOLUME = 0;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MSG_PERSIST_VOLUME = 1;
1425c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood    private static final int MSG_PERSIST_MASTER_VOLUME = 2;
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MSG_PERSIST_RINGER_MODE = 3;
144bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_MEDIA_SERVER_DIED = 4;
145dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_PLAY_SOUND_EFFECT = 5;
146dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
147dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_LOAD_SOUND_EFFECTS = 7;
148dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_SET_FORCE_USE = 8;
149dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
150dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_SET_ALL_VOLUMES = 10;
151dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
152dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_REPORT_NEW_ROUTES = 12;
153dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
154dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
155dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
156dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
157dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
158dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
159dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
160dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
1613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // start of messages handled under wakelock
1623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
163e12c39bb9cedb8b363658979872694eb55b1386eJean-Michel Trivi    //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
164fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
165fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int MSG_SET_A2DP_CONNECTION_STATE = 101;
1663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // end of messages handled under wakelock
167afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent
1684c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
169dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // Timeout for connection to bluetooth headset service
170dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
171dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioSystemThread */
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private AudioSystemThread mAudioSystemThread;
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioHandler */
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private AudioHandler mAudioHandler;
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see VolumeStreamState */
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private VolumeStreamState[] mStreamStates;
178b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    private SettingsObserver mSettingsObserver;
179a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
180fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private int mMode = AudioSystem.MODE_NORMAL;
181ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    // protects mRingerMode
182ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    private final Object mSettingsLock = new Object();
18345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private SoundPool mSoundPool;
18530c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final Object mSoundEffectsLock = new Object();
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int NUM_SOUNDPOOL_CHANNELS = 4;
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1884767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    // Internally master volume is a float in the 0.0 - 1.0 range,
1894767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    // but to support integer based AudioManager API we translate it to 0 - 100
1904767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    private static final int MAX_MASTER_VOLUME = 100;
1914767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood
1926c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    // Maximum volume adjust steps allowed in a single batch call.
1936c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
1946c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Sound effect file names  */
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
197e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * uses soundpool (second column) */
202e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2045982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles   /** @hide Maximum volume index values for audio streams */
205fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int[] MAX_STREAM_VOLUME = new int[] {
2066ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        5,  // STREAM_VOICE_CALL
2076ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_SYSTEM
2086ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_RING
2096ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15, // STREAM_MUSIC
2106ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_ALARM
2116ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_NOTIFICATION
2126ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15, // STREAM_BLUETOOTH_SCO
2136ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_SYSTEM_ENFORCED
2146ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15, // STREAM_DTMF
2156ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15  // STREAM_TTS
2165982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles    };
2176d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
218a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     * of another stream: This avoids multiplying the volume settings for hidden
219a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     * stream types that follow other stream behavior for volume settings
2206d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     * NOTE: do not create loops in aliases!
2216d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     * Some streams alias to different streams according to device category (phone or tablet) or
22224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent     * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
2236d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     *  mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and
2246d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     *  STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/
22530c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final int[] STREAM_VOLUME_ALIAS = new int[] {
2266d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
2276d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_SYSTEM
2286d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_RING
2296d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
2306d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
2316d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
2326d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
2336d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
2346d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_DTMF
2356d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC            // STREAM_TTS
236a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    };
2376d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] {
2386d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
2396d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_SYSTEM
2406d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_RING
2416d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
2426d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
2436d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
2446d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
2456d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_SYSTEM_ENFORCED
2466d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_DTMF
2476d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC            // STREAM_TTS
2486d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    };
2496d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private int[] mStreamVolumeAlias;
250a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
251ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    /**
252ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn     * Map AudioSystem.STREAM_* constants to app ops.  This should be used
253ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn     * after mapping through mStreamVolumeAlias.
254ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn     */
255ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    private static final int[] STEAM_VOLUME_OPS = new int[] {
256ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_VOICE_VOLUME,            // STREAM_VOICE_CALL
257ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM
258ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_RING_VOLUME,             // STREAM_RING
259ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_MUSIC
260ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_ALARM_VOLUME,            // STREAM_ALARM
261ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME,     // STREAM_NOTIFICATION
262ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME,        // STREAM_BLUETOOTH_SCO
263ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM_ENFORCED
264ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_DTMF
265ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_TTS
266ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    };
267ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn
26883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent    private final boolean mUseFixedVolume;
26983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
270bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    // stream names used by dumpStreamStates()
271bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private final String[] STREAM_NAMES = new String[] {
272bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_VOICE_CALL",
273bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_SYSTEM",
274bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_RING",
275bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_MUSIC",
276bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_ALARM",
277bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_NOTIFICATION",
278bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_BLUETOOTH_SCO",
279bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_SYSTEM_ENFORCED",
280bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_DTMF",
281bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_TTS"
282bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    };
283bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
28430c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onError(int error) {
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (error) {
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioSystem.AUDIO_STATUS_SERVER_DIED:
288dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
289dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                        SENDMSG_NOOP, 0, 0, null, 0);
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
294dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent        }
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link AudioManager#RINGER_MODE_SILENT}, or
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link AudioManager#RINGER_MODE_VIBRATE}.
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
302ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    // protected by mSettingsLock
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mRingerMode;
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3059bcf401d13d47416043a704430388abd59aef7cdEric Laurent    /** @see System#MODE_RINGER_STREAMS_AFFECTED */
30624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent    private int mRingerModeAffectedStreams = 0;
3079bcf401d13d47416043a704430388abd59aef7cdEric Laurent
3085b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    // Streams currently muted by ringer mode
3095b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    private int mRingerModeMutedStreams;
3105b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see System#MUTE_STREAMS_AFFECTED */
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mMuteAffectedStreams;
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
315bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent     * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
316bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent     * mVibrateSetting is just maintained during deprecation period but vibration policy is
317bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent     * now only controlled by mHasVibrator and mRingerMode
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mVibrateSetting;
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
321bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    // Is there a vibrator
322bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private final boolean mHasVibrator;
323bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
324a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    // Broadcast receiver for device connections intent broadcasts
325a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
326a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
327c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    // Devices currently connected
32830c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
329c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
330c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    // Forced device usage for communications
331c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    private int mForcedUseForComm;
332c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
3330dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    // True if we have master volume support
3340dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    private final boolean mUseMasterVolume;
3350dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
3369760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood    private final int[] mMasterVolumeRamp;
3379760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood
3389272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    // List of binder death handlers for setMode() client processes.
3399272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    // The last process to have called setMode() is at the top of the list.
34030c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
341eb14a783be073b5fd6e8c8c9bc87d2d1919f2c9eEric Laurent
3423def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    // List of clients having issued a SCO start request
34330c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
3443def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
3453def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    // BluetoothHeadset API to control SCO connection
3463def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    private BluetoothHeadset mBluetoothHeadset;
3473def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
34882aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh    // Bluetooth headset device
34982aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh    private BluetoothDevice mBluetoothHeadsetDevice;
3503def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
35162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // Indicate if SCO audio connection is currently active and if the initiator is
35262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // audio service (internal) or bluetooth headset (external)
35362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private int mScoAudioState;
35462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // SCO audio state is not active
35562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private static final int SCO_STATE_INACTIVE = 0;
356dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // SCO audio activation request waiting for headset service to connect
357dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_ACTIVATE_REQ = 1;
35825fc29b3691a1d2a84164988dc74b2e7d301868eEric Laurent    // SCO audio state is active or starting due to a request from AudioManager API
359dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
360dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // SCO audio deactivation request waiting for headset service to connect
361dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_DEACTIVATE_REQ = 5;
362dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
36362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // SCO audio state is active due to an action in BT handsfree (either voice recognition or
36462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // in call audio)
36562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
366dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // Deactivation request for all SCO connections (initiated by audio mode change)
367dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // waiting for headset service to connect
368dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
369dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
370c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
371c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    // originated from an app targeting an API version before JB MR2 and raw audio after that.
372c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    private int mScoAudioMode;
373c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
374c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    private static final int SCO_MODE_VIRTUAL_CALL = 0;
375c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
376c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    private static final int SCO_MODE_RAW = 1;
377c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent
378dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // Current connection state indicated by bluetooth headset
379dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private int mScoConnectionState;
38062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent
381a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // true if boot sequence has been completed
382a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private boolean mBootCompleted;
383a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // listener for SoundPool sample load completion indication
384a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private SoundPoolCallback mSoundPoolCallBack;
385a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // thread for SoundPool listener
386a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private SoundPoolListenerThread mSoundPoolListenerThread;
387a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // message looper for SoundPool listener
388a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private Looper mSoundPoolLooper = null;
389c55b393efd462490cd5e27fc373bceafdd25662eJean-Michel Trivi    // volume applied to sound played with playSoundEffect()
390f2b0c11f4e797e183131261724d8de310dac5431Jean-Michel Trivi    private static int sSoundEffectVolumeDb;
3919903e2638a6c502d96413680d3ebae4fb77fc412Eric Laurent    // getActiveStreamType() will return:
3929903e2638a6c502d96413680d3ebae4fb77fc412Eric Laurent    // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
3939903e2638a6c502d96413680d3ebae4fb77fc412Eric Laurent    // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
39425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    // stopped
3959903e2638a6c502d96413680d3ebae4fb77fc412Eric Laurent    private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
39625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    // previous volume adjustment direction received by checkForRingerModeChange()
39725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    private int mPrevVolDirection = AudioManager.ADJUST_SAME;
3986243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani    // Keyguard manager proxy
3996243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani    private KeyguardManager mKeyguardManager;
40045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
40145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // is controlled by Vol keys.
40245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private int  mVolumeControlStream = -1;
40345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private final Object mForceControlStreamLock = new Object();
40445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
40545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // server process so in theory it is not necessary to monitor the client death.
40645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // However it is good to be ready for future evolutions.
40745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private ForceControlStreamClient mForceControlStreamClient = null;
408098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    // Used to play ringtones outside system_server
409098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    private volatile IRingtonePlayer mRingtonePlayer;
4109bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
411f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
412bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    private int mDeviceRotation = Surface.ROTATION_0;
413f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
4147847211fb4699bf6018e29d214a918ed6657319bEric Laurent    // Request to override default use of A2DP for media.
4157847211fb4699bf6018e29d214a918ed6657319bEric Laurent    private boolean mBluetoothA2dpEnabled;
4167847211fb4699bf6018e29d214a918ed6657319bEric Laurent    private final Object mBluetoothA2dpEnabledLock = new Object();
4177847211fb4699bf6018e29d214a918ed6657319bEric Laurent
418632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    // Monitoring of audio routes.  Protected by mCurAudioRoutes.
419632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
420632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
421632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            = new RemoteCallbackList<IAudioRoutesObserver>();
422632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
4233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
4243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * A fake stream type to match the notion of remote media playback
4253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
4263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int STREAM_REMOTE_MUSIC = -200;
4273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
4284bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent    // Devices for which the volume is fixed and VolumePanel slider should be disabled
4294bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent    final int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_AUX_DIGITAL |
4304bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
4317ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
4324bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            AudioSystem.DEVICE_OUT_ALL_USB;
4334bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent
434bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    // TODO merge orientation and rotation
435d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private final boolean mMonitorOrientation;
436bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    private final boolean mMonitorRotation;
437d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent
4387ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent    private boolean mDockAudioMediaEnabled = true;
4397ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent
44008ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent    private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
44108ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent
442fde16d5879ea88a971004c984093409468b6139cEric Laurent    // Used when safe volume warning message display is requested by setStreamVolume(). In this
443fde16d5879ea88a971004c984093409468b6139cEric Laurent    // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
444fde16d5879ea88a971004c984093409468b6139cEric Laurent    // and used later when/if disableSafeMediaVolume() is called.
445fde16d5879ea88a971004c984093409468b6139cEric Laurent    private StreamVolumeCommand mPendingVolumeCommand;
446fde16d5879ea88a971004c984093409468b6139cEric Laurent
447fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private PowerManager.WakeLock mAudioEventWakeLock;
448fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
449fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final MediaFocusControl mMediaFocusControl;
450fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
4515a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    // Reference to BluetoothA2dp to query for AbsoluteVolume.
4525a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    private BluetoothA2dp mA2dp;
4535a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    private final Object mA2dpAvrcpLock = new Object();
4545a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    // If absolute volume is supported in AVRCP device
4555a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    private boolean mAvrcpAbsVolSupported = false;
4565a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Construction
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @hide */
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public AudioService(Context context) {
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContentResolver = context.getContentResolver();
465ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
466c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato        mVoiceCapable = mContext.getResources().getBoolean(
467c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato                com.android.internal.R.bool.config_voice_capable);
4685982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles
469c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
470fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
471c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
472bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
473bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
474bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
4755982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles       // Intialized volume
4765982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles        MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt(
4775982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles            "ro.config.vc_call_vol_steps",
4785982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles           MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
4795982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles
480f2b0c11f4e797e183131261724d8de310dac5431Jean-Michel Trivi        sSoundEffectVolumeDb = context.getResources().getInteger(
481c55b393efd462490cd5e27fc373bceafdd25662eJean-Michel Trivi                com.android.internal.R.integer.config_soundEffectVolumeDb);
48225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVolumePanel = new VolumePanel(context, this);
484c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent        mForcedUseForComm = AudioSystem.FORCE_NONE;
485dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        createAudioSystemThread();
487dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
488fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
489fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                mContext, /*VolumeController*/ mVolumePanel, this);
490fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
491dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent        AudioSystem.setErrorCallback(mAudioSystemCallback);
492dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent
493dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        boolean cameraSoundForced = mContext.getResources().getBoolean(
494dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                com.android.internal.R.bool.config_camera_sound_forced);
495dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        mCameraSoundForced = new Boolean(cameraSoundForced);
496dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        sendMsg(mAudioHandler,
497dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                MSG_SET_FORCE_USE,
498dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                SENDMSG_QUEUE,
499dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                AudioSystem.FOR_SYSTEM,
500dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                cameraSoundForced ?
501dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
502dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                null,
503dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                0);
504dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
50505274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
50605274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                                                        Settings.Global.AUDIO_SAFE_VOLUME_STATE,
50705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                                                        SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
50805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        // The default safe volume index read here will be replaced by the actual value when
50905274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        // the mcc is read by onConfigureSafeVolume()
51005274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        mSafeMediaVolumeIndex = mContext.getResources().getInteger(
51105274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                com.android.internal.R.integer.config_safe_media_volume_index) * 10;
51205274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent
51383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        mUseFixedVolume = mContext.getResources().getBoolean(
51483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                com.android.internal.R.bool.config_useFixedVolume);
51583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
51624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
51724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // array initialized by updateStreamVolumeAlias()
51824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        updateStreamVolumeAlias(false /*updateVolumes*/);
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        readPersistedSettings();
520c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent        mSettingsObserver = new SettingsObserver();
521a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        createStreamStates();
5229f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent
523fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten        readAndSetLowRamDevice();
5243891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent
5253891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        // Call setRingerModeInt() to apply correct mute
5263891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        // state on streams affected by ringer mode.
5273891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        mRingerModeMutedStreams = 0;
5283891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        setRingerModeInt(getRingerMode(), false);
5293891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent
530a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        // Register for device connection intent broadcasts.
531a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        IntentFilter intentFilter =
532b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
53382aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
53482aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
53559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
53659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
53762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent        intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
538950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
539950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
540bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
541f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
542d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
543bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        // TODO merge orientation and rotation
544d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
545d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        if (mMonitorOrientation) {
546f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            Log.v(TAG, "monitoring device orientation");
547f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            // initialize orientation in AudioSystem
548f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            setOrientationForAudioSystem();
549f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        }
550bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
551bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        if (mMonitorRotation) {
552bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
553bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                    .getDefaultDisplay().getRotation();
554bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
555bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            // initialize rotation in AudioSystem
556bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            setRotationForAudioSystem();
557bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        }
558f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
559a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        context.registerReceiver(mReceiver, intentFilter);
5605982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles
5610dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        mUseMasterVolume = context.getResources().getBoolean(
5620dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood                com.android.internal.R.bool.config_useMasterVolume);
5639063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood        restoreMasterVolume();
5649760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood
5659760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        mMasterVolumeRamp = context.getResources().getIntArray(
5669760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood                com.android.internal.R.array.config_masterVolumeRamp);
5677847211fb4699bf6018e29d214a918ed6657319bEric Laurent
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void createAudioSystemThread() {
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAudioSystemThread = new AudioSystemThread();
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAudioSystemThread.start();
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        waitForAudioHandlerCreation();
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Waits for the volume handler to be created by the other thread. */
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void waitForAudioHandlerCreation() {
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized(this) {
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (mAudioHandler == null) {
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Wait for mAudioHandler to be set by the other thread
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    wait();
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (InterruptedException e) {
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.e(TAG, "Interrupted while waiting on volume handler.");
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
590244820185269991186d07068b92985624cede4a5Eric Laurent    private void checkAllAliasStreamVolumes() {
591244820185269991186d07068b92985624cede4a5Eric Laurent        int numStreamTypes = AudioSystem.getNumStreamTypes();
592244820185269991186d07068b92985624cede4a5Eric Laurent        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
593244820185269991186d07068b92985624cede4a5Eric Laurent            if (streamType != mStreamVolumeAlias[streamType]) {
594244820185269991186d07068b92985624cede4a5Eric Laurent                mStreamStates[streamType].
59542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                    setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
596244820185269991186d07068b92985624cede4a5Eric Laurent            }
597244820185269991186d07068b92985624cede4a5Eric Laurent            // apply stream volume
59842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            if (!mStreamStates[streamType].isMuted()) {
599244820185269991186d07068b92985624cede4a5Eric Laurent                mStreamStates[streamType].applyAllVolumes();
600244820185269991186d07068b92985624cede4a5Eric Laurent            }
601244820185269991186d07068b92985624cede4a5Eric Laurent        }
602244820185269991186d07068b92985624cede4a5Eric Laurent    }
603244820185269991186d07068b92985624cede4a5Eric Laurent
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void createStreamStates() {
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int numStreamTypes = AudioSystem.getNumStreamTypes();
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < numStreamTypes; i++) {
6096d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
612244820185269991186d07068b92985624cede4a5Eric Laurent        checkAllAliasStreamVolumes();
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
615bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private void dumpStreamStates(PrintWriter pw) {
616bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        pw.println("\nStream volumes (device: index)");
617bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        int numStreamTypes = AudioSystem.getNumStreamTypes();
618bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        for (int i = 0; i < numStreamTypes; i++) {
619bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.println("- "+STREAM_NAMES[i]+":");
620bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            mStreamStates[i].dump(pw);
621bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.println("");
622bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
623dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.print("\n- mute affected streams = 0x");
624dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println(Integer.toHexString(mMuteAffectedStreams));
625bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    }
626bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
6276d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
6286d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private void updateStreamVolumeAlias(boolean updateVolumes) {
6296d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        int dtmfStreamAlias;
6306d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (mVoiceCapable) {
6316d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            mStreamVolumeAlias = STREAM_VOLUME_ALIAS;
6326d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            dtmfStreamAlias = AudioSystem.STREAM_RING;
6336d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        } else {
6346d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE;
6356d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
6366d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
6376d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (isInCommunication()) {
6386d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
63924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
64024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        } else {
64124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
6426d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
6436d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
6446d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (updateVolumes) {
64542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
64624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            // apply stream mute states according to new value of mRingerModeAffectedStreams
64724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            setRingerModeInt(getRingerMode(), false);
6486d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            sendMsg(mAudioHandler,
6496d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    MSG_SET_ALL_VOLUMES,
6506d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    SENDMSG_QUEUE,
6516d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    0,
6526d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    0,
6536d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    mStreamStates[AudioSystem.STREAM_DTMF], 0);
6546d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
6556d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    }
6566d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
6577ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent    private void readDockAudioSettings(ContentResolver cr)
6587ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent    {
6597ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent        mDockAudioMediaEnabled = Settings.Global.getInt(
6605ba0ffa0237a5c300545e4c72591613c6e5b2ed9Eric Laurent                                        cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
6617ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent
6627ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent        if (mDockAudioMediaEnabled) {
6637ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent            mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
6647ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent        } else {
6657ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent            mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
6667ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent        }
6677ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent
6687ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent        sendMsg(mAudioHandler,
6697ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                MSG_SET_FORCE_USE,
6707ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                SENDMSG_QUEUE,
6717ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                AudioSystem.FOR_DOCK,
6727ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                mDockAudioMediaEnabled ?
6737ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
6747ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                null,
6757ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                0);
6767ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent    }
6777ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void readPersistedSettings() {
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ContentResolver cr = mContentResolver;
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
681bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        int ringerModeFromSettings =
6828d9a1f66d9d3dbbd45a56d441a746ec11dba7645Jeff Sharkey                Settings.Global.getInt(
6838d9a1f66d9d3dbbd45a56d441a746ec11dba7645Jeff Sharkey                        cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
684bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        int ringerMode = ringerModeFromSettings;
68572668b2c040b581b298b069f3b5af5ed7f212d89Eric Laurent        // sanity check in case the settings are restored from a device with incompatible
68672668b2c040b581b298b069f3b5af5ed7f212d89Eric Laurent        // ringer modes
687ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        if (!AudioManager.isValidRingerMode(ringerMode)) {
688ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            ringerMode = AudioManager.RINGER_MODE_NORMAL;
689bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
690bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
691bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            ringerMode = AudioManager.RINGER_MODE_SILENT;
692bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
693bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (ringerMode != ringerModeFromSettings) {
6948d9a1f66d9d3dbbd45a56d441a746ec11dba7645Jeff Sharkey            Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
695ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
69683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
69783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            ringerMode = AudioManager.RINGER_MODE_NORMAL;
69883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
699ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        synchronized(mSettingsLock) {
700ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            mRingerMode = ringerMode;
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
702dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
703dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            // are still needed while setVibrateSetting() and getVibrateSetting() are being
704dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            // deprecated.
705dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            mVibrateSetting = getValueForVibrateSetting(0,
706dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                            AudioManager.VIBRATE_TYPE_NOTIFICATION,
707dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
708dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                                            : AudioManager.VIBRATE_SETTING_OFF);
709dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
710dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                            AudioManager.VIBRATE_TYPE_RINGER,
711dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
712dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                                            : AudioManager.VIBRATE_SETTING_OFF);
713dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
71424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            updateRingerModeAffectedStreams();
7157ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent            readDockAudioSettings(cr);
716402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        }
717c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent
718bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent        mMuteAffectedStreams = System.getIntForUser(cr,
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                System.MUTE_STREAMS_AFFECTED,
720bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                ((1 << AudioSystem.STREAM_MUSIC)|
721bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                 (1 << AudioSystem.STREAM_RING)|
722bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                 (1 << AudioSystem.STREAM_SYSTEM)),
723bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                 UserHandle.USER_CURRENT);
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
725bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent        boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
726bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                  0, UserHandle.USER_CURRENT) == 1;
72783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
72883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            masterMute = false;
72983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            AudioSystem.setMasterVolume(1.0f);
73083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
73157978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        AudioSystem.setMasterMute(masterMute);
73257978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        broadcastMasterMuteStatus(masterMute);
73357978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Each stream will read its own persisted settings
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Broadcast the sticky intent
737ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        broadcastRingerMode(ringerMode);
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Broadcast vibrate settings
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
742d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
743d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        // Restore the default media button receiver from the system settings
744fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.restoreMediaButtonReceiver();
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
747a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    private int rescaleIndex(int index, int srcStream, int dstStream) {
748a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
749a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    }
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // IPC methods
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
754fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    /** @see AudioManager#isLocalOrRemoteMusicActive() */
755fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    public boolean isLocalOrRemoteMusicActive() {
756fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
757fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            // local / wired / BT playback active
758fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): local");
759fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            return true;
760fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        }
761fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
762fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            // remote "cast-like" playback active
763fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): has PLAYBACK_TYPE_REMOTE");
764fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            return true;
765fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        }
766fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        if (AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, 0)) {
767fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            // remote submix playback active
768fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): remote submix");
769fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            return true;
770fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        }
771fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): no");
772fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        return false;
773fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    }
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#adjustVolume(int, int) */
776ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void adjustVolume(int direction, int flags, String callingPackage) {
777ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags,
778ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn                callingPackage);
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /** @see AudioManager#adjustLocalOrRemoteStreamVolume(int, int) with current assumption
7823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *  on streamType: fixed to STREAM_MUSIC */
783ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void adjustLocalOrRemoteStreamVolume(int streamType, int direction,
784ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            String callingPackage) {
7853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (DEBUG_VOL) Log.d(TAG, "adjustLocalOrRemoteStreamVolume(dir="+direction+")");
786fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
787ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            adjustStreamVolume(AudioSystem.STREAM_MUSIC, direction, 0, callingPackage);
788fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        } else if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
789fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            mMediaFocusControl.adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, 0);
7903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
7913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
7923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
793961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#adjustVolume(int, int) */
794ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
795ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            String callingPackage) {
7963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType);
797402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        int streamType;
79845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        if (mVolumeControlStream != -1) {
79945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            streamType = mVolumeControlStream;
800402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        } else {
801402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent            streamType = getActiveStreamType(suggestedStreamType);
802402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        }
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8046243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani        // Play sounds on STREAM_RING only and if lock screen is not on.
8053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if ((streamType != STREAM_REMOTE_MUSIC) &&
8063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                (flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
8076d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                ((mStreamVolumeAlias[streamType] != AudioSystem.STREAM_RING)
8086243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani                 || (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) {
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flags &= ~AudioManager.FLAG_PLAY_SOUND;
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (streamType == STREAM_REMOTE_MUSIC) {
8133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            // don't play sounds for remote
814799448bee167c046ed715c7c4e3fe3486bf80d43Eric Laurent            flags &= ~(AudioManager.FLAG_PLAY_SOUND|AudioManager.FLAG_FIXED_VOLUME);
8153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            //if (DEBUG_VOL) Log.i(TAG, "Need to adjust remote volume: calling adjustRemoteVolume()");
816fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mMediaFocusControl.adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, flags);
8173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        } else {
818ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            adjustStreamVolume(streamType, direction, flags, callingPackage);
8193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#adjustStreamVolume(int, int, int) */
823ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void adjustStreamVolume(int streamType, int direction, int flags,
824ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            String callingPackage) {
82583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
82683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
82783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
8283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction);
8293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidDirection(direction);
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
83396a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent        // use stream type alias here so that streams with same alias have the same behavior,
83496a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent        // including with regard to silent mode control (e.g the use of STREAM_RING below and in
83596a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent        // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
8366d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        int streamTypeAlias = mStreamVolumeAlias[streamType];
837b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
8389bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
8399bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        final int device = getDeviceForStream(streamTypeAlias);
8403ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent
84142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        int aliasIndex = streamState.getIndex(device);
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean adjustVolume = true;
8433ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        int step;
844244820185269991186d07068b92985624cede4a5Eric Laurent
845c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        // skip a2dp absolute volume control request when the device
846c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        // is not an a2dp device
847c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
848c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
849c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            return;
850c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        }
851c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie
852ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
853ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn                callingPackage) != AppOpsManager.MODE_ALLOWED) {
854ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            return;
855ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        }
856ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn
857fde16d5879ea88a971004c984093409468b6139cEric Laurent        // reset any pending volume command
858fde16d5879ea88a971004c984093409468b6139cEric Laurent        synchronized (mSafeMediaVolumeState) {
859fde16d5879ea88a971004c984093409468b6139cEric Laurent            mPendingVolumeCommand = null;
860fde16d5879ea88a971004c984093409468b6139cEric Laurent        }
861fde16d5879ea88a971004c984093409468b6139cEric Laurent
8623ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        flags &= ~AudioManager.FLAG_FIXED_VOLUME;
8633ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
8643ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent               ((device & mFixedVolumeDevices) != 0)) {
8653ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            flags |= AudioManager.FLAG_FIXED_VOLUME;
8663ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent
8673ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            // Always toggle between max safe volume and 0 for fixed volume devices where safe
8683ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            // volume is enforced, and max and 0 for the others.
8693ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            // This is simulated by stepping by the full allowed volume range
8703ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
8713ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                    (device & mSafeMediaVolumeDevices) != 0) {
8723ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                step = mSafeMediaVolumeIndex;
8733ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            } else {
8743ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                step = streamState.getMaxIndex();
8753ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            }
8763ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            if (aliasIndex != 0) {
8773ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                aliasIndex = step;
8783ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            }
8793ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        } else {
8803ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            // convert one UI step (+/-1) into a number of internal units on the stream alias
8813ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            step = rescaleIndex(10, streamType, streamTypeAlias);
8823ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        }
8833ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent
88442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        // If either the client forces allowing ringer modes for this adjustment,
88542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        // or the stream type is one that is affected by ringer modes
88642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
88742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                (streamTypeAlias == getMasterStreamType())) {
88842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            int ringerMode = getRingerMode();
88942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // do not vibrate if already in vibrate mode
89042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
89142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                flags &= ~AudioManager.FLAG_VIBRATE;
89242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            }
89342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // Check if the ringer mode changes with this volume adjustment. If
89442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // it does, it will handle adjusting the volume, so we won't below
89542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            adjustVolume = checkForRingerModeChange(aliasIndex, direction, step);
89642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        }
89742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent
89842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        int oldIndex = mStreamStates[streamType].getIndex(device);
89942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent
90042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
901c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie
9025a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du            // Check if volume update should be send to AVRCP
903c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
904c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
905c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
906c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                synchronized (mA2dpAvrcpLock) {
907c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                    if (mA2dp != null && mAvrcpAbsVolSupported) {
908c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                        mA2dp.adjustAvrcpAbsoluteVolume(direction);
909c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                    }
9105a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                }
9115a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du            }
912c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie
91342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            if ((direction == AudioManager.ADJUST_RAISE) &&
91442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
91542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
91642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                mVolumePanel.postDisplaySafeVolumeWarning(flags);
91742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            } else if (streamState.adjustIndex(direction * step, device)) {
91842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                // Post message to set system volume (it in turn will post a message
91942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                // to persist). Do not change volume if stream is muted.
92042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                sendMsg(mAudioHandler,
92142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        MSG_SET_DEVICE_VOLUME,
92242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        SENDMSG_QUEUE,
92342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        device,
92442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        0,
92542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        streamState,
92642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        0);
9274bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            }
9284bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        }
92942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        int index = mStreamStates[streamType].getIndex(device);
93025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        sendVolumeUpdate(streamType, oldIndex, index, flags);
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
933961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#adjustMasterVolume(int, int) */
934ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void adjustMasterVolume(int steps, int flags, String callingPackage) {
93583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
93683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
93783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
9386c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        ensureValidSteps(steps);
9399760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
9409760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        int delta = 0;
9416c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        int numSteps = Math.abs(steps);
9426c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
9436c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        for (int i = 0; i < numSteps; ++i) {
9446c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            delta = findVolumeDelta(direction, volume);
9456c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            volume += delta;
946cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood        }
94724b082f87e96c00d5c17d60c735423900be40e70RoboErik
9486c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
949ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        setMasterVolume(volume, flags, callingPackage);
950cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood    }
951cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood
952fde16d5879ea88a971004c984093409468b6139cEric Laurent    // StreamVolumeCommand contains the information needed to defer the process of
953fde16d5879ea88a971004c984093409468b6139cEric Laurent    // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
954fde16d5879ea88a971004c984093409468b6139cEric Laurent    class StreamVolumeCommand {
955fde16d5879ea88a971004c984093409468b6139cEric Laurent        public final int mStreamType;
956fde16d5879ea88a971004c984093409468b6139cEric Laurent        public final int mIndex;
957fde16d5879ea88a971004c984093409468b6139cEric Laurent        public final int mFlags;
958fde16d5879ea88a971004c984093409468b6139cEric Laurent        public final int mDevice;
9593ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent
960fde16d5879ea88a971004c984093409468b6139cEric Laurent        StreamVolumeCommand(int streamType, int index, int flags, int device) {
961fde16d5879ea88a971004c984093409468b6139cEric Laurent            mStreamType = streamType;
962fde16d5879ea88a971004c984093409468b6139cEric Laurent            mIndex = index;
963fde16d5879ea88a971004c984093409468b6139cEric Laurent            mFlags = flags;
964fde16d5879ea88a971004c984093409468b6139cEric Laurent            mDevice = device;
9654bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        }
966fde16d5879ea88a971004c984093409468b6139cEric Laurent    };
9673ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent
968fde16d5879ea88a971004c984093409468b6139cEric Laurent    private void onSetStreamVolume(int streamType, int index, int flags, int device) {
96942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
9703ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        // setting volume on master stream type also controls silent mode
9713ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
9723ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
9733ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            int newRingerMode;
9743ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            if (index == 0) {
9753ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
9763ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                                              : AudioManager.RINGER_MODE_SILENT;
9773ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            } else {
9783ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                newRingerMode = AudioManager.RINGER_MODE_NORMAL;
9793ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            }
9803ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            setRingerMode(newRingerMode);
9813ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        }
982fde16d5879ea88a971004c984093409468b6139cEric Laurent    }
983fde16d5879ea88a971004c984093409468b6139cEric Laurent
984fde16d5879ea88a971004c984093409468b6139cEric Laurent    /** @see AudioManager#setStreamVolume(int, int, int) */
985ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
98683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
98783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
98883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
98983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
990fde16d5879ea88a971004c984093409468b6139cEric Laurent        ensureValidStreamType(streamType);
991ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        int streamTypeAlias = mStreamVolumeAlias[streamType];
992ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
993fde16d5879ea88a971004c984093409468b6139cEric Laurent
994fde16d5879ea88a971004c984093409468b6139cEric Laurent        final int device = getDeviceForStream(streamType);
995fde16d5879ea88a971004c984093409468b6139cEric Laurent        int oldIndex;
996fde16d5879ea88a971004c984093409468b6139cEric Laurent
997c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        // skip a2dp absolute volume control request when the device
998c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        // is not an a2dp device
999c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1000c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1001c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            return;
1002c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        }
1003c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie
1004ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
1005ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn                callingPackage) != AppOpsManager.MODE_ALLOWED) {
1006ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            return;
1007ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        }
1008ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn
1009fde16d5879ea88a971004c984093409468b6139cEric Laurent        synchronized (mSafeMediaVolumeState) {
1010fde16d5879ea88a971004c984093409468b6139cEric Laurent            // reset any pending volume command
1011fde16d5879ea88a971004c984093409468b6139cEric Laurent            mPendingVolumeCommand = null;
1012fde16d5879ea88a971004c984093409468b6139cEric Laurent
101342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            oldIndex = streamState.getIndex(device);
1014fde16d5879ea88a971004c984093409468b6139cEric Laurent
1015ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            index = rescaleIndex(index * 10, streamType, streamTypeAlias);
1016fde16d5879ea88a971004c984093409468b6139cEric Laurent
1017c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1018c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1019c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1020c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                synchronized (mA2dpAvrcpLock) {
1021c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                    if (mA2dp != null && mAvrcpAbsVolSupported) {
1022c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                        mA2dp.setAvrcpAbsoluteVolume(index);
1023c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                    }
10245a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                }
10255a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du            }
10265a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
1027fde16d5879ea88a971004c984093409468b6139cEric Laurent            flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1028ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1029fde16d5879ea88a971004c984093409468b6139cEric Laurent                    ((device & mFixedVolumeDevices) != 0)) {
1030fde16d5879ea88a971004c984093409468b6139cEric Laurent                flags |= AudioManager.FLAG_FIXED_VOLUME;
1031fde16d5879ea88a971004c984093409468b6139cEric Laurent
1032fde16d5879ea88a971004c984093409468b6139cEric Laurent                // volume is either 0 or max allowed for fixed volume devices
1033fde16d5879ea88a971004c984093409468b6139cEric Laurent                if (index != 0) {
1034fde16d5879ea88a971004c984093409468b6139cEric Laurent                    if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1035fde16d5879ea88a971004c984093409468b6139cEric Laurent                            (device & mSafeMediaVolumeDevices) != 0) {
1036fde16d5879ea88a971004c984093409468b6139cEric Laurent                        index = mSafeMediaVolumeIndex;
1037fde16d5879ea88a971004c984093409468b6139cEric Laurent                    } else {
1038fde16d5879ea88a971004c984093409468b6139cEric Laurent                        index = streamState.getMaxIndex();
1039fde16d5879ea88a971004c984093409468b6139cEric Laurent                    }
1040fde16d5879ea88a971004c984093409468b6139cEric Laurent                }
1041fde16d5879ea88a971004c984093409468b6139cEric Laurent            }
1042fde16d5879ea88a971004c984093409468b6139cEric Laurent
1043ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
1044fde16d5879ea88a971004c984093409468b6139cEric Laurent                mVolumePanel.postDisplaySafeVolumeWarning(flags);
1045fde16d5879ea88a971004c984093409468b6139cEric Laurent                mPendingVolumeCommand = new StreamVolumeCommand(
1046fde16d5879ea88a971004c984093409468b6139cEric Laurent                                                    streamType, index, flags, device);
1047fde16d5879ea88a971004c984093409468b6139cEric Laurent            } else {
1048fde16d5879ea88a971004c984093409468b6139cEric Laurent                onSetStreamVolume(streamType, index, flags, device);
104942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                index = mStreamStates[streamType].getIndex(device);
1050fde16d5879ea88a971004c984093409468b6139cEric Laurent            }
1051fde16d5879ea88a971004c984093409468b6139cEric Laurent        }
105225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        sendVolumeUpdate(streamType, oldIndex, index, flags);
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
105545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    /** @see AudioManager#forceVolumeControlStream(int) */
105645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    public void forceVolumeControlStream(int streamType, IBinder cb) {
105745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        synchronized(mForceControlStreamLock) {
105845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            mVolumeControlStream = streamType;
105945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            if (mVolumeControlStream == -1) {
106045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                if (mForceControlStreamClient != null) {
106145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mForceControlStreamClient.release();
106245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mForceControlStreamClient = null;
106345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                }
106445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            } else {
106545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                mForceControlStreamClient = new ForceControlStreamClient(cb);
106645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
106745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
106845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    }
106945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
107045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private class ForceControlStreamClient implements IBinder.DeathRecipient {
107145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        private IBinder mCb; // To be notified of client's death
107245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
107345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        ForceControlStreamClient(IBinder cb) {
107445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            if (cb != null) {
107545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                try {
107645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    cb.linkToDeath(this, 0);
107745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                } catch (RemoteException e) {
107845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    // Client has died!
107945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
108045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    cb = null;
108145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                }
108245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
108345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            mCb = cb;
108445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
108545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
108645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        public void binderDied() {
108745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            synchronized(mForceControlStreamLock) {
108845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                Log.w(TAG, "SCO client died");
108945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                if (mForceControlStreamClient != this) {
109045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    Log.w(TAG, "unregistered control stream client died");
109145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                } else {
109245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mForceControlStreamClient = null;
109345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mVolumeControlStream = -1;
109445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                }
109545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
109645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
109745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
109845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        public void release() {
109945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            if (mCb != null) {
110045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                mCb.unlinkToDeath(this, 0);
110145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                mCb = null;
110245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
110345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
110445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    }
110545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
11066c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    private int findVolumeDelta(int direction, int volume) {
11076c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        int delta = 0;
11086c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        if (direction == AudioManager.ADJUST_RAISE) {
11096c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            if (volume == MAX_MASTER_VOLUME) {
11106c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                return 0;
11116c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
11126c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // This is the default value if we make it to the end
11136c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            delta = mMasterVolumeRamp[1];
11146c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // If we're raising the volume move down the ramp array until we
11156c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // find the volume we're above and use that groups delta.
11166c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
11176c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                if (volume >= mMasterVolumeRamp[i - 1]) {
11186c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    delta = mMasterVolumeRamp[i];
11196c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    break;
11206c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                }
11216c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
11226c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        } else if (direction == AudioManager.ADJUST_LOWER){
11236c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            if (volume == 0) {
11246c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                return 0;
11256c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
11266c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            int length = mMasterVolumeRamp.length;
11276c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // This is the default value if we make it to the end
11286c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            delta = -mMasterVolumeRamp[length - 1];
11296c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // If we're lowering the volume move up the ramp array until we
11306c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // find the volume we're below and use the group below it's delta
11316c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            for (int i = 2; i < length; i += 2) {
11326c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                if (volume <= mMasterVolumeRamp[i]) {
11336c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    delta = -mMasterVolumeRamp[i - 1];
11346c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    break;
11356c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                }
11366c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
11376c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        }
11386c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        return delta;
11396c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    }
11406c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang
11415ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn    private void sendBroadcastToAll(Intent intent) {
11425ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        final long ident = Binder.clearCallingIdentity();
11435ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        try {
11445ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
11455ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        } finally {
11465ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            Binder.restoreCallingIdentity(ident);
11475ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        }
11485ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn    }
11495ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn
11505ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn    private void sendStickyBroadcastToAll(Intent intent) {
11515ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        final long ident = Binder.clearCallingIdentity();
11525ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        try {
11535ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
11545ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        } finally {
11555ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            Binder.restoreCallingIdentity(ident);
11565ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        }
11575ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn    }
11585ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn
115925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    // UI update and Broadcast Intent
116025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
116125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) {
116225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            streamType = AudioSystem.STREAM_NOTIFICATION;
116325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        }
116425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
116525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        mVolumePanel.postVolumeChanged(streamType, flags);
116625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
11674bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
11684bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            oldIndex = (oldIndex + 5) / 10;
11694bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            index = (index + 5) / 10;
11704bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
11714bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
11724bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
11734bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
11744bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            sendBroadcastToAll(intent);
11754bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        }
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11780dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    // UI update and Broadcast Intent
11790dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
11800dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        mVolumePanel.postMasterVolumeChanged(flags);
11810dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
11820dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
11830dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
11840dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
11855ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        sendBroadcastToAll(intent);
11860dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    }
11870dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
11880dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    // UI update and Broadcast Intent
11890dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    private void sendMasterMuteUpdate(boolean muted, int flags) {
11900dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        mVolumePanel.postMasterMuteChanged(flags);
119157978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        broadcastMasterMuteStatus(muted);
119257978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh    }
11930dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
119457978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh    private void broadcastMasterMuteStatus(boolean muted) {
11950dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
11960dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
119757978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
119857978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
11995ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        sendStickyBroadcastToAll(intent);
12000dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    }
12010dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the stream state's index, and posts a message to set system volume.
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This will not call out to the UI. Assumes a valid stream type.
12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param streamType Type of the stream
12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param index Desired volume index of the stream
12089bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent     * @param device the device whose volume must be changed
12099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param force If true, set the volume even if the desired volume is same
12109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * as the current volume.
12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12129bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    private void setStreamVolumeInt(int streamType,
12139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    int index,
12149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    int device,
121542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                    boolean force) {
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        VolumeStreamState streamState = mStreamStates[streamType];
12175b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
121842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        if (streamState.setIndex(index, device) || force) {
121942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // Post message to set system volume (it in turn will post a message
122042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // to persist).
122142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            sendMsg(mAudioHandler,
122242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    MSG_SET_DEVICE_VOLUME,
122342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    SENDMSG_QUEUE,
122442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    device,
122542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    0,
122642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    streamState,
122742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    0);
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setStreamSolo(int, boolean) */
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setStreamSolo(int streamType, boolean state, IBinder cb) {
123383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
123483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
123583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
123683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int stream = 0; stream < mStreamStates.length; stream++) {
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!isStreamAffectedByMute(stream) || stream == streamType) continue;
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStreamStates[stream].mute(cb, state);
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         }
12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setStreamMute(int, boolean) */
12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setStreamMute(int streamType, boolean state, IBinder cb) {
124583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
124683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
124783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
124883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (isStreamAffectedByMute(streamType)) {
12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStreamStates[streamType].mute(cb, state);
12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
125425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    /** get stream mute state. */
125525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    public boolean isStreamMute(int streamType) {
125642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        return mStreamStates[streamType].isMuted();
125725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    }
125825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
1259961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#setMasterMute(boolean, int) */
12600273af55cf68d54d26d154b44d105d40fed79701Justin Koh    public void setMasterMute(boolean state, int flags, IBinder cb) {
126183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
126283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
126383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
126483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
12651ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons        if (state != AudioSystem.getMasterMute()) {
12661ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons            AudioSystem.setMasterMute(state);
126757978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh            // Post a persist master volume msg
126875cf9e19a575c28c200c02c0ab6f83bb79f5c50dJustin Koh            sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
126957978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                    : 0, 0, null, PERSIST_DELAY);
12700273af55cf68d54d26d154b44d105d40fed79701Justin Koh            sendMasterMuteUpdate(state, flags);
12711ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons        }
1272ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1273ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
1274ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    /** get master mute state. */
1275ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    public boolean isMasterMute() {
12763194ea94348bce8e7ee9f803698d877f46f8279aMike Lockwood        return AudioSystem.getMasterMute();
1277ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1278ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
1279fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected static int getMaxStreamVolume(int streamType) {
1280fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return MAX_STREAM_VOLUME[streamType];
1281fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1282fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getStreamVolume(int) */
12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStreamVolume(int streamType) {
12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
12869bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = getDeviceForStream(streamType);
128742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        int index = mStreamStates[streamType].getIndex(device);
12884bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent
128942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        // by convention getStreamVolume() returns 0 when a stream is muted.
129042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        if (mStreamStates[streamType].isMuted()) {
129142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            index = 0;
129242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        }
12933ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
12944bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent                (device & mFixedVolumeDevices) != 0) {
12954bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            index = mStreamStates[streamType].getMaxIndex();
12964bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        }
12974bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        return (index + 5) / 10;
12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13004767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    public int getMasterVolume() {
1301ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        if (isMasterMute()) return 0;
1302ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        return getLastAudibleMasterVolume();
13038dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    }
13048dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood
1305ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void setMasterVolume(int volume, int flags, String callingPackage) {
130683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
130783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
130883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
130983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
1310ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
1311ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn                callingPackage) != AppOpsManager.MODE_ALLOWED) {
1312ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            return;
1313ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        }
1314ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn
13159760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        if (volume < 0) {
13169760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood            volume = 0;
13179760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        } else if (volume > MAX_MASTER_VOLUME) {
13189760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood            volume = MAX_MASTER_VOLUME;
13199760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        }
13205c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
13215c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood    }
13225c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
13235c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood    private void doSetMasterVolume(float volume, int flags) {
13245c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        // don't allow changing master volume when muted
13255c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        if (!AudioSystem.getMasterMute()) {
13265c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            int oldVolume = getMasterVolume();
13275c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            AudioSystem.setMasterVolume(volume);
13285c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
13295c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            int newVolume = getMasterVolume();
13305c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            if (newVolume != oldVolume) {
13315c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                // Post a persist master volume msg
13325c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
13335c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                        Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
13345c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            }
13353caba517253d1703fc29b50740c4567b932279fbJustin Koh            // Send the volume update regardless whether there was a change.
13363caba517253d1703fc29b50740c4567b932279fbJustin Koh            sendMasterVolumeUpdate(flags, oldVolume, newVolume);
13375c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        }
13388dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    }
13398dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood
13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getStreamMaxVolume(int) */
13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStreamMaxVolume(int streamType) {
13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
1343a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13464767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    public int getMasterMaxVolume() {
13474767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood        return MAX_MASTER_VOLUME;
13484767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    }
134925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
135025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    /** Get last audible volume before stream was muted. */
135125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    public int getLastAudibleStreamVolume(int streamType) {
135225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        ensureValidStreamType(streamType);
13539bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = getDeviceForStream(streamType);
135442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        return (mStreamStates[streamType].getIndex(device) + 5) / 10;
135525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    }
135625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
1357ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    /** Get last audible master volume before it was muted. */
1358ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    public int getLastAudibleMasterVolume() {
1359ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1360ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1361ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
1362961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#getMasterStreamType()  */
13636d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    public int getMasterStreamType() {
13646d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (mVoiceCapable) {
13656d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            return AudioSystem.STREAM_RING;
13666d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        } else {
13676d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            return AudioSystem.STREAM_MUSIC;
13686d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
13696d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    }
13706d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
13719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getRingerMode() */
13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getRingerMode() {
1373ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        synchronized(mSettingsLock) {
1374ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            return mRingerMode;
1375ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
1376ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    }
1377ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten
1378ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    private void ensureValidRingerMode(int ringerMode) {
1379ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        if (!AudioManager.isValidRingerMode(ringerMode)) {
1380ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1381ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setRingerMode(int) */
13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setRingerMode(int ringerMode) {
138683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
138783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
138883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
138983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
1390244820185269991186d07068b92985624cede4a5Eric Laurent        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1391244820185269991186d07068b92985624cede4a5Eric Laurent            ringerMode = AudioManager.RINGER_MODE_SILENT;
1392244820185269991186d07068b92985624cede4a5Eric Laurent        }
1393ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        if (ringerMode != getRingerMode()) {
1394ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            setRingerModeInt(ringerMode, true);
1395ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            // Send sticky broadcast
1396ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            broadcastRingerMode(ringerMode);
1397b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
1398b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    }
13999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14004050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    private void setRingerModeInt(int ringerMode, boolean persist) {
1401ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        synchronized(mSettingsLock) {
1402ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            mRingerMode = ringerMode;
1403ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
1404b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh
14055b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // Mute stream if not previously muted by ringer mode and ringer mode
14065b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
14075b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // Unmute stream if previously muted by ringer mode and ringer mode
14085b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
1409b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        int numStreamTypes = AudioSystem.getNumStreamTypes();
14105b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
14115b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent            if (isStreamMutedByRingerMode(streamType)) {
14125b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                if (!isStreamAffectedByRingerMode(streamType) ||
1413ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    ringerMode == AudioManager.RINGER_MODE_NORMAL) {
1414b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    // ring and notifications volume should never be 0 when not silenced
1415b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    // on voice capable devices
1416b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    if (mVoiceCapable &&
14176d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                            mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
14183172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        synchronized (mStreamStates[streamType]) {
141942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            Set set = mStreamStates[streamType].mIndex.entrySet();
14203172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            Iterator i = set.iterator();
14213172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            while (i.hasNext()) {
14223172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                Map.Entry entry = (Map.Entry)i.next();
14233172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                if ((Integer)entry.getValue() == 0) {
14243172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                    entry.setValue(10);
14253172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                }
14269bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                            }
14279bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        }
1428b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    }
14295b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                    mStreamStates[streamType].mute(null, false);
14305b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                    mRingerModeMutedStreams &= ~(1 << streamType);
14319bcf401d13d47416043a704430388abd59aef7cdEric Laurent                }
14325b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent            } else {
14335b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                if (isStreamAffectedByRingerMode(streamType) &&
1434ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    ringerMode != AudioManager.RINGER_MODE_NORMAL) {
14355b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                   mStreamStates[streamType].mute(null, true);
14365b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                   mRingerModeMutedStreams |= (1 << streamType);
14375b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent               }
1438b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            }
14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1440a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
1441b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        // Post a persist ringer mode msg
14424050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        if (persist) {
1443afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
14444050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent                    SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
14454050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        }
14469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14489063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood    private void restoreMasterVolume() {
144983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
145083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            AudioSystem.setMasterVolume(1.0f);
145183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
145283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
14539063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood        if (mUseMasterVolume) {
1454bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent            float volume = Settings.System.getFloatForUser(mContentResolver,
1455bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                    Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
14569063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood            if (volume >= 0.0f) {
14579063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                AudioSystem.setMasterVolume(volume);
14589063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood            }
14599063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood        }
14609063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood    }
14619063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood
14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#shouldVibrate(int) */
14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean shouldVibrate(int vibrateType) {
1464bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return false;
14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (getVibrateSetting(vibrateType)) {
14679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_ON:
1469ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                return getRingerMode() != AudioManager.RINGER_MODE_SILENT;
14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
1472ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE;
14739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_OFF:
1475bcac496076ef6f439147e7a2be71e8a2b76ddedeDaniel Sandler                // return false, even for incoming calls
1476bcac496076ef6f439147e7a2be71e8a2b76ddedeDaniel Sandler                return false;
14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getVibrateSetting(int) */
14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getVibrateSetting(int vibrateType) {
1485bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mVibrateSetting >> (vibrateType * 2)) & 3;
14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setVibrateSetting(int, int) */
14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setVibrateSetting(int vibrateType, int vibrateSetting) {
14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1492bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return;
1493bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Broadcast change
14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        broadcastVibrateSetting(vibrateType);
14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #setVibrateSetting(int, int)
15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static int getValueForVibrateSetting(int existingValue, int vibrateType,
15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int vibrateSetting) {
15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // First clear the existing setting. Each vibrate type has two bits in
15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // the value. Note '3' is '11' in binary.
15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        existingValue &= ~(3 << (vibrateType * 2));
15109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Set into the old value
15129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return existingValue;
15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15179272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    private class SetModeDeathHandler implements IBinder.DeathRecipient {
15189272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        private IBinder mCb; // To be notified of client's death
1519f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        private int mPid;
15209272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
15219272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
15229f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        SetModeDeathHandler(IBinder cb, int pid) {
15239272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            mCb = cb;
15249f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            mPid = pid;
15259272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
15269272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
15279272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public void binderDied() {
1528d7454be47f4111c0478a502353e11dea401378bdEric Laurent            int newModeOwnerPid = 0;
15299272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            synchronized(mSetModeDeathHandlers) {
15309272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                Log.w(TAG, "setMode() client died");
15319272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                int index = mSetModeDeathHandlers.indexOf(this);
15329272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                if (index < 0) {
15339272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                    Log.w(TAG, "unregistered setMode() client died");
15349272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                } else {
1535d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
15369272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                }
15379272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            }
15389f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
15399f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            // SCO connections not started by the application changing the mode
1540d7454be47f4111c0478a502353e11dea401378bdEric Laurent            if (newModeOwnerPid != 0) {
15416b5e22d52c69cb6d80ff09bd32395b0034ada343Eric Laurent                final long ident = Binder.clearCallingIdentity();
15426b5e22d52c69cb6d80ff09bd32395b0034ada343Eric Laurent                disconnectBluetoothSco(newModeOwnerPid);
15436b5e22d52c69cb6d80ff09bd32395b0034ada343Eric Laurent                Binder.restoreCallingIdentity(ident);
15449f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
15459272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
15469272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
1547f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        public int getPid() {
1548f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen            return mPid;
1549f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        }
1550f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen
15519272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public void setMode(int mode) {
15529272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            mMode = mode;
15539272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
15549272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
15559272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public int getMode() {
15569272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            return mMode;
15579272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
15589272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
15599272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public IBinder getBinder() {
15609272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            return mCb;
15619272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
15629272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    }
15639272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setMode(int) */
15659272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    public void setMode(int mode, IBinder cb) {
15669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!checkAudioSettingsPermission("setMode()")) {
15679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
15689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1569a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
15708f677d66d9c3ba34c97e69b2bb9e161f129af0eeJean-Michel Trivi        if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
1571a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            return;
1572a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        }
1573a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
1574d7454be47f4111c0478a502353e11dea401378bdEric Laurent        int newModeOwnerPid = 0;
15759f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        synchronized(mSetModeDeathHandlers) {
1576a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            if (mode == AudioSystem.MODE_CURRENT) {
1577a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                mode = mMode;
1578a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
1579d7454be47f4111c0478a502353e11dea401378bdEric Laurent            newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
15809f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
15819f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
15829f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        // SCO connections not started by the application changing the mode
1583d7454be47f4111c0478a502353e11dea401378bdEric Laurent        if (newModeOwnerPid != 0) {
1584d7454be47f4111c0478a502353e11dea401378bdEric Laurent             disconnectBluetoothSco(newModeOwnerPid);
15859f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
15869f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    }
15872ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi
15889f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    // must be called synchronized on mSetModeDeathHandlers
1589d7454be47f4111c0478a502353e11dea401378bdEric Laurent    // setModeInt() returns a valid PID if the audio mode was successfully set to
15909f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    // any mode other than NORMAL.
1591d7454be47f4111c0478a502353e11dea401378bdEric Laurent    int setModeInt(int mode, IBinder cb, int pid) {
1592d7454be47f4111c0478a502353e11dea401378bdEric Laurent        int newModeOwnerPid = 0;
15939f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        if (cb == null) {
15949f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            Log.e(TAG, "setModeInt() called with null binder");
1595d7454be47f4111c0478a502353e11dea401378bdEric Laurent            return newModeOwnerPid;
15969f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
15972ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi
15989f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        SetModeDeathHandler hdlr = null;
15999f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        Iterator iter = mSetModeDeathHandlers.iterator();
16009f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        while (iter.hasNext()) {
16019f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
16029f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (h.getPid() == pid) {
16039f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr = h;
16049f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Remove from client list so that it is re-inserted at top of list
16059f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                iter.remove();
16069f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr.getBinder().unlinkToDeath(hdlr, 0);
16079f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                break;
16089f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
16099f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
16109f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        int status = AudioSystem.AUDIO_STATUS_OK;
16119f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        do {
16129f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode == AudioSystem.MODE_NORMAL) {
16139f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // get new mode from client at top the list if any
16149f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (!mSetModeDeathHandlers.isEmpty()) {
16159f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    hdlr = mSetModeDeathHandlers.get(0);
16169f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    cb = hdlr.getBinder();
16179f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mode = hdlr.getMode();
16189f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
16199f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            } else {
16209f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (hdlr == null) {
16219f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    hdlr = new SetModeDeathHandler(cb, pid);
16229f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
16239f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Register for client death notification
16249f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                try {
16259f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    cb.linkToDeath(hdlr, 0);
16269f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                } catch (RemoteException e) {
16279f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    // Client has died!
16289f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    Log.w(TAG, "setMode() could not link to "+cb+" binder death");
16299f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
16309272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
16319f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Last client to call setMode() is always at top of client list
16329f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // as required by SetModeDeathHandler.binderDied()
16339f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                mSetModeDeathHandlers.add(0, hdlr);
16349f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr.setMode(mode);
16359f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
16363def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
16379f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode != mMode) {
16389f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                status = AudioSystem.setPhoneState(mode);
16399f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (status == AudioSystem.AUDIO_STATUS_OK) {
16409f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mMode = mode;
16419f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                } else {
16429f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    if (hdlr != null) {
16439f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        mSetModeDeathHandlers.remove(hdlr);
16449f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        cb.unlinkToDeath(hdlr, 0);
16453def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
16469f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    // force reading new top of mSetModeDeathHandlers stack
16479f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mode = AudioSystem.MODE_NORMAL;
1648b9c9d260f21b321527c4622a123af9767630d94dEric Laurent                }
16499f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            } else {
16509f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                status = AudioSystem.AUDIO_STATUS_OK;
16519f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
16529f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
16539f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent
16549f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        if (status == AudioSystem.AUDIO_STATUS_OK) {
16559f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode != AudioSystem.MODE_NORMAL) {
1656d7454be47f4111c0478a502353e11dea401378bdEric Laurent                if (mSetModeDeathHandlers.isEmpty()) {
1657d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
1658d7454be47f4111c0478a502353e11dea401378bdEric Laurent                } else {
1659d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
1660d7454be47f4111c0478a502353e11dea401378bdEric Laurent                }
16619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
16633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            if (streamType == STREAM_REMOTE_MUSIC) {
16643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                // here handle remote media playback the same way as local playback
16653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                streamType = AudioManager.STREAM_MUSIC;
16663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
16679bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            int device = getDeviceForStream(streamType);
166842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
166942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
16706d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
16716d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            updateStreamVolumeAlias(true /*updateVolumes*/);
16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1673d7454be47f4111c0478a502353e11dea401378bdEric Laurent        return newModeOwnerPid;
16749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getMode() */
16779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getMode() {
16789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mMode;
16799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1681e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    //==========================================================================================
1682e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    // Sound Effects
1683e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    //==========================================================================================
1684e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1685e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String TAG_AUDIO_ASSETS = "audio_assets";
1686e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ATTR_VERSION = "version";
1687e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String TAG_GROUP = "group";
1688e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ATTR_GROUP_NAME = "name";
1689e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String TAG_ASSET = "asset";
1690e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ATTR_ASSET_ID = "id";
1691e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ATTR_ASSET_FILE = "file";
1692e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1693e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ASSET_FILE_VERSION = "1.0";
1694e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
1695e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
16965d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent    private static final int SOUND_EFECTS_LOAD_TIMEOUT_MS = 5000;
16975d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
16985d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent    class LoadSoundEffectReply {
16995d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        public int mStatus = 1;
17005d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent    };
17015d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
1702e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private void loadTouchSoundAssetDefaults() {
1703e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
1704e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
1705e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            SOUND_EFFECT_FILES_MAP[i][0] = 0;
1706e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            SOUND_EFFECT_FILES_MAP[i][1] = -1;
1707e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        }
1708e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    }
1709e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1710e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private void loadTouchSoundAssets() {
1711e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        XmlResourceParser parser = null;
1712e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
17135d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        // only load assets once.
17145d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        if (!SOUND_EFFECT_FILES.isEmpty()) {
17155d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            return;
17165d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        }
17175d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
1718e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        loadTouchSoundAssetDefaults();
1719e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1720e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        try {
1721e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
1722e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1723e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
1724e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            String version = parser.getAttributeValue(null, ATTR_VERSION);
1725e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            boolean inTouchSoundsGroup = false;
1726e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1727e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            if (ASSET_FILE_VERSION.equals(version)) {
1728e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                while (true) {
1729e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    XmlUtils.nextElement(parser);
1730e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    String element = parser.getName();
1731e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    if (element == null) {
1732e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        break;
1733e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    }
1734e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    if (element.equals(TAG_GROUP)) {
1735e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
1736e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        if (GROUP_TOUCH_SOUNDS.equals(name)) {
1737e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            inTouchSoundsGroup = true;
1738e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            break;
1739e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        }
1740e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    }
1741e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                }
1742e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                while (inTouchSoundsGroup) {
1743e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    XmlUtils.nextElement(parser);
1744e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    String element = parser.getName();
1745e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    if (element == null) {
1746e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        break;
1747e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    }
1748e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    if (element.equals(TAG_ASSET)) {
1749e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
1750e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
1751e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        int fx;
1752e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1753e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        try {
1754e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            Field field = AudioManager.class.getField(id);
1755e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            fx = field.getInt(null);
1756e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        } catch (Exception e) {
1757e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            Log.w(TAG, "Invalid touch sound ID: "+id);
1758e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            continue;
1759e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        }
1760e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1761e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        int i = SOUND_EFFECT_FILES.indexOf(file);
1762e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        if (i == -1) {
1763e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            i = SOUND_EFFECT_FILES.size();
1764e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            SOUND_EFFECT_FILES.add(file);
1765e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        }
1766e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        SOUND_EFFECT_FILES_MAP[fx][0] = i;
1767e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    } else {
1768e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        break;
1769e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    }
1770e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                }
1771e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            }
1772e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        } catch (Resources.NotFoundException e) {
1773e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            Log.w(TAG, "audio assets file not found", e);
1774e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        } catch (XmlPullParserException e) {
1775e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            Log.w(TAG, "XML parser exception reading touch sound assets", e);
1776e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        } catch (IOException e) {
1777e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            Log.w(TAG, "I/O exception reading touch sound assets", e);
1778e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        } finally {
1779e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            if (parser != null) {
1780e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                parser.close();
1781e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            }
1782e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        }
1783e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    }
1784e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
17859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#playSoundEffect(int) */
17869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void playSoundEffect(int effectType) {
17875d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        playSoundEffectVolume(effectType, -1.0f);
17889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#playSoundEffect(int, float) */
17919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void playSoundEffectVolume(int effectType, float volume) {
17925d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
17939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                effectType, (int) (volume * 1000), null, 0);
17949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
17979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Loads samples into the soundpool.
17985c17a820f9e46e0756c11795b3e6f89105f2f539Glenn Kasten     * This method must be called at first when sound effects are enabled
17999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
18009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean loadSoundEffects() {
18015d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        int attempts = 3;
18025d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        LoadSoundEffectReply reply = new LoadSoundEffectReply();
1803117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent
18045d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        synchronized (reply) {
18055d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
18065d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            while ((reply.mStatus == 1) && (attempts-- > 0)) {
1807117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                try {
18085d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    reply.wait(SOUND_EFECTS_LOAD_TIMEOUT_MS);
18095d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                } catch (InterruptedException e) {
18105d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
1811117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                }
1812a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
18139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18145d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        return (reply.mStatus == 0);
18159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
18189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  Unloads samples from the sound pool.
18199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  This method can be called to free some memory when
18209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  sound effects are disabled.
18219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
18229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void unloadSoundEffects() {
18235d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
18249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1826a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    class SoundPoolListenerThread extends Thread {
1827a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public SoundPoolListenerThread() {
1828a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            super("SoundPoolListenerThread");
1829a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1830a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1831a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        @Override
1832a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public void run() {
1833a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1834a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            Looper.prepare();
1835a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            mSoundPoolLooper = Looper.myLooper();
1836a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1837a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            synchronized (mSoundEffectsLock) {
1838a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                if (mSoundPool != null) {
1839a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundPoolCallBack = new SoundPoolCallback();
1840a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
1841a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
1842a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundEffectsLock.notify();
1843a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
1844a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            Looper.loop();
1845a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1846a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    }
1847a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1848a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private final class SoundPoolCallback implements
1849a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            android.media.SoundPool.OnLoadCompleteListener {
1850a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
18515d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        int mStatus = 1; // 1 means neither error nor last sample loaded yet
18525d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        List<Integer> mSamples = new ArrayList<Integer>();
1853a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1854a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public int status() {
1855a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            return mStatus;
1856a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1857a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
18585d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        public void setSamples(int[] samples) {
18595d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            for (int i = 0; i < samples.length; i++) {
18605d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                // do not wait ack for samples rejected upfront by SoundPool
18615d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (samples[i] > 0) {
18625d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSamples.add(samples[i]);
18635d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
18645d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            }
1865a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1866a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1867a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
1868a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            synchronized (mSoundEffectsLock) {
18695d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int i = mSamples.indexOf(sampleId);
18705d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (i >= 0) {
18715d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSamples.remove(i);
1872a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
18735d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if ((status != 0) || mSamples. isEmpty()) {
18745d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mStatus = status;
1875a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundEffectsLock.notify();
1876a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
1877a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
1878a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1879a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    }
1880a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
18814050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    /** @see AudioManager#reloadAudioSettings() */
18824050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    public void reloadAudioSettings() {
1883bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent        readAudioSettings(false /*userSwitch*/);
1884bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent    }
1885bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent
1886bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent    private void readAudioSettings(boolean userSwitch) {
18874050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
18884050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        readPersistedSettings();
18894050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
18904050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        // restore volume settings
18914050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        int numStreamTypes = AudioSystem.getNumStreamTypes();
18924050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
18934050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent            VolumeStreamState streamState = mStreamStates[streamType];
18944050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
1895bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent            if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
1896bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                continue;
1897bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent            }
1898bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent
18993172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            synchronized (streamState) {
19003172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                streamState.readSettings();
1901a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
19023172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                // unmute stream that was muted but is not affect by mute anymore
190342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                if (streamState.isMuted() && ((!isStreamAffectedByMute(streamType) &&
190483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                        !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
19053172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    int size = streamState.mDeathHandlers.size();
19063172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    for (int i = 0; i < size; i++) {
19073172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        streamState.mDeathHandlers.get(i).mMuteCount = 1;
19083172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        streamState.mDeathHandlers.get(i).mute(false);
19093172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    }
19103172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                }
19114050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent            }
19124050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        }
19134050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
191433902db75011d863009585682bd08560c5b89a75Eric Laurent        // apply new ringer mode before checking volume for alias streams so that streams
191533902db75011d863009585682bd08560c5b89a75Eric Laurent        // muted by ringer mode have the correct volume
191633902db75011d863009585682bd08560c5b89a75Eric Laurent        setRingerModeInt(getRingerMode(), false);
191733902db75011d863009585682bd08560c5b89a75Eric Laurent
1918244820185269991186d07068b92985624cede4a5Eric Laurent        checkAllAliasStreamVolumes();
1919244820185269991186d07068b92985624cede4a5Eric Laurent
1920d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
1921d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
1922f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                enforceSafeMediaVolume();
1923f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent            }
1924c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
19254050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    }
19264050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
1927961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#setSpeakerphoneOn(boolean) */
1928c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public void setSpeakerphoneOn(boolean on){
1929dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
1930dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent            return;
1931dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        }
19327337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson
19337337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        if (on) {
19347337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
19357337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson                    sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
19367337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson                            AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
19377337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            }
19387337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
19397337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
19407337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            mForcedUseForComm = AudioSystem.FORCE_NONE;
19417337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        }
1942fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
1943afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
1944fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
1945c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
1946c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
1947c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    /** @see AudioManager#isSpeakerphoneOn() */
1948c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public boolean isSpeakerphoneOn() {
1949fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
1950c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
1951c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
1952961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#setBluetoothScoOn(boolean) */
1953c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public void setBluetoothScoOn(boolean on){
1954dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
1955dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent            return;
1956dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        }
19577337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson
19587337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        if (on) {
19597337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
19607337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
19617337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            mForcedUseForComm = AudioSystem.FORCE_NONE;
19627337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        }
1963fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
1964afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
1965fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
1966afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
1967fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
1968c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
1969c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
1970c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    /** @see AudioManager#isBluetoothScoOn() */
1971c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public boolean isBluetoothScoOn() {
1972fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
1973c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
1974c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
1975961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#setBluetoothA2dpOn(boolean) */
19767847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public void setBluetoothA2dpOn(boolean on) {
1977c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent        synchronized (mBluetoothA2dpEnabledLock) {
1978c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            mBluetoothA2dpEnabled = on;
1979c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
1980c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    AudioSystem.FOR_MEDIA,
1981c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
1982c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    null, 0);
1983c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent        }
19847847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
19857847211fb4699bf6018e29d214a918ed6657319bEric Laurent
19867847211fb4699bf6018e29d214a918ed6657319bEric Laurent    /** @see AudioManager#isBluetoothA2dpOn() */
19877847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public boolean isBluetoothA2dpOn() {
19887847211fb4699bf6018e29d214a918ed6657319bEric Laurent        synchronized (mBluetoothA2dpEnabledLock) {
19897847211fb4699bf6018e29d214a918ed6657319bEric Laurent            return mBluetoothA2dpEnabled;
19907847211fb4699bf6018e29d214a918ed6657319bEric Laurent        }
19917847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
19927847211fb4699bf6018e29d214a918ed6657319bEric Laurent
19933def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    /** @see AudioManager#startBluetoothSco() */
1994c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    public void startBluetoothSco(IBinder cb, int targetSdkVersion){
1995dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (!checkAudioSettingsPermission("startBluetoothSco()") ||
1996dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                !mBootCompleted) {
19973def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return;
19983def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
1999854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        ScoClient client = getScoClient(cb, true);
2000f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // The calling identity must be cleared before calling ScoClient.incCount().
2001f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2002f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // and this must be done on behalf of system server to make sure permissions are granted.
2003f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // The caller identity must be cleared after getScoClient() because it is needed if a new
2004f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // client is created.
2005f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        final long ident = Binder.clearCallingIdentity();
2006c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent        client.incCount(targetSdkVersion);
20072a57ca931fefe817b6110101289721acaacfc808Eric Laurent        Binder.restoreCallingIdentity(ident);
20083def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
20093def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
20103def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    /** @see AudioManager#stopBluetoothSco() */
20113def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    public void stopBluetoothSco(IBinder cb){
2012dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
2013dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                !mBootCompleted) {
20143def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return;
20153def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
2016854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        ScoClient client = getScoClient(cb, false);
2017f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // The calling identity must be cleared before calling ScoClient.decCount().
2018f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2019f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // and this must be done on behalf of system server to make sure permissions are granted.
2020f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        final long ident = Binder.clearCallingIdentity();
2021854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        if (client != null) {
2022854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            client.decCount();
2023854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        }
20242a57ca931fefe817b6110101289721acaacfc808Eric Laurent        Binder.restoreCallingIdentity(ident);
20253def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
20263def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
20277847211fb4699bf6018e29d214a918ed6657319bEric Laurent
20283def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    private class ScoClient implements IBinder.DeathRecipient {
20293def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        private IBinder mCb; // To be notified of client's death
2030f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        private int mCreatorPid;
20313def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        private int mStartcount; // number of SCO connections started by this client
20323def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
20333def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        ScoClient(IBinder cb) {
20343def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            mCb = cb;
2035f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen            mCreatorPid = Binder.getCallingPid();
20363def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            mStartcount = 0;
20373def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
20383def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
20393def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void binderDied() {
20403def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
20413def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                Log.w(TAG, "SCO client died");
20423def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int index = mScoClients.indexOf(this);
20433def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (index < 0) {
20443def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    Log.w(TAG, "unregistered SCO client died");
20453def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                } else {
20463def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    clearCount(true);
20473def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    mScoClients.remove(this);
20483def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
20493def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
20503def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
20513def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
2052c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent        public void incCount(int targetSdkVersion) {
20533def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
2054c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, targetSdkVersion);
20553def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (mStartcount == 0) {
20563def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    try {
20573def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        mCb.linkToDeath(this, 0);
20583def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    } catch (RemoteException e) {
20593def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        // client has already died!
20603def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        Log.w(TAG, "ScoClient  incCount() could not link to "+mCb+" binder death");
20613def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
20623def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
20633def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                mStartcount++;
20643def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
20653def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
20663def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
20673def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void decCount() {
20683def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
20693def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (mStartcount == 0) {
20703def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    Log.w(TAG, "ScoClient.decCount() already 0");
20713def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                } else {
20723def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    mStartcount--;
20733def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    if (mStartcount == 0) {
2074e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        try {
2075e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                            mCb.unlinkToDeath(this, 0);
2076e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        } catch (NoSuchElementException e) {
2077e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                            Log.w(TAG, "decCount() going to 0 but not registered to binder");
2078e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        }
20793def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
2080c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
20813def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
20823def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
20833def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
20843def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
20853def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void clearCount(boolean stopSco) {
20863def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
2087e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                if (mStartcount != 0) {
2088e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    try {
2089e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        mCb.unlinkToDeath(this, 0);
2090e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    } catch (NoSuchElementException e) {
2091e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2092e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    }
2093e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                }
20943def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                mStartcount = 0;
20953def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (stopSco) {
2096c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
20973def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
20983def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
20993def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
21003def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
21013def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public int getCount() {
21023def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return mStartcount;
21033def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
21043def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
21053def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public IBinder getBinder() {
21063def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return mCb;
21073def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
21083def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
2109d7454be47f4111c0478a502353e11dea401378bdEric Laurent        public int getPid() {
2110d7454be47f4111c0478a502353e11dea401378bdEric Laurent            return mCreatorPid;
2111d7454be47f4111c0478a502353e11dea401378bdEric Laurent        }
2112d7454be47f4111c0478a502353e11dea401378bdEric Laurent
21133def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public int totalCount() {
21143def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
21153def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int count = 0;
21163def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int size = mScoClients.size();
21173def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                for (int i = 0; i < size; i++) {
21183def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    count += mScoClients.get(i).getCount();
21193def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
21203def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                return count;
21213def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
21223def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
21233def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
2124c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent        private void requestScoState(int state, int targetSdkVersion) {
212562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent            checkScoAudioState();
2126dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            if (totalCount() == 0) {
2127dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2128dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // Make sure that the state transitions to CONNECTING even if we cannot initiate
2129dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // the connection.
2130dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2131dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // Accept SCO audio activation only in NORMAL audio mode or if the mode is
2132f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen                    // currently controlled by the same client process.
21339f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    synchronized(mSetModeDeathHandlers) {
21349f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        if ((mSetModeDeathHandlers.isEmpty() ||
21359f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
21369f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                (mScoAudioState == SCO_STATE_INACTIVE ||
21379f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
21389f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            if (mScoAudioState == SCO_STATE_INACTIVE) {
2139c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                mScoAudioMode =
2140c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                        (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
2141c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                SCO_MODE_VIRTUAL_CALL : SCO_MODE_RAW;
21429f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
2143c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    boolean status;
2144c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    if (mScoAudioMode == SCO_MODE_RAW) {
2145c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                        status = mBluetoothHeadset.connectAudio();
2146c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    } else {
2147c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                        status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2148c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                                            mBluetoothHeadsetDevice);
2149c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    }
2150c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    if (status) {
21519f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                        mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
21529f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    } else {
21539f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                        broadcastScoConnectionState(
21549f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
21559f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    }
21569f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                } else if (getBluetoothHeadset()) {
21579f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    mScoAudioState = SCO_STATE_ACTIVATE_REQ;
2158dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                }
21599f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            } else {
21609f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
21619f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
2162dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            }
2163dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        } else {
21649f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2165dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
2166dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
216762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
2168dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                              (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2169dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                               mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2170dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
2171671db6f3ba1fdb3c907e0735fe6d0d284f5c34deMarco Nelissen                        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
2172c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                            boolean status;
2173c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                            if (mScoAudioMode == SCO_MODE_RAW) {
2174c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                status = mBluetoothHeadset.disconnectAudio();
2175c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                            } else {
2176c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2177c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                                        mBluetoothHeadsetDevice);
2178c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                            }
2179c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                            if (!status) {
2180dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                mScoAudioState = SCO_STATE_INACTIVE;
2181dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                broadcastScoConnectionState(
2182dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2183dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            }
2184dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        } else if (getBluetoothHeadset()) {
2185dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2186dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
2187dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    } else {
2188dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        mScoAudioState = SCO_STATE_INACTIVE;
2189dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2190dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
21913def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
21923def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
21933def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
21943def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
21953def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
219662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private void checkScoAudioState() {
219762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
2198dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                mScoAudioState == SCO_STATE_INACTIVE &&
219962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
220062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
220162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
220262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent        }
220362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    }
220462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent
2205854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent    private ScoClient getScoClient(IBinder cb, boolean create) {
22063def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        synchronized(mScoClients) {
2207854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            ScoClient client = null;
22083def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            int size = mScoClients.size();
22093def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            for (int i = 0; i < size; i++) {
22103def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                client = mScoClients.get(i);
22113def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (client.getBinder() == cb)
22123def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    return client;
22133def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
2214854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            if (create) {
2215854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                client = new ScoClient(cb);
2216854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                mScoClients.add(client);
2217854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            }
22183def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return client;
22193def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
22203def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
22213def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
2222d7454be47f4111c0478a502353e11dea401378bdEric Laurent    public void clearAllScoClients(int exceptPid, boolean stopSco) {
22233def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        synchronized(mScoClients) {
2224854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            ScoClient savedClient = null;
22253def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            int size = mScoClients.size();
22263def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            for (int i = 0; i < size; i++) {
2227854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                ScoClient cl = mScoClients.get(i);
2228d7454be47f4111c0478a502353e11dea401378bdEric Laurent                if (cl.getPid() != exceptPid) {
2229854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                    cl.clearCount(stopSco);
2230854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                } else {
2231854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                    savedClient = cl;
2232854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                }
2233854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            }
2234854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            mScoClients.clear();
2235854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            if (savedClient != null) {
2236854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                mScoClients.add(savedClient);
22373def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
22383def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
22393def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
22403def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
2241dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private boolean getBluetoothHeadset() {
2242dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        boolean result = false;
2243dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2244dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (adapter != null) {
2245dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2246dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                    BluetoothProfile.HEADSET);
2247dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
2248dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // If we could not get a bluetooth headset proxy, send a failure message
2249dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // without delay to reset the SCO audio state and clear SCO clients.
2250dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // If we could get a proxy, send a delayed failure message that will reset our state
2251dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // in case we don't receive onServiceConnected().
2252afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2253dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2254dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        return result;
2255dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
2256dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
2257d7454be47f4111c0478a502353e11dea401378bdEric Laurent    private void disconnectBluetoothSco(int exceptPid) {
2258dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        synchronized(mScoClients) {
2259dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            checkScoAudioState();
2260dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2261dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2262dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                if (mBluetoothHeadsetDevice != null) {
2263dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (mBluetoothHeadset != null) {
2264dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (!mBluetoothHeadset.stopVoiceRecognition(
2265b06ac839dd2d0437fc8314f6deb7233af5af521eEric Laurent                                mBluetoothHeadsetDevice)) {
2266afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2267dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                    SENDMSG_REPLACE, 0, 0, null, 0);
2268dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
2269dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2270dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            getBluetoothHeadset()) {
2271dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2272dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
2273dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                }
2274dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            } else {
2275d7454be47f4111c0478a502353e11dea401378bdEric Laurent                clearAllScoClients(exceptPid, true);
2276dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            }
2277dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
2278dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
2279dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
2280dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private void resetBluetoothSco() {
2281dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        synchronized(mScoClients) {
2282d7454be47f4111c0478a502353e11dea401378bdEric Laurent            clearAllScoClients(0, false);
2283dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            mScoAudioState = SCO_STATE_INACTIVE;
2284dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2285dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
2286dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
2287dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
2288dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private void broadcastScoConnectionState(int state) {
22892a57ca931fefe817b6110101289721acaacfc808Eric Laurent        sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
22902a57ca931fefe817b6110101289721acaacfc808Eric Laurent                SENDMSG_QUEUE, state, 0, null, 0);
22912a57ca931fefe817b6110101289721acaacfc808Eric Laurent    }
22922a57ca931fefe817b6110101289721acaacfc808Eric Laurent
22932a57ca931fefe817b6110101289721acaacfc808Eric Laurent    private void onBroadcastScoConnectionState(int state) {
2294dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (state != mScoConnectionState) {
2295dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2296dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2297dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2298dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    mScoConnectionState);
22995ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            sendStickyBroadcastToAll(newIntent);
2300dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            mScoConnectionState = state;
2301dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
2302dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
2303dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
230482aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
230582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        new BluetoothProfile.ServiceListener() {
230682aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        public void onServiceConnected(int profile, BluetoothProfile proxy) {
23076bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            BluetoothDevice btDevice;
23086bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            List<BluetoothDevice> deviceList;
23096bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            switch(profile) {
23106bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.A2DP:
23115a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                synchronized (mA2dpAvrcpLock) {
23125a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    mA2dp = (BluetoothA2dp) proxy;
23135a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    deviceList = mA2dp.getConnectedDevices();
23145a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    if (deviceList.size() > 0) {
23155a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        btDevice = deviceList.get(0);
23165a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        synchronized (mConnectedDevices) {
23175a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                            int state = mA2dp.getConnectionState(btDevice);
23185a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                            int delay = checkSendBecomingNoisyIntent(
23195a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
23205a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                                    (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
23215a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                            queueMsgUnderWakeLock(mAudioHandler,
23225a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    MSG_SET_A2DP_CONNECTION_STATE,
23235a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    state,
23245a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    0,
23255a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    btDevice,
23265a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    delay);
23275a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        }
2328b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    }
23296bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
23306bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
23316bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
23326bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.HEADSET:
23336bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                synchronized (mScoClients) {
23346bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Discard timeout message
23356bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
23366bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mBluetoothHeadset = (BluetoothHeadset) proxy;
23376bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    deviceList = mBluetoothHeadset.getConnectedDevices();
23386bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (deviceList.size() > 0) {
23396bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        mBluetoothHeadsetDevice = deviceList.get(0);
23406bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    } else {
23416bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        mBluetoothHeadsetDevice = null;
2342dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
23436bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Refresh SCO audio state
23446bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    checkScoAudioState();
23456bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Continue pending action if any
23466bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
23476bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
23486bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
23496bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        boolean status = false;
23506bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        if (mBluetoothHeadsetDevice != null) {
23516bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            switch (mScoAudioState) {
23526bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_ACTIVATE_REQ:
23536bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2354c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                if (mScoAudioMode == SCO_MODE_RAW) {
2355c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    status = mBluetoothHeadset.connectAudio();
2356c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                } else {
2357c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2358c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                                        mBluetoothHeadsetDevice);
2359c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                }
23606bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                break;
23616bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_DEACTIVATE_REQ:
2362c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                if (mScoAudioMode == SCO_MODE_RAW) {
2363c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    status = mBluetoothHeadset.disconnectAudio();
2364c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                } else {
2365c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2366c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                                        mBluetoothHeadsetDevice);
2367c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                }
23686bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                break;
23696bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_DEACTIVATE_EXT_REQ:
23706bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                status = mBluetoothHeadset.stopVoiceRecognition(
23716bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                        mBluetoothHeadsetDevice);
23726bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            }
23736bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
23746bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        if (!status) {
2375afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
23766bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                    SENDMSG_REPLACE, 0, 0, null, 0);
23776bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
2378dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
2379dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                }
23806bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
23816bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
23826bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            default:
23836bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
23843def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
23853def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
238682aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        public void onServiceDisconnected(int profile) {
23876bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            switch(profile) {
23886bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.A2DP:
23895a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                synchronized (mA2dpAvrcpLock) {
23905a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    mA2dp = null;
23915a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    synchronized (mConnectedDevices) {
23925a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
23935a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                            makeA2dpDeviceUnavailableNow(
23945a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
23955a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        }
23966bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
23976bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
23986bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
23996bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
24006bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.HEADSET:
24016bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                synchronized (mScoClients) {
24026bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mBluetoothHeadset = null;
24036bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
24046bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
24056bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
24066bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            default:
24076bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
24083def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
24093def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
24103def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    };
2411d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
2412c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private void onCheckMusicActive() {
2413d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
2414d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
2415c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
2416c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
2417c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                if ((device & mSafeMediaVolumeDevices) != 0) {
2418c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    sendMsg(mAudioHandler,
2419c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            MSG_CHECK_MUSIC_ACTIVE,
2420c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            SENDMSG_REPLACE,
2421f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            0,
2422c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            0,
2423c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            null,
2424c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            MUSIC_ACTIVE_POLL_PERIOD_MS);
242542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
2426f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                    if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
2427f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            (index > mSafeMediaVolumeIndex)) {
2428c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                        // Approximate cumulative active music time
2429c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                        mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
2430c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                        if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
2431c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            setSafeMediaVolumeEnabled(true);
2432c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            mMusicActiveMs = 0;
2433c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                        }
2434c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    }
2435c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                }
2436c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
2437c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
2438c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
2439c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
2440d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private void onConfigureSafeVolume(boolean force) {
2441d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
2442d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            int mcc = mContext.getResources().getConfiguration().mcc;
2443d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if ((mMcc != mcc) || ((mMcc == 0) && force)) {
2444d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                mSafeMediaVolumeIndex = mContext.getResources().getInteger(
2445d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                        com.android.internal.R.integer.config_safe_media_volume_index) * 10;
2446d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                boolean safeMediaVolumeEnabled = mContext.getResources().getBoolean(
2447d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                        com.android.internal.R.bool.config_safe_media_volume_enabled);
244805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent
244905274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                // The persisted state is either "disabled" or "active": this is the state applied
245005274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                // next time we boot and cannot be "inactive"
245105274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                int persistedState;
2452d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                if (safeMediaVolumeEnabled) {
245305274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
245405274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    // The state can already be "inactive" here if the user has forced it before
245505274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    // the 30 seconds timeout for forced configuration. In this case we don't reset
245605274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    // it to "active".
245705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
245805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
245905274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        enforceSafeMediaVolume();
246005274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    }
2461d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                } else {
246205274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    persistedState = SAFE_MEDIA_VOLUME_DISABLED;
2463d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
2464d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                }
2465d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                mMcc = mcc;
246605274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                sendMsg(mAudioHandler,
246705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        MSG_PERSIST_SAFE_VOLUME_STATE,
246805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        SENDMSG_QUEUE,
246905274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        persistedState,
247005274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        0,
247105274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        null,
247205274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        0);
2473d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            }
2474d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        }
2475d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    }
2476d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent
24779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
24789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Internal methods
24799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
24809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
24829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Checks if the adjustment should change ringer mode instead of just
24839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * adjusting volume. If so, this will set the proper ringer mode and volume
24849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * indices on the stream states.
24859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2486244820185269991186d07068b92985624cede4a5Eric Laurent    private boolean checkForRingerModeChange(int oldIndex, int direction,  int step) {
24879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean adjustVolumeIndex = true;
2488ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        int ringerMode = getRingerMode();
2489bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
2490bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        switch (ringerMode) {
2491bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_NORMAL:
2492bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            if (direction == AudioManager.ADJUST_LOWER) {
2493bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                if (mHasVibrator) {
2494244820185269991186d07068b92985624cede4a5Eric Laurent                    // "step" is the delta in internal index units corresponding to a
2495244820185269991186d07068b92985624cede4a5Eric Laurent                    // change of 1 in UI index units.
2496244820185269991186d07068b92985624cede4a5Eric Laurent                    // Because of rounding when rescaling from one stream index range to its alias
2497244820185269991186d07068b92985624cede4a5Eric Laurent                    // index range, we cannot simply test oldIndex == step:
2498244820185269991186d07068b92985624cede4a5Eric Laurent                    //   (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
2499244820185269991186d07068b92985624cede4a5Eric Laurent                    if (step <= oldIndex && oldIndex < 2 * step) {
2500bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        ringerMode = RINGER_MODE_VIBRATE;
2501bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    }
2502bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                } else {
2503244820185269991186d07068b92985624cede4a5Eric Laurent                    // (oldIndex < step) is equivalent to (old UI index == 0)
2504244820185269991186d07068b92985624cede4a5Eric Laurent                    if ((oldIndex < step) && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
2505bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        ringerMode = RINGER_MODE_SILENT;
2506bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    }
25073d4c06f90726a85e89dab13c41ddc15b9c912a3fEric Laurent                }
25086329bf7b1e2217c6c9477bd57349a1edade18417Daniel Sandler            }
2509bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
2510bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_VIBRATE:
2511bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            if (!mHasVibrator) {
2512bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
2513bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        "but no vibrator is present");
2514bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                break;
2515bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            }
2516c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            if ((direction == AudioManager.ADJUST_LOWER)) {
2517c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani                if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
2518bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    ringerMode = RINGER_MODE_SILENT;
2519c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani                }
2520c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            } else if (direction == AudioManager.ADJUST_RAISE) {
2521bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                ringerMode = RINGER_MODE_NORMAL;
2522c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            }
2523c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            adjustVolumeIndex = false;
2524bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
2525bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_SILENT:
25269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (direction == AudioManager.ADJUST_RAISE) {
2527bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                if (mHasVibrator) {
2528bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    ringerMode = RINGER_MODE_VIBRATE;
2529bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                } else {
2530bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    ringerMode = RINGER_MODE_NORMAL;
2531bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                }
25329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2533b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent            adjustVolumeIndex = false;
2534bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
2535bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        default:
2536bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
2537bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
25389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
25399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2540bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        setRingerMode(ringerMode);
25419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
254225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        mPrevVolDirection = direction;
254325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
25449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return adjustVolumeIndex;
25459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
25469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isStreamAffectedByRingerMode(int streamType) {
25489bcf401d13d47416043a704430388abd59aef7cdEric Laurent        return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
25499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
25509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25515b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    private boolean isStreamMutedByRingerMode(int streamType) {
25525b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        return (mRingerModeMutedStreams & (1 << streamType)) != 0;
25535b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    }
25545b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
255524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent    boolean updateRingerModeAffectedStreams() {
255624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        int ringerModeAffectedStreams;
255724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // make sure settings for ringer mode are consistent with device type: non voice capable
255824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // devices (tablets) include media stream in silent mode whereas phones don't.
255924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
256024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                Settings.System.MODE_RINGER_STREAMS_AFFECTED,
256124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
256224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
256324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                 UserHandle.USER_CURRENT);
256424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent
256524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // ringtone, notification and system streams are always affected by ringer mode
256624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
256724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                                        (1 << AudioSystem.STREAM_NOTIFICATION)|
256824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                                        (1 << AudioSystem.STREAM_SYSTEM);
256924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent
257024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        if (mVoiceCapable) {
257124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
257224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        } else {
257324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
257424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        }
257524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        synchronized (mCameraSoundForced) {
257624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            if (mCameraSoundForced) {
257724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
257824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            } else {
257924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
258024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            }
258124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        }
258224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
258324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
258424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        } else {
258524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
258624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        }
258724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent
258824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
258924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            Settings.System.putIntForUser(mContentResolver,
259024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                    Settings.System.MODE_RINGER_STREAMS_AFFECTED,
259124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                    ringerModeAffectedStreams,
259224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                    UserHandle.USER_CURRENT);
259324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            mRingerModeAffectedStreams = ringerModeAffectedStreams;
259424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            return true;
259524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        }
259624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        return false;
259724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent    }
259824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent
25999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isStreamAffectedByMute(int streamType) {
26009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mMuteAffectedStreams & (1 << streamType)) != 0;
26019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
26029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void ensureValidDirection(int direction) {
26049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
26059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("Bad direction " + direction);
26069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
26079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
26089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26096c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    private void ensureValidSteps(int steps) {
26106c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
26116c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            throw new IllegalArgumentException("Bad volume adjust steps " + steps);
26126c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        }
26136c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    }
26146c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang
26159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void ensureValidStreamType(int streamType) {
26169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (streamType < 0 || streamType >= mStreamStates.length) {
26179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("Bad stream type " + streamType);
26189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
26199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
26209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26216d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private boolean isInCommunication() {
26226d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        boolean isOffhook = false;
262325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
262425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        if (mVoiceCapable) {
262525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            try {
262625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
262725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                if (phone != null) isOffhook = phone.isOffhook();
262825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            } catch (RemoteException e) {
262925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                Log.w(TAG, "Couldn't connect to phone service", e);
263025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            }
26316d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
26326d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        return (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION);
26336d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    }
263425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
2635fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    /**
2636fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     * For code clarity for getActiveStreamType(int)
2637fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     * @param delay_ms max time since last STREAM_MUSIC activity to consider
2638fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
2639fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     *     in the last "delay_ms" ms.
2640fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     */
2641fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    private boolean isAfMusicActiveRecently(int delay_ms) {
2642fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
2643fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
2644fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    }
2645fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi
26466d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private int getActiveStreamType(int suggestedStreamType) {
26476d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (mVoiceCapable) {
26486d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            if (isInCommunication()) {
264925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
265025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                        == AudioSystem.FORCE_BT_SCO) {
265125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
265225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_BLUETOOTH_SCO;
265325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                } else {
265425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
265525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_VOICE_CALL;
265625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                }
26573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
2658fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
26593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL)
26603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
26613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return AudioSystem.STREAM_MUSIC;
2662fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                } else
2663fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC))
2664fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    {
2665fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        if (DEBUG_VOL)
2666fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
2667fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        return STREAM_REMOTE_MUSIC;
2668fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    } else {
2669fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        if (DEBUG_VOL)
2670fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
2671fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        return AudioSystem.STREAM_RING;
26723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
2673fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            } else if (isAfMusicActiveRecently(0)) {
26743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL)
26753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
267625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return AudioSystem.STREAM_MUSIC;
2677c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato            } else {
26783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
26793114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        + suggestedStreamType);
268025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return suggestedStreamType;
268125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            }
268225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        } else {
26836d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            if (isInCommunication()) {
268425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
268525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                        == AudioSystem.FORCE_BT_SCO) {
26863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
268725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_BLUETOOTH_SCO;
268825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                } else {
26893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL)  Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
269025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_VOICE_CALL;
269125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                }
269225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
26939903e2638a6c502d96413680d3ebae4fb77fc412Eric Laurent                    DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS) ||
26943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
26959903e2638a6c502d96413680d3ebae4fb77fc412Eric Laurent                            DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
26963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
269725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return AudioSystem.STREAM_NOTIFICATION;
26983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
2699fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
2700fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
2701fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    return AudioSystem.STREAM_MUSIC;
2702fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                } else
2703fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC))
2704fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    {
2705fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        if (DEBUG_VOL)
2706fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
2707fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        return STREAM_REMOTE_MUSIC;
27083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                } else {
2709fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default");
27103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return AudioSystem.STREAM_MUSIC;
27113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
271225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            } else {
27133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
27143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        + suggestedStreamType);
271525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return suggestedStreamType;
2716c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato            }
27179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
27199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2720ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    private void broadcastRingerMode(int ringerMode) {
27219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Send sticky broadcast
27221c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn        Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION);
2723ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
27241c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn        broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
27251c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
27265ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        sendStickyBroadcastToAll(broadcast);
27279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
27289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void broadcastVibrateSetting(int vibrateType) {
27309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Send broadcast
27319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (ActivityManagerNative.isSystemReady()) {
27329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
27339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
27349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
27355ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            sendBroadcastToAll(broadcast);
27369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
27389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Message helper methods
27402d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    /**
27412d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     * Queue a message on the given handler's message queue, after acquiring the service wake lock.
27422d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     * Note that the wake lock needs to be released after the message has been handled.
27432d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     */
27442d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    private void queueMsgUnderWakeLock(Handler handler, int msg,
27452d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            int arg1, int arg2, Object obj, int delay) {
2746a4dfbdc54d8898491d3a7d1d9d818c7db3fd773dEric Laurent        final long ident = Binder.clearCallingIdentity();
2747a4dfbdc54d8898491d3a7d1d9d818c7db3fd773dEric Laurent        // Always acquire the wake lock as AudioService because it is released by the
2748a4dfbdc54d8898491d3a7d1d9d818c7db3fd773dEric Laurent        // message handler.
2749fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mAudioEventWakeLock.acquire();
2750a4dfbdc54d8898491d3a7d1d9d818c7db3fd773dEric Laurent        Binder.restoreCallingIdentity(ident);
27512d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi        sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
27522d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    }
27539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2754afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent    private static void sendMsg(Handler handler, int msg,
27559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
27569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (existingMsgPolicy == SENDMSG_REPLACE) {
27589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handler.removeMessages(msg);
27599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
27609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
27619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2763afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
27649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
27659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean checkAudioSettingsPermission(String method) {
27679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS")
27689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                == PackageManager.PERMISSION_GRANTED) {
27699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
27709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String msg = "Audio Settings Permission Denial: " + method + " from pid="
27729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + Binder.getCallingPid()
27739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + ", uid=" + Binder.getCallingUid();
27749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.w(TAG, msg);
27759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
27769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
27779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27789bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    private int getDeviceForStream(int stream) {
27799bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = AudioSystem.getDevicesForStream(stream);
27809bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        if ((device & (device - 1)) != 0) {
27819bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Multiple device selection is either:
27829bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            //  - speaker + one other device: give priority to speaker in this case.
27839bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            //  - one A2DP device + another device: happens with duplicated output. In this case
27849bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // retain the device on the A2DP output as the other must not correspond to an active
27859bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // selection if not the speaker.
27869bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
27879bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                device = AudioSystem.DEVICE_OUT_SPEAKER;
27889bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            } else {
27899bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
27909bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
27919bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
27929bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        return device;
27939bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    }
27949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2795b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    public void setWiredDeviceConnectionState(int device, int state, String name) {
2796b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
2797b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            int delay = checkSendBecomingNoisyIntent(device, state);
27982d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            queueMsgUnderWakeLock(mAudioHandler,
2799b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
2800b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    device,
2801b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    state,
2802b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    name,
2803b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    delay);
2804b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
2805b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
2806b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
2807b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state)
2808b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
2809b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        int delay;
2810b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
2811b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2812b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                                            (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
28132d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            queueMsgUnderWakeLock(mAudioHandler,
2814b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    MSG_SET_A2DP_CONNECTION_STATE,
2815b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    state,
2816b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    0,
2817b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    device,
2818b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    delay);
2819b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
2820b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        return delay;
2821b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
2822b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
28239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
28249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Inner classes
28259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
28269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public class VolumeStreamState {
28289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final int mStreamType;
28299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
283011a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi        private String mVolumeIndexSettingName;
2831a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        private int mIndexMax;
28323172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        private final ConcurrentHashMap<Integer, Integer> mIndex =
28333172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                            new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
28349bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
28359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2836a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        private VolumeStreamState(String settingName, int streamType) {
28379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28389bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            mVolumeIndexSettingName = settingName;
28399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStreamType = streamType;
28415982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles            mIndexMax = MAX_STREAM_VOLUME[streamType];
2842a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
2843a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            mIndexMax *= 10;
28449bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
284533902db75011d863009585682bd08560c5b89a75Eric Laurent            // mDeathHandlers must be created before calling readSettings()
28469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDeathHandlers = new ArrayList<VolumeDeathHandler>();
284733902db75011d863009585682bd08560c5b89a75Eric Laurent
284833902db75011d863009585682bd08560c5b89a75Eric Laurent            readSettings();
28499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
28509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
285142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        public String getSettingNameForDevice(int device) {
285242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            String name = mVolumeIndexSettingName;
28539bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            String suffix = AudioSystem.getDeviceName(device);
28549bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if (suffix.isEmpty()) {
28559bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                return name;
28569bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
28579bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            return name + "_" + suffix;
28589bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
28599bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
28603172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public synchronized void readSettings() {
286183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            // force maximum volume on all streams if fixed volume property is set
286283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            if (mUseFixedVolume) {
286383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
286483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                return;
286583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            }
2866002e9d382d2daa7ed41636463ecdbddbd4897abaEric Laurent            // do not read system stream volume from settings: this stream is always aliased
2867002e9d382d2daa7ed41636463ecdbddbd4897abaEric Laurent            // to another stream type and its volume is never persisted. Values in settings can
2868002e9d382d2daa7ed41636463ecdbddbd4897abaEric Laurent            // only be stale values
2869dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
2870002e9d382d2daa7ed41636463ecdbddbd4897abaEric Laurent                    (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
2871dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
2872dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                synchronized (mCameraSoundForced) {
2873dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    if (mCameraSoundForced) {
2874dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        index = mIndexMax;
2875dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    }
2876dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                }
287742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
2878002e9d382d2daa7ed41636463ecdbddbd4897abaEric Laurent                return;
2879002e9d382d2daa7ed41636463ecdbddbd4897abaEric Laurent            }
2880002e9d382d2daa7ed41636463ecdbddbd4897abaEric Laurent
288183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
288283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
28839bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            for (int i = 0; remainingDevices != 0; i++) {
28849bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                int device = (1 << i);
28859bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                if ((device & remainingDevices) == 0) {
28869bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    continue;
28879bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                }
28889bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                remainingDevices &= ~device;
28899bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
28909bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                // retrieve current volume for device
289142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                String name = getSettingNameForDevice(device);
28929ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                // if no volume stored for current stream and device, use default volume if default
28939ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                // device, continue otherwise
28949ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
28959ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                                        AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
2896bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                int index = Settings.System.getIntForUser(
2897bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
28989bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                if (index == -1) {
28999bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    continue;
29009bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                }
29019bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
29023ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                // ignore settings for fixed volume devices: volume should always be at max or 0
29033ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) &&
29043ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                        ((device & mFixedVolumeDevices) != 0)) {
290542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    mIndex.put(device, (index != 0) ? mIndexMax : 0);
290642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                } else {
2907dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    mIndex.put(device, getValidIndex(10 * index));
2908dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                }
29099bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
29109bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
29119bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
29129bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        public void applyDeviceVolume(int device) {
291342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            int index;
291442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            if (isMuted()) {
291542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                index = 0;
2916c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            } else if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC &&
2917c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                       (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
2918c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                       mAvrcpAbsVolSupported) {
2919c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                index = (mIndexMax + 5)/10;
2920c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            }
2921c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            else {
292242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                index = (getIndex(device) + 5)/10;
292342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            }
292442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
29259bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
29269bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
29273172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public synchronized void applyAllVolumes() {
29289bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // apply default volume first: by convention this will reset all
29299bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // devices volumes in audio policy manager to the supplied value
293042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            int index;
293142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            if (isMuted()) {
293242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                index = 0;
293342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            } else {
293442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
293542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            }
293642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
29379bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // then apply device specific volumes
29389bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            Set set = mIndex.entrySet();
29399bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            Iterator i = set.iterator();
29409bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            while (i.hasNext()) {
29419bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                Map.Entry entry = (Map.Entry)i.next();
29429bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                int device = ((Integer)entry.getKey()).intValue();
29439bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
294442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    if (isMuted()) {
294542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        index = 0;
294642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    } else {
294742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        index = ((Integer)entry.getValue() + 5)/10;
294842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    }
294942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
29509bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                }
29519bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
295211a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi        }
295311a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi
29549bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        public boolean adjustIndex(int deltaIndex, int device) {
295542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            return setIndex(getIndex(device) + deltaIndex,
295642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            device);
29579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
29589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
295942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        public synchronized boolean setIndex(int index, int device) {
296042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            int oldIndex = getIndex(device);
29619bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            index = getValidIndex(index);
2962dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            synchronized (mCameraSoundForced) {
2963dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
2964dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    index = mIndexMax;
2965dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                }
2966dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            }
296783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            mIndex.put(device, index);
29689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29699bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if (oldIndex != index) {
2970a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                // Apply change to all streams using this one as alias
2971bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                // if changing volume of current device, also change volume of current
2972bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                // device on aliased stream
2973bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                boolean currentDevice = (device == getDeviceForStream(mStreamType));
2974a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                int numStreamTypes = AudioSystem.getNumStreamTypes();
2975a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
2976bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    if (streamType != mStreamType &&
2977bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                            mStreamVolumeAlias[streamType] == mStreamType) {
2978bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        int scaledIndex = rescaleIndex(index, mStreamType, streamType);
2979bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        mStreamStates[streamType].setIndex(scaledIndex,
298042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                                           device);
2981bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        if (currentDevice) {
2982bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                            mStreamStates[streamType].setIndex(scaledIndex,
298342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                                               getDeviceForStream(streamType));
2984bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        }
2985a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    }
2986a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
29879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
29889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
29899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
29909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
29919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
29929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
299342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        public synchronized int getIndex(int device) {
299442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            Integer index = mIndex.get(device);
29959bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if (index == null) {
29969bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
299742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
29989bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
29999bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            return index.intValue();
30009bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
30019bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
30029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getMaxIndex() {
3003a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            return mIndexMax;
30049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
30059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
300642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        public synchronized void setAllIndexes(VolumeStreamState srcStream) {
300724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            int srcStreamType = srcStream.getStreamType();
300824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            // apply default device volume from source stream to all devices first in case
300924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            // some devices are present in this stream state but not in source stream state
301024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
301124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            index = rescaleIndex(index, srcStreamType, mStreamType);
301224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            Set set = mIndex.entrySet();
30136d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            Iterator i = set.iterator();
30146d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            while (i.hasNext()) {
30156d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                Map.Entry entry = (Map.Entry)i.next();
301624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                entry.setValue(index);
301724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            }
301824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            // Now apply actual volume for devices in source stream state
301924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            set = srcStream.mIndex.entrySet();
302024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            i = set.iterator();
302124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            while (i.hasNext()) {
302224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                Map.Entry entry = (Map.Entry)i.next();
30236d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                int device = ((Integer)entry.getKey()).intValue();
302424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                index = ((Integer)entry.getValue()).intValue();
302524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                index = rescaleIndex(index, srcStreamType, mStreamType);
302633902db75011d863009585682bd08560c5b89a75Eric Laurent
302742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                setIndex(index, device);
30286d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            }
30296d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
30306d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
3031dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        public synchronized void setAllIndexesToMax() {
3032dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            Set set = mIndex.entrySet();
3033dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            Iterator i = set.iterator();
3034dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            while (i.hasNext()) {
3035dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                Map.Entry entry = (Map.Entry)i.next();
3036dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                entry.setValue(mIndexMax);
3037dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            }
3038dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        }
3039dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
30403172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public synchronized void mute(IBinder cb, boolean state) {
30419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            VolumeDeathHandler handler = getDeathHandler(cb, state);
30429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (handler == null) {
30439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
30449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
30459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
30469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handler.mute(state);
30479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
30489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30496d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        public int getStreamType() {
30506d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            return mStreamType;
30516d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
30526d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
30539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int getValidIndex(int index) {
30549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (index < 0) {
30559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
305683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            } else if (mUseFixedVolume || index > mIndexMax) {
3057a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                return mIndexMax;
30589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
30599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return index;
30619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
30629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private class VolumeDeathHandler implements IBinder.DeathRecipient {
30649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            private IBinder mICallback; // To be notified of client's death
30659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            private int mMuteCount; // Number of active mutes for this client
30669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            VolumeDeathHandler(IBinder cb) {
30689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mICallback = cb;
30699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
30709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30713172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            // must be called while synchronized on parent VolumeStreamState
30729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void mute(boolean state) {
307342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                boolean updateVolume = false;
30743172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                if (state) {
30753172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    if (mMuteCount == 0) {
30763172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        // Register for client death notification
30773172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        try {
30783172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // mICallback can be 0 if muted by AudioService
30793172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            if (mICallback != null) {
30803172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                mICallback.linkToDeath(this, 0);
30813172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
308242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            VolumeStreamState.this.mDeathHandlers.add(this);
30833172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // If the stream is not yet muted by any client, set level to 0
308442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            if (!VolumeStreamState.this.isMuted()) {
308542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                updateVolume = true;
30863172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
30873172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        } catch (RemoteException e) {
30883172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // Client has died!
30893172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            binderDied();
30903172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            return;
30913172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        }
30923172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    } else {
30933172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
30943172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    }
30953172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    mMuteCount++;
30963172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                } else {
30973172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    if (mMuteCount == 0) {
30983172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
30993172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    } else {
31003172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        mMuteCount--;
31013172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        if (mMuteCount == 0) {
31023172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // Unregister from client death notification
310342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            VolumeStreamState.this.mDeathHandlers.remove(this);
31043172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // mICallback can be 0 if muted by AudioService
31053172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            if (mICallback != null) {
31063172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                mICallback.unlinkToDeath(this, 0);
31073172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
310842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            if (!VolumeStreamState.this.isMuted()) {
310942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                updateVolume = true;
31109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
31119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
31129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
31139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
311442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                if (updateVolume) {
311542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    sendMsg(mAudioHandler,
311642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            MSG_SET_ALL_VOLUMES,
311742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            SENDMSG_QUEUE,
311842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            0,
311942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            0,
312042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            VolumeStreamState.this, 0);
312142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                }
31229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
31239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void binderDied() {
31259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.w(TAG, "Volume service client died for stream: "+mStreamType);
31269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mMuteCount != 0) {
31279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Reset all active mute requests from this client.
31289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mMuteCount = 1;
31299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mute(false);
31309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
31319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
31329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
31339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31343172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        private synchronized int muteCount() {
31359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int count = 0;
31369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int size = mDeathHandlers.size();
31379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < size; i++) {
31389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                count += mDeathHandlers.get(i).mMuteCount;
31399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
31409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return count;
31419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
31429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
314342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        private synchronized boolean isMuted() {
314442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            return muteCount() != 0;
314542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        }
314642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent
31473172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        // only called by mute() which is already synchronized
31489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
31493172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            VolumeDeathHandler handler;
31503172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            int size = mDeathHandlers.size();
31513172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            for (int i = 0; i < size; i++) {
31523172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = mDeathHandlers.get(i);
31533172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                if (cb == handler.mICallback) {
31543172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    return handler;
3155ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood                }
3156ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood            }
31573172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            // If this is the first mute request for this client, create a new
31583172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            // client death handler. Otherwise, it is an out of sequence unmute request.
31593172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            if (state) {
31603172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = new VolumeDeathHandler(cb);
31613172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            } else {
31623172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                Log.w(TAG, "stream was not muted by this client");
31633172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = null;
31643172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            }
31653172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            return handler;
3166ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        }
3167bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
3168bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        private void dump(PrintWriter pw) {
3169dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            pw.print("   Mute count: ");
3170dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            pw.println(muteCount());
3171bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.print("   Current: ");
3172bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Set set = mIndex.entrySet();
3173bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Iterator i = set.iterator();
3174bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            while (i.hasNext()) {
3175bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                Map.Entry entry = (Map.Entry)i.next();
3176bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue())
3177bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                             + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", ");
3178bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            }
3179bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
3180ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
3181ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
31829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Thread that handles native AudioSystem control. */
31839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class AudioSystemThread extends Thread {
31849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        AudioSystemThread() {
31859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super("AudioService");
31869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
31879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
31899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
31909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Set this thread up so the handler will work on it
31919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Looper.prepare();
31929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized(AudioService.this) {
31949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAudioHandler = new AudioHandler();
31959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Notify that the handler has been created
31979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                AudioService.this.notify();
31989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
31999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Listen for volume change requests that are set by VolumePanel
32019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Looper.loop();
32029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
32039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
32049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Handles internal volume messages in separate volume thread. */
32069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class AudioHandler extends Handler {
32079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32089bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private void setDeviceVolume(VolumeStreamState streamState, int device) {
32099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32109bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Apply volume
32119bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            streamState.applyDeviceVolume(device);
3212a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
3213a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            // Apply change to all streams using this one as alias
3214a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            int numStreamTypes = AudioSystem.getNumStreamTypes();
3215a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3216a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                if (streamType != streamState.mStreamType &&
32176d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
32186d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    mStreamStates[streamType].applyDeviceVolume(getDeviceForStream(streamType));
3219a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
3220a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
32219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Post a persist volume msg
3223afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            sendMsg(mAudioHandler,
3224afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    MSG_PERSIST_VOLUME,
322598ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent                    SENDMSG_QUEUE,
32269bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    device,
322742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    0,
3228afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    streamState,
3229afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    PERSIST_DELAY);
3230afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent
32319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
32329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32339bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private void setAllVolumes(VolumeStreamState streamState) {
32349bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
32359bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Apply volume
32369bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            streamState.applyAllVolumes();
32379bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
32389bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Apply change to all streams using this one as alias
32399bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            int numStreamTypes = AudioSystem.getNumStreamTypes();
32409bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
32419bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                if (streamType != streamState.mStreamType &&
32426d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
32439bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    mStreamStates[streamType].applyAllVolumes();
32449bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                }
32459bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
32469bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
32479bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
324842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        private void persistVolume(VolumeStreamState streamState, int device) {
324983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            if (mUseFixedVolume) {
325083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                return;
325183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            }
325242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            System.putIntForUser(mContentResolver,
325342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                      streamState.getSettingNameForDevice(device),
325442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                      (streamState.getIndex(device) + 5)/ 10,
325542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                      UserHandle.USER_CURRENT);
32569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
32579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3258ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        private void persistRingerMode(int ringerMode) {
325983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            if (mUseFixedVolume) {
326083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                return;
326183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            }
32628d9a1f66d9d3dbbd45a56d441a746ec11dba7645Jeff Sharkey            Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
32639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
32649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32655d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        private boolean onLoadSoundEffects() {
32665d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            int status;
32675d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
32685d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            synchronized (mSoundEffectsLock) {
32695d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (!mBootCompleted) {
32705d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    Log.w(TAG, "onLoadSoundEffects() called before boot complete");
32715d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    return false;
32725d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
32735d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
32745d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (mSoundPool != null) {
32755d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    return true;
32765d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
32775d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
32785d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                loadTouchSoundAssets();
32795d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
32805d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0);
32815d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPoolCallBack = null;
32825d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPoolListenerThread = new SoundPoolListenerThread();
32835d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPoolListenerThread.start();
32845d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int attempts = 3;
32855d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
32865d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    try {
32875d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        // Wait for mSoundPoolCallBack to be set by the other thread
32885d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        mSoundEffectsLock.wait(SOUND_EFECTS_LOAD_TIMEOUT_MS);
32895d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    } catch (InterruptedException e) {
32905d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
32915d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
32925d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
32935d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
32945d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (mSoundPoolCallBack == null) {
32955d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
32965d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (mSoundPoolLooper != null) {
32975d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        mSoundPoolLooper.quit();
32985d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        mSoundPoolLooper = null;
32995d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
33005d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPoolListenerThread = null;
33015d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool.release();
33025d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool = null;
33035d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    return false;
33045d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
33055d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                /*
33065d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * poolId table: The value -1 in this table indicates that corresponding
33075d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
33085d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * Once loaded, the value in poolId is the sample ID and the same
33095d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * sample can be reused for another effect using the same file.
33105d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 */
33115d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
33125d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
33135d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    poolId[fileIdx] = -1;
33145d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
33155d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                /*
33165d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
33175d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
33185d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * this indicates we have a valid sample loaded for this effect.
33195d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 */
33205d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
33215d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int numSamples = 0;
33225d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
33235d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    // Do not load sample if this effect uses the MediaPlayer
33245d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
33255d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        continue;
33265d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
33275d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
33285d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        String filePath = Environment.getRootDirectory()
33295d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                                + SOUND_EFFECTS_PATH
33305d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                                + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
33315d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        int sampleId = mSoundPool.load(filePath, 0);
33325d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        if (sampleId <= 0) {
33335d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            Log.w(TAG, "Soundpool could not load file: "+filePath);
33345d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        } else {
33355d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
33365d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
33375d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            numSamples++;
33385d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        }
33395d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    } else {
33405d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        SOUND_EFFECT_FILES_MAP[effect][1] =
33415d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                                poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
33425d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
33435d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
33445d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                // wait for all samples to be loaded
33455d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (numSamples > 0) {
33465d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPoolCallBack.setSamples(poolId);
33475d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
33485d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    attempts = 3;
33495d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    status = 1;
33505d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    while ((status == 1) && (attempts-- > 0)) {
33515d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        try {
33525d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            mSoundEffectsLock.wait(SOUND_EFECTS_LOAD_TIMEOUT_MS);
33535d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            status = mSoundPoolCallBack.status();
33545d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        } catch (InterruptedException e) {
33555d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            Log.w(TAG, "Interrupted while waiting sound pool callback.");
33565d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        }
33575d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
33585d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                } else {
33595d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    status = -1;
33605d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
33615d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
33625d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (mSoundPoolLooper != null) {
33635d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPoolLooper.quit();
33645d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPoolLooper = null;
33655d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
33665d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPoolListenerThread = null;
33675d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (status != 0) {
33685d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    Log.w(TAG,
33695d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            "onLoadSoundEffects(), Error "+status+ " while loading samples");
33705d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
33715d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
33725d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            SOUND_EFFECT_FILES_MAP[effect][1] = -1;
33735d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        }
33745d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
33755d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
33765d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool.release();
33775d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool = null;
33785d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
33795d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            }
33805d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            return (status == 0);
33815d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        }
33825d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
33835d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        /**
33845d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent         *  Unloads samples from the sound pool.
33855d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent         *  This method can be called to free some memory when
33865d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent         *  sound effects are disabled.
33875d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent         */
33885d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        private void onUnloadSoundEffects() {
33895d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            synchronized (mSoundEffectsLock) {
33905d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (mSoundPool == null) {
33915d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    return;
33925d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
33935d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
33945d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
33955d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
33965d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    poolId[fileIdx] = 0;
33975d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
33985d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
33995d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
34005d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
34015d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        continue;
34025d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
34035d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
34045d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
34055d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        SOUND_EFFECT_FILES_MAP[effect][1] = -1;
34065d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
34075d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
34085d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
34095d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPool.release();
34105d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPool = null;
34115d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            }
34125d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        }
34135d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
34145d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        private void onPlaySoundEffect(int effectType, int volume) {
34159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mSoundEffectsLock) {
34165d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
34175d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                onLoadSoundEffects();
34185d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
34199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSoundPool == null) {
34209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return;
34219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3422a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                float volFloat;
342325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                // use default if volume is not specified by caller
3424a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                if (volume < 0) {
3425f2b0c11f4e797e183131261724d8de310dac5431Jean-Michel Trivi                    volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
3426a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                } else {
3427a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                    volFloat = (float) volume / 1000.0f;
3428a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                }
34299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
34315d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
34325d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                                        volFloat, volFloat, 0, 0, 1.0f);
34339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
34349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MediaPlayer mediaPlayer = new MediaPlayer();
343562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    try {
3436e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
3437e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                                    SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
343862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setDataSource(filePath);
343962b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
344062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.prepare();
3441068225de0197df07a0247b2877666ea91c22c992Glenn Kasten                        mediaPlayer.setVolume(volFloat);
344262b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
344362b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            public void onCompletion(MediaPlayer mp) {
344462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                cleanupPlayer(mp);
344562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            }
344662b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        });
344762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setOnErrorListener(new OnErrorListener() {
344862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            public boolean onError(MediaPlayer mp, int what, int extra) {
344962b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                cleanupPlayer(mp);
345062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                return true;
345162b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            }
345262b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        });
345362b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.start();
345462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IOException ex) {
345562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IOException: "+ex);
345662b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IllegalArgumentException ex) {
345762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
345862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IllegalStateException ex) {
345962b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
34609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
34619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
34629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
34639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
34649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private void cleanupPlayer(MediaPlayer mp) {
34669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mp != null) {
34679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
34689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mp.stop();
34699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mp.release();
34709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (IllegalStateException ex) {
34719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
34729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
34739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
34749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
34759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3476fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        private void setForceUse(int usage, int config) {
3477fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent            AudioSystem.setForceUse(usage, config);
3478fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        }
3479fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
348005274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        private void onPersistSafeVolumeState(int state) {
348105274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent            Settings.Global.putInt(mContentResolver,
348205274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    Settings.Global.AUDIO_SAFE_VOLUME_STATE,
348305274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    state);
348405274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        }
348505274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent
34869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
34879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
34889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3489afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            switch (msg.what) {
34909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34919bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                case MSG_SET_DEVICE_VOLUME:
34929bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
34939bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    break;
34949bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
34959bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                case MSG_SET_ALL_VOLUMES:
34969bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    setAllVolumes((VolumeStreamState) msg.obj);
34979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
34989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PERSIST_VOLUME:
350042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    persistVolume((VolumeStreamState) msg.obj, msg.arg1);
35019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
35029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35035c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                case MSG_PERSIST_MASTER_VOLUME:
350483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                    if (mUseFixedVolume) {
350583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                        return;
350683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                    }
3507bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                    Settings.System.putFloatForUser(mContentResolver,
3508bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                    Settings.System.VOLUME_MASTER,
3509bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                    (float)msg.arg1 / (float)1000.0,
3510bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                    UserHandle.USER_CURRENT);
35115c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                    break;
35125c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
351357978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                case MSG_PERSIST_MASTER_VOLUME_MUTE:
351483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                    if (mUseFixedVolume) {
351583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                        return;
351683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                    }
3517bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                    Settings.System.putIntForUser(mContentResolver,
3518bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                 Settings.System.VOLUME_MASTER_MUTE,
3519bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                 msg.arg1,
3520bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                 UserHandle.USER_CURRENT);
352157978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                    break;
352257978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh
35239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PERSIST_RINGER_MODE:
3524ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    // note that the value persisted is the current ringer mode, not the
3525ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    // value of ringer mode as of the time the request was made to persist
3526ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    persistRingerMode(getRingerMode());
35279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
35289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_MEDIA_SERVER_DIED:
3530dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                    if (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK) {
353189e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                        Log.e(TAG, "Media server died.");
3532afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
353389e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                                null, 500);
3534dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                        break;
353589e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                    }
35369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.e(TAG, "Media server started.");
3537dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent
35383c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // indicate to audio HAL that we start the reconfiguration phase after a media
35393c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // server crash
3540dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                    // Note that we only execute this when the media server
35413c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // process restarts after a crash, not the first time it is started.
35423c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    AudioSystem.setParameters("restarting=true");
35433c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent
3544fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten                    readAndSetLowRamDevice();
3545fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten
3546c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore device connection states
35476bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mConnectedDevices) {
35486bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        Set set = mConnectedDevices.entrySet();
35496bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        Iterator i = set.iterator();
35509bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        while (i.hasNext()) {
35516bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            Map.Entry device = (Map.Entry)i.next();
35526bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            AudioSystem.setDeviceConnectionState(
35536bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            ((Integer)device.getKey()).intValue(),
35546bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            AudioSystem.DEVICE_STATE_AVAILABLE,
35556bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            (String)device.getValue());
35566bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
3557c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    }
3558c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore call state
3559c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    AudioSystem.setPhoneState(mMode);
3560c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
3561d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    // Restore forced usage for communcations and record
3562c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
3563d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
3564dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
3565dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                    AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
3566c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
3567a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    // Restore stream volumes
35689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int numStreamTypes = AudioSystem.getNumStreamTypes();
35699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
35709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        VolumeStreamState streamState = mStreamStates[streamType];
3571c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                        AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
35729bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
35739bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        streamState.applyAllVolumes();
35749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
3575c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
3576c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore ringer mode
3577c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    setRingerModeInt(getRingerMode(), false);
35783c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent
35799063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                    // Restore master volume
35809063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                    restoreMasterVolume();
35819063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood
3582f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                    // Reset device orientation (if monitored for this device)
3583d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    if (mMonitorOrientation) {
3584f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                        setOrientationForAudioSystem();
3585f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                    }
3586bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                    if (mMonitorRotation) {
3587bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                        setRotationForAudioSystem();
3588bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                    }
3589f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
35907847211fb4699bf6018e29d214a918ed6657319bEric Laurent                    synchronized (mBluetoothA2dpEnabledLock) {
35917847211fb4699bf6018e29d214a918ed6657319bEric Laurent                        AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
35927847211fb4699bf6018e29d214a918ed6657319bEric Laurent                                mBluetoothA2dpEnabled ?
35937847211fb4699bf6018e29d214a918ed6657319bEric Laurent                                        AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
35947847211fb4699bf6018e29d214a918ed6657319bEric Laurent                    }
3595bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent
3596bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                    synchronized (mSettingsLock) {
3597bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                        AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
3598bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                                mDockAudioMediaEnabled ?
3599bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
3600bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                    }
3601bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent
36023c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // indicate the end of reconfiguration phase to audio HAL
36033c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    AudioSystem.setParameters("restarting=false");
36049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
36059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36065d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                case MSG_UNLOAD_SOUND_EFFECTS:
36075d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    onUnloadSoundEffects();
36085d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    break;
36095d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
3610117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                case MSG_LOAD_SOUND_EFFECTS:
36115d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
36125d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    // can take several dozens of milliseconds to complete
36135d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    boolean loaded = onLoadSoundEffects();
36145d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (msg.obj != null) {
36155d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
36165d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        synchronized (reply) {
36175d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            reply.mStatus = loaded ? 0 : -1;
36185d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            reply.notify();
36195d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        }
36205d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
3621117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    break;
3622117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent
36239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PLAY_SOUND_EFFECT:
36245d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    onPlaySoundEffect(msg.arg1, msg.arg2);
36259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
36264c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
36274c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                case MSG_BTA2DP_DOCK_TIMEOUT:
36284c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                    // msg.obj  == address of BTA2DP device
36296bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mConnectedDevices) {
36306bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableNow( (String) msg.obj );
36316bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
36324c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                    break;
3633fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
3634fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                case MSG_SET_FORCE_USE:
3635c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                case MSG_SET_FORCE_BT_A2DP_USE:
3636fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                    setForceUse(msg.arg1, msg.arg2);
3637fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                    break;
3638d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
3639dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                case MSG_BT_HEADSET_CNCT_FAILED:
3640dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    resetBluetoothSco();
3641dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    break;
3642b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3643b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
3644b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
3645fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mAudioEventWakeLock.release();
3646b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    break;
3647b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3648b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                case MSG_SET_A2DP_CONNECTION_STATE:
3649b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    onSetA2dpConnectionState((BluetoothDevice)msg.obj, msg.arg1);
3650fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mAudioEventWakeLock.release();
3651b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    break;
3652632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
3653632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                case MSG_REPORT_NEW_ROUTES: {
3654632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    int N = mRoutesObservers.beginBroadcast();
3655632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (N > 0) {
3656632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        AudioRoutesInfo routes;
3657632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        synchronized (mCurAudioRoutes) {
3658632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            routes = new AudioRoutesInfo(mCurAudioRoutes);
3659632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        }
3660632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        while (N > 0) {
3661632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            N--;
3662632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
3663632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            try {
3664632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                obs.dispatchAudioRoutesChanged(routes);
3665632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            } catch (RemoteException e) {
3666632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            }
3667632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        }
3668632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
3669632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    mRoutesObservers.finishBroadcast();
3670632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    break;
3671632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
36723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
3673c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                case MSG_CHECK_MUSIC_ACTIVE:
3674c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    onCheckMusicActive();
3675c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    break;
36765bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent
36775bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
36785bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                    onSendBecomingNoisyIntent();
36795bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                    break;
3680d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent
3681d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
3682d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
3683d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
3684d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    break;
368505274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                case MSG_PERSIST_SAFE_VOLUME_STATE:
368605274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    onPersistSafeVolumeState(msg.arg1);
368705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    break;
3688a578c48e6c8677bcb54340aadb9470f8a275e56cJean-Michel Trivi
36892a57ca931fefe817b6110101289721acaacfc808Eric Laurent                case MSG_BROADCAST_BT_CONNECTION_STATE:
36902a57ca931fefe817b6110101289721acaacfc808Eric Laurent                    onBroadcastScoConnectionState(msg.arg1);
36912a57ca931fefe817b6110101289721acaacfc808Eric Laurent                    break;
36929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
36939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
36949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
36959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3696b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    private class SettingsObserver extends ContentObserver {
3697a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
3698b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        SettingsObserver() {
3699b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            super(new Handler());
3700b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            mContentResolver.registerContentObserver(Settings.System.getUriFor(
3701b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh                Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
37027ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent            mContentResolver.registerContentObserver(Settings.Global.getUriFor(
37037ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
3704b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
3705b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh
3706b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        @Override
3707b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        public void onChange(boolean selfChange) {
3708b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            super.onChange(selfChange);
3709ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
3710ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       However there appear to be some missing locks around mRingerModeMutedStreams
3711ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       and mRingerModeAffectedStreams, so will leave this synchronized for now.
3712ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
3713a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            synchronized (mSettingsLock) {
371424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                if (updateRingerModeAffectedStreams()) {
3715a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    /*
3716a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     * Ensure all stream types that should be affected by ringer mode
3717a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     * are in the proper state.
3718a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     */
3719a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    setRingerModeInt(getRingerMode(), false);
3720a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
37217ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                readDockAudioSettings(mContentResolver);
3722a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
3723b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
3724b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    }
3725a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
37266bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
37274c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceAvailable(String address) {
37287847211fb4699bf6018e29d214a918ed6657319bEric Laurent        // enable A2DP before notifying A2DP connection to avoid unecessary processing in
37297847211fb4699bf6018e29d214a918ed6657319bEric Laurent        // audio policy manager
3730c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
3731c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
3732c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
37337847211fb4699bf6018e29d214a918ed6657319bEric Laurent        setBluetoothA2dpOnInt(true);
37344c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
37354c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                AudioSystem.DEVICE_STATE_AVAILABLE,
37364c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
37374c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // Reset A2DP suspend state each time a new sink is connected
37384c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setParameters("A2dpSuspended=false");
37394c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
37404c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
37414c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
37424c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
37435bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent    private void onSendBecomingNoisyIntent() {
37445ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
37459841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood    }
37469841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood
37476bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
37484c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceUnavailableNow(String address) {
3749c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        synchronized (mA2dpAvrcpLock) {
3750c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            mAvrcpAbsVolSupported = false;
3751c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        }
37524c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
37534c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                AudioSystem.DEVICE_STATE_UNAVAILABLE,
37544c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
37554c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
37564c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
37574c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
37586bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
37594c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceUnavailableLater(String address) {
37603b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        // prevent any activity on the A2DP audio output to avoid unwanted
37613b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        // reconnection of the sink.
37623b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        AudioSystem.setParameters("A2dpSuspended=true");
37634c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // the device will be made unavailable later, so consider it disconnected right away
37644c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
37654c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // send the delayed message to make the device unavailable later
37664c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
37674c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
37684c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
37694c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
37704c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
37716bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
3772a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private void cancelA2dpDeviceTimeout() {
37734c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
37744c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
37754c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
37766bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
3777a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private boolean hasScheduledA2dpDockTimeout() {
3778a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi        return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
3779a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    }
3780a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi
3781b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private void onSetA2dpConnectionState(BluetoothDevice btDevice, int state)
37826bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    {
37835a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        if (DEBUG_VOL) Log.d(TAG, "onSetA2dpConnectionState btDevice="+btDevice+" state="+state);
37846bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        if (btDevice == null) {
37856bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            return;
37866bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
37876bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        String address = btDevice.getAddress();
37886bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
37896bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            address = "";
37906bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
37915a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
37926bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        synchronized (mConnectedDevices) {
37936bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            boolean isConnected =
37946bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
37956bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
37966bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
37976bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
37986bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                if (btDevice.isBluetoothDock()) {
37996bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (state == BluetoothProfile.STATE_DISCONNECTED) {
38006bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // introduction of a delay for transient disconnections of docks when
38016bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // power is rapidly turned off/on, this message will be canceled if
38026bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // we reconnect the dock under a preset delay
38036bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableLater(address);
38046bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // the next time isConnected is evaluated, it will be false for the dock
38056bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
38066bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                } else {
38076bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    makeA2dpDeviceUnavailableNow(address);
38086bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
3809632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                synchronized (mCurAudioRoutes) {
3810632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (mCurAudioRoutes.mBluetoothName != null) {
3811632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        mCurAudioRoutes.mBluetoothName = null;
3812632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3813632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                SENDMSG_NOOP, 0, 0, null, 0);
3814632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
3815632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
38166bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
38176bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                if (btDevice.isBluetoothDock()) {
38186bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // this could be a reconnection after a transient disconnection
38196bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    cancelA2dpDeviceTimeout();
38206bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mDockAddress = address;
38216bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                } else {
38226bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // this could be a connection of another A2DP device before the timeout of
38236bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // a dock: cancel the dock timeout, and make the dock unavailable now
38246bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if(hasScheduledA2dpDockTimeout()) {
38256bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        cancelA2dpDeviceTimeout();
38266bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableNow(mDockAddress);
38276bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
38286bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
38296bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                makeA2dpDeviceAvailable(address);
3830632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                synchronized (mCurAudioRoutes) {
3831632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    String name = btDevice.getAliasName();
3832632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
3833632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        mCurAudioRoutes.mBluetoothName = name;
3834632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3835632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                SENDMSG_NOOP, 0, 0, null, 0);
3836632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
3837632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
38386bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            }
38396bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
38406bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    }
38416bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
38425a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
38435a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        // address is not used for now, but may be used when multiple a2dp devices are supported
38445a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        synchronized (mA2dpAvrcpLock) {
38455a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du            mAvrcpAbsVolSupported = support;
3846c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
3847c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
3848c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
38495a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        }
38505a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    }
38515a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
385259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent    private boolean handleDeviceConnection(boolean connected, int device, String params) {
385359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        synchronized (mConnectedDevices) {
385459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            boolean isConnected = (mConnectedDevices.containsKey(device) &&
38559841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                    (params.isEmpty() || mConnectedDevices.get(device).equals(params)));
385659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent
385759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            if (isConnected && !connected) {
385859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                AudioSystem.setDeviceConnectionState(device,
385959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                              AudioSystem.DEVICE_STATE_UNAVAILABLE,
38609841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                                              mConnectedDevices.get(device));
386159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 mConnectedDevices.remove(device);
386259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 return true;
386359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            } else if (!isConnected && connected) {
386459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 AudioSystem.setDeviceConnectionState(device,
386559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                                      AudioSystem.DEVICE_STATE_AVAILABLE,
386659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                                      params);
386759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 mConnectedDevices.put(new Integer(device), params);
386859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 return true;
386959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            }
387059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        }
387159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        return false;
387259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent    }
387359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent
3874b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
3875b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // sent if none of these devices is connected.
3876b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    int mBecomingNoisyIntentDevices =
3877b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
3878794da7a0543cbecffefb73794aa68d1a93e41adfEric Laurent            AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_AUX_DIGITAL |
3879794da7a0543cbecffefb73794aa68d1a93e41adfEric Laurent            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
3880794da7a0543cbecffefb73794aa68d1a93e41adfEric Laurent            AudioSystem.DEVICE_OUT_ALL_USB;
3881b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3882b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // must be called before removing the device from mConnectedDevices
3883b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private int checkSendBecomingNoisyIntent(int device, int state) {
3884b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        int delay = 0;
3885b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
3886b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            int devices = 0;
3887b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            for (int dev : mConnectedDevices.keySet()) {
3888b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                if ((dev & mBecomingNoisyIntentDevices) != 0) {
3889b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                   devices |= dev;
3890b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                }
3891b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
3892b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            if (devices == device) {
38935bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                sendMsg(mAudioHandler,
38945bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
38955bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        SENDMSG_REPLACE,
38965bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0,
38975bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0,
38985bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        null,
38995bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0);
3900b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                delay = 1000;
3901b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
3902b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
3903b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3904b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        if (mAudioHandler.hasMessages(MSG_SET_A2DP_CONNECTION_STATE) ||
3905b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
3906b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            delay = 1000;
3907b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
3908b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        return delay;
3909b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
3910b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3911b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private void sendDeviceConnectionIntent(int device, int state, String name)
3912b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
3913b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        Intent intent = new Intent();
3914b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3915b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.putExtra("state", state);
3916b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.putExtra("name", name);
3917b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
3918b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3919632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        int connType = 0;
3920632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
3921b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
3922632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HEADSET;
3923b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_HEADSET_PLUG);
3924b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.putExtra("microphone", 1);
3925b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) {
3926632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HEADPHONES;
3927b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_HEADSET_PLUG);
3928b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.putExtra("microphone", 0);
3929b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
3930632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
3931b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
3932b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
3933632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
3934b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
3935b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_AUX_DIGITAL) {
3936632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HDMI;
3937b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);
3938b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
3939b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3940632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        synchronized (mCurAudioRoutes) {
3941632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            if (connType != 0) {
3942632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                int newConn = mCurAudioRoutes.mMainType;
3943632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                if (state != 0) {
3944632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    newConn |= connType;
3945632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                } else {
3946632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    newConn &= ~connType;
3947632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
3948632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                if (newConn != mCurAudioRoutes.mMainType) {
3949632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    mCurAudioRoutes.mMainType = newConn;
3950632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3951632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            SENDMSG_NOOP, 0, 0, null, 0);
3952632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
3953632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            }
3954632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        }
3955632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
39565ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        final long ident = Binder.clearCallingIdentity();
39575ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        try {
39585ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
39595ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        } finally {
39605ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            Binder.restoreCallingIdentity(ident);
39615ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        }
3962b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
3963b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3964b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private void onSetWiredDeviceConnectionState(int device, int state, String name)
3965b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
3966b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
3967b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
3968b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) {
3969b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                setBluetoothA2dpOnInt(true);
3970b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
3971db45484e4b5858d14da93d3a06311b93bf0cf320Mike Lockwood            boolean isUsb = ((device & AudioSystem.DEVICE_OUT_ALL_USB) != 0);
3972db45484e4b5858d14da93d3a06311b93bf0cf320Mike Lockwood            handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
3973f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent            if (state != 0) {
3974f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
3975f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE)) {
3976f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                    setBluetoothA2dpOnInt(false);
3977f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                }
3978f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                if ((device & mSafeMediaVolumeDevices) != 0) {
3979f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                    sendMsg(mAudioHandler,
3980f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            MSG_CHECK_MUSIC_ACTIVE,
3981f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            SENDMSG_REPLACE,
3982f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            0,
3983f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            0,
3984f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            null,
3985f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            MUSIC_ACTIVE_POLL_PERIOD_MS);
3986f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                }
3987b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
3988db45484e4b5858d14da93d3a06311b93bf0cf320Mike Lockwood            if (!isUsb) {
3989db45484e4b5858d14da93d3a06311b93bf0cf320Mike Lockwood                sendDeviceConnectionIntent(device, state, name);
3990db45484e4b5858d14da93d3a06311b93bf0cf320Mike Lockwood            }
3991b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
3992b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
3993b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3994a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    /* cache of the address of the last dock the device was connected to */
3995a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private String mDockAddress;
3996a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi
3997a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    /**
3998a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     * Receiver for misc intent broadcasts the Phone app cares about.
3999a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     */
4000a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4001a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        @Override
4002a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        public void onReceive(Context context, Intent intent) {
4003a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            String action = intent.getAction();
400459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            int device;
400559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            int state;
4006a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
4007758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi            if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4008758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4009758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
4010758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                int config;
4011758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                switch (dockState) {
4012758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_DESK:
4013758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_BT_DESK_DOCK;
4014758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        break;
4015758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_CAR:
4016758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_BT_CAR_DOCK;
4017758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        break;
401821e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                    case Intent.EXTRA_DOCK_STATE_LE_DESK:
401908ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                        config = AudioSystem.FORCE_ANALOG_DOCK;
402021e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        break;
402121e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                    case Intent.EXTRA_DOCK_STATE_HE_DESK:
402221e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        config = AudioSystem.FORCE_DIGITAL_DOCK;
402321e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        break;
4024758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4025758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    default:
4026758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_NONE;
4027758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                }
402808ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                // Low end docks have a menu to enable or disable audio
402908ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                // (see mDockAudioMediaEnabled)
403008ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
403108ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                      ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
403208ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                       (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
403308ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
403408ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                }
403508ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                mDockState = dockState;
403682aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh            } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
403759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
403882aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh                                               BluetoothProfile.STATE_DISCONNECTED);
403959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
4040a56d1c72190462aa9e377906583eceb58e0efcddNick Pelly                String address = null;
4041dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent
4042dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
4043dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (btDevice == null) {
4044dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    return;
4045dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                }
4046dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent
4047dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                address = btDevice.getAddress();
4048dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                BluetoothClass btClass = btDevice.getBluetoothClass();
4049dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (btClass != null) {
4050dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    switch (btClass.getDeviceClass()) {
4051dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
4052dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
4053dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                        device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
4054dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                        break;
4055dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
4056dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                        device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
4057dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                        break;
4058d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    }
4059d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                }
4060d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent
4061dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4062dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    address = "";
4063dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                }
4064d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent
406559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
406659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                if (handleDeviceConnection(connected, device, address)) {
40676bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mScoClients) {
406859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        if (connected) {
406959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                            mBluetoothHeadsetDevice = btDevice;
407059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        } else {
40716bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mBluetoothHeadsetDevice = null;
40726bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            resetBluetoothSco();
40736bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
407462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    }
4075a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
407659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ||
407759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                           action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
407859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                state = intent.getIntExtra("state", 0);
407959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int alsaCard = intent.getIntExtra("card", -1);
408059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int alsaDevice = intent.getIntExtra("device", -1);
40819841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
40829841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                                    : "card=" + alsaCard + ";device=" + alsaDevice);
408359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                device = action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
408459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE;
408559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                Log.v(TAG, "Broadcast Receiver: Got "
408659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        + (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
408759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                              "ACTION_USB_AUDIO_ACCESSORY_PLUG" : "ACTION_USB_AUDIO_DEVICE_PLUG")
408859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        + ", state = " + state + ", card: " + alsaCard + ", device: " + alsaDevice);
4089db45484e4b5858d14da93d3a06311b93bf0cf320Mike Lockwood                setWiredDeviceConnectionState(device, state, params);
40903def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
409162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                boolean broadcast = false;
409259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
40933def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                synchronized (mScoClients) {
409462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
4095dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // broadcast intent if the connection was initated by AudioService
4096dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (!mScoClients.isEmpty() &&
4097dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
4098dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                             mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
4099dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                             mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
410062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        broadcast = true;
410162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    }
410262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    switch (btState) {
410362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_CONNECTED:
410459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
4105dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4106dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4107dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
410862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
41093def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        }
411062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
411162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
411259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
411362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        mScoAudioState = SCO_STATE_INACTIVE;
4114d7454be47f4111c0478a502353e11dea401378bdEric Laurent                        clearAllScoClients(0, false);
411562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
411662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_CONNECTING:
4117dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4118dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4119dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
412062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
41213def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        }
412262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    default:
412362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        // do not broadcast CONNECTING or invalid state
412462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        broadcast = false;
412562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
41263def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
41273def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
412862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                if (broadcast) {
412959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                    broadcastScoConnectionState(scoAudioState);
4130dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    //FIXME: this is to maintain compatibility with deprecated intent
4131dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
413262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
413359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                    newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
41345ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn                    sendStickyBroadcastToAll(newIntent);
413562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                }
413662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent            } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
4137a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mBootCompleted = true;
41385d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
4139117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                        0, 0, null, 0);
4140dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
41416243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani                mKeyguardManager =
41426243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani                        (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
4143dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
4144dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                resetBluetoothSco();
4145dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                getBluetoothHeadset();
4146dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                //FIXME: this is to maintain compatibility with deprecated intent
4147dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
414862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
414962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
415062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
41515ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn                sendStickyBroadcastToAll(newIntent);
41526bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
41536bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
41546bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                if (adapter != null) {
41556bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
41566bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                            BluetoothProfile.A2DP);
41576bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
4158d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent
4159d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                sendMsg(mAudioHandler,
4160d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                        MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
4161d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                        SENDMSG_REPLACE,
4162d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                        0,
4163d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                        0,
4164d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                        null,
4165d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                        SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
4166950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent            } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
4167950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent                AudioSystem.setParameters("screen_state=on");
4168950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
4169950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent                AudioSystem.setParameters("screen_state=off");
4170961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
4171f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                handleConfigurationChanged(context);
4172bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
4173f4a8eb22112c534f436357b50f231778c5c15c25Jean-Michel Trivi                // attempt to stop music playback for background user
41745bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                sendMsg(mAudioHandler,
41755bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
41765bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        SENDMSG_REPLACE,
41775bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0,
41785bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0,
41795bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        null,
41805bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0);
4181f4a8eb22112c534f436357b50f231778c5c15c25Jean-Michel Trivi                // the current audio focus owner is no longer valid
4182fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                mMediaFocusControl.discardAudioFocusOwner();
4183f4a8eb22112c534f436357b50f231778c5c15c25Jean-Michel Trivi
41845bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                // load volume settings for new user
4185bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                readAudioSettings(true /*userSwitch*/);
4186bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                // preserve STREAM_MUSIC volume from one user to the next.
4187bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                sendMsg(mAudioHandler,
4188bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        MSG_SET_ALL_VOLUMES,
4189bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        SENDMSG_QUEUE,
4190bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        0,
4191bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        0,
4192bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4193a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
4194a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        }
4195a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    }
4196d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
4197d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    //==========================================================================================
4198fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    // RemoteControlDisplay / RemoteControlClient / Remote info
4199d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    //==========================================================================================
4200f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
4201f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            ComponentName listenerComp) {
4202f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
4203f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    }
4204f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
42057ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi    public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
4206f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
4207e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi    }
4208e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi
4209fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
4210fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
4211d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
4212d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
4213fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
4214fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
4215d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
4216d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
4217fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
4218fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            boolean wantsSync) {
4219fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
4220d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
4221d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
4222fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void registerMediaButtonEventReceiverForCalls(ComponentName c) {
4223fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.registerMediaButtonEventReceiverForCalls(c);
4224d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
4225d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
4226fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void unregisterMediaButtonEventReceiverForCalls() {
4227fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.unregisterMediaButtonEventReceiverForCalls();
4228d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
4229d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
4230fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void registerMediaButtonIntent(PendingIntent pi, ComponentName c, IBinder token) {
4231fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.registerMediaButtonIntent(pi, c, token);
4232d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
4233d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
4234fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void unregisterMediaButtonIntent(PendingIntent pi) {
4235fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.unregisterMediaButtonIntent(pi);
4236d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
4237f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
4238fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public int registerRemoteControlClient(PendingIntent mediaIntent,
4239fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            IRemoteControlClient rcClient, String callingPckg) {
4240fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return mMediaFocusControl.registerRemoteControlClient(mediaIntent, rcClient, callingPckg);
4241d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
4242d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
4243fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void unregisterRemoteControlClient(PendingIntent mediaIntent,
4244fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            IRemoteControlClient rcClient) {
4245fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.unregisterRemoteControlClient(mediaIntent, rcClient);
4246d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
4247d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
4248fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
4249fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.setRemoteControlClientPlaybackPosition(generationId, timeMs);
4250c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    }
4251c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
42527ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi    public void updateRemoteControlClientMetadata(int generationId, int key, Rating value) {
4253f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi        mMediaFocusControl.updateRemoteControlClientMetadata(generationId, key, value);
4254f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    }
4255f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
4256fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
4257fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.registerRemoteVolumeObserverForRcc(rccId, rvo);
4258c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    }
4259c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
4260fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public int getRemoteStreamVolume() {
4261fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return mMediaFocusControl.getRemoteStreamVolume();
42624294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    }
42634294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
4264fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public int getRemoteStreamMaxVolume() {
4265fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return mMediaFocusControl.getRemoteStreamMaxVolume();
4266722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    }
4267722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi
4268fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void setRemoteStreamVolume(int index) {
4269fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.setRemoteStreamVolume(index);
4270d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    }
4271d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
4272fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed) {
4273fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.setPlaybackStateForRcc(rccId, state, timeMs, speed);
42744294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    }
42754294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
4276fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void setPlaybackInfoForRcc(int rccId, int what, int value) {
4277fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.setPlaybackInfoForRcc(rccId, what, value);
42784294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    }
42794294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
4280fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
4281fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.dispatchMediaKeyEvent(keyEvent);
4282c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    }
4283c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
4284fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
4285fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.dispatchMediaKeyEventUnderWakelock(keyEvent);
42864294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    }
42874294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
4288fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    //==========================================================================================
4289fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    // Audio Focus
4290fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    //==========================================================================================
4291fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb,
4292fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
4293fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return mMediaFocusControl.requestAudioFocus(mainStreamType, durationHint, cb, fd,
4294fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                clientId, callingPackageName);
42954294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    }
42964294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
4297fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId) {
4298fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return mMediaFocusControl.abandonAudioFocus(fd, clientId);
4299c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    }
4300c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
4301fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void unregisterAudioFocusClient(String clientId) {
4302fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.unregisterAudioFocusClient(clientId);
43033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
43043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
43052380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi    public int getCurrentAudioFocus() {
43062380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi        return mMediaFocusControl.getCurrentAudioFocus();
43072380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi    }
43082380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi
4309f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    //==========================================================================================
4310f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    // Device orientation
4311f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    //==========================================================================================
4312f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    /**
4313bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi     * Handles device configuration changes that may map to a change in the orientation
4314bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi     * or orientation.
4315bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi     * Monitoring orientation and rotation is optional, and is defined by the definition and value
4316bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi     * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
4317f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi     */
4318f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    private void handleConfigurationChanged(Context context) {
4319f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        try {
4320f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            // reading new orientation "safely" (i.e. under try catch) in case anything
4321f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            // goes wrong when obtaining resources and configuration
4322d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            Configuration config = context.getResources().getConfiguration();
4323bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            // TODO merge rotation and orientation
4324d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if (mMonitorOrientation) {
4325d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                int newOrientation = config.orientation;
4326d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                if (newOrientation != mDeviceOrientation) {
4327d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mDeviceOrientation = newOrientation;
4328d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    setOrientationForAudioSystem();
4329d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                }
4330f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            }
4331bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            if (mMonitorRotation) {
4332bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                int newRotation = ((WindowManager) context.getSystemService(
4333bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                        Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
4334bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                if (newRotation != mDeviceRotation) {
4335bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                    mDeviceRotation = newRotation;
4336bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                    setRotationForAudioSystem();
4337bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                }
4338bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            }
4339d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            sendMsg(mAudioHandler,
4340d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
4341d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    SENDMSG_REPLACE,
4342d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    0,
4343d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    0,
4344d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    null,
4345d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    0);
4346dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4347dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            boolean cameraSoundForced = mContext.getResources().getBoolean(
4348dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    com.android.internal.R.bool.config_camera_sound_forced);
4349dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            synchronized (mSettingsLock) {
4350dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                synchronized (mCameraSoundForced) {
4351dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    if (cameraSoundForced != mCameraSoundForced) {
4352dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        mCameraSoundForced = cameraSoundForced;
4353dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4354dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
4355dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        if (cameraSoundForced) {
4356dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                            s.setAllIndexesToMax();
4357dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                            mRingerModeAffectedStreams &=
4358dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                    ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4359dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        } else {
436042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
4361dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                            mRingerModeAffectedStreams |=
4362dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                    (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4363dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        }
4364dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        // take new state into account for streams muted by ringer mode
4365dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        setRingerModeInt(getRingerMode(), false);
4366dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4367dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        sendMsg(mAudioHandler,
4368dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                MSG_SET_FORCE_USE,
4369dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                SENDMSG_QUEUE,
4370dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                AudioSystem.FOR_SYSTEM,
4371dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                cameraSoundForced ?
4372dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                        AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
4373dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                null,
4374dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                0);
4375dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4376dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        sendMsg(mAudioHandler,
4377dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                MSG_SET_ALL_VOLUMES,
4378dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                SENDMSG_QUEUE,
4379dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                0,
4380dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                0,
4381dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
4382dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    }
4383dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                }
4384dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            }
43858c02884c8c3c97cdc2366ac187c8a326308b895bFabrice Di Meglio            mVolumePanel.setLayoutDirection(config.getLayoutDirection());
4386f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        } catch (Exception e) {
4387bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            Log.e(TAG, "Error handling configuration change: ", e);
4388f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        }
4389f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    }
4390f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
4391f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    private void setOrientationForAudioSystem() {
4392f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        switch (mDeviceOrientation) {
4393f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_LANDSCAPE:
4394f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is landscape");
4395f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=landscape");
4396f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
4397f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_PORTRAIT:
4398f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is portrait");
4399f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=portrait");
4400f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
4401f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_SQUARE:
4402f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is square");
4403f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=square");
4404f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
4405f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_UNDEFINED:
4406f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is undefined");
4407f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=undefined");
4408f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
4409f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            default:
4410f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                Log.e(TAG, "Unknown orientation");
4411f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        }
4412f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    }
4413f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
4414bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    private void setRotationForAudioSystem() {
4415bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        switch (mDeviceRotation) {
4416bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            case Surface.ROTATION_0:
4417bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                AudioSystem.setParameters("rotation=0");
4418bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                break;
4419bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            case Surface.ROTATION_90:
4420bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                AudioSystem.setParameters("rotation=90");
4421bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                break;
4422bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            case Surface.ROTATION_180:
4423bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                AudioSystem.setParameters("rotation=180");
4424bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                break;
4425bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            case Surface.ROTATION_270:
4426bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                AudioSystem.setParameters("rotation=270");
4427bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                break;
4428bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            default:
4429bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                Log.e(TAG, "Unknown device rotation");
4430bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        }
4431bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    }
4432bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi
4433f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
44347847211fb4699bf6018e29d214a918ed6657319bEric Laurent    // Handles request to override default use of A2DP for media.
44357847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public void setBluetoothA2dpOnInt(boolean on) {
44367847211fb4699bf6018e29d214a918ed6657319bEric Laurent        synchronized (mBluetoothA2dpEnabledLock) {
44377847211fb4699bf6018e29d214a918ed6657319bEric Laurent            mBluetoothA2dpEnabled = on;
4438c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
4439c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
4440c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
44417847211fb4699bf6018e29d214a918ed6657319bEric Laurent        }
44427847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
44437847211fb4699bf6018e29d214a918ed6657319bEric Laurent
4444d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    @Override
4445098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    public void setRingtonePlayer(IRingtonePlayer player) {
4446098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
4447098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        mRingtonePlayer = player;
4448098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    }
4449098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
4450098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    @Override
4451098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    public IRingtonePlayer getRingtonePlayer() {
4452098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        return mRingtonePlayer;
4453098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    }
4454098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
4455098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    @Override
4456632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
4457632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        synchronized (mCurAudioRoutes) {
4458632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
4459632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            mRoutesObservers.register(observer);
4460632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            return routes;
4461632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        }
4462632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    }
4463632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
4464c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4465c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    //==========================================================================================
4466c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // Safe media volume management.
4467c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // MUSIC stream volume level is limited when headphones are connected according to safety
4468c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // regulation. When the user attempts to raise the volume above the limit, a warning is
4469c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // displayed and the user has to acknowlegde before the volume is actually changed.
4470c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // The volume index corresponding to the limit is stored in config_safe_media_volume_index
4471c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // property. Platforms with a different limit must set this property accordingly in their
4472c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // overlay.
4473c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    //==========================================================================================
4474c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4475d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
4476d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
4477d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
4478d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
4479d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
4480d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // (when user opts out).
4481d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
4482d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private final int SAFE_MEDIA_VOLUME_DISABLED = 1;
4483d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private final int SAFE_MEDIA_VOLUME_INACTIVE = 2;
4484d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private final int SAFE_MEDIA_VOLUME_ACTIVE = 3;
4485d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private Integer mSafeMediaVolumeState;
4486d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent
4487d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private int mMcc = 0;
4488c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
4489d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private int mSafeMediaVolumeIndex;
4490c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
4491c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
4492c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                                                AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
4493c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
4494c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
4495c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
4496c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private int mMusicActiveMs;
4497c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
4498c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000;  // 1 minute polling interval
4499d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000;  // 30s after boot completed
4500c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4501c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private void setSafeMediaVolumeEnabled(boolean on) {
4502d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
4503d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
4504d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
4505d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
4506d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
4507d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    enforceSafeMediaVolume();
4508d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
4509d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
4510d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mMusicActiveMs = 0;
4511d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    sendMsg(mAudioHandler,
4512d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            MSG_CHECK_MUSIC_ACTIVE,
4513d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            SENDMSG_REPLACE,
4514d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            0,
4515d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            0,
4516d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            null,
4517d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            MUSIC_ACTIVE_POLL_PERIOD_MS);
4518d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                }
4519c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
4520c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
4521c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
4522c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4523c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private void enforceSafeMediaVolume() {
4524c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4525c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        int devices = mSafeMediaVolumeDevices;
4526c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        int i = 0;
4527c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4528c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        while (devices != 0) {
4529c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            int device = 1 << i++;
4530c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            if ((device & devices) == 0) {
4531c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                continue;
4532c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
453342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            int index = streamState.getIndex(device);
4534c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            if (index > mSafeMediaVolumeIndex) {
453542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                streamState.setIndex(mSafeMediaVolumeIndex, device);
453642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                sendMsg(mAudioHandler,
453742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        MSG_SET_DEVICE_VOLUME,
453842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        SENDMSG_QUEUE,
453942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        device,
454042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        0,
454142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        streamState,
454242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        0);
4543c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
4544c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            devices &= ~device;
4545c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
4546c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
4547c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4548c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private boolean checkSafeMediaVolume(int streamType, int index, int device) {
4549d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
4550d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
4551c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
4552c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    ((device & mSafeMediaVolumeDevices) != 0) &&
4553c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    (index > mSafeMediaVolumeIndex)) {
4554c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                return false;
4555c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
4556c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            return true;
4557c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
4558c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
4559c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4560c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    public void disableSafeMediaVolume() {
4561d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
4562c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            setSafeMediaVolumeEnabled(false);
4563fde16d5879ea88a971004c984093409468b6139cEric Laurent            if (mPendingVolumeCommand != null) {
4564fde16d5879ea88a971004c984093409468b6139cEric Laurent                onSetStreamVolume(mPendingVolumeCommand.mStreamType,
4565fde16d5879ea88a971004c984093409468b6139cEric Laurent                                  mPendingVolumeCommand.mIndex,
4566fde16d5879ea88a971004c984093409468b6139cEric Laurent                                  mPendingVolumeCommand.mFlags,
4567fde16d5879ea88a971004c984093409468b6139cEric Laurent                                  mPendingVolumeCommand.mDevice);
4568fde16d5879ea88a971004c984093409468b6139cEric Laurent                mPendingVolumeCommand = null;
4569fde16d5879ea88a971004c984093409468b6139cEric Laurent            }
4570c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
4571c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
4572c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4573c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4574dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    //==========================================================================================
4575dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // Camera shutter sound policy.
4576dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
4577dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // sound is forced (sound even if the device is in silent mode) or not. This option is false by
4578dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
4579dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    //==========================================================================================
4580dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4581dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // cached value of com.android.internal.R.bool.config_camera_sound_forced
4582dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    private Boolean mCameraSoundForced;
4583dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4584dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
4585dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    public boolean isCameraSoundForced() {
4586dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        synchronized (mCameraSoundForced) {
4587dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            return mCameraSoundForced;
4588dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        }
4589dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    }
4590dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4591dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    private static final String[] RINGER_MODE_NAMES = new String[] {
4592dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            "SILENT",
4593dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            "VIBRATE",
4594dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            "NORMAL"
4595dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    };
4596dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4597dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    private void dumpRingerMode(PrintWriter pw) {
4598dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println("\nRinger mode: ");
4599dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]);
4600dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.print("- ringer mode affected streams = 0x");
4601dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println(Integer.toHexString(mRingerModeAffectedStreams));
4602dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.print("- ringer mode muted streams = 0x");
4603dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println(Integer.toHexString(mRingerModeMutedStreams));
4604dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    }
4605dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4606632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    @Override
4607d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
4608eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
4609eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey
4610fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.dump(pw);
4611bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        dumpStreamStates(pw);
4612dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        dumpRingerMode(pw);
4613632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.println("\nAudio routes:");
4614632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
4615632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
4616d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
4617fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten
4618fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten    // Inform AudioFlinger of our device's low RAM attribute
4619fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten    private static void readAndSetLowRamDevice()
4620fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten    {
4621fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten        int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
4622fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten        if (status != 0) {
4623fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten            Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
4624fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten        }
4625fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten    }
46269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4627