AudioService.java revision eb1d88ddf9a0888455c82b83f19da124e5ca6f16
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
24fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kastenimport android.app.ActivityManager;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.ActivityManagerNative;
26ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackbornimport android.app.AppOpsManager;
276243edd818b84adfbe712d5d233d6414b33653acAmith Yamasaniimport android.app.KeyguardManager;
28f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Triviimport android.app.PendingIntent;
2982aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothA2dp;
3082aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothAdapter;
3182aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothClass;
3282aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothDevice;
3382aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothHeadset;
3482aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothProfile;
35bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.content.BroadcastReceiver;
36d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Triviimport android.content.ComponentName;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
40a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurentimport android.content.IntentFilter;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager;
42f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Triviimport android.content.res.Configuration;
43e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurentimport android.content.res.Resources;
44e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurentimport android.content.res.XmlResourceParser;
45b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekhimport android.database.ContentObserver;
4641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jangimport android.hardware.hdmi.HdmiControlManager;
4741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jangimport android.hardware.hdmi.HdmiTvClient;
48c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLeanimport android.hardware.usb.UsbManager;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.MediaPlayer.OnCompletionListener;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.MediaPlayer.OnErrorListener;
51a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Triviimport android.media.audiopolicy.AudioPolicyConfig;
528a2cfc309ab9126e90022916967c65a793c034f0RoboErikimport android.media.session.MediaSessionLegacyHelper;
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
54c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurentimport android.os.Build;
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;
6433f4e04e32fac42f158733d6a731e50490fa9951John Spurlockimport android.os.SystemClock;
6582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.os.SystemProperties;
665ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackbornimport android.os.UserHandle;
67bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurentimport android.os.Vibrator;
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings.System;
709eb45934c582a0bf5060125690de8bce4f10ca76Santos Cordonimport android.telecomm.TelecommManager;
71632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.text.TextUtils;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
73a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Triviimport android.util.Slog;
74d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Triviimport android.view.KeyEvent;
75bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Triviimport android.view.Surface;
76bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Triviimport android.view.WindowManager;
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.telephony.ITelephony;
79e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurentimport com.android.internal.util.XmlUtils;
80e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
81e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurentimport org.xmlpull.v1.XmlPullParserException;
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
83d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Triviimport java.io.FileDescriptor;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
85d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Triviimport java.io.PrintWriter;
86e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurentimport java.lang.reflect.Field;
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
883172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurentimport java.util.concurrent.ConcurrentHashMap;
896f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jangimport java.util.Arrays;
90c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.HashMap;
91c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Iterator;
925a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganeshimport java.util.List;
93c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Map;
9482aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport java.util.NoSuchElementException;
95d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErikimport java.util.Objects;
96c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Set;
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The implementation of the volume manager service.
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This implementation focuses on delivering a responsive UI. Most methods are
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * asynchronous to external calls. For example, the task of setting a volume
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will update our internal state, but in a separate thread will set the system
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * volume and later persist to the database. Similarly, setting the ringer mode
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will update the state and broadcast a change and in a separate thread later
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * persist the ringer mode.
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
110fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivipublic class AudioService extends IAudioService.Stub {
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "AudioService";
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi    /** Debug remote control client/display feature */
115ae641c9ccd3f81214cee54a5f13804f1765187adJohn Spurlock    protected static final boolean DEBUG_RC = Log.isLoggable(TAG + ".RC", Log.DEBUG);
1163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /** Debug volumes */
117ae641c9ccd3f81214cee54a5f13804f1765187adJohn Spurlock    protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
11818e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi
119430fc48865e5a371b08f180390946b96d73848feRoboErik    /** debug calls to media session apis */
120ae641c9ccd3f81214cee54a5f13804f1765187adJohn Spurlock    private static final boolean DEBUG_SESSIONS = Log.isLoggable(TAG + ".SESSIONS", Log.DEBUG);
1218a2cfc309ab9126e90022916967c65a793c034f0RoboErik
1228600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock    /** Allow volume changes to set ringer mode to silent? */
1238600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock    private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
1248600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock
125a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock    /** In silent mode, are volume adjustments (raises) prevented? */
126a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock    private static final boolean PREVENT_VOLUME_ADJUSTMENT_IF_SILENT = true;
127a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** How long to delay before persisting a change in volume/ringer mode. */
12945edba1b8b0377dfe70a4f2b0afb0f04dd8e1ee9RoboErik    private static final int PERSIST_DELAY = 500;
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1313346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    /**
1323346a802087f621c6441bc512dfcc17b07143fc6John Spurlock     * The delay before playing a sound. This small period exists so the user
1333346a802087f621c6441bc512dfcc17b07143fc6John Spurlock     * can press another key (non-volume keys, too) to have it NOT be audible.
1343346a802087f621c6441bc512dfcc17b07143fc6John Spurlock     * <p>
1353346a802087f621c6441bc512dfcc17b07143fc6John Spurlock     * PhoneWindow will implement this part.
1363346a802087f621c6441bc512dfcc17b07143fc6John Spurlock     */
1373346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    public static final int PLAY_SOUND_DELAY = 300;
1383346a802087f621c6441bc512dfcc17b07143fc6John Spurlock
139a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock    /**
140a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock     * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
141a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock     */
142a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock    private static final int FLAG_ADJUST_VOLUME = 1;
143a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock
144ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    private final Context mContext;
145ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    private final ContentResolver mContentResolver;
146ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    private final AppOpsManager mAppOps;
147ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    private final boolean mVoiceCapable;
148d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
1493346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    /** The controller for the volume UI. */
1503346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    private final VolumeController mVolumeController = new VolumeController();
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // sendMsg() flags
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** If the msg is already queued, replace it with this one. */
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int SENDMSG_REPLACE = 0;
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** If the msg is already queued, ignore this one and leave the old. */
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int SENDMSG_NOOP = 1;
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** If the msg is already queued, queue this one and leave the old. */
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int SENDMSG_QUEUE = 2;
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // AudioHandler messages
1619bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    private static final int MSG_SET_DEVICE_VOLUME = 0;
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MSG_PERSIST_VOLUME = 1;
1635c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood    private static final int MSG_PERSIST_MASTER_VOLUME = 2;
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MSG_PERSIST_RINGER_MODE = 3;
165bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_MEDIA_SERVER_DIED = 4;
166dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_PLAY_SOUND_EFFECT = 5;
167dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
168dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_LOAD_SOUND_EFFECTS = 7;
169dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_SET_FORCE_USE = 8;
170dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
171dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_SET_ALL_VOLUMES = 10;
172dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
173dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_REPORT_NEW_ROUTES = 12;
174dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
175dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
176dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
177dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
178dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
179dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
180dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
181dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
1824a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent    private static final int MSG_SYSTEM_READY = 21;
1833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // start of messages handled under wakelock
1843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
185e12c39bb9cedb8b363658979872694eb55b1386eJean-Michel Trivi    //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
186fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
1870a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
1880a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
1893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // end of messages handled under wakelock
190afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent
1914c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
192dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // Timeout for connection to bluetooth headset service
193dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
194dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioSystemThread */
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private AudioSystemThread mAudioSystemThread;
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioHandler */
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private AudioHandler mAudioHandler;
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see VolumeStreamState */
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private VolumeStreamState[] mStreamStates;
201b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    private SettingsObserver mSettingsObserver;
202a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
203fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private int mMode = AudioSystem.MODE_NORMAL;
204ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    // protects mRingerMode
205ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    private final Object mSettingsLock = new Object();
20645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private SoundPool mSoundPool;
20830c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final Object mSoundEffectsLock = new Object();
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int NUM_SOUNDPOOL_CHANNELS = 4;
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2114767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    // Internally master volume is a float in the 0.0 - 1.0 range,
2124767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    // but to support integer based AudioManager API we translate it to 0 - 100
2134767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    private static final int MAX_MASTER_VOLUME = 100;
2144767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood
2156c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    // Maximum volume adjust steps allowed in a single batch call.
2166c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
2176c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Sound effect file names  */
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
220e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * uses soundpool (second column) */
225e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2275982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles   /** @hide Maximum volume index values for audio streams */
228fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int[] MAX_STREAM_VOLUME = new int[] {
2296ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        5,  // STREAM_VOICE_CALL
2306ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_SYSTEM
2316ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_RING
2326ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15, // STREAM_MUSIC
2336ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_ALARM
2346ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_NOTIFICATION
2356ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15, // STREAM_BLUETOOTH_SCO
2366ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_SYSTEM_ENFORCED
2376ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15, // STREAM_DTMF
2386ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15  // STREAM_TTS
2395982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles    };
2406d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
241a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     * of another stream: This avoids multiplying the volume settings for hidden
242a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     * stream types that follow other stream behavior for volume settings
2436d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     * NOTE: do not create loops in aliases!
2446d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     * Some streams alias to different streams according to device category (phone or tablet) or
24524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent     * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
2466d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     *  mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and
2476d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     *  STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/
24830c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final int[] STREAM_VOLUME_ALIAS = new int[] {
2496d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
2506d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_SYSTEM
2516d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_RING
2526d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
2536d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
2546d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
2556d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
2566d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
2576d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_DTMF
2586d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC            // STREAM_TTS
259a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    };
2606d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] {
2616d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
2626d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_SYSTEM
2636d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_RING
2646d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
2656d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
2666d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
2676d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
2686d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_SYSTEM_ENFORCED
2696d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_DTMF
2706d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC            // STREAM_TTS
2716d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    };
2726d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private int[] mStreamVolumeAlias;
273a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
274ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    /**
275ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn     * Map AudioSystem.STREAM_* constants to app ops.  This should be used
276ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn     * after mapping through mStreamVolumeAlias.
277ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn     */
278ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    private static final int[] STEAM_VOLUME_OPS = new int[] {
279ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_VOICE_VOLUME,            // STREAM_VOICE_CALL
280ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM
281ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_RING_VOLUME,             // STREAM_RING
282ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_MUSIC
283ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_ALARM_VOLUME,            // STREAM_ALARM
284ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME,     // STREAM_NOTIFICATION
285ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME,        // STREAM_BLUETOOTH_SCO
286ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM_ENFORCED
287ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_DTMF
288ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_TTS
289ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    };
290ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn
29183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent    private final boolean mUseFixedVolume;
29283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
293bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    // stream names used by dumpStreamStates()
2941af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock    private static final String[] STREAM_NAMES = new String[] {
295bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_VOICE_CALL",
296bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_SYSTEM",
297bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_RING",
298bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_MUSIC",
299bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_ALARM",
300bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_NOTIFICATION",
301bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_BLUETOOTH_SCO",
302bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_SYSTEM_ENFORCED",
303bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_DTMF",
304bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_TTS"
305bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    };
306bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
30730c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onError(int error) {
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (error) {
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioSystem.AUDIO_STATUS_SERVER_DIED:
311dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
312dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                        SENDMSG_NOOP, 0, 0, null, 0);
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
317dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent        }
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link AudioManager#RINGER_MODE_SILENT}, or
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link AudioManager#RINGER_MODE_VIBRATE}.
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
325ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    // protected by mSettingsLock
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mRingerMode;
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3289bcf401d13d47416043a704430388abd59aef7cdEric Laurent    /** @see System#MODE_RINGER_STREAMS_AFFECTED */
32924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent    private int mRingerModeAffectedStreams = 0;
3309bcf401d13d47416043a704430388abd59aef7cdEric Laurent
3315b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    // Streams currently muted by ringer mode
3325b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    private int mRingerModeMutedStreams;
3335b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see System#MUTE_STREAMS_AFFECTED */
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mMuteAffectedStreams;
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
338bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent     * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
339bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent     * mVibrateSetting is just maintained during deprecation period but vibration policy is
340bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent     * now only controlled by mHasVibrator and mRingerMode
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mVibrateSetting;
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
344bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    // Is there a vibrator
345bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private final boolean mHasVibrator;
346bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
347a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    // Broadcast receiver for device connections intent broadcasts
348a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
349a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
350c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    // Devices currently connected
35130c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
352c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
353c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    // Forced device usage for communications
354c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    private int mForcedUseForComm;
355c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
3560dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    // True if we have master volume support
3570dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    private final boolean mUseMasterVolume;
3580dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
3599760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood    private final int[] mMasterVolumeRamp;
3609760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood
3619272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    // List of binder death handlers for setMode() client processes.
3629272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    // The last process to have called setMode() is at the top of the list.
36330c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
364eb14a783be073b5fd6e8c8c9bc87d2d1919f2c9eEric Laurent
3653def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    // List of clients having issued a SCO start request
36630c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
3673def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
3683def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    // BluetoothHeadset API to control SCO connection
3693def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    private BluetoothHeadset mBluetoothHeadset;
3703def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
37182aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh    // Bluetooth headset device
37282aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh    private BluetoothDevice mBluetoothHeadsetDevice;
3733def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
37462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // Indicate if SCO audio connection is currently active and if the initiator is
37562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // audio service (internal) or bluetooth headset (external)
37662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private int mScoAudioState;
37762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // SCO audio state is not active
37862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private static final int SCO_STATE_INACTIVE = 0;
379dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // SCO audio activation request waiting for headset service to connect
380dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_ACTIVATE_REQ = 1;
38125fc29b3691a1d2a84164988dc74b2e7d301868eEric Laurent    // SCO audio state is active or starting due to a request from AudioManager API
382dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
383dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // SCO audio deactivation request waiting for headset service to connect
384dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_DEACTIVATE_REQ = 5;
385dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
38662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // SCO audio state is active due to an action in BT handsfree (either voice recognition or
38762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // in call audio)
38862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
389dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // Deactivation request for all SCO connections (initiated by audio mode change)
390dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // waiting for headset service to connect
391dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
392dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
393c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
394c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    // originated from an app targeting an API version before JB MR2 and raw audio after that.
395c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    private int mScoAudioMode;
396f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao    // SCO audio mode is undefined
397f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao    private static final int SCO_MODE_UNDEFINED = -1;
398c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
399c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    private static final int SCO_MODE_VIRTUAL_CALL = 0;
400c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
401c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    private static final int SCO_MODE_RAW = 1;
402f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao    // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
403f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao    private static final int SCO_MODE_VR = 2;
404f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao
405f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao    private static final int SCO_MODE_MAX = 2;
406c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent
407dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // Current connection state indicated by bluetooth headset
408dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private int mScoConnectionState;
40962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent
410a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // true if boot sequence has been completed
4114a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent    private boolean mSystemReady;
412a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // listener for SoundPool sample load completion indication
413a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private SoundPoolCallback mSoundPoolCallBack;
414a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // thread for SoundPool listener
415a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private SoundPoolListenerThread mSoundPoolListenerThread;
416a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // message looper for SoundPool listener
417a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private Looper mSoundPoolLooper = null;
418c55b393efd462490cd5e27fc373bceafdd25662eJean-Michel Trivi    // volume applied to sound played with playSoundEffect()
419f2b0c11f4e797e183131261724d8de310dac5431Jean-Michel Trivi    private static int sSoundEffectVolumeDb;
4209903e2638a6c502d96413680d3ebae4fb77fc412Eric Laurent    // getActiveStreamType() will return:
4219903e2638a6c502d96413680d3ebae4fb77fc412Eric Laurent    // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
4229903e2638a6c502d96413680d3ebae4fb77fc412Eric Laurent    // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
42325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    // stopped
4249903e2638a6c502d96413680d3ebae4fb77fc412Eric Laurent    private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
42525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    // previous volume adjustment direction received by checkForRingerModeChange()
42625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    private int mPrevVolDirection = AudioManager.ADJUST_SAME;
4276243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani    // Keyguard manager proxy
4286243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani    private KeyguardManager mKeyguardManager;
42945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
43045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // is controlled by Vol keys.
43145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private int  mVolumeControlStream = -1;
43245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private final Object mForceControlStreamLock = new Object();
43345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
43445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // server process so in theory it is not necessary to monitor the client death.
43545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // However it is good to be ready for future evolutions.
43645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private ForceControlStreamClient mForceControlStreamClient = null;
437098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    // Used to play ringtones outside system_server
438098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    private volatile IRingtonePlayer mRingtonePlayer;
4399bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
440f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
441bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    private int mDeviceRotation = Surface.ROTATION_0;
442f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
4437847211fb4699bf6018e29d214a918ed6657319bEric Laurent    // Request to override default use of A2DP for media.
4447847211fb4699bf6018e29d214a918ed6657319bEric Laurent    private boolean mBluetoothA2dpEnabled;
4457847211fb4699bf6018e29d214a918ed6657319bEric Laurent    private final Object mBluetoothA2dpEnabledLock = new Object();
4467847211fb4699bf6018e29d214a918ed6657319bEric Laurent
447632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    // Monitoring of audio routes.  Protected by mCurAudioRoutes.
448632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
449632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
450632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            = new RemoteCallbackList<IAudioRoutesObserver>();
451632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
4523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
4533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * A fake stream type to match the notion of remote media playback
4543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
4553114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int STREAM_REMOTE_MUSIC = -200;
4563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
4574bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent    // Devices for which the volume is fixed and VolumePanel slider should be disabled
458948d32748caaac5be06c991ebf00f74265a7849fEric Laurent    final int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
4594bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
460fb917e019f04d60f4924114fe2684c0d67981af6Paul McLean            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
4614bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent
462bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    // TODO merge orientation and rotation
463d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private final boolean mMonitorOrientation;
464bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    private final boolean mMonitorRotation;
465d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent
4667ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent    private boolean mDockAudioMediaEnabled = true;
4677ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent
46808ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent    private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
46908ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent
470fde16d5879ea88a971004c984093409468b6139cEric Laurent    // Used when safe volume warning message display is requested by setStreamVolume(). In this
471fde16d5879ea88a971004c984093409468b6139cEric Laurent    // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
472fde16d5879ea88a971004c984093409468b6139cEric Laurent    // and used later when/if disableSafeMediaVolume() is called.
473fde16d5879ea88a971004c984093409468b6139cEric Laurent    private StreamVolumeCommand mPendingVolumeCommand;
474fde16d5879ea88a971004c984093409468b6139cEric Laurent
475fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private PowerManager.WakeLock mAudioEventWakeLock;
476fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
477fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final MediaFocusControl mMediaFocusControl;
478fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
4795a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    // Reference to BluetoothA2dp to query for AbsoluteVolume.
4805a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    private BluetoothA2dp mA2dp;
4815a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    private final Object mA2dpAvrcpLock = new Object();
4825a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    // If absolute volume is supported in AVRCP device
4835a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    private boolean mAvrcpAbsVolSupported = false;
4845a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Construction
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @hide */
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public AudioService(Context context) {
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContentResolver = context.getContentResolver();
493ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
494c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato        mVoiceCapable = mContext.getResources().getBoolean(
495c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato                com.android.internal.R.bool.config_voice_capable);
4965982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles
497c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
498fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
499c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
500bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
501bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
502bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
5035982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles       // Intialized volume
5045982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles        MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt(
5055982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles            "ro.config.vc_call_vol_steps",
5065982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles           MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
5075982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles
508f2b0c11f4e797e183131261724d8de310dac5431Jean-Michel Trivi        sSoundEffectVolumeDb = context.getResources().getInteger(
509c55b393efd462490cd5e27fc373bceafdd25662eJean-Michel Trivi                com.android.internal.R.integer.config_soundEffectVolumeDb);
51025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
511c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent        mForcedUseForComm = AudioSystem.FORCE_NONE;
512dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        createAudioSystemThread();
514dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
515fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
5163346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                mContext, mVolumeController, this);
517fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
518dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent        AudioSystem.setErrorCallback(mAudioSystemCallback);
519dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent
520dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        boolean cameraSoundForced = mContext.getResources().getBoolean(
521dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                com.android.internal.R.bool.config_camera_sound_forced);
522dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        mCameraSoundForced = new Boolean(cameraSoundForced);
523dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        sendMsg(mAudioHandler,
524dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                MSG_SET_FORCE_USE,
525dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                SENDMSG_QUEUE,
526dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                AudioSystem.FOR_SYSTEM,
527dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                cameraSoundForced ?
528dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
529dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                null,
530dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                0);
531dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
53205274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
53305274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                                                        Settings.Global.AUDIO_SAFE_VOLUME_STATE,
53405274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                                                        SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
53505274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        // The default safe volume index read here will be replaced by the actual value when
53605274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        // the mcc is read by onConfigureSafeVolume()
53705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        mSafeMediaVolumeIndex = mContext.getResources().getInteger(
53805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                com.android.internal.R.integer.config_safe_media_volume_index) * 10;
53905274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent
54083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        mUseFixedVolume = mContext.getResources().getBoolean(
54183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                com.android.internal.R.bool.config_useFixedVolume);
54283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
54324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
54424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // array initialized by updateStreamVolumeAlias()
54524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        updateStreamVolumeAlias(false /*updateVolumes*/);
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        readPersistedSettings();
547c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent        mSettingsObserver = new SettingsObserver();
548a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        createStreamStates();
5499f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent
550fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten        readAndSetLowRamDevice();
5513891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent
5523891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        // Call setRingerModeInt() to apply correct mute
5533891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        // state on streams affected by ringer mode.
5543891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        mRingerModeMutedStreams = 0;
5553891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        setRingerModeInt(getRingerMode(), false);
5563891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent
557a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        // Register for device connection intent broadcasts.
558a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        IntentFilter intentFilter =
559b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
56082aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
56182aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
56259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
56359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
564950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
565950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
566bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
567c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean        intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
568f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
569d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
570bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        // TODO merge orientation and rotation
571d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
572d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        if (mMonitorOrientation) {
573f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            Log.v(TAG, "monitoring device orientation");
574f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            // initialize orientation in AudioSystem
575f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            setOrientationForAudioSystem();
576f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        }
577bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
578bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        if (mMonitorRotation) {
579bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
580bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                    .getDefaultDisplay().getRotation();
581bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
582bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            // initialize rotation in AudioSystem
583bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            setRotationForAudioSystem();
584bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        }
585f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
58641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang        HdmiControlManager hdmiManager =
58741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
58841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang        // Null if device is not Tv.
58941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang        mHdmiTvClient = hdmiManager.getTvClient();
59041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang
591a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        context.registerReceiver(mReceiver, intentFilter);
5925982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles
5930dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        mUseMasterVolume = context.getResources().getBoolean(
5940dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood                com.android.internal.R.bool.config_useMasterVolume);
5959063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood        restoreMasterVolume();
5969760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood
5979760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        mMasterVolumeRamp = context.getResources().getIntArray(
5989760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood                com.android.internal.R.array.config_masterVolumeRamp);
5997847211fb4699bf6018e29d214a918ed6657319bEric Laurent
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6024a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent    public void systemReady() {
6034a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
6044a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                0, 0, null, 0);
6054a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent    }
6064a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent
6074a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent    public void onSystemReady() {
6084a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        mSystemReady = true;
6094a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
6104a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                0, 0, null, 0);
6114a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent
6124a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        mKeyguardManager =
6134a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
6144a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
6154a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        resetBluetoothSco();
6164a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        getBluetoothHeadset();
6174a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        //FIXME: this is to maintain compatibility with deprecated intent
6184a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
6194a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
6204a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
6214a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
6224a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        sendStickyBroadcastToAll(newIntent);
6234a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent
6244a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
6254a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        if (adapter != null) {
6264a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent            adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
6274a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                                    BluetoothProfile.A2DP);
6284a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        }
6294a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent
6304a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        sendMsg(mAudioHandler,
6314a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
6324a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                SENDMSG_REPLACE,
6334a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                0,
6344a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                0,
6354a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                null,
6364a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
6374a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent    }
6384a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void createAudioSystemThread() {
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAudioSystemThread = new AudioSystemThread();
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAudioSystemThread.start();
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        waitForAudioHandlerCreation();
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Waits for the volume handler to be created by the other thread. */
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void waitForAudioHandlerCreation() {
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized(this) {
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (mAudioHandler == null) {
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Wait for mAudioHandler to be set by the other thread
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    wait();
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (InterruptedException e) {
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.e(TAG, "Interrupted while waiting on volume handler.");
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
659244820185269991186d07068b92985624cede4a5Eric Laurent    private void checkAllAliasStreamVolumes() {
660244820185269991186d07068b92985624cede4a5Eric Laurent        int numStreamTypes = AudioSystem.getNumStreamTypes();
661244820185269991186d07068b92985624cede4a5Eric Laurent        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
662244820185269991186d07068b92985624cede4a5Eric Laurent            if (streamType != mStreamVolumeAlias[streamType]) {
663244820185269991186d07068b92985624cede4a5Eric Laurent                mStreamStates[streamType].
66442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                    setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
665244820185269991186d07068b92985624cede4a5Eric Laurent            }
666244820185269991186d07068b92985624cede4a5Eric Laurent            // apply stream volume
66742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            if (!mStreamStates[streamType].isMuted()) {
668244820185269991186d07068b92985624cede4a5Eric Laurent                mStreamStates[streamType].applyAllVolumes();
669244820185269991186d07068b92985624cede4a5Eric Laurent            }
670244820185269991186d07068b92985624cede4a5Eric Laurent        }
671244820185269991186d07068b92985624cede4a5Eric Laurent    }
672244820185269991186d07068b92985624cede4a5Eric Laurent
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void createStreamStates() {
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int numStreamTypes = AudioSystem.getNumStreamTypes();
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < numStreamTypes; i++) {
6786d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
681244820185269991186d07068b92985624cede4a5Eric Laurent        checkAllAliasStreamVolumes();
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
684bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private void dumpStreamStates(PrintWriter pw) {
685bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        pw.println("\nStream volumes (device: index)");
686bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        int numStreamTypes = AudioSystem.getNumStreamTypes();
687bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        for (int i = 0; i < numStreamTypes; i++) {
688bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.println("- "+STREAM_NAMES[i]+":");
689bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            mStreamStates[i].dump(pw);
690bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.println("");
691bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
692dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.print("\n- mute affected streams = 0x");
693dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println(Integer.toHexString(mMuteAffectedStreams));
694bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    }
695bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
6961af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock    /** @hide */
6971af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock    public static String streamToString(int stream) {
6981af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock        if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream];
6991af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock        if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE";
7001af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock        return "UNKNOWN_STREAM_" + stream;
7011af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock    }
7026d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
7036d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private void updateStreamVolumeAlias(boolean updateVolumes) {
7046d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        int dtmfStreamAlias;
7056d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (mVoiceCapable) {
7066d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            mStreamVolumeAlias = STREAM_VOLUME_ALIAS;
7076d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            dtmfStreamAlias = AudioSystem.STREAM_RING;
7086d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        } else {
7096d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE;
7106d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
7116d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
7126d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (isInCommunication()) {
7136d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
71424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
71524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        } else {
71624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
7176d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
7186d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
7196d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (updateVolumes) {
72042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
72124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            // apply stream mute states according to new value of mRingerModeAffectedStreams
72224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            setRingerModeInt(getRingerMode(), false);
7236d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            sendMsg(mAudioHandler,
7246d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    MSG_SET_ALL_VOLUMES,
7256d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    SENDMSG_QUEUE,
7266d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    0,
7276d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    0,
7286d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    mStreamStates[AudioSystem.STREAM_DTMF], 0);
7296d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
7306d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    }
7316d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
7327ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent    private void readDockAudioSettings(ContentResolver cr)
7337ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent    {
7347ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent        mDockAudioMediaEnabled = Settings.Global.getInt(
7355ba0ffa0237a5c300545e4c72591613c6e5b2ed9Eric Laurent                                        cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
7367ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent
7377ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent        if (mDockAudioMediaEnabled) {
7387ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent            mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
7397ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent        } else {
7407ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent            mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
7417ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent        }
7427ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent
7437ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent        sendMsg(mAudioHandler,
7447ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                MSG_SET_FORCE_USE,
7457ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                SENDMSG_QUEUE,
7467ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                AudioSystem.FOR_DOCK,
7477ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                mDockAudioMediaEnabled ?
7487ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
7497ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                null,
7507ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                0);
7517ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent    }
7527ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void readPersistedSettings() {
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ContentResolver cr = mContentResolver;
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
756bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        int ringerModeFromSettings =
7578d9a1f66d9d3dbbd45a56d441a746ec11dba7645Jeff Sharkey                Settings.Global.getInt(
7588d9a1f66d9d3dbbd45a56d441a746ec11dba7645Jeff Sharkey                        cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
759bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        int ringerMode = ringerModeFromSettings;
76072668b2c040b581b298b069f3b5af5ed7f212d89Eric Laurent        // sanity check in case the settings are restored from a device with incompatible
76172668b2c040b581b298b069f3b5af5ed7f212d89Eric Laurent        // ringer modes
762ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        if (!AudioManager.isValidRingerMode(ringerMode)) {
763ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            ringerMode = AudioManager.RINGER_MODE_NORMAL;
764bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
765bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
766bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            ringerMode = AudioManager.RINGER_MODE_SILENT;
767bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
768bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (ringerMode != ringerModeFromSettings) {
7698d9a1f66d9d3dbbd45a56d441a746ec11dba7645Jeff Sharkey            Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
770ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
77183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
77283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            ringerMode = AudioManager.RINGER_MODE_NORMAL;
77383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
774ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        synchronized(mSettingsLock) {
775ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            mRingerMode = ringerMode;
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
777dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
778dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            // are still needed while setVibrateSetting() and getVibrateSetting() are being
779dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            // deprecated.
780dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            mVibrateSetting = getValueForVibrateSetting(0,
781dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                            AudioManager.VIBRATE_TYPE_NOTIFICATION,
782dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
783dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                                            : AudioManager.VIBRATE_SETTING_OFF);
784dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
785dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                            AudioManager.VIBRATE_TYPE_RINGER,
786dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
787dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                                            : AudioManager.VIBRATE_SETTING_OFF);
788dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
78924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            updateRingerModeAffectedStreams();
7907ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent            readDockAudioSettings(cr);
791402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        }
792c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent
793bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent        mMuteAffectedStreams = System.getIntForUser(cr,
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                System.MUTE_STREAMS_AFFECTED,
795bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                ((1 << AudioSystem.STREAM_MUSIC)|
796bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                 (1 << AudioSystem.STREAM_RING)|
797bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                 (1 << AudioSystem.STREAM_SYSTEM)),
798bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                 UserHandle.USER_CURRENT);
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
800bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent        boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
801bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                  0, UserHandle.USER_CURRENT) == 1;
80283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
80383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            masterMute = false;
80483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            AudioSystem.setMasterVolume(1.0f);
80583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
80657978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        AudioSystem.setMasterMute(masterMute);
80757978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        broadcastMasterMuteStatus(masterMute);
80857978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Each stream will read its own persisted settings
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Broadcast the sticky intent
812ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        broadcastRingerMode(ringerMode);
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Broadcast vibrate settings
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
817d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
818d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        // Restore the default media button receiver from the system settings
819fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.restoreMediaButtonReceiver();
82033f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
82133f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        // Load settings for the volume controller
82233f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        mVolumeController.loadSettings(cr);
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
825a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    private int rescaleIndex(int index, int srcStream, int dstStream) {
826a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
827a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    }
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // IPC methods
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
832fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    /** @see AudioManager#isLocalOrRemoteMusicActive() */
833fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    public boolean isLocalOrRemoteMusicActive() {
834fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
835fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            // local / wired / BT playback active
836fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): local");
837fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            return true;
838fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        }
839fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
840fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            // remote "cast-like" playback active
841fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): has PLAYBACK_TYPE_REMOTE");
842fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            return true;
843fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        }
844fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        if (AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, 0)) {
845fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            // remote submix playback active
846fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): remote submix");
847fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            return true;
848fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        }
849fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): no");
850fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        return false;
851fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    }
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#adjustVolume(int, int) */
854ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
855ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            String callingPackage) {
856ae641c9ccd3f81214cee54a5f13804f1765187adJohn Spurlock        if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType
857ae641c9ccd3f81214cee54a5f13804f1765187adJohn Spurlock                + ", flags=" + flags);
858402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        int streamType;
85945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        if (mVolumeControlStream != -1) {
86045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            streamType = mVolumeControlStream;
861402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        } else {
862402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent            streamType = getActiveStreamType(suggestedStreamType);
863402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        }
86433f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        final int resolvedStream = mStreamVolumeAlias[streamType];
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8666bd096c8d608197535a6a6a26663fd1e717246deJohn Spurlock        // Play sounds on STREAM_RING and STREAM_REMOTE_MUSIC only.
8673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if ((streamType != STREAM_REMOTE_MUSIC) &&
8683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                (flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
86933f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                resolvedStream != AudioSystem.STREAM_RING) {
87033f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            flags &= ~AudioManager.FLAG_PLAY_SOUND;
87133f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        }
87233f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
87333f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        // For notifications/ring, show the ui before making any adjustments
87433f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        if (mVolumeController.suppressAdjustment(resolvedStream, flags)) {
87533f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            direction = 0;
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flags &= ~AudioManager.FLAG_PLAY_SOUND;
87733f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            flags &= ~AudioManager.FLAG_VIBRATE;
87833f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (streamType == STREAM_REMOTE_MUSIC) {
88219c9518f6a817d53d5234de0020313cab6950b2fRoboErik            // TODO bounce it to MediaSessionService to find an appropriate
88319c9518f6a817d53d5234de0020313cab6950b2fRoboErik            // session
8843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        } else {
885ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            adjustStreamVolume(streamType, direction, flags, callingPackage);
8863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#adjustStreamVolume(int, int, int) */
890ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void adjustStreamVolume(int streamType, int direction, int flags,
891ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            String callingPackage) {
89283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
89383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
89483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
895ae641c9ccd3f81214cee54a5f13804f1765187adJohn Spurlock        if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction
896ae641c9ccd3f81214cee54a5f13804f1765187adJohn Spurlock                + ", flags="+flags);
8973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidDirection(direction);
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
90196a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent        // use stream type alias here so that streams with same alias have the same behavior,
90296a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent        // including with regard to silent mode control (e.g the use of STREAM_RING below and in
90396a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent        // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
9046d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        int streamTypeAlias = mStreamVolumeAlias[streamType];
905b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
9069bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
9079bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        final int device = getDeviceForStream(streamTypeAlias);
9083ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent
90942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        int aliasIndex = streamState.getIndex(device);
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean adjustVolume = true;
9113ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        int step;
912244820185269991186d07068b92985624cede4a5Eric Laurent
913c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        // skip a2dp absolute volume control request when the device
914c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        // is not an a2dp device
915c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
916c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
917c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            return;
918c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        }
919c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie
920ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
921ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn                callingPackage) != AppOpsManager.MODE_ALLOWED) {
922ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            return;
923ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        }
924ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn
925fde16d5879ea88a971004c984093409468b6139cEric Laurent        // reset any pending volume command
926fde16d5879ea88a971004c984093409468b6139cEric Laurent        synchronized (mSafeMediaVolumeState) {
927fde16d5879ea88a971004c984093409468b6139cEric Laurent            mPendingVolumeCommand = null;
928fde16d5879ea88a971004c984093409468b6139cEric Laurent        }
929fde16d5879ea88a971004c984093409468b6139cEric Laurent
9303ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        flags &= ~AudioManager.FLAG_FIXED_VOLUME;
9313ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
9323ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent               ((device & mFixedVolumeDevices) != 0)) {
9333ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            flags |= AudioManager.FLAG_FIXED_VOLUME;
9343ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent
9353ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            // Always toggle between max safe volume and 0 for fixed volume devices where safe
9363ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            // volume is enforced, and max and 0 for the others.
9373ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            // This is simulated by stepping by the full allowed volume range
9383ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
9393ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                    (device & mSafeMediaVolumeDevices) != 0) {
9403ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                step = mSafeMediaVolumeIndex;
9413ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            } else {
9423ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                step = streamState.getMaxIndex();
9433ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            }
9443ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            if (aliasIndex != 0) {
9453ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                aliasIndex = step;
9463ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            }
9473ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        } else {
9483ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            // convert one UI step (+/-1) into a number of internal units on the stream alias
9493ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            step = rescaleIndex(10, streamType, streamTypeAlias);
9503ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        }
9513ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent
95242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        // If either the client forces allowing ringer modes for this adjustment,
95342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        // or the stream type is one that is affected by ringer modes
95442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
95542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                (streamTypeAlias == getMasterStreamType())) {
95642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            int ringerMode = getRingerMode();
95742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // do not vibrate if already in vibrate mode
95842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
95942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                flags &= ~AudioManager.FLAG_VIBRATE;
96042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            }
96142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // Check if the ringer mode changes with this volume adjustment. If
96242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // it does, it will handle adjusting the volume, so we won't below
963a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            final int result = checkForRingerModeChange(aliasIndex, direction, step);
964a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
965a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            // If suppressing a volume adjustment in silent mode, display the UI hint
966a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
967a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
968a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            }
96942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        }
97042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent
97142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        int oldIndex = mStreamStates[streamType].getIndex(device);
97242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent
97342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
974c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie
9755a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du            // Check if volume update should be send to AVRCP
976c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
977c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
978c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
979c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                synchronized (mA2dpAvrcpLock) {
980c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                    if (mA2dp != null && mAvrcpAbsVolSupported) {
981c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                        mA2dp.adjustAvrcpAbsoluteVolume(direction);
982c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                    }
9835a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                }
9845a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du            }
985c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie
98642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            if ((direction == AudioManager.ADJUST_RAISE) &&
98742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
98842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
9893346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                mVolumeController.postDisplaySafeVolumeWarning(flags);
99042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            } else if (streamState.adjustIndex(direction * step, device)) {
99142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                // Post message to set system volume (it in turn will post a message
99242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                // to persist). Do not change volume if stream is muted.
99342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                sendMsg(mAudioHandler,
99442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        MSG_SET_DEVICE_VOLUME,
99542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        SENDMSG_QUEUE,
99642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        device,
99742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        0,
99842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        streamState,
99942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        0);
10004bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            }
100141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang
100241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang            // Check if volume update should be send to Hdmi system audio.
100341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang            int newIndex = mStreamStates[streamType].getIndex(device);
100441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang            if (mHdmiTvClient != null &&
100541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                streamTypeAlias == AudioSystem.STREAM_MUSIC &&
100641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 &&
100741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                oldIndex != newIndex) {
100841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                int maxIndex = getStreamMaxVolume(streamType);
100941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                synchronized (mHdmiTvClient) {
101041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                    if (mHdmiSystemAudioSupported) {
101141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                        mHdmiTvClient.setSystemAudioVolume(
101241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                                (oldIndex + 5) / 10, (newIndex + 5) / 10, maxIndex);
101341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                    }
101441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                }
101541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang            }
10164bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        }
101742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        int index = mStreamStates[streamType].getIndex(device);
101825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        sendVolumeUpdate(streamType, oldIndex, index, flags);
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1021961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#adjustMasterVolume(int, int) */
1022ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void adjustMasterVolume(int steps, int flags, String callingPackage) {
102383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
102483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
102583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
10266c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        ensureValidSteps(steps);
10279760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
10289760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        int delta = 0;
10296c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        int numSteps = Math.abs(steps);
10306c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
10316c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        for (int i = 0; i < numSteps; ++i) {
10326c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            delta = findVolumeDelta(direction, volume);
10336c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            volume += delta;
1034cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood        }
103524b082f87e96c00d5c17d60c735423900be40e70RoboErik
10366c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
1037ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        setMasterVolume(volume, flags, callingPackage);
1038cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood    }
1039cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood
1040fde16d5879ea88a971004c984093409468b6139cEric Laurent    // StreamVolumeCommand contains the information needed to defer the process of
1041fde16d5879ea88a971004c984093409468b6139cEric Laurent    // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1042fde16d5879ea88a971004c984093409468b6139cEric Laurent    class StreamVolumeCommand {
1043fde16d5879ea88a971004c984093409468b6139cEric Laurent        public final int mStreamType;
1044fde16d5879ea88a971004c984093409468b6139cEric Laurent        public final int mIndex;
1045fde16d5879ea88a971004c984093409468b6139cEric Laurent        public final int mFlags;
1046fde16d5879ea88a971004c984093409468b6139cEric Laurent        public final int mDevice;
10473ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent
1048fde16d5879ea88a971004c984093409468b6139cEric Laurent        StreamVolumeCommand(int streamType, int index, int flags, int device) {
1049fde16d5879ea88a971004c984093409468b6139cEric Laurent            mStreamType = streamType;
1050fde16d5879ea88a971004c984093409468b6139cEric Laurent            mIndex = index;
1051fde16d5879ea88a971004c984093409468b6139cEric Laurent            mFlags = flags;
1052fde16d5879ea88a971004c984093409468b6139cEric Laurent            mDevice = device;
10534bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        }
1054fde16d5879ea88a971004c984093409468b6139cEric Laurent    };
10553ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent
1056fde16d5879ea88a971004c984093409468b6139cEric Laurent    private void onSetStreamVolume(int streamType, int index, int flags, int device) {
105742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
10583ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        // setting volume on master stream type also controls silent mode
10593ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
10603ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
10613ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            int newRingerMode;
10623ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            if (index == 0) {
10633ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
10648600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                        : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
10658600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                        : AudioManager.RINGER_MODE_NORMAL;
10663ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            } else {
10673ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                newRingerMode = AudioManager.RINGER_MODE_NORMAL;
10683ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            }
10693ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            setRingerMode(newRingerMode);
10703ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        }
1071fde16d5879ea88a971004c984093409468b6139cEric Laurent    }
1072fde16d5879ea88a971004c984093409468b6139cEric Laurent
1073fde16d5879ea88a971004c984093409468b6139cEric Laurent    /** @see AudioManager#setStreamVolume(int, int, int) */
1074ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
107583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
107683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
107783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
107883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
1079fde16d5879ea88a971004c984093409468b6139cEric Laurent        ensureValidStreamType(streamType);
1080ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        int streamTypeAlias = mStreamVolumeAlias[streamType];
1081ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
1082fde16d5879ea88a971004c984093409468b6139cEric Laurent
1083fde16d5879ea88a971004c984093409468b6139cEric Laurent        final int device = getDeviceForStream(streamType);
1084fde16d5879ea88a971004c984093409468b6139cEric Laurent        int oldIndex;
1085fde16d5879ea88a971004c984093409468b6139cEric Laurent
1086c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        // skip a2dp absolute volume control request when the device
1087c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        // is not an a2dp device
1088c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1089c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1090c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            return;
1091c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        }
1092c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie
1093ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
1094ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn                callingPackage) != AppOpsManager.MODE_ALLOWED) {
1095ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            return;
1096ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        }
1097ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn
1098fde16d5879ea88a971004c984093409468b6139cEric Laurent        synchronized (mSafeMediaVolumeState) {
1099fde16d5879ea88a971004c984093409468b6139cEric Laurent            // reset any pending volume command
1100fde16d5879ea88a971004c984093409468b6139cEric Laurent            mPendingVolumeCommand = null;
1101fde16d5879ea88a971004c984093409468b6139cEric Laurent
110242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            oldIndex = streamState.getIndex(device);
1103fde16d5879ea88a971004c984093409468b6139cEric Laurent
1104ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            index = rescaleIndex(index * 10, streamType, streamTypeAlias);
1105fde16d5879ea88a971004c984093409468b6139cEric Laurent
1106c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1107c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1108c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1109c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                synchronized (mA2dpAvrcpLock) {
1110c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                    if (mA2dp != null && mAvrcpAbsVolSupported) {
11112f4a2b139b4c1dde7be1d14333ad02553734c528Zhihai Xu                        mA2dp.setAvrcpAbsoluteVolume(index / 10);
1112c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                    }
11135a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                }
11145a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du            }
11155a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
111641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang            if (mHdmiTvClient != null &&
111741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                streamTypeAlias == AudioSystem.STREAM_MUSIC &&
111841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 &&
111941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                oldIndex != index) {
112041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                int maxIndex = getStreamMaxVolume(streamType);
112141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                synchronized (mHdmiTvClient) {
112241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                    if (mHdmiSystemAudioSupported) {
112341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                        mHdmiTvClient.setSystemAudioVolume(
112441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                                (oldIndex + 5) / 10, (index + 5) / 10, maxIndex);
112541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                    }
112641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                }
112741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang            }
112841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang
1129fde16d5879ea88a971004c984093409468b6139cEric Laurent            flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1130ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1131fde16d5879ea88a971004c984093409468b6139cEric Laurent                    ((device & mFixedVolumeDevices) != 0)) {
1132fde16d5879ea88a971004c984093409468b6139cEric Laurent                flags |= AudioManager.FLAG_FIXED_VOLUME;
1133fde16d5879ea88a971004c984093409468b6139cEric Laurent
1134fde16d5879ea88a971004c984093409468b6139cEric Laurent                // volume is either 0 or max allowed for fixed volume devices
1135fde16d5879ea88a971004c984093409468b6139cEric Laurent                if (index != 0) {
1136fde16d5879ea88a971004c984093409468b6139cEric Laurent                    if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1137fde16d5879ea88a971004c984093409468b6139cEric Laurent                            (device & mSafeMediaVolumeDevices) != 0) {
1138fde16d5879ea88a971004c984093409468b6139cEric Laurent                        index = mSafeMediaVolumeIndex;
1139fde16d5879ea88a971004c984093409468b6139cEric Laurent                    } else {
1140fde16d5879ea88a971004c984093409468b6139cEric Laurent                        index = streamState.getMaxIndex();
1141fde16d5879ea88a971004c984093409468b6139cEric Laurent                    }
1142fde16d5879ea88a971004c984093409468b6139cEric Laurent                }
1143fde16d5879ea88a971004c984093409468b6139cEric Laurent            }
1144fde16d5879ea88a971004c984093409468b6139cEric Laurent
1145ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
11463346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                mVolumeController.postDisplaySafeVolumeWarning(flags);
1147fde16d5879ea88a971004c984093409468b6139cEric Laurent                mPendingVolumeCommand = new StreamVolumeCommand(
1148fde16d5879ea88a971004c984093409468b6139cEric Laurent                                                    streamType, index, flags, device);
1149fde16d5879ea88a971004c984093409468b6139cEric Laurent            } else {
1150fde16d5879ea88a971004c984093409468b6139cEric Laurent                onSetStreamVolume(streamType, index, flags, device);
115142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                index = mStreamStates[streamType].getIndex(device);
1152fde16d5879ea88a971004c984093409468b6139cEric Laurent            }
1153fde16d5879ea88a971004c984093409468b6139cEric Laurent        }
115425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        sendVolumeUpdate(streamType, oldIndex, index, flags);
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
115745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    /** @see AudioManager#forceVolumeControlStream(int) */
115845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    public void forceVolumeControlStream(int streamType, IBinder cb) {
115945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        synchronized(mForceControlStreamLock) {
116045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            mVolumeControlStream = streamType;
116145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            if (mVolumeControlStream == -1) {
116245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                if (mForceControlStreamClient != null) {
116345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mForceControlStreamClient.release();
116445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mForceControlStreamClient = null;
116545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                }
116645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            } else {
116745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                mForceControlStreamClient = new ForceControlStreamClient(cb);
116845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
116945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
117045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    }
117145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
117245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private class ForceControlStreamClient implements IBinder.DeathRecipient {
117345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        private IBinder mCb; // To be notified of client's death
117445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
117545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        ForceControlStreamClient(IBinder cb) {
117645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            if (cb != null) {
117745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                try {
117845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    cb.linkToDeath(this, 0);
117945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                } catch (RemoteException e) {
118045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    // Client has died!
118145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
118245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    cb = null;
118345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                }
118445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
118545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            mCb = cb;
118645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
118745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
118845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        public void binderDied() {
118945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            synchronized(mForceControlStreamLock) {
119045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                Log.w(TAG, "SCO client died");
119145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                if (mForceControlStreamClient != this) {
119245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    Log.w(TAG, "unregistered control stream client died");
119345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                } else {
119445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mForceControlStreamClient = null;
119545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mVolumeControlStream = -1;
119645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                }
119745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
119845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
119945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
120045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        public void release() {
120145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            if (mCb != null) {
120245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                mCb.unlinkToDeath(this, 0);
120345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                mCb = null;
120445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
120545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
120645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    }
120745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
12086c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    private int findVolumeDelta(int direction, int volume) {
12096c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        int delta = 0;
12106c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        if (direction == AudioManager.ADJUST_RAISE) {
12116c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            if (volume == MAX_MASTER_VOLUME) {
12126c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                return 0;
12136c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
12146c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // This is the default value if we make it to the end
12156c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            delta = mMasterVolumeRamp[1];
12166c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // If we're raising the volume move down the ramp array until we
12176c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // find the volume we're above and use that groups delta.
12186c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
12196c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                if (volume >= mMasterVolumeRamp[i - 1]) {
12206c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    delta = mMasterVolumeRamp[i];
12216c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    break;
12226c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                }
12236c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
12246c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        } else if (direction == AudioManager.ADJUST_LOWER){
12256c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            if (volume == 0) {
12266c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                return 0;
12276c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
12286c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            int length = mMasterVolumeRamp.length;
12296c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // This is the default value if we make it to the end
12306c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            delta = -mMasterVolumeRamp[length - 1];
12316c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // If we're lowering the volume move up the ramp array until we
12326c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // find the volume we're below and use the group below it's delta
12336c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            for (int i = 2; i < length; i += 2) {
12346c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                if (volume <= mMasterVolumeRamp[i]) {
12356c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    delta = -mMasterVolumeRamp[i - 1];
12366c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    break;
12376c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                }
12386c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
12396c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        }
12406c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        return delta;
12416c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    }
12426c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang
12435ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn    private void sendBroadcastToAll(Intent intent) {
12445ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        final long ident = Binder.clearCallingIdentity();
12455ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        try {
12465ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
12475ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        } finally {
12485ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            Binder.restoreCallingIdentity(ident);
12495ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        }
12505ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn    }
12515ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn
12525ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn    private void sendStickyBroadcastToAll(Intent intent) {
12535ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        final long ident = Binder.clearCallingIdentity();
12545ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        try {
12555ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
12565ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        } finally {
12575ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            Binder.restoreCallingIdentity(ident);
12585ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        }
12595ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn    }
12605ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn
126125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    // UI update and Broadcast Intent
126225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
126325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) {
126425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            streamType = AudioSystem.STREAM_NOTIFICATION;
126525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        }
126625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
12673346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        mVolumeController.postVolumeChanged(streamType, flags);
126825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
12694bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
12704bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            oldIndex = (oldIndex + 5) / 10;
12714bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            index = (index + 5) / 10;
12724bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
12734bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
12744bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
12754bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
12764bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            sendBroadcastToAll(intent);
12774bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        }
12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12800dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    // UI update and Broadcast Intent
12810dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
12823346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        mVolumeController.postMasterVolumeChanged(flags);
12830dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
12840dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
12850dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
12860dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
12875ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        sendBroadcastToAll(intent);
12880dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    }
12890dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
12900dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    // UI update and Broadcast Intent
12910dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    private void sendMasterMuteUpdate(boolean muted, int flags) {
12923346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        mVolumeController.postMasterMuteChanged(flags);
129357978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        broadcastMasterMuteStatus(muted);
129457978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh    }
12950dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
129657978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh    private void broadcastMasterMuteStatus(boolean muted) {
12970dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
12980dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
129957978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
130057978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
13015ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        sendStickyBroadcastToAll(intent);
13020dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    }
13030dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
13049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
13059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the stream state's index, and posts a message to set system volume.
13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This will not call out to the UI. Assumes a valid stream type.
13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param streamType Type of the stream
13099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param index Desired volume index of the stream
13109bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent     * @param device the device whose volume must be changed
13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param force If true, set the volume even if the desired volume is same
13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * as the current volume.
13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
13149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    private void setStreamVolumeInt(int streamType,
13159bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    int index,
13169bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    int device,
131742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                    boolean force) {
13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        VolumeStreamState streamState = mStreamStates[streamType];
13195b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
132042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        if (streamState.setIndex(index, device) || force) {
132142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // Post message to set system volume (it in turn will post a message
132242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // to persist).
132342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            sendMsg(mAudioHandler,
132442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    MSG_SET_DEVICE_VOLUME,
132542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    SENDMSG_QUEUE,
132642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    device,
132742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    0,
132842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    streamState,
132942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    0);
13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setStreamSolo(int, boolean) */
13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setStreamSolo(int streamType, boolean state, IBinder cb) {
133583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
133683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
133783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
133883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int stream = 0; stream < mStreamStates.length; stream++) {
13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!isStreamAffectedByMute(stream) || stream == streamType) continue;
13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStreamStates[stream].mute(cb, state);
13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         }
13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setStreamMute(int, boolean) */
13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setStreamMute(int streamType, boolean state, IBinder cb) {
134783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
134883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
134983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
135083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
13519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (isStreamAffectedByMute(streamType)) {
135241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang            if (streamType == AudioSystem.STREAM_MUSIC && mHdmiTvClient != null) {
135341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                synchronized (mHdmiTvClient) {
135441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                    if (mHdmiSystemAudioSupported) {
135541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                        mHdmiTvClient.setSystemAudioMute(state);
135641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                    }
135741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                }
135841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang            }
13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStreamStates[streamType].mute(cb, state);
13609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
136325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    /** get stream mute state. */
136425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    public boolean isStreamMute(int streamType) {
136542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        return mStreamStates[streamType].isMuted();
136625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    }
136725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
1368961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#setMasterMute(boolean, int) */
13694a21b25fad62e4f19d13ba814263841c931f56efJulia Reynolds    public void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb) {
137083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
137183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
137283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
137383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
13744a21b25fad62e4f19d13ba814263841c931f56efJulia Reynolds        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
13754a21b25fad62e4f19d13ba814263841c931f56efJulia Reynolds                callingPackage) != AppOpsManager.MODE_ALLOWED) {
13764a21b25fad62e4f19d13ba814263841c931f56efJulia Reynolds            return;
13774a21b25fad62e4f19d13ba814263841c931f56efJulia Reynolds        }
13784a21b25fad62e4f19d13ba814263841c931f56efJulia Reynolds
13791ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons        if (state != AudioSystem.getMasterMute()) {
13801ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons            AudioSystem.setMasterMute(state);
138157978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh            // Post a persist master volume msg
138275cf9e19a575c28c200c02c0ab6f83bb79f5c50dJustin Koh            sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
138357978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                    : 0, 0, null, PERSIST_DELAY);
13840273af55cf68d54d26d154b44d105d40fed79701Justin Koh            sendMasterMuteUpdate(state, flags);
13851ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons        }
1386ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1387ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
1388ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    /** get master mute state. */
1389ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    public boolean isMasterMute() {
13903194ea94348bce8e7ee9f803698d877f46f8279aMike Lockwood        return AudioSystem.getMasterMute();
1391ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1392ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
1393fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected static int getMaxStreamVolume(int streamType) {
1394fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return MAX_STREAM_VOLUME[streamType];
1395fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1396fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
13979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getStreamVolume(int) */
13989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStreamVolume(int streamType) {
13999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
14009bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = getDeviceForStream(streamType);
140142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        int index = mStreamStates[streamType].getIndex(device);
14024bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent
140342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        // by convention getStreamVolume() returns 0 when a stream is muted.
140442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        if (mStreamStates[streamType].isMuted()) {
140542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            index = 0;
140642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        }
14073ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
14084bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent                (device & mFixedVolumeDevices) != 0) {
14094bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            index = mStreamStates[streamType].getMaxIndex();
14104bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        }
14114bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        return (index + 5) / 10;
14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14144767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    public int getMasterVolume() {
1415ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        if (isMasterMute()) return 0;
1416ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        return getLastAudibleMasterVolume();
14178dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    }
14188dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood
1419ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void setMasterVolume(int volume, int flags, String callingPackage) {
142083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
142183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
142283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
142383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
1424ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
1425ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn                callingPackage) != AppOpsManager.MODE_ALLOWED) {
1426ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            return;
1427ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        }
1428ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn
14299760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        if (volume < 0) {
14309760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood            volume = 0;
14319760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        } else if (volume > MAX_MASTER_VOLUME) {
14329760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood            volume = MAX_MASTER_VOLUME;
14339760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        }
14345c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
14355c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood    }
14365c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
14375c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood    private void doSetMasterVolume(float volume, int flags) {
14385c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        // don't allow changing master volume when muted
14395c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        if (!AudioSystem.getMasterMute()) {
14405c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            int oldVolume = getMasterVolume();
14415c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            AudioSystem.setMasterVolume(volume);
14425c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
14435c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            int newVolume = getMasterVolume();
14445c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            if (newVolume != oldVolume) {
14455c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                // Post a persist master volume msg
14465c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
14475c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                        Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
14485c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            }
14493caba517253d1703fc29b50740c4567b932279fbJustin Koh            // Send the volume update regardless whether there was a change.
14503caba517253d1703fc29b50740c4567b932279fbJustin Koh            sendMasterVolumeUpdate(flags, oldVolume, newVolume);
14515c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        }
14528dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    }
14538dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood
14549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getStreamMaxVolume(int) */
14559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStreamMaxVolume(int streamType) {
14569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
1457a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14604767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    public int getMasterMaxVolume() {
14614767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood        return MAX_MASTER_VOLUME;
14624767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    }
146325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
146425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    /** Get last audible volume before stream was muted. */
146525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    public int getLastAudibleStreamVolume(int streamType) {
146625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        ensureValidStreamType(streamType);
14679bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = getDeviceForStream(streamType);
146842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        return (mStreamStates[streamType].getIndex(device) + 5) / 10;
146925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    }
147025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
1471ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    /** Get last audible master volume before it was muted. */
1472ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    public int getLastAudibleMasterVolume() {
1473ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1474ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1475ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
1476961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#getMasterStreamType()  */
14776d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    public int getMasterStreamType() {
14786d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (mVoiceCapable) {
14796d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            return AudioSystem.STREAM_RING;
14806d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        } else {
14816d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            return AudioSystem.STREAM_MUSIC;
14826d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
14836d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    }
14846d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
148522c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier    /** @see AudioManager#setMicrophoneMute(boolean) */
148622c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier    public void setMicrophoneMute(boolean on, String callingPackage) {
148722c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier        if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(),
148822c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier                callingPackage) != AppOpsManager.MODE_ALLOWED) {
148922c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier            return;
149022c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier        }
149122c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier
149222c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier        AudioSystem.muteMicrophone(on);
149322c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier    }
149422c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier
14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getRingerMode() */
14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getRingerMode() {
1497ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        synchronized(mSettingsLock) {
1498ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            return mRingerMode;
1499ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
1500ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    }
1501ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten
1502ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    private void ensureValidRingerMode(int ringerMode) {
1503ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        if (!AudioManager.isValidRingerMode(ringerMode)) {
1504ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1505ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setRingerMode(int) */
15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setRingerMode(int ringerMode) {
151083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
151183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
151283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
151383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
1514244820185269991186d07068b92985624cede4a5Eric Laurent        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1515244820185269991186d07068b92985624cede4a5Eric Laurent            ringerMode = AudioManager.RINGER_MODE_SILENT;
1516244820185269991186d07068b92985624cede4a5Eric Laurent        }
1517ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        if (ringerMode != getRingerMode()) {
1518ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            setRingerModeInt(ringerMode, true);
1519ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            // Send sticky broadcast
1520ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            broadcastRingerMode(ringerMode);
1521b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
1522b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    }
15239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15244050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    private void setRingerModeInt(int ringerMode, boolean persist) {
1525ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        synchronized(mSettingsLock) {
1526ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            mRingerMode = ringerMode;
1527ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
1528b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh
15295b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // Mute stream if not previously muted by ringer mode and ringer mode
15305b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
15315b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // Unmute stream if previously muted by ringer mode and ringer mode
15325b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
1533b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        int numStreamTypes = AudioSystem.getNumStreamTypes();
15345b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
15355b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent            if (isStreamMutedByRingerMode(streamType)) {
15365b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                if (!isStreamAffectedByRingerMode(streamType) ||
1537ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    ringerMode == AudioManager.RINGER_MODE_NORMAL) {
1538b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    // ring and notifications volume should never be 0 when not silenced
1539b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    // on voice capable devices
1540b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    if (mVoiceCapable &&
15416d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                            mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
15423172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        synchronized (mStreamStates[streamType]) {
154342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            Set set = mStreamStates[streamType].mIndex.entrySet();
15443172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            Iterator i = set.iterator();
15453172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            while (i.hasNext()) {
15463172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                Map.Entry entry = (Map.Entry)i.next();
15473172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                if ((Integer)entry.getValue() == 0) {
15483172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                    entry.setValue(10);
15493172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                }
15509bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                            }
15519bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        }
1552b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    }
15535b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                    mStreamStates[streamType].mute(null, false);
15545b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                    mRingerModeMutedStreams &= ~(1 << streamType);
15559bcf401d13d47416043a704430388abd59aef7cdEric Laurent                }
15565b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent            } else {
15575b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                if (isStreamAffectedByRingerMode(streamType) &&
1558ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    ringerMode != AudioManager.RINGER_MODE_NORMAL) {
15595b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                   mStreamStates[streamType].mute(null, true);
15605b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                   mRingerModeMutedStreams |= (1 << streamType);
15615b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent               }
1562b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            }
15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1564a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
1565b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        // Post a persist ringer mode msg
15664050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        if (persist) {
1567afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
15684050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent                    SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
15694050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        }
15709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15729063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood    private void restoreMasterVolume() {
157383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
157483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            AudioSystem.setMasterVolume(1.0f);
157583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
157683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
15779063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood        if (mUseMasterVolume) {
1578bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent            float volume = Settings.System.getFloatForUser(mContentResolver,
1579bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                    Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
15809063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood            if (volume >= 0.0f) {
15819063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                AudioSystem.setMasterVolume(volume);
15829063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood            }
15839063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood        }
15849063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood    }
15859063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood
15869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#shouldVibrate(int) */
15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean shouldVibrate(int vibrateType) {
1588bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return false;
15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (getVibrateSetting(vibrateType)) {
15919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_ON:
1593ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                return getRingerMode() != AudioManager.RINGER_MODE_SILENT;
15949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
1596ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE;
15979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_OFF:
1599bcac496076ef6f439147e7a2be71e8a2b76ddedeDaniel Sandler                // return false, even for incoming calls
1600bcac496076ef6f439147e7a2be71e8a2b76ddedeDaniel Sandler                return false;
16019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
16039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
16049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getVibrateSetting(int) */
16089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getVibrateSetting(int vibrateType) {
1609bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
16109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mVibrateSetting >> (vibrateType * 2)) & 3;
16119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setVibrateSetting(int, int) */
16149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setVibrateSetting(int vibrateType, int vibrateSetting) {
16159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1616bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return;
1617bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
16189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
16199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Broadcast change
16219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        broadcastVibrateSetting(vibrateType);
16229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
16269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #setVibrateSetting(int, int)
16279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
16289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static int getValueForVibrateSetting(int existingValue, int vibrateType,
16299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int vibrateSetting) {
16309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // First clear the existing setting. Each vibrate type has two bits in
16329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // the value. Note '3' is '11' in binary.
16339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        existingValue &= ~(3 << (vibrateType * 2));
16349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Set into the old value
16369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
16379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return existingValue;
16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16419272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    private class SetModeDeathHandler implements IBinder.DeathRecipient {
16429272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        private IBinder mCb; // To be notified of client's death
1643f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        private int mPid;
16449272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
16459272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
16469f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        SetModeDeathHandler(IBinder cb, int pid) {
16479272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            mCb = cb;
16489f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            mPid = pid;
16499272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
16509272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
16519272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public void binderDied() {
1652d7454be47f4111c0478a502353e11dea401378bdEric Laurent            int newModeOwnerPid = 0;
16539272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            synchronized(mSetModeDeathHandlers) {
16549272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                Log.w(TAG, "setMode() client died");
16559272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                int index = mSetModeDeathHandlers.indexOf(this);
16569272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                if (index < 0) {
16579272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                    Log.w(TAG, "unregistered setMode() client died");
16589272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                } else {
1659d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
16609272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                }
16619272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            }
16629f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
16639f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            // SCO connections not started by the application changing the mode
1664d7454be47f4111c0478a502353e11dea401378bdEric Laurent            if (newModeOwnerPid != 0) {
16656b5e22d52c69cb6d80ff09bd32395b0034ada343Eric Laurent                final long ident = Binder.clearCallingIdentity();
16666b5e22d52c69cb6d80ff09bd32395b0034ada343Eric Laurent                disconnectBluetoothSco(newModeOwnerPid);
16676b5e22d52c69cb6d80ff09bd32395b0034ada343Eric Laurent                Binder.restoreCallingIdentity(ident);
16689f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
16699272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
16709272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
1671f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        public int getPid() {
1672f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen            return mPid;
1673f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        }
1674f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen
16759272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public void setMode(int mode) {
16769272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            mMode = mode;
16779272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
16789272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
16799272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public int getMode() {
16809272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            return mMode;
16819272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
16829272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
16839272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public IBinder getBinder() {
16849272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            return mCb;
16859272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
16869272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    }
16879272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
16889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setMode(int) */
16899272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    public void setMode(int mode, IBinder cb) {
16909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!checkAudioSettingsPermission("setMode()")) {
16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
16929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1693a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
16948f677d66d9c3ba34c97e69b2bb9e161f129af0eeJean-Michel Trivi        if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
1695a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            return;
1696a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        }
1697a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
1698d7454be47f4111c0478a502353e11dea401378bdEric Laurent        int newModeOwnerPid = 0;
16999f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        synchronized(mSetModeDeathHandlers) {
1700a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            if (mode == AudioSystem.MODE_CURRENT) {
1701a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                mode = mMode;
1702a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
1703d7454be47f4111c0478a502353e11dea401378bdEric Laurent            newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
17049f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
17059f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
17069f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        // SCO connections not started by the application changing the mode
1707d7454be47f4111c0478a502353e11dea401378bdEric Laurent        if (newModeOwnerPid != 0) {
1708d7454be47f4111c0478a502353e11dea401378bdEric Laurent             disconnectBluetoothSco(newModeOwnerPid);
17099f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
17109f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    }
17112ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi
17129f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    // must be called synchronized on mSetModeDeathHandlers
1713d7454be47f4111c0478a502353e11dea401378bdEric Laurent    // setModeInt() returns a valid PID if the audio mode was successfully set to
17149f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    // any mode other than NORMAL.
1715d7454be47f4111c0478a502353e11dea401378bdEric Laurent    int setModeInt(int mode, IBinder cb, int pid) {
1716d7454be47f4111c0478a502353e11dea401378bdEric Laurent        int newModeOwnerPid = 0;
17179f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        if (cb == null) {
17189f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            Log.e(TAG, "setModeInt() called with null binder");
1719d7454be47f4111c0478a502353e11dea401378bdEric Laurent            return newModeOwnerPid;
17209f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
17212ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi
17229f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        SetModeDeathHandler hdlr = null;
17239f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        Iterator iter = mSetModeDeathHandlers.iterator();
17249f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        while (iter.hasNext()) {
17259f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
17269f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (h.getPid() == pid) {
17279f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr = h;
17289f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Remove from client list so that it is re-inserted at top of list
17299f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                iter.remove();
17309f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr.getBinder().unlinkToDeath(hdlr, 0);
17319f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                break;
17329f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
17339f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
17349f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        int status = AudioSystem.AUDIO_STATUS_OK;
17359f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        do {
17369f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode == AudioSystem.MODE_NORMAL) {
17379f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // get new mode from client at top the list if any
17389f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (!mSetModeDeathHandlers.isEmpty()) {
17399f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    hdlr = mSetModeDeathHandlers.get(0);
17409f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    cb = hdlr.getBinder();
17419f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mode = hdlr.getMode();
17429f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
17439f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            } else {
17449f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (hdlr == null) {
17459f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    hdlr = new SetModeDeathHandler(cb, pid);
17469f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
17479f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Register for client death notification
17489f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                try {
17499f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    cb.linkToDeath(hdlr, 0);
17509f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                } catch (RemoteException e) {
17519f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    // Client has died!
17529f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    Log.w(TAG, "setMode() could not link to "+cb+" binder death");
17539f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
17549272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
17559f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Last client to call setMode() is always at top of client list
17569f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // as required by SetModeDeathHandler.binderDied()
17579f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                mSetModeDeathHandlers.add(0, hdlr);
17589f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr.setMode(mode);
17599f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
17603def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
17619f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode != mMode) {
17629f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                status = AudioSystem.setPhoneState(mode);
17639f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (status == AudioSystem.AUDIO_STATUS_OK) {
17649f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mMode = mode;
17659f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                } else {
17669f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    if (hdlr != null) {
17679f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        mSetModeDeathHandlers.remove(hdlr);
17689f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        cb.unlinkToDeath(hdlr, 0);
17693def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
17709f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    // force reading new top of mSetModeDeathHandlers stack
17719f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mode = AudioSystem.MODE_NORMAL;
1772b9c9d260f21b321527c4622a123af9767630d94dEric Laurent                }
17739f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            } else {
17749f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                status = AudioSystem.AUDIO_STATUS_OK;
17759f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
17769f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
17779f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent
17789f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        if (status == AudioSystem.AUDIO_STATUS_OK) {
17799f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode != AudioSystem.MODE_NORMAL) {
1780d7454be47f4111c0478a502353e11dea401378bdEric Laurent                if (mSetModeDeathHandlers.isEmpty()) {
1781d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
1782d7454be47f4111c0478a502353e11dea401378bdEric Laurent                } else {
1783d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
1784d7454be47f4111c0478a502353e11dea401378bdEric Laurent                }
17859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
17873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            if (streamType == STREAM_REMOTE_MUSIC) {
17883114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                // here handle remote media playback the same way as local playback
17893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                streamType = AudioManager.STREAM_MUSIC;
17903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
17919bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            int device = getDeviceForStream(streamType);
179242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
179342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
17946d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
17956d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            updateStreamVolumeAlias(true /*updateVolumes*/);
17969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1797d7454be47f4111c0478a502353e11dea401378bdEric Laurent        return newModeOwnerPid;
17989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getMode() */
18019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getMode() {
18029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mMode;
18039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1805e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    //==========================================================================================
1806e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    // Sound Effects
1807e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    //==========================================================================================
1808e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1809e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String TAG_AUDIO_ASSETS = "audio_assets";
1810e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ATTR_VERSION = "version";
1811e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String TAG_GROUP = "group";
1812e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ATTR_GROUP_NAME = "name";
1813e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String TAG_ASSET = "asset";
1814e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ATTR_ASSET_ID = "id";
1815e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ATTR_ASSET_FILE = "file";
1816e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1817e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ASSET_FILE_VERSION = "1.0";
1818e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
1819e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1820167d1a27713ab64cd3c0aa70de96434083ef0400Glenn Kasten    private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
18215d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
18225d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent    class LoadSoundEffectReply {
18235d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        public int mStatus = 1;
18245d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent    };
18255d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
1826e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private void loadTouchSoundAssetDefaults() {
1827e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
1828e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
1829e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            SOUND_EFFECT_FILES_MAP[i][0] = 0;
1830e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            SOUND_EFFECT_FILES_MAP[i][1] = -1;
1831e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        }
1832e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    }
1833e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1834e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private void loadTouchSoundAssets() {
1835e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        XmlResourceParser parser = null;
1836e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
18375d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        // only load assets once.
18385d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        if (!SOUND_EFFECT_FILES.isEmpty()) {
18395d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            return;
18405d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        }
18415d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
1842e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        loadTouchSoundAssetDefaults();
1843e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1844e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        try {
1845e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
1846e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1847e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
1848e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            String version = parser.getAttributeValue(null, ATTR_VERSION);
1849e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            boolean inTouchSoundsGroup = false;
1850e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1851e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            if (ASSET_FILE_VERSION.equals(version)) {
1852e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                while (true) {
1853e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    XmlUtils.nextElement(parser);
1854e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    String element = parser.getName();
1855e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    if (element == null) {
1856e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        break;
1857e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    }
1858e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    if (element.equals(TAG_GROUP)) {
1859e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
1860e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        if (GROUP_TOUCH_SOUNDS.equals(name)) {
1861e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            inTouchSoundsGroup = true;
1862e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            break;
1863e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        }
1864e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    }
1865e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                }
1866e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                while (inTouchSoundsGroup) {
1867e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    XmlUtils.nextElement(parser);
1868e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    String element = parser.getName();
1869e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    if (element == null) {
1870e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        break;
1871e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    }
1872e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    if (element.equals(TAG_ASSET)) {
1873e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
1874e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
1875e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        int fx;
1876e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1877e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        try {
1878e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            Field field = AudioManager.class.getField(id);
1879e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            fx = field.getInt(null);
1880e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        } catch (Exception e) {
1881e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            Log.w(TAG, "Invalid touch sound ID: "+id);
1882e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            continue;
1883e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        }
1884e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1885e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        int i = SOUND_EFFECT_FILES.indexOf(file);
1886e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        if (i == -1) {
1887e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            i = SOUND_EFFECT_FILES.size();
1888e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            SOUND_EFFECT_FILES.add(file);
1889e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        }
1890e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        SOUND_EFFECT_FILES_MAP[fx][0] = i;
1891e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    } else {
1892e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        break;
1893e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    }
1894e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                }
1895e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            }
1896e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        } catch (Resources.NotFoundException e) {
1897e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            Log.w(TAG, "audio assets file not found", e);
1898e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        } catch (XmlPullParserException e) {
1899e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            Log.w(TAG, "XML parser exception reading touch sound assets", e);
1900e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        } catch (IOException e) {
1901e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            Log.w(TAG, "I/O exception reading touch sound assets", e);
1902e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        } finally {
1903e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            if (parser != null) {
1904e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                parser.close();
1905e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            }
1906e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        }
1907e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    }
1908e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
19099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#playSoundEffect(int) */
19109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void playSoundEffect(int effectType) {
19115d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        playSoundEffectVolume(effectType, -1.0f);
19129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#playSoundEffect(int, float) */
19159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void playSoundEffectVolume(int effectType, float volume) {
1916559c76dbc37ff25b204ed1f060d3ec2fa43d718cNatalie Silvanovich        if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
1917559c76dbc37ff25b204ed1f060d3ec2fa43d718cNatalie Silvanovich            Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
1918559c76dbc37ff25b204ed1f060d3ec2fa43d718cNatalie Silvanovich            return;
1919559c76dbc37ff25b204ed1f060d3ec2fa43d718cNatalie Silvanovich        }
1920559c76dbc37ff25b204ed1f060d3ec2fa43d718cNatalie Silvanovich
19215d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
19229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                effectType, (int) (volume * 1000), null, 0);
19239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
19269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Loads samples into the soundpool.
19275c17a820f9e46e0756c11795b3e6f89105f2f539Glenn Kasten     * This method must be called at first when sound effects are enabled
19289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
19299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean loadSoundEffects() {
19305d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        int attempts = 3;
19315d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        LoadSoundEffectReply reply = new LoadSoundEffectReply();
1932117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent
19335d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        synchronized (reply) {
19345d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
19355d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            while ((reply.mStatus == 1) && (attempts-- > 0)) {
1936117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                try {
1937167d1a27713ab64cd3c0aa70de96434083ef0400Glenn Kasten                    reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
19385d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                } catch (InterruptedException e) {
19395d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
1940117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                }
1941a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
19429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19435d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        return (reply.mStatus == 0);
19449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
19479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  Unloads samples from the sound pool.
19489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  This method can be called to free some memory when
19499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  sound effects are disabled.
19509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
19519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void unloadSoundEffects() {
19525d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
19539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1955a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    class SoundPoolListenerThread extends Thread {
1956a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public SoundPoolListenerThread() {
1957a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            super("SoundPoolListenerThread");
1958a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1959a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1960a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        @Override
1961a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public void run() {
1962a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1963a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            Looper.prepare();
1964a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            mSoundPoolLooper = Looper.myLooper();
1965a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1966a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            synchronized (mSoundEffectsLock) {
1967a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                if (mSoundPool != null) {
1968a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundPoolCallBack = new SoundPoolCallback();
1969a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
1970a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
1971a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundEffectsLock.notify();
1972a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
1973a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            Looper.loop();
1974a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1975a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    }
1976a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1977a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private final class SoundPoolCallback implements
1978a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            android.media.SoundPool.OnLoadCompleteListener {
1979a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
19805d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        int mStatus = 1; // 1 means neither error nor last sample loaded yet
19815d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        List<Integer> mSamples = new ArrayList<Integer>();
1982a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1983a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public int status() {
1984a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            return mStatus;
1985a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1986a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
19875d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        public void setSamples(int[] samples) {
19885d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            for (int i = 0; i < samples.length; i++) {
19895d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                // do not wait ack for samples rejected upfront by SoundPool
19905d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (samples[i] > 0) {
19915d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSamples.add(samples[i]);
19925d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
19935d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            }
1994a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1995a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1996a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
1997a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            synchronized (mSoundEffectsLock) {
19985d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int i = mSamples.indexOf(sampleId);
19995d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (i >= 0) {
20005d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSamples.remove(i);
2001a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
20025d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if ((status != 0) || mSamples. isEmpty()) {
20035d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mStatus = status;
2004a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundEffectsLock.notify();
2005a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
2006a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
2007a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
2008a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    }
2009a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
20104050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    /** @see AudioManager#reloadAudioSettings() */
20114050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    public void reloadAudioSettings() {
2012bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent        readAudioSettings(false /*userSwitch*/);
2013bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent    }
2014bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent
2015bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent    private void readAudioSettings(boolean userSwitch) {
20164050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
20174050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        readPersistedSettings();
20184050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
20194050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        // restore volume settings
20204050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        int numStreamTypes = AudioSystem.getNumStreamTypes();
20214050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
20224050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent            VolumeStreamState streamState = mStreamStates[streamType];
20234050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
2024bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent            if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2025bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                continue;
2026bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent            }
2027bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent
20283172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            synchronized (streamState) {
20293172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                streamState.readSettings();
2030a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
20313172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                // unmute stream that was muted but is not affect by mute anymore
203242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                if (streamState.isMuted() && ((!isStreamAffectedByMute(streamType) &&
203383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                        !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
20343172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    int size = streamState.mDeathHandlers.size();
20353172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    for (int i = 0; i < size; i++) {
20363172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        streamState.mDeathHandlers.get(i).mMuteCount = 1;
20373172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        streamState.mDeathHandlers.get(i).mute(false);
20383172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    }
20393172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                }
20404050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent            }
20414050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        }
20424050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
204333902db75011d863009585682bd08560c5b89a75Eric Laurent        // apply new ringer mode before checking volume for alias streams so that streams
204433902db75011d863009585682bd08560c5b89a75Eric Laurent        // muted by ringer mode have the correct volume
204533902db75011d863009585682bd08560c5b89a75Eric Laurent        setRingerModeInt(getRingerMode(), false);
204633902db75011d863009585682bd08560c5b89a75Eric Laurent
2047244820185269991186d07068b92985624cede4a5Eric Laurent        checkAllAliasStreamVolumes();
2048244820185269991186d07068b92985624cede4a5Eric Laurent
2049d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
2050d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
2051f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                enforceSafeMediaVolume();
2052f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent            }
2053c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
20544050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    }
20554050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
2056961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#setSpeakerphoneOn(boolean) */
2057c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public void setSpeakerphoneOn(boolean on){
2058dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2059dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent            return;
2060dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        }
20617337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson
20627337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        if (on) {
20637337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
20647337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson                    sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
20657337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson                            AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
20667337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            }
20677337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
20687337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
20697337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            mForcedUseForComm = AudioSystem.FORCE_NONE;
20707337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        }
2071fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
2072afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2073fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
2074c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
2075c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
2076c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    /** @see AudioManager#isSpeakerphoneOn() */
2077c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public boolean isSpeakerphoneOn() {
2078fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
2079c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
2080c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
2081961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#setBluetoothScoOn(boolean) */
2082c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public void setBluetoothScoOn(boolean on){
2083dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2084dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent            return;
2085dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        }
20867337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson
20877337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        if (on) {
20887337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
20897337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
20907337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            mForcedUseForComm = AudioSystem.FORCE_NONE;
20917337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        }
2092fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
2093afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2094fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
2095afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2096fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
2097c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
2098c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
2099c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    /** @see AudioManager#isBluetoothScoOn() */
2100c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public boolean isBluetoothScoOn() {
2101fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
2102c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
2103c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
2104961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#setBluetoothA2dpOn(boolean) */
21057847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public void setBluetoothA2dpOn(boolean on) {
2106c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent        synchronized (mBluetoothA2dpEnabledLock) {
2107c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            mBluetoothA2dpEnabled = on;
2108c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2109c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    AudioSystem.FOR_MEDIA,
2110c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2111c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    null, 0);
2112c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent        }
21137847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
21147847211fb4699bf6018e29d214a918ed6657319bEric Laurent
21157847211fb4699bf6018e29d214a918ed6657319bEric Laurent    /** @see AudioManager#isBluetoothA2dpOn() */
21167847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public boolean isBluetoothA2dpOn() {
21177847211fb4699bf6018e29d214a918ed6657319bEric Laurent        synchronized (mBluetoothA2dpEnabledLock) {
21187847211fb4699bf6018e29d214a918ed6657319bEric Laurent            return mBluetoothA2dpEnabled;
21197847211fb4699bf6018e29d214a918ed6657319bEric Laurent        }
21207847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
21217847211fb4699bf6018e29d214a918ed6657319bEric Laurent
21223def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    /** @see AudioManager#startBluetoothSco() */
212383900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
212483900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        int scoAudioMode =
212583900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent                (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
2126f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                        SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
212783900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        startBluetoothScoInt(cb, scoAudioMode);
212883900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    }
212983900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent
213083900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    /** @see AudioManager#startBluetoothScoVirtualCall() */
213183900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    public void startBluetoothScoVirtualCall(IBinder cb) {
213283900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
213383900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    }
213483900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent
213583900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    void startBluetoothScoInt(IBinder cb, int scoAudioMode){
2136dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (!checkAudioSettingsPermission("startBluetoothSco()") ||
21374a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                !mSystemReady) {
21383def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return;
21393def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
2140854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        ScoClient client = getScoClient(cb, true);
2141f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // The calling identity must be cleared before calling ScoClient.incCount().
2142f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2143f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // and this must be done on behalf of system server to make sure permissions are granted.
2144f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // The caller identity must be cleared after getScoClient() because it is needed if a new
2145f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // client is created.
2146f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        final long ident = Binder.clearCallingIdentity();
214783900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        client.incCount(scoAudioMode);
21482a57ca931fefe817b6110101289721acaacfc808Eric Laurent        Binder.restoreCallingIdentity(ident);
21493def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
21503def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
21513def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    /** @see AudioManager#stopBluetoothSco() */
21523def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    public void stopBluetoothSco(IBinder cb){
2153dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
21544a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                !mSystemReady) {
21553def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return;
21563def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
2157854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        ScoClient client = getScoClient(cb, false);
2158f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // The calling identity must be cleared before calling ScoClient.decCount().
2159f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2160f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // and this must be done on behalf of system server to make sure permissions are granted.
2161f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        final long ident = Binder.clearCallingIdentity();
2162854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        if (client != null) {
2163854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            client.decCount();
2164854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        }
21652a57ca931fefe817b6110101289721acaacfc808Eric Laurent        Binder.restoreCallingIdentity(ident);
21663def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
21673def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
21687847211fb4699bf6018e29d214a918ed6657319bEric Laurent
21693def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    private class ScoClient implements IBinder.DeathRecipient {
21703def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        private IBinder mCb; // To be notified of client's death
2171f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        private int mCreatorPid;
21723def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        private int mStartcount; // number of SCO connections started by this client
21733def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
21743def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        ScoClient(IBinder cb) {
21753def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            mCb = cb;
2176f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen            mCreatorPid = Binder.getCallingPid();
21773def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            mStartcount = 0;
21783def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
21793def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
21803def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void binderDied() {
21813def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
21823def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                Log.w(TAG, "SCO client died");
21833def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int index = mScoClients.indexOf(this);
21843def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (index < 0) {
21853def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    Log.w(TAG, "unregistered SCO client died");
21863def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                } else {
21873def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    clearCount(true);
21883def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    mScoClients.remove(this);
21893def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
21903def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
21913def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
21923def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
219383900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        public void incCount(int scoAudioMode) {
21943def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
219583900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent                requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
21963def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (mStartcount == 0) {
21973def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    try {
21983def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        mCb.linkToDeath(this, 0);
21993def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    } catch (RemoteException e) {
22003def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        // client has already died!
22013def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        Log.w(TAG, "ScoClient  incCount() could not link to "+mCb+" binder death");
22023def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
22033def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
22043def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                mStartcount++;
22053def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
22063def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
22073def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
22083def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void decCount() {
22093def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
22103def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (mStartcount == 0) {
22113def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    Log.w(TAG, "ScoClient.decCount() already 0");
22123def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                } else {
22133def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    mStartcount--;
22143def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    if (mStartcount == 0) {
2215e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        try {
2216e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                            mCb.unlinkToDeath(this, 0);
2217e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        } catch (NoSuchElementException e) {
2218e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                            Log.w(TAG, "decCount() going to 0 but not registered to binder");
2219e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        }
22203def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
2221c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
22223def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
22233def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
22243def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
22253def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
22263def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void clearCount(boolean stopSco) {
22273def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
2228e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                if (mStartcount != 0) {
2229e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    try {
2230e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        mCb.unlinkToDeath(this, 0);
2231e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    } catch (NoSuchElementException e) {
2232e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2233e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    }
2234e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                }
22353def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                mStartcount = 0;
22363def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (stopSco) {
2237c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
22383def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
22393def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
22403def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
22413def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
22423def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public int getCount() {
22433def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return mStartcount;
22443def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
22453def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
22463def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public IBinder getBinder() {
22473def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return mCb;
22483def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
22493def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
2250d7454be47f4111c0478a502353e11dea401378bdEric Laurent        public int getPid() {
2251d7454be47f4111c0478a502353e11dea401378bdEric Laurent            return mCreatorPid;
2252d7454be47f4111c0478a502353e11dea401378bdEric Laurent        }
2253d7454be47f4111c0478a502353e11dea401378bdEric Laurent
22543def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public int totalCount() {
22553def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
22563def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int count = 0;
22573def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int size = mScoClients.size();
22583def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                for (int i = 0; i < size; i++) {
22593def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    count += mScoClients.get(i).getCount();
22603def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
22613def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                return count;
22623def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
22633def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
22643def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
226583900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        private void requestScoState(int state, int scoAudioMode) {
226662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent            checkScoAudioState();
2267dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            if (totalCount() == 0) {
2268dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2269dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // Make sure that the state transitions to CONNECTING even if we cannot initiate
2270dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // the connection.
2271dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2272dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // Accept SCO audio activation only in NORMAL audio mode or if the mode is
2273f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen                    // currently controlled by the same client process.
22749f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    synchronized(mSetModeDeathHandlers) {
22759f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        if ((mSetModeDeathHandlers.isEmpty() ||
22769f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
22779f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                (mScoAudioState == SCO_STATE_INACTIVE ||
22789f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
22799f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            if (mScoAudioState == SCO_STATE_INACTIVE) {
228083900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent                                mScoAudioMode = scoAudioMode;
2281f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                if (scoAudioMode == SCO_MODE_UNDEFINED) {
2282f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                    mScoAudioMode = new Integer(Settings.Global.getInt(
2283f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                                            mContentResolver,
2284f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                                            "bluetooth_sco_channel_"+
2285f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                                            mBluetoothHeadsetDevice.getAddress(),
2286f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                                            SCO_MODE_VIRTUAL_CALL));
2287f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                    if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2288f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                        mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2289f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                    }
2290f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                }
22919f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
2292f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                    boolean status = false;
2293c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    if (mScoAudioMode == SCO_MODE_RAW) {
2294c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                        status = mBluetoothHeadset.connectAudio();
2295f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                    } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
2296c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                        status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2297c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                                            mBluetoothHeadsetDevice);
2298f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                    } else if (mScoAudioMode == SCO_MODE_VR) {
2299f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                        status = mBluetoothHeadset.startVoiceRecognition(
2300f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                                                           mBluetoothHeadsetDevice);
2301c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    }
2302f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao
2303c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    if (status) {
23049f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                        mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
23059f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    } else {
23069f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                        broadcastScoConnectionState(
23079f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
23089f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    }
23099f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                } else if (getBluetoothHeadset()) {
23109f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    mScoAudioState = SCO_STATE_ACTIVATE_REQ;
2311dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                }
23129f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            } else {
23139f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
23149f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
2315dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            }
2316dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        } else {
23179f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2318dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
2319dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
232062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
2321dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                              (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2322dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                               mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2323dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
2324671db6f3ba1fdb3c907e0735fe6d0d284f5c34deMarco Nelissen                        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
2325f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                            boolean status = false;
2326c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                            if (mScoAudioMode == SCO_MODE_RAW) {
2327c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                status = mBluetoothHeadset.disconnectAudio();
2328f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                            } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
2329c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2330c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                                        mBluetoothHeadsetDevice);
2331f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                            } else if (mScoAudioMode == SCO_MODE_VR) {
2332f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                        status = mBluetoothHeadset.stopVoiceRecognition(
2333f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                                                      mBluetoothHeadsetDevice);
2334c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                            }
2335f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao
2336c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                            if (!status) {
2337dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                mScoAudioState = SCO_STATE_INACTIVE;
2338dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                broadcastScoConnectionState(
2339dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2340dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            }
2341dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        } else if (getBluetoothHeadset()) {
2342dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2343dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
2344dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    } else {
2345dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        mScoAudioState = SCO_STATE_INACTIVE;
2346dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2347dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
23483def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
23493def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
23503def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
23513def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
23523def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
235362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private void checkScoAudioState() {
235462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
2355dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                mScoAudioState == SCO_STATE_INACTIVE &&
235662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
235762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
235862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
235962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent        }
236062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    }
236162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent
2362854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent    private ScoClient getScoClient(IBinder cb, boolean create) {
23633def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        synchronized(mScoClients) {
2364854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            ScoClient client = null;
23653def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            int size = mScoClients.size();
23663def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            for (int i = 0; i < size; i++) {
23673def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                client = mScoClients.get(i);
23683def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (client.getBinder() == cb)
23693def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    return client;
23703def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
2371854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            if (create) {
2372854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                client = new ScoClient(cb);
2373854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                mScoClients.add(client);
2374854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            }
23753def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return client;
23763def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
23773def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
23783def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
2379d7454be47f4111c0478a502353e11dea401378bdEric Laurent    public void clearAllScoClients(int exceptPid, boolean stopSco) {
23803def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        synchronized(mScoClients) {
2381854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            ScoClient savedClient = null;
23823def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            int size = mScoClients.size();
23833def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            for (int i = 0; i < size; i++) {
2384854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                ScoClient cl = mScoClients.get(i);
2385d7454be47f4111c0478a502353e11dea401378bdEric Laurent                if (cl.getPid() != exceptPid) {
2386854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                    cl.clearCount(stopSco);
2387854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                } else {
2388854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                    savedClient = cl;
2389854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                }
2390854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            }
2391854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            mScoClients.clear();
2392854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            if (savedClient != null) {
2393854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                mScoClients.add(savedClient);
23943def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
23953def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
23963def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
23973def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
2398dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private boolean getBluetoothHeadset() {
2399dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        boolean result = false;
2400dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2401dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (adapter != null) {
2402dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2403dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                    BluetoothProfile.HEADSET);
2404dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
2405dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // If we could not get a bluetooth headset proxy, send a failure message
2406dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // without delay to reset the SCO audio state and clear SCO clients.
2407dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // If we could get a proxy, send a delayed failure message that will reset our state
2408dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // in case we don't receive onServiceConnected().
2409afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2410dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2411dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        return result;
2412dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
2413dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
2414d7454be47f4111c0478a502353e11dea401378bdEric Laurent    private void disconnectBluetoothSco(int exceptPid) {
2415dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        synchronized(mScoClients) {
2416dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            checkScoAudioState();
2417dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2418dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2419dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                if (mBluetoothHeadsetDevice != null) {
2420dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (mBluetoothHeadset != null) {
2421dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (!mBluetoothHeadset.stopVoiceRecognition(
2422b06ac839dd2d0437fc8314f6deb7233af5af521eEric Laurent                                mBluetoothHeadsetDevice)) {
2423afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2424dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                    SENDMSG_REPLACE, 0, 0, null, 0);
2425dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
2426dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2427dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            getBluetoothHeadset()) {
2428dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2429dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
2430dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                }
2431dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            } else {
2432d7454be47f4111c0478a502353e11dea401378bdEric Laurent                clearAllScoClients(exceptPid, true);
2433dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            }
2434dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
2435dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
2436dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
2437dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private void resetBluetoothSco() {
2438dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        synchronized(mScoClients) {
2439d7454be47f4111c0478a502353e11dea401378bdEric Laurent            clearAllScoClients(0, false);
2440dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            mScoAudioState = SCO_STATE_INACTIVE;
2441dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2442dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
2443dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
2444dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
2445dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private void broadcastScoConnectionState(int state) {
24462a57ca931fefe817b6110101289721acaacfc808Eric Laurent        sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
24472a57ca931fefe817b6110101289721acaacfc808Eric Laurent                SENDMSG_QUEUE, state, 0, null, 0);
24482a57ca931fefe817b6110101289721acaacfc808Eric Laurent    }
24492a57ca931fefe817b6110101289721acaacfc808Eric Laurent
24502a57ca931fefe817b6110101289721acaacfc808Eric Laurent    private void onBroadcastScoConnectionState(int state) {
2451dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (state != mScoConnectionState) {
2452dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2453dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2454dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2455dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    mScoConnectionState);
24565ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            sendStickyBroadcastToAll(newIntent);
2457dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            mScoConnectionState = state;
2458dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
2459dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
2460dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
246182aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
246282aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        new BluetoothProfile.ServiceListener() {
246382aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        public void onServiceConnected(int profile, BluetoothProfile proxy) {
24646bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            BluetoothDevice btDevice;
24656bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            List<BluetoothDevice> deviceList;
24666bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            switch(profile) {
24676bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.A2DP:
24685a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                synchronized (mA2dpAvrcpLock) {
24695a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    mA2dp = (BluetoothA2dp) proxy;
24705a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    deviceList = mA2dp.getConnectedDevices();
24715a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    if (deviceList.size() > 0) {
24725a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        btDevice = deviceList.get(0);
24735a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        synchronized (mConnectedDevices) {
24745a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                            int state = mA2dp.getConnectionState(btDevice);
24755a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                            int delay = checkSendBecomingNoisyIntent(
24760a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
24770a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
24785a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                            queueMsgUnderWakeLock(mAudioHandler,
24790a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                    MSG_SET_A2DP_SINK_CONNECTION_STATE,
24805a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    state,
24815a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    0,
24825a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    btDevice,
24835a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    delay);
24845a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        }
2485b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    }
24866bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
24876bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
24886bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
24890a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            case BluetoothProfile.A2DP_SINK:
24900a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                deviceList = proxy.getConnectedDevices();
24910a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                if (deviceList.size() > 0) {
24920a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    btDevice = deviceList.get(0);
24930a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    synchronized (mConnectedDevices) {
24940a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                        int state = proxy.getConnectionState(btDevice);
24950a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                        queueMsgUnderWakeLock(mAudioHandler,
24960a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                MSG_SET_A2DP_SRC_CONNECTION_STATE,
24970a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                state,
24980a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                0,
24990a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                btDevice,
25000a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                0 /* delay */);
25010a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    }
25020a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                }
25030a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                break;
25040a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
25056bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.HEADSET:
25066bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                synchronized (mScoClients) {
25076bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Discard timeout message
25086bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
25096bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mBluetoothHeadset = (BluetoothHeadset) proxy;
25106bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    deviceList = mBluetoothHeadset.getConnectedDevices();
25116bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (deviceList.size() > 0) {
25126bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        mBluetoothHeadsetDevice = deviceList.get(0);
25136bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    } else {
25146bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        mBluetoothHeadsetDevice = null;
2515dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
25166bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Refresh SCO audio state
25176bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    checkScoAudioState();
25186bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Continue pending action if any
25196bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
25206bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
25216bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
25226bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        boolean status = false;
25236bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        if (mBluetoothHeadsetDevice != null) {
25246bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            switch (mScoAudioState) {
25256bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_ACTIVATE_REQ:
25266bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2527c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                if (mScoAudioMode == SCO_MODE_RAW) {
2528c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    status = mBluetoothHeadset.connectAudio();
2529f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
2530c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2531c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                                        mBluetoothHeadsetDevice);
2532f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                } else if (mScoAudioMode == SCO_MODE_VR) {
2533f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                    status = mBluetoothHeadset.startVoiceRecognition(
2534f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                                                      mBluetoothHeadsetDevice);
2535c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                }
25366bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                break;
25376bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_DEACTIVATE_REQ:
2538c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                if (mScoAudioMode == SCO_MODE_RAW) {
2539c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    status = mBluetoothHeadset.disconnectAudio();
2540f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
2541c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2542c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                                        mBluetoothHeadsetDevice);
2543f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                } else if (mScoAudioMode == SCO_MODE_VR) {
2544f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                    status = mBluetoothHeadset.stopVoiceRecognition(
2545f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                                                      mBluetoothHeadsetDevice);
2546c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                }
25476bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                break;
25486bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_DEACTIVATE_EXT_REQ:
25496bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                status = mBluetoothHeadset.stopVoiceRecognition(
25506bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                        mBluetoothHeadsetDevice);
25516bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            }
25526bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
25536bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        if (!status) {
2554afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
25556bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                    SENDMSG_REPLACE, 0, 0, null, 0);
25566bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
2557dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
2558dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                }
25596bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
25606bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
25616bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            default:
25626bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
25633def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
25643def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
256582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        public void onServiceDisconnected(int profile) {
25666bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            switch(profile) {
25676bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.A2DP:
25685a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                synchronized (mA2dpAvrcpLock) {
25695a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    mA2dp = null;
25705a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    synchronized (mConnectedDevices) {
25715a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
25725a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                            makeA2dpDeviceUnavailableNow(
25735a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
25745a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        }
25756bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
25766bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
25776bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
25786bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
25790a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            case BluetoothProfile.A2DP_SINK:
25800a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                synchronized (mConnectedDevices) {
25810a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    if (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) {
25820a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                        makeA2dpSrcUnavailable(
25830a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP));
25840a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    }
25850a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                }
25860a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                break;
25870a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
25886bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.HEADSET:
25896bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                synchronized (mScoClients) {
25906bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mBluetoothHeadset = null;
25916bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
25926bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
25936bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
25946bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            default:
25956bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
25963def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
25973def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
25983def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    };
2599d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
2600c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private void onCheckMusicActive() {
2601d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
2602d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
2603c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
2604c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
2605c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                if ((device & mSafeMediaVolumeDevices) != 0) {
2606c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    sendMsg(mAudioHandler,
2607c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            MSG_CHECK_MUSIC_ACTIVE,
2608c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            SENDMSG_REPLACE,
2609f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            0,
2610c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            0,
2611c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            null,
2612c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            MUSIC_ACTIVE_POLL_PERIOD_MS);
261342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
2614f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                    if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
2615f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            (index > mSafeMediaVolumeIndex)) {
2616c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                        // Approximate cumulative active music time
2617c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                        mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
2618c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                        if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
2619c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            setSafeMediaVolumeEnabled(true);
2620c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            mMusicActiveMs = 0;
2621c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                        }
2622c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    }
2623c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                }
2624c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
2625c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
2626c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
2627c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
2628d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private void onConfigureSafeVolume(boolean force) {
2629d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
2630d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            int mcc = mContext.getResources().getConfiguration().mcc;
2631d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if ((mMcc != mcc) || ((mMcc == 0) && force)) {
2632d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                mSafeMediaVolumeIndex = mContext.getResources().getInteger(
2633d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                        com.android.internal.R.integer.config_safe_media_volume_index) * 10;
2634d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                boolean safeMediaVolumeEnabled = mContext.getResources().getBoolean(
2635d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                        com.android.internal.R.bool.config_safe_media_volume_enabled);
263605274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent
263705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                // The persisted state is either "disabled" or "active": this is the state applied
263805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                // next time we boot and cannot be "inactive"
263905274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                int persistedState;
2640d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                if (safeMediaVolumeEnabled) {
264105274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
264205274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    // The state can already be "inactive" here if the user has forced it before
264305274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    // the 30 seconds timeout for forced configuration. In this case we don't reset
264405274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    // it to "active".
264505274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
264605274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
264705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        enforceSafeMediaVolume();
264805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    }
2649d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                } else {
265005274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    persistedState = SAFE_MEDIA_VOLUME_DISABLED;
2651d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
2652d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                }
2653d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                mMcc = mcc;
265405274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                sendMsg(mAudioHandler,
265505274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        MSG_PERSIST_SAFE_VOLUME_STATE,
265605274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        SENDMSG_QUEUE,
265705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        persistedState,
265805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        0,
265905274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        null,
266005274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        0);
2661d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            }
2662d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        }
2663d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    }
2664d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent
26659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
26669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Internal methods
26679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
26689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
26709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Checks if the adjustment should change ringer mode instead of just
26719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * adjusting volume. If so, this will set the proper ringer mode and volume
26729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * indices on the stream states.
26739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2674a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock    private int checkForRingerModeChange(int oldIndex, int direction,  int step) {
2675a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock        int result = FLAG_ADJUST_VOLUME;
2676ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        int ringerMode = getRingerMode();
2677bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
2678bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        switch (ringerMode) {
2679bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_NORMAL:
2680bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            if (direction == AudioManager.ADJUST_LOWER) {
2681bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                if (mHasVibrator) {
2682244820185269991186d07068b92985624cede4a5Eric Laurent                    // "step" is the delta in internal index units corresponding to a
2683244820185269991186d07068b92985624cede4a5Eric Laurent                    // change of 1 in UI index units.
2684244820185269991186d07068b92985624cede4a5Eric Laurent                    // Because of rounding when rescaling from one stream index range to its alias
2685244820185269991186d07068b92985624cede4a5Eric Laurent                    // index range, we cannot simply test oldIndex == step:
2686244820185269991186d07068b92985624cede4a5Eric Laurent                    //   (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
2687244820185269991186d07068b92985624cede4a5Eric Laurent                    if (step <= oldIndex && oldIndex < 2 * step) {
2688bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        ringerMode = RINGER_MODE_VIBRATE;
2689bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    }
2690bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                } else {
2691244820185269991186d07068b92985624cede4a5Eric Laurent                    // (oldIndex < step) is equivalent to (old UI index == 0)
26928600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                    if ((oldIndex < step)
26938600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                            && VOLUME_SETS_RINGER_MODE_SILENT
26948600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                            && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
2695bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        ringerMode = RINGER_MODE_SILENT;
2696bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    }
26973d4c06f90726a85e89dab13c41ddc15b9c912a3fEric Laurent                }
26986329bf7b1e2217c6c9477bd57349a1edade18417Daniel Sandler            }
2699bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
2700bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_VIBRATE:
2701bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            if (!mHasVibrator) {
2702bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
2703bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        "but no vibrator is present");
2704bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                break;
2705bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            }
2706c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            if ((direction == AudioManager.ADJUST_LOWER)) {
27078600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                if (VOLUME_SETS_RINGER_MODE_SILENT
27088600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                        && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
2709bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    ringerMode = RINGER_MODE_SILENT;
2710c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani                }
2711c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            } else if (direction == AudioManager.ADJUST_RAISE) {
2712bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                ringerMode = RINGER_MODE_NORMAL;
2713c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            }
2714a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            result &= ~FLAG_ADJUST_VOLUME;
2715bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
2716bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_SILENT:
27179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (direction == AudioManager.ADJUST_RAISE) {
2718a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                if (PREVENT_VOLUME_ADJUSTMENT_IF_SILENT) {
2719a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                    result |= AudioManager.FLAG_SHOW_SILENT_HINT;
2720bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                } else {
2721a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                  if (mHasVibrator) {
2722a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                      ringerMode = RINGER_MODE_VIBRATE;
2723a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                  } else {
2724a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                      ringerMode = RINGER_MODE_NORMAL;
2725a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                  }
2726bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                }
27279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2728a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            result &= ~FLAG_ADJUST_VOLUME;
2729bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
2730bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        default:
2731bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
2732bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
27339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2735bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        setRingerMode(ringerMode);
27369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
273725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        mPrevVolDirection = direction;
273825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
2739a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock        return result;
27409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
27419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27423346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    @Override
27439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isStreamAffectedByRingerMode(int streamType) {
27449bcf401d13d47416043a704430388abd59aef7cdEric Laurent        return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
27459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
27469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27475b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    private boolean isStreamMutedByRingerMode(int streamType) {
27485b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        return (mRingerModeMutedStreams & (1 << streamType)) != 0;
27495b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    }
27505b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
275124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent    boolean updateRingerModeAffectedStreams() {
275224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        int ringerModeAffectedStreams;
275324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // make sure settings for ringer mode are consistent with device type: non voice capable
275424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // devices (tablets) include media stream in silent mode whereas phones don't.
275524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
275624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                Settings.System.MODE_RINGER_STREAMS_AFFECTED,
275724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
275824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
275924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                 UserHandle.USER_CURRENT);
276024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent
276124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // ringtone, notification and system streams are always affected by ringer mode
276224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
276324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                                        (1 << AudioSystem.STREAM_NOTIFICATION)|
276424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                                        (1 << AudioSystem.STREAM_SYSTEM);
276524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent
276624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        if (mVoiceCapable) {
276724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
276824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        } else {
276924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
277024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        }
277124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        synchronized (mCameraSoundForced) {
277224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            if (mCameraSoundForced) {
277324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
277424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            } else {
277524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
277624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            }
277724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        }
277824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
277924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
278024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        } else {
278124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
278224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        }
278324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent
278424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
278524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            Settings.System.putIntForUser(mContentResolver,
278624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                    Settings.System.MODE_RINGER_STREAMS_AFFECTED,
278724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                    ringerModeAffectedStreams,
278824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                    UserHandle.USER_CURRENT);
278924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            mRingerModeAffectedStreams = ringerModeAffectedStreams;
279024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            return true;
279124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        }
279224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        return false;
279324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent    }
279424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent
27959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isStreamAffectedByMute(int streamType) {
27969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mMuteAffectedStreams & (1 << streamType)) != 0;
27979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
27989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void ensureValidDirection(int direction) {
28009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
28019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("Bad direction " + direction);
28029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
28039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
28049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28056c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    private void ensureValidSteps(int steps) {
28066c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
28076c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            throw new IllegalArgumentException("Bad volume adjust steps " + steps);
28086c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        }
28096c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    }
28106c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang
28119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void ensureValidStreamType(int streamType) {
28129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (streamType < 0 || streamType >= mStreamStates.length) {
28139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("Bad stream type " + streamType);
28149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
28159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
28169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28176d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private boolean isInCommunication() {
28189eb45934c582a0bf5060125690de8bce4f10ca76Santos Cordon        boolean isInAPhoneCall = false;
281925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
28209eb45934c582a0bf5060125690de8bce4f10ca76Santos Cordon        TelecommManager telecommManager =
28219eb45934c582a0bf5060125690de8bce4f10ca76Santos Cordon                (TelecommManager) mContext.getSystemService(Context.TELECOMM_SERVICE);
28229eb45934c582a0bf5060125690de8bce4f10ca76Santos Cordon        isInAPhoneCall = telecommManager.isInAPhoneCall();
28239eb45934c582a0bf5060125690de8bce4f10ca76Santos Cordon
28249eb45934c582a0bf5060125690de8bce4f10ca76Santos Cordon        return (isInAPhoneCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
28256d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    }
282625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
2827fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    /**
2828fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     * For code clarity for getActiveStreamType(int)
2829fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     * @param delay_ms max time since last STREAM_MUSIC activity to consider
2830fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
2831fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     *     in the last "delay_ms" ms.
2832fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     */
2833fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    private boolean isAfMusicActiveRecently(int delay_ms) {
2834fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
2835fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
2836fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    }
2837fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi
28386d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private int getActiveStreamType(int suggestedStreamType) {
28396d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (mVoiceCapable) {
28406d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            if (isInCommunication()) {
284125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
284225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                        == AudioSystem.FORCE_BT_SCO) {
284325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
284425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_BLUETOOTH_SCO;
284525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                } else {
284625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
284725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_VOICE_CALL;
284825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                }
28493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
2850fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
28513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL)
28523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
28533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return AudioSystem.STREAM_MUSIC;
2854fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                } else
2855fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC))
2856fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    {
2857fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        if (DEBUG_VOL)
2858fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
2859fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        return STREAM_REMOTE_MUSIC;
2860fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    } else {
2861fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        if (DEBUG_VOL)
2862fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
2863fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        return AudioSystem.STREAM_RING;
28643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
2865fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            } else if (isAfMusicActiveRecently(0)) {
28663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL)
28673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
286825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return AudioSystem.STREAM_MUSIC;
2869c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato            } else {
28703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
28713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        + suggestedStreamType);
287225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return suggestedStreamType;
287325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            }
287425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        } else {
28756d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            if (isInCommunication()) {
287625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
287725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                        == AudioSystem.FORCE_BT_SCO) {
28783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
287925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_BLUETOOTH_SCO;
288025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                } else {
28813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL)  Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
288225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_VOICE_CALL;
288325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                }
288425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
28859903e2638a6c502d96413680d3ebae4fb77fc412Eric Laurent                    DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS) ||
28863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
28879903e2638a6c502d96413680d3ebae4fb77fc412Eric Laurent                            DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
28883114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
288925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return AudioSystem.STREAM_NOTIFICATION;
28903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
2891fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
2892fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
2893fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    return AudioSystem.STREAM_MUSIC;
2894fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                } else
2895fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC))
2896fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    {
2897fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        if (DEBUG_VOL)
2898fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
2899fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        return STREAM_REMOTE_MUSIC;
29003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                } else {
2901eb1d88ddf9a0888455c82b83f19da124e5ca6f16John Spurlock                    if (DEBUG_VOL) Log.v(TAG,
2902eb1d88ddf9a0888455c82b83f19da124e5ca6f16John Spurlock                            "getActiveStreamType: using STREAM_NOTIFICATION as default");
2903eb1d88ddf9a0888455c82b83f19da124e5ca6f16John Spurlock                    return AudioSystem.STREAM_NOTIFICATION;
29043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
290525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            } else {
29063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
29073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        + suggestedStreamType);
290825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return suggestedStreamType;
2909c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato            }
29109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
29119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
29129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2913ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    private void broadcastRingerMode(int ringerMode) {
29149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Send sticky broadcast
29151c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn        Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION);
2916ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
29171c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn        broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
29181c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
29195ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        sendStickyBroadcastToAll(broadcast);
29209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
29219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void broadcastVibrateSetting(int vibrateType) {
29239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Send broadcast
29249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (ActivityManagerNative.isSystemReady()) {
29259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
29269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
29279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
29285ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            sendBroadcastToAll(broadcast);
29299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
29309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
29319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Message helper methods
29332d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    /**
29342d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     * Queue a message on the given handler's message queue, after acquiring the service wake lock.
29352d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     * Note that the wake lock needs to be released after the message has been handled.
29362d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     */
29372d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    private void queueMsgUnderWakeLock(Handler handler, int msg,
29382d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            int arg1, int arg2, Object obj, int delay) {
2939a4dfbdc54d8898491d3a7d1d9d818c7db3fd773dEric Laurent        final long ident = Binder.clearCallingIdentity();
2940a4dfbdc54d8898491d3a7d1d9d818c7db3fd773dEric Laurent        // Always acquire the wake lock as AudioService because it is released by the
2941a4dfbdc54d8898491d3a7d1d9d818c7db3fd773dEric Laurent        // message handler.
2942fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mAudioEventWakeLock.acquire();
2943a4dfbdc54d8898491d3a7d1d9d818c7db3fd773dEric Laurent        Binder.restoreCallingIdentity(ident);
29442d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi        sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
29452d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    }
29469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2947afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent    private static void sendMsg(Handler handler, int msg,
29489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
29499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (existingMsgPolicy == SENDMSG_REPLACE) {
29519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handler.removeMessages(msg);
29529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
29539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
29549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
29559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2956afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
29579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
29589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean checkAudioSettingsPermission(String method) {
29609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS")
29619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                == PackageManager.PERMISSION_GRANTED) {
29629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
29639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
29649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String msg = "Audio Settings Permission Denial: " + method + " from pid="
29659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + Binder.getCallingPid()
29669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + ", uid=" + Binder.getCallingUid();
29679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.w(TAG, msg);
29689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
29699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
29709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29719bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    private int getDeviceForStream(int stream) {
29729bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = AudioSystem.getDevicesForStream(stream);
29739bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        if ((device & (device - 1)) != 0) {
29749bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Multiple device selection is either:
29759bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            //  - speaker + one other device: give priority to speaker in this case.
29769bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            //  - one A2DP device + another device: happens with duplicated output. In this case
29779bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // retain the device on the A2DP output as the other must not correspond to an active
29789bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // selection if not the speaker.
29799bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
29809bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                device = AudioSystem.DEVICE_OUT_SPEAKER;
29819bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            } else {
29829bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
29839bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
29849bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
29859bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        return device;
29869bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    }
29879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2988b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    public void setWiredDeviceConnectionState(int device, int state, String name) {
2989b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
2990b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            int delay = checkSendBecomingNoisyIntent(device, state);
29912d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            queueMsgUnderWakeLock(mAudioHandler,
2992b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
2993b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    device,
2994b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    state,
2995b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    name,
2996b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    delay);
2997b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
2998b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
2999b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
30000a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
3001b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
3002b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        int delay;
30030a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
30040a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            throw new IllegalArgumentException("invalid profile " + profile);
30050a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
3006b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
30070a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            if (profile == BluetoothProfile.A2DP) {
30080a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
30090a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
30100a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            } else {
30110a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                delay = 0;
30120a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            }
30132d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            queueMsgUnderWakeLock(mAudioHandler,
30140a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    (profile == BluetoothProfile.A2DP ?
30150a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                        MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
3016b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    state,
3017b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    0,
3018b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    device,
3019b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    delay);
3020b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
3021b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        return delay;
3022b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
3023b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
30249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
30259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Inner classes
30269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
30279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public class VolumeStreamState {
30299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final int mStreamType;
30309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
303111a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi        private String mVolumeIndexSettingName;
3032a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        private int mIndexMax;
30333172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        private final ConcurrentHashMap<Integer, Integer> mIndex =
30343172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                            new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
30359bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
30369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3037a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        private VolumeStreamState(String settingName, int streamType) {
30389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30399bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            mVolumeIndexSettingName = settingName;
30409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStreamType = streamType;
30425982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles            mIndexMax = MAX_STREAM_VOLUME[streamType];
3043a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
3044a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            mIndexMax *= 10;
30459bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
304633902db75011d863009585682bd08560c5b89a75Eric Laurent            // mDeathHandlers must be created before calling readSettings()
30479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDeathHandlers = new ArrayList<VolumeDeathHandler>();
304833902db75011d863009585682bd08560c5b89a75Eric Laurent
304933902db75011d863009585682bd08560c5b89a75Eric Laurent            readSettings();
30509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
30519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
305242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        public String getSettingNameForDevice(int device) {
305342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            String name = mVolumeIndexSettingName;
3054948d32748caaac5be06c991ebf00f74265a7849fEric Laurent            String suffix = AudioSystem.getOutputDeviceName(device);
30559bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if (suffix.isEmpty()) {
30569bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                return name;
30579bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
30589bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            return name + "_" + suffix;
30599bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
30609bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
3061fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public void readSettings() {
3062fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3063fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // force maximum volume on all streams if fixed volume property is set
3064fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                if (mUseFixedVolume) {
3065fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
3066fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    return;
3067fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3068fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // do not read system stream volume from settings: this stream is always aliased
3069fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // to another stream type and its volume is never persisted. Values in settings can
3070fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // only be stale values
3071fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3072fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
3073fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
3074fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    synchronized (mCameraSoundForced) {
3075fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        if (mCameraSoundForced) {
3076fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            index = mIndexMax;
3077fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        }
3078dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    }
3079fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
3080fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    return;
3081dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                }
3082002e9d382d2daa7ed41636463ecdbddbd4897abaEric Laurent
3083fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
308483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
3085fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                for (int i = 0; remainingDevices != 0; i++) {
3086fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int device = (1 << i);
3087fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    if ((device & remainingDevices) == 0) {
3088fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        continue;
3089fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    }
3090fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    remainingDevices &= ~device;
3091fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent
3092fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // retrieve current volume for device
3093fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    String name = getSettingNameForDevice(device);
3094fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // if no volume stored for current stream and device, use default volume if default
3095fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // device, continue otherwise
3096fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
3097fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                                            AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
3098fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int index = Settings.System.getIntForUser(
3099fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3100fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    if (index == -1) {
3101fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        continue;
3102fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    }
31039bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
3104fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // ignore settings for fixed volume devices: volume should always be at max or 0
3105fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) &&
3106fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            ((device & mFixedVolumeDevices) != 0)) {
3107fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        mIndex.put(device, (index != 0) ? mIndexMax : 0);
3108fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    } else {
3109fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        mIndex.put(device, getValidIndex(10 * index));
3110fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    }
3111dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                }
31129bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
31139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
31149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
31159bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        public void applyDeviceVolume(int device) {
311642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            int index;
311742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            if (isMuted()) {
311842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                index = 0;
3119cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent            } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3120c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                       mAvrcpAbsVolSupported) {
3121c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                index = (mIndexMax + 5)/10;
3122cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent            } else {
312342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                index = (getIndex(device) + 5)/10;
312442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            }
312542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
31269bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
31279bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
3128fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public void applyAllVolumes() {
3129fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3130fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // apply default volume first: by convention this will reset all
3131fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // devices volumes in audio policy manager to the supplied value
3132fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                int index;
3133fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                if (isMuted()) {
3134fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    index = 0;
3135fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                } else {
3136fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3137fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3138fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3139fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // then apply device specific volumes
3140fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Set set = mIndex.entrySet();
3141fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Iterator i = set.iterator();
3142fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                while (i.hasNext()) {
3143fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    Map.Entry entry = (Map.Entry)i.next();
3144fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int device = ((Integer)entry.getKey()).intValue();
3145fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
3146fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        if (isMuted()) {
3147fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            index = 0;
3148fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3149fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                                mAvrcpAbsVolSupported) {
3150fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            index = (mIndexMax + 5)/10;
3151fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        } else {
3152fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            index = ((Integer)entry.getValue() + 5)/10;
3153fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        }
3154fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
315542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    }
31569bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                }
31579bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
315811a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi        }
315911a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi
31609bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        public boolean adjustIndex(int deltaIndex, int device) {
316142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            return setIndex(getIndex(device) + deltaIndex,
316242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            device);
31639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
31649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3165fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public boolean setIndex(int index, int device) {
3166fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3167fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                int oldIndex = getIndex(device);
3168fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                index = getValidIndex(index);
3169fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                synchronized (mCameraSoundForced) {
3170fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3171fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        index = mIndexMax;
3172fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    }
3173dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                }
3174fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                mIndex.put(device, index);
3175fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent
3176fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                if (oldIndex != index) {
3177fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // Apply change to all streams using this one as alias
3178fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // if changing volume of current device, also change volume of current
3179fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // device on aliased stream
3180fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    boolean currentDevice = (device == getDeviceForStream(mStreamType));
3181fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int numStreamTypes = AudioSystem.getNumStreamTypes();
3182fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3183fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        if (streamType != mStreamType &&
3184fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                                mStreamVolumeAlias[streamType] == mStreamType) {
3185fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            int scaledIndex = rescaleIndex(index, mStreamType, streamType);
3186bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                            mStreamStates[streamType].setIndex(scaledIndex,
3187fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                                                               device);
3188fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            if (currentDevice) {
3189fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                                mStreamStates[streamType].setIndex(scaledIndex,
3190fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                                                                   getDeviceForStream(streamType));
3191fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            }
3192bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        }
3193a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    }
3194fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    return true;
3195fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                } else {
3196fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    return false;
3197a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
31989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
31999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
32009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3201fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public int getIndex(int device) {
3202fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3203fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Integer index = mIndex.get(device);
3204fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                if (index == null) {
3205fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
3206fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
3207fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3208fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                return index.intValue();
32099bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
32109bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
32119bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
32129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getMaxIndex() {
3213a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            return mIndexMax;
32149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
32159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3216fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public void setAllIndexes(VolumeStreamState srcStream) {
3217fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3218fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                int srcStreamType = srcStream.getStreamType();
3219fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // apply default device volume from source stream to all devices first in case
3220fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // some devices are present in this stream state but not in source stream state
3221fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
322224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                index = rescaleIndex(index, srcStreamType, mStreamType);
3223fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Set set = mIndex.entrySet();
3224fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Iterator i = set.iterator();
3225fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                while (i.hasNext()) {
3226fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    Map.Entry entry = (Map.Entry)i.next();
3227fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    entry.setValue(index);
3228fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3229fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // Now apply actual volume for devices in source stream state
3230fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                set = srcStream.mIndex.entrySet();
3231fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                i = set.iterator();
3232fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                while (i.hasNext()) {
3233fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    Map.Entry entry = (Map.Entry)i.next();
3234fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int device = ((Integer)entry.getKey()).intValue();
3235fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    index = ((Integer)entry.getValue()).intValue();
3236fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    index = rescaleIndex(index, srcStreamType, mStreamType);
3237fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent
3238fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    setIndex(index, device);
3239fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
32406d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            }
32416d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
32426d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
3243fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public void setAllIndexesToMax() {
3244fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3245fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Set set = mIndex.entrySet();
3246fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Iterator i = set.iterator();
3247fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                while (i.hasNext()) {
3248fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    Map.Entry entry = (Map.Entry)i.next();
3249fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    entry.setValue(mIndexMax);
3250fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3251dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            }
3252dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        }
3253dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
3254fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public void mute(IBinder cb, boolean state) {
3255fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3256fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                VolumeDeathHandler handler = getDeathHandler(cb, state);
3257fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                if (handler == null) {
3258fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
3259fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    return;
3260fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3261fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                handler.mute(state);
32629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
32639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
32649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32656d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        public int getStreamType() {
32666d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            return mStreamType;
32676d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
32686d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
32699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int getValidIndex(int index) {
32709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (index < 0) {
32719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
327283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            } else if (mUseFixedVolume || index > mIndexMax) {
3273a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                return mIndexMax;
32749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
32759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return index;
32779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
32789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private class VolumeDeathHandler implements IBinder.DeathRecipient {
32809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            private IBinder mICallback; // To be notified of client's death
32819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            private int mMuteCount; // Number of active mutes for this client
32829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            VolumeDeathHandler(IBinder cb) {
32849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mICallback = cb;
32859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
32869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32873172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            // must be called while synchronized on parent VolumeStreamState
32889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void mute(boolean state) {
328942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                boolean updateVolume = false;
32903172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                if (state) {
32913172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    if (mMuteCount == 0) {
32923172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        // Register for client death notification
32933172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        try {
32943172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // mICallback can be 0 if muted by AudioService
32953172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            if (mICallback != null) {
32963172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                mICallback.linkToDeath(this, 0);
32973172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
329842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            VolumeStreamState.this.mDeathHandlers.add(this);
32993172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // If the stream is not yet muted by any client, set level to 0
330042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            if (!VolumeStreamState.this.isMuted()) {
330142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                updateVolume = true;
33023172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
33033172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        } catch (RemoteException e) {
33043172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // Client has died!
33053172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            binderDied();
33063172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            return;
33073172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        }
33083172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    } else {
33093172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
33103172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    }
33113172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    mMuteCount++;
33123172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                } else {
33133172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    if (mMuteCount == 0) {
33143172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
33153172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    } else {
33163172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        mMuteCount--;
33173172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        if (mMuteCount == 0) {
33183172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // Unregister from client death notification
331942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            VolumeStreamState.this.mDeathHandlers.remove(this);
33203172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // mICallback can be 0 if muted by AudioService
33213172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            if (mICallback != null) {
33223172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                mICallback.unlinkToDeath(this, 0);
33233172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
332442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            if (!VolumeStreamState.this.isMuted()) {
332542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                updateVolume = true;
33269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
33279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
33289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
33299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
333042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                if (updateVolume) {
333142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    sendMsg(mAudioHandler,
333242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            MSG_SET_ALL_VOLUMES,
333342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            SENDMSG_QUEUE,
333442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            0,
333542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            0,
333642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            VolumeStreamState.this, 0);
333742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                }
33389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
33399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void binderDied() {
33419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.w(TAG, "Volume service client died for stream: "+mStreamType);
33429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mMuteCount != 0) {
33439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Reset all active mute requests from this client.
33449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mMuteCount = 1;
33459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mute(false);
33469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
33479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
33489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
33499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33503172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        private synchronized int muteCount() {
33519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int count = 0;
33529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int size = mDeathHandlers.size();
33539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < size; i++) {
33549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                count += mDeathHandlers.get(i).mMuteCount;
33559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
33569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return count;
33579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
33589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
335942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        private synchronized boolean isMuted() {
336042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            return muteCount() != 0;
336142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        }
336242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent
33633172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        // only called by mute() which is already synchronized
33649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
33653172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            VolumeDeathHandler handler;
33663172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            int size = mDeathHandlers.size();
33673172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            for (int i = 0; i < size; i++) {
33683172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = mDeathHandlers.get(i);
33693172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                if (cb == handler.mICallback) {
33703172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    return handler;
3371ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood                }
3372ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood            }
33733172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            // If this is the first mute request for this client, create a new
33743172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            // client death handler. Otherwise, it is an out of sequence unmute request.
33753172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            if (state) {
33763172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = new VolumeDeathHandler(cb);
33773172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            } else {
33783172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                Log.w(TAG, "stream was not muted by this client");
33793172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = null;
33803172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            }
33813172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            return handler;
3382ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        }
3383bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
3384bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        private void dump(PrintWriter pw) {
3385dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            pw.print("   Mute count: ");
3386dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            pw.println(muteCount());
3387bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.print("   Current: ");
3388bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Set set = mIndex.entrySet();
3389bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Iterator i = set.iterator();
3390bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            while (i.hasNext()) {
3391bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                Map.Entry entry = (Map.Entry)i.next();
3392bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue())
3393bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                             + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", ");
3394bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            }
3395bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
3396ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
3397ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
33989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Thread that handles native AudioSystem control. */
33999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class AudioSystemThread extends Thread {
34009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        AudioSystemThread() {
34019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super("AudioService");
34029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
34039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
34059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
34069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Set this thread up so the handler will work on it
34079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Looper.prepare();
34089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized(AudioService.this) {
34109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAudioHandler = new AudioHandler();
34119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Notify that the handler has been created
34139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                AudioService.this.notify();
34149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
34159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Listen for volume change requests that are set by VolumePanel
34179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Looper.loop();
34189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
34199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
34209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Handles internal volume messages in separate volume thread. */
34229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class AudioHandler extends Handler {
34239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34249bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private void setDeviceVolume(VolumeStreamState streamState, int device) {
34259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34269bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Apply volume
34279bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            streamState.applyDeviceVolume(device);
3428a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
3429a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            // Apply change to all streams using this one as alias
3430a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            int numStreamTypes = AudioSystem.getNumStreamTypes();
3431a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3432a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                if (streamType != streamState.mStreamType &&
34336d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
3434cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    // Make sure volume is also maxed out on A2DP device for aliased stream
3435cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    // that may have a different device selected
3436cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    int streamDevice = getDeviceForStream(streamType);
3437cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    if ((device != streamDevice) && mAvrcpAbsVolSupported &&
3438cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                            ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
3439cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                        mStreamStates[streamType].applyDeviceVolume(device);
3440cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    }
3441cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    mStreamStates[streamType].applyDeviceVolume(streamDevice);
3442a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
3443a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
34449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Post a persist volume msg
3446afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            sendMsg(mAudioHandler,
3447afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    MSG_PERSIST_VOLUME,
344898ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent                    SENDMSG_QUEUE,
34499bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    device,
345042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    0,
3451afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    streamState,
3452afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    PERSIST_DELAY);
3453afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent
34549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
34559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34569bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private void setAllVolumes(VolumeStreamState streamState) {
34579bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
34589bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Apply volume
34599bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            streamState.applyAllVolumes();
34609bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
34619bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Apply change to all streams using this one as alias
34629bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            int numStreamTypes = AudioSystem.getNumStreamTypes();
34639bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
34649bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                if (streamType != streamState.mStreamType &&
34656d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
34669bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    mStreamStates[streamType].applyAllVolumes();
34679bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                }
34689bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
34699bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
34709bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
347142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        private void persistVolume(VolumeStreamState streamState, int device) {
347283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            if (mUseFixedVolume) {
347383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                return;
347483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            }
347542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            System.putIntForUser(mContentResolver,
347642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                      streamState.getSettingNameForDevice(device),
347742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                      (streamState.getIndex(device) + 5)/ 10,
347842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                      UserHandle.USER_CURRENT);
34799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
34809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3481ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        private void persistRingerMode(int ringerMode) {
348283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            if (mUseFixedVolume) {
348383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                return;
348483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            }
34858d9a1f66d9d3dbbd45a56d441a746ec11dba7645Jeff Sharkey            Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
34869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
34879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34885d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        private boolean onLoadSoundEffects() {
34895d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            int status;
34905d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
34915d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            synchronized (mSoundEffectsLock) {
34924a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                if (!mSystemReady) {
34935d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    Log.w(TAG, "onLoadSoundEffects() called before boot complete");
34945d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    return false;
34955d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
34965d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
34975d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (mSoundPool != null) {
34985d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    return true;
34995d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
35005d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
35015d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                loadTouchSoundAssets();
35025d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
35035d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0);
35045d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPoolCallBack = null;
35055d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPoolListenerThread = new SoundPoolListenerThread();
35065d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPoolListenerThread.start();
35075d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int attempts = 3;
35085d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
35095d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    try {
35105d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        // Wait for mSoundPoolCallBack to be set by the other thread
3511167d1a27713ab64cd3c0aa70de96434083ef0400Glenn Kasten                        mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
35125d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    } catch (InterruptedException e) {
35135d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
35145d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
35155d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
35165d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
35175d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (mSoundPoolCallBack == null) {
35185d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
35195d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (mSoundPoolLooper != null) {
35205d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        mSoundPoolLooper.quit();
35215d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        mSoundPoolLooper = null;
35225d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
35235d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPoolListenerThread = null;
35245d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool.release();
35255d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool = null;
35265d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    return false;
35275d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
35285d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                /*
35295d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * poolId table: The value -1 in this table indicates that corresponding
35305d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
35315d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * Once loaded, the value in poolId is the sample ID and the same
35325d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * sample can be reused for another effect using the same file.
35335d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 */
35345d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
35355d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
35365d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    poolId[fileIdx] = -1;
35375d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
35385d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                /*
35395d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
35405d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
35415d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * this indicates we have a valid sample loaded for this effect.
35425d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 */
35435d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
35445d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int numSamples = 0;
35455d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
35465d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    // Do not load sample if this effect uses the MediaPlayer
35475d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
35485d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        continue;
35495d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
35505d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
35515d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        String filePath = Environment.getRootDirectory()
35525d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                                + SOUND_EFFECTS_PATH
35535d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                                + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
35545d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        int sampleId = mSoundPool.load(filePath, 0);
35555d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        if (sampleId <= 0) {
35565d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            Log.w(TAG, "Soundpool could not load file: "+filePath);
35575d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        } else {
35585d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
35595d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
35605d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            numSamples++;
35615d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        }
35625d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    } else {
35635d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        SOUND_EFFECT_FILES_MAP[effect][1] =
35645d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                                poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
35655d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
35665d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
35675d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                // wait for all samples to be loaded
35685d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (numSamples > 0) {
35695d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPoolCallBack.setSamples(poolId);
35705d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
35715d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    attempts = 3;
35725d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    status = 1;
35735d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    while ((status == 1) && (attempts-- > 0)) {
35745d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        try {
3575167d1a27713ab64cd3c0aa70de96434083ef0400Glenn Kasten                            mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
35765d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            status = mSoundPoolCallBack.status();
35775d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        } catch (InterruptedException e) {
35785d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            Log.w(TAG, "Interrupted while waiting sound pool callback.");
35795d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        }
35805d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
35815d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                } else {
35825d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    status = -1;
35835d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
35845d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
35855d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (mSoundPoolLooper != null) {
35865d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPoolLooper.quit();
35875d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPoolLooper = null;
35885d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
35895d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPoolListenerThread = null;
35905d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (status != 0) {
35915d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    Log.w(TAG,
35925d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            "onLoadSoundEffects(), Error "+status+ " while loading samples");
35935d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
35945d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
35955d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            SOUND_EFFECT_FILES_MAP[effect][1] = -1;
35965d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        }
35975d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
35985d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
35995d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool.release();
36005d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool = null;
36015d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
36025d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            }
36035d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            return (status == 0);
36045d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        }
36055d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
36065d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        /**
36075d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent         *  Unloads samples from the sound pool.
36085d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent         *  This method can be called to free some memory when
36095d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent         *  sound effects are disabled.
36105d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent         */
36115d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        private void onUnloadSoundEffects() {
36125d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            synchronized (mSoundEffectsLock) {
36135d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (mSoundPool == null) {
36145d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    return;
36155d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
36165d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
36175d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
36185d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
36195d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    poolId[fileIdx] = 0;
36205d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
36215d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
36225d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
36235d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
36245d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        continue;
36255d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
36265d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
36275d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
36285d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        SOUND_EFFECT_FILES_MAP[effect][1] = -1;
36295d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
36305d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
36315d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
36325d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPool.release();
36335d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPool = null;
36345d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            }
36355d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        }
36365d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
36375d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        private void onPlaySoundEffect(int effectType, int volume) {
36389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mSoundEffectsLock) {
36395d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
36405d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                onLoadSoundEffects();
36415d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
36429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSoundPool == null) {
36439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return;
36449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3645a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                float volFloat;
364625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                // use default if volume is not specified by caller
3647a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                if (volume < 0) {
3648f2b0c11f4e797e183131261724d8de310dac5431Jean-Michel Trivi                    volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
3649a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                } else {
36508a2cfc309ab9126e90022916967c65a793c034f0RoboErik                    volFloat = volume / 1000.0f;
3651a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                }
36529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
36545d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
36555d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                                        volFloat, volFloat, 0, 0, 1.0f);
36569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
36579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MediaPlayer mediaPlayer = new MediaPlayer();
365862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    try {
3659e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
3660e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                                    SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
366162b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setDataSource(filePath);
366262b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
366362b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.prepare();
3664068225de0197df07a0247b2877666ea91c22c992Glenn Kasten                        mediaPlayer.setVolume(volFloat);
366562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
366662b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            public void onCompletion(MediaPlayer mp) {
366762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                cleanupPlayer(mp);
366862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            }
366962b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        });
367062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setOnErrorListener(new OnErrorListener() {
367162b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            public boolean onError(MediaPlayer mp, int what, int extra) {
367262b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                cleanupPlayer(mp);
367362b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                return true;
367462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            }
367562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        });
367662b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.start();
367762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IOException ex) {
367862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IOException: "+ex);
367962b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IllegalArgumentException ex) {
368062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
368162b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IllegalStateException ex) {
368262b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
36839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
36849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
36859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
36869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
36879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private void cleanupPlayer(MediaPlayer mp) {
36899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mp != null) {
36909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
36919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mp.stop();
36929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mp.release();
36939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (IllegalStateException ex) {
36949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
36959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
36969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
36979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
36989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3699fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        private void setForceUse(int usage, int config) {
3700fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent            AudioSystem.setForceUse(usage, config);
3701fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        }
3702fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
370305274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        private void onPersistSafeVolumeState(int state) {
370405274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent            Settings.Global.putInt(mContentResolver,
370505274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    Settings.Global.AUDIO_SAFE_VOLUME_STATE,
370605274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    state);
370705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        }
370805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent
37099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
37109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
37119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3712afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            switch (msg.what) {
37139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                case MSG_SET_DEVICE_VOLUME:
37159bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
37169bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    break;
37179bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
37189bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                case MSG_SET_ALL_VOLUMES:
37199bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    setAllVolumes((VolumeStreamState) msg.obj);
37209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
37219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PERSIST_VOLUME:
372342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    persistVolume((VolumeStreamState) msg.obj, msg.arg1);
37249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
37259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37265c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                case MSG_PERSIST_MASTER_VOLUME:
372783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                    if (mUseFixedVolume) {
372883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                        return;
372983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                    }
3730bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                    Settings.System.putFloatForUser(mContentResolver,
3731bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                    Settings.System.VOLUME_MASTER,
37328a2cfc309ab9126e90022916967c65a793c034f0RoboErik                                                    msg.arg1 / (float)1000.0,
3733bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                    UserHandle.USER_CURRENT);
37345c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                    break;
37355c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
373657978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                case MSG_PERSIST_MASTER_VOLUME_MUTE:
373783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                    if (mUseFixedVolume) {
373883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                        return;
373983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                    }
3740bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                    Settings.System.putIntForUser(mContentResolver,
3741bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                 Settings.System.VOLUME_MASTER_MUTE,
3742bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                 msg.arg1,
3743bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                 UserHandle.USER_CURRENT);
374457978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                    break;
374557978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh
37469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PERSIST_RINGER_MODE:
3747ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    // note that the value persisted is the current ringer mode, not the
3748ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    // value of ringer mode as of the time the request was made to persist
3749ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    persistRingerMode(getRingerMode());
37509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
37519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_MEDIA_SERVER_DIED:
3753dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                    if (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK) {
375489e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                        Log.e(TAG, "Media server died.");
3755afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
375689e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                                null, 500);
3757dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                        break;
375889e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                    }
37599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.e(TAG, "Media server started.");
3760dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent
37613c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // indicate to audio HAL that we start the reconfiguration phase after a media
37623c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // server crash
3763dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                    // Note that we only execute this when the media server
37643c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // process restarts after a crash, not the first time it is started.
37653c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    AudioSystem.setParameters("restarting=true");
37663c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent
3767fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten                    readAndSetLowRamDevice();
3768fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten
3769c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore device connection states
37706bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mConnectedDevices) {
37716bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        Set set = mConnectedDevices.entrySet();
37726bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        Iterator i = set.iterator();
37739bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        while (i.hasNext()) {
37746bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            Map.Entry device = (Map.Entry)i.next();
37756bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            AudioSystem.setDeviceConnectionState(
37766bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            ((Integer)device.getKey()).intValue(),
37776bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            AudioSystem.DEVICE_STATE_AVAILABLE,
37786bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            (String)device.getValue());
37796bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
3780c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    }
3781c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore call state
3782c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    AudioSystem.setPhoneState(mMode);
3783c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
3784d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    // Restore forced usage for communcations and record
3785c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
3786d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
3787dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
3788dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                    AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
3789c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
3790a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    // Restore stream volumes
37919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int numStreamTypes = AudioSystem.getNumStreamTypes();
37929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
37939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        VolumeStreamState streamState = mStreamStates[streamType];
3794c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                        AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
37959bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
37969bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        streamState.applyAllVolumes();
37979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
3798c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
3799c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore ringer mode
3800c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    setRingerModeInt(getRingerMode(), false);
38013c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent
38029063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                    // Restore master volume
38039063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                    restoreMasterVolume();
38049063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood
3805f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                    // Reset device orientation (if monitored for this device)
3806d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    if (mMonitorOrientation) {
3807f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                        setOrientationForAudioSystem();
3808f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                    }
3809bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                    if (mMonitorRotation) {
3810bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                        setRotationForAudioSystem();
3811bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                    }
3812f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
38137847211fb4699bf6018e29d214a918ed6657319bEric Laurent                    synchronized (mBluetoothA2dpEnabledLock) {
38147847211fb4699bf6018e29d214a918ed6657319bEric Laurent                        AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
38157847211fb4699bf6018e29d214a918ed6657319bEric Laurent                                mBluetoothA2dpEnabled ?
38167847211fb4699bf6018e29d214a918ed6657319bEric Laurent                                        AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
38177847211fb4699bf6018e29d214a918ed6657319bEric Laurent                    }
3818bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent
3819bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                    synchronized (mSettingsLock) {
3820bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                        AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
3821bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                                mDockAudioMediaEnabled ?
3822bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
3823bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                    }
3824bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent
38256f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang                    if (mHdmiTvClient != null) {
382612307ca810e8100981b2b60e3f2c6a7e451b9774Jungshik Jang                        setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
38276f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang                    }
38286f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang
38293c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // indicate the end of reconfiguration phase to audio HAL
38303c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    AudioSystem.setParameters("restarting=false");
38319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
38329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38335d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                case MSG_UNLOAD_SOUND_EFFECTS:
38345d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    onUnloadSoundEffects();
38355d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    break;
38365d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
3837117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                case MSG_LOAD_SOUND_EFFECTS:
38385d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
38395d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    // can take several dozens of milliseconds to complete
38405d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    boolean loaded = onLoadSoundEffects();
38415d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (msg.obj != null) {
38425d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
38435d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        synchronized (reply) {
38445d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            reply.mStatus = loaded ? 0 : -1;
38455d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            reply.notify();
38465d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        }
38475d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
3848117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    break;
3849117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent
38509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PLAY_SOUND_EFFECT:
38515d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    onPlaySoundEffect(msg.arg1, msg.arg2);
38529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
38534c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
38544c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                case MSG_BTA2DP_DOCK_TIMEOUT:
38554c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                    // msg.obj  == address of BTA2DP device
38566bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mConnectedDevices) {
38576bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableNow( (String) msg.obj );
38586bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
38594c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                    break;
3860fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
3861fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                case MSG_SET_FORCE_USE:
3862c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                case MSG_SET_FORCE_BT_A2DP_USE:
3863fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                    setForceUse(msg.arg1, msg.arg2);
3864fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                    break;
3865d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
3866dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                case MSG_BT_HEADSET_CNCT_FAILED:
3867dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    resetBluetoothSco();
3868dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    break;
3869b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3870b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
3871b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
3872fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mAudioEventWakeLock.release();
3873b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    break;
3874b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
38750a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                case MSG_SET_A2DP_SRC_CONNECTION_STATE:
38760a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
38770a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    mAudioEventWakeLock.release();
38780a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    break;
38790a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
38800a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                case MSG_SET_A2DP_SINK_CONNECTION_STATE:
38810a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
3882fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mAudioEventWakeLock.release();
3883b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    break;
3884632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
3885632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                case MSG_REPORT_NEW_ROUTES: {
3886632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    int N = mRoutesObservers.beginBroadcast();
3887632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (N > 0) {
3888632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        AudioRoutesInfo routes;
3889632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        synchronized (mCurAudioRoutes) {
3890632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            routes = new AudioRoutesInfo(mCurAudioRoutes);
3891632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        }
3892632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        while (N > 0) {
3893632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            N--;
3894632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
3895632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            try {
3896632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                obs.dispatchAudioRoutesChanged(routes);
3897632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            } catch (RemoteException e) {
3898632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            }
3899632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        }
3900632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
3901632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    mRoutesObservers.finishBroadcast();
3902632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    break;
3903632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
39043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
3905c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                case MSG_CHECK_MUSIC_ACTIVE:
3906c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    onCheckMusicActive();
3907c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    break;
39085bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent
39095bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
39105bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                    onSendBecomingNoisyIntent();
39115bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                    break;
3912d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent
3913d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
3914d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
3915d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
3916d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    break;
391705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                case MSG_PERSIST_SAFE_VOLUME_STATE:
391805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    onPersistSafeVolumeState(msg.arg1);
391905274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    break;
3920a578c48e6c8677bcb54340aadb9470f8a275e56cJean-Michel Trivi
39212a57ca931fefe817b6110101289721acaacfc808Eric Laurent                case MSG_BROADCAST_BT_CONNECTION_STATE:
39222a57ca931fefe817b6110101289721acaacfc808Eric Laurent                    onBroadcastScoConnectionState(msg.arg1);
39232a57ca931fefe817b6110101289721acaacfc808Eric Laurent                    break;
39244a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent
39254a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                case MSG_SYSTEM_READY:
39264a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                    onSystemReady();
39274a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                    break;
39289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
39299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
39309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
39319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3932b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    private class SettingsObserver extends ContentObserver {
3933a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
3934b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        SettingsObserver() {
3935b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            super(new Handler());
3936b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            mContentResolver.registerContentObserver(Settings.System.getUriFor(
3937b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh                Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
39387ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent            mContentResolver.registerContentObserver(Settings.Global.getUriFor(
39397ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
3940b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
3941b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh
3942b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        @Override
3943b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        public void onChange(boolean selfChange) {
3944b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            super.onChange(selfChange);
3945ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
3946ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       However there appear to be some missing locks around mRingerModeMutedStreams
3947ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       and mRingerModeAffectedStreams, so will leave this synchronized for now.
3948ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
3949a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            synchronized (mSettingsLock) {
395024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                if (updateRingerModeAffectedStreams()) {
3951a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    /*
3952a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     * Ensure all stream types that should be affected by ringer mode
3953a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     * are in the proper state.
3954a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     */
3955a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    setRingerModeInt(getRingerMode(), false);
3956a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
39577ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                readDockAudioSettings(mContentResolver);
3958a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
3959b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
3960b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    }
3961a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
39626bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
39634c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceAvailable(String address) {
39647847211fb4699bf6018e29d214a918ed6657319bEric Laurent        // enable A2DP before notifying A2DP connection to avoid unecessary processing in
39657847211fb4699bf6018e29d214a918ed6657319bEric Laurent        // audio policy manager
3966c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
3967c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
3968c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
39697847211fb4699bf6018e29d214a918ed6657319bEric Laurent        setBluetoothA2dpOnInt(true);
39704c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
39714c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                AudioSystem.DEVICE_STATE_AVAILABLE,
39724c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
39734c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // Reset A2DP suspend state each time a new sink is connected
39744c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setParameters("A2dpSuspended=false");
39754c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
39764c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
39774c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
39784c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
39795bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent    private void onSendBecomingNoisyIntent() {
39805ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
39819841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood    }
39829841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood
39836bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
39844c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceUnavailableNow(String address) {
3985c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        synchronized (mA2dpAvrcpLock) {
3986c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            mAvrcpAbsVolSupported = false;
3987c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        }
39884c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
39894c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                AudioSystem.DEVICE_STATE_UNAVAILABLE,
39904c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
39914c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
39924c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
39934c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
39946bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
39954c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceUnavailableLater(String address) {
39963b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        // prevent any activity on the A2DP audio output to avoid unwanted
39973b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        // reconnection of the sink.
39983b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        AudioSystem.setParameters("A2dpSuspended=true");
39994c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // the device will be made unavailable later, so consider it disconnected right away
40004c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
40014c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // send the delayed message to make the device unavailable later
40024c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
40034c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
40044c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
40054c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
40064c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
40076bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
40080a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private void makeA2dpSrcAvailable(String address) {
40090a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
40100a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                AudioSystem.DEVICE_STATE_AVAILABLE,
40110a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                address);
40120a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
40130a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                address);
40140a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    }
40150a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
40160a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    // must be called synchronized on mConnectedDevices
40170a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private void makeA2dpSrcUnavailable(String address) {
40180a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
40190a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                AudioSystem.DEVICE_STATE_UNAVAILABLE,
40200a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                address);
40210a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
40220a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    }
40230a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
40240a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    // must be called synchronized on mConnectedDevices
4025a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private void cancelA2dpDeviceTimeout() {
40264c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
40274c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
40284c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
40296bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
4030a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private boolean hasScheduledA2dpDockTimeout() {
4031a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi        return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4032a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    }
4033a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi
40340a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
40356bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    {
40360a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (DEBUG_VOL) {
40370a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
40380a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
40396bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        if (btDevice == null) {
40406bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            return;
40416bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
40426bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        String address = btDevice.getAddress();
40436bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
40446bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            address = "";
40456bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
40465a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
40476bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        synchronized (mConnectedDevices) {
40486bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            boolean isConnected =
40496bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
40506bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
40516bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
40526bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
40536bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                if (btDevice.isBluetoothDock()) {
40546bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (state == BluetoothProfile.STATE_DISCONNECTED) {
40556bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // introduction of a delay for transient disconnections of docks when
40566bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // power is rapidly turned off/on, this message will be canceled if
40576bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // we reconnect the dock under a preset delay
40586bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableLater(address);
40596bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // the next time isConnected is evaluated, it will be false for the dock
40606bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
40616bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                } else {
40626bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    makeA2dpDeviceUnavailableNow(address);
40636bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
4064632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                synchronized (mCurAudioRoutes) {
4065632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (mCurAudioRoutes.mBluetoothName != null) {
4066632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        mCurAudioRoutes.mBluetoothName = null;
4067632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4068632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                SENDMSG_NOOP, 0, 0, null, 0);
4069632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
4070632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
40716bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
40726bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                if (btDevice.isBluetoothDock()) {
40736bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // this could be a reconnection after a transient disconnection
40746bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    cancelA2dpDeviceTimeout();
40756bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mDockAddress = address;
40766bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                } else {
40776bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // this could be a connection of another A2DP device before the timeout of
40786bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // a dock: cancel the dock timeout, and make the dock unavailable now
40796bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if(hasScheduledA2dpDockTimeout()) {
40806bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        cancelA2dpDeviceTimeout();
40816bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableNow(mDockAddress);
40826bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
40836bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
40846bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                makeA2dpDeviceAvailable(address);
4085632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                synchronized (mCurAudioRoutes) {
4086632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    String name = btDevice.getAliasName();
4087632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
4088632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        mCurAudioRoutes.mBluetoothName = name;
4089632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4090632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                SENDMSG_NOOP, 0, 0, null, 0);
4091632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
4092632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
40936bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            }
40946bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
40956bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    }
40966bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
40970a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
40980a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    {
40990a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (DEBUG_VOL) {
41000a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
41010a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
41020a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (btDevice == null) {
41030a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            return;
41040a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
41050a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        String address = btDevice.getAddress();
41060a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
41070a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            address = "";
41080a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
41090a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
41100a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        synchronized (mConnectedDevices) {
41110a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                boolean isConnected =
41120a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
41130a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));
41140a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
41150a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
41160a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                makeA2dpSrcUnavailable(address);
41170a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
41180a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                makeA2dpSrcAvailable(address);
41190a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            }
41200a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
41210a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    }
41220a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
41235a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
41245a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        // address is not used for now, but may be used when multiple a2dp devices are supported
41255a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        synchronized (mA2dpAvrcpLock) {
41265a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du            mAvrcpAbsVolSupported = support;
4127c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4128cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4129cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4130cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4131cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4132cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    mStreamStates[AudioSystem.STREAM_RING], 0);
41335a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        }
41345a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    }
41355a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
413659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent    private boolean handleDeviceConnection(boolean connected, int device, String params) {
413759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        synchronized (mConnectedDevices) {
413859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            boolean isConnected = (mConnectedDevices.containsKey(device) &&
41399841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                    (params.isEmpty() || mConnectedDevices.get(device).equals(params)));
414059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent
414159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            if (isConnected && !connected) {
414259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                AudioSystem.setDeviceConnectionState(device,
414359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                              AudioSystem.DEVICE_STATE_UNAVAILABLE,
41449841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                                              mConnectedDevices.get(device));
414559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 mConnectedDevices.remove(device);
414659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 return true;
414759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            } else if (!isConnected && connected) {
414859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 AudioSystem.setDeviceConnectionState(device,
414959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                                      AudioSystem.DEVICE_STATE_AVAILABLE,
415059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                                      params);
415159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 mConnectedDevices.put(new Integer(device), params);
415259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 return true;
415359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            }
415459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        }
415559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        return false;
415659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent    }
415759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent
4158b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4159b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // sent if none of these devices is connected.
4160b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    int mBecomingNoisyIntentDevices =
4161b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
4162948d32748caaac5be06c991ebf00f74265a7849fEric Laurent            AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
4163794da7a0543cbecffefb73794aa68d1a93e41adfEric Laurent            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
4164794da7a0543cbecffefb73794aa68d1a93e41adfEric Laurent            AudioSystem.DEVICE_OUT_ALL_USB;
4165b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4166b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // must be called before removing the device from mConnectedDevices
4167b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private int checkSendBecomingNoisyIntent(int device, int state) {
4168b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        int delay = 0;
4169b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4170b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            int devices = 0;
4171b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            for (int dev : mConnectedDevices.keySet()) {
4172b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                if ((dev & mBecomingNoisyIntentDevices) != 0) {
4173b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                   devices |= dev;
4174b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                }
4175b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
4176b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            if (devices == device) {
41775bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                sendMsg(mAudioHandler,
41785bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
41795bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        SENDMSG_REPLACE,
41805bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0,
41815bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0,
41825bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        null,
41835bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0);
4184b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                delay = 1000;
4185b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
4186b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
4187b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
41880a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
41890a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
4190b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
4191b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            delay = 1000;
4192b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
4193b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        return delay;
4194b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
4195b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4196b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private void sendDeviceConnectionIntent(int device, int state, String name)
4197b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
4198b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        Intent intent = new Intent();
4199b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4200b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.putExtra("state", state);
4201b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.putExtra("name", name);
4202b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4203b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4204632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        int connType = 0;
4205632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
4206b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
4207632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HEADSET;
4208b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_HEADSET_PLUG);
4209b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.putExtra("microphone", 1);
4210b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) {
4211632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HEADPHONES;
4212b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_HEADSET_PLUG);
4213b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.putExtra("microphone", 0);
4214b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
4215632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
4216b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
4217b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
4218632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
4219b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
4220948d32748caaac5be06c991ebf00f74265a7849fEric Laurent        } else if (device == AudioSystem.DEVICE_OUT_HDMI) {
4221632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HDMI;
4222b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);
4223b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
4224b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4225632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        synchronized (mCurAudioRoutes) {
4226632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            if (connType != 0) {
4227632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                int newConn = mCurAudioRoutes.mMainType;
4228632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                if (state != 0) {
4229632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    newConn |= connType;
4230632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                } else {
4231632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    newConn &= ~connType;
4232632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
4233632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                if (newConn != mCurAudioRoutes.mMainType) {
4234632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    mCurAudioRoutes.mMainType = newConn;
4235632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4236632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            SENDMSG_NOOP, 0, 0, null, 0);
4237632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
4238632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            }
4239632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        }
4240632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
42415ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        final long ident = Binder.clearCallingIdentity();
42425ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        try {
42435ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
42445ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        } finally {
42455ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            Binder.restoreCallingIdentity(ident);
42465ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        }
4247b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
4248b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4249b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private void onSetWiredDeviceConnectionState(int device, int state, String name)
4250b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
4251b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
4252b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
4253b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) {
4254b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                setBluetoothA2dpOnInt(true);
4255b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
4256ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent            boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
4257ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                            (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
4258ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                             ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
4259db45484e4b5858d14da93d3a06311b93bf0cf320Mike Lockwood            handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
4260f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent            if (state != 0) {
4261f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
4262f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE)) {
4263f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                    setBluetoothA2dpOnInt(false);
4264f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                }
4265f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                if ((device & mSafeMediaVolumeDevices) != 0) {
4266f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                    sendMsg(mAudioHandler,
4267f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            MSG_CHECK_MUSIC_ACTIVE,
4268f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            SENDMSG_REPLACE,
4269f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            0,
4270f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            0,
4271f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            null,
4272f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            MUSIC_ACTIVE_POLL_PERIOD_MS);
4273f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                }
4274b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
4275ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent            if (!isUsb && (device != AudioSystem.DEVICE_IN_WIRED_HEADSET)) {
4276db45484e4b5858d14da93d3a06311b93bf0cf320Mike Lockwood                sendDeviceConnectionIntent(device, state, name);
4277db45484e4b5858d14da93d3a06311b93bf0cf320Mike Lockwood            }
4278b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
4279b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
4280b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4281a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    /* cache of the address of the last dock the device was connected to */
4282a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private String mDockAddress;
4283a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi
4284a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    /**
4285a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     * Receiver for misc intent broadcasts the Phone app cares about.
4286a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     */
4287a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4288a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        @Override
4289a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        public void onReceive(Context context, Intent intent) {
4290a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            String action = intent.getAction();
4291ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent            int outDevice;
4292ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent            int inDevice;
429359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            int state;
4294a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
4295758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi            if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4296758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4297758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
4298758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                int config;
4299758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                switch (dockState) {
4300758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_DESK:
4301758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_BT_DESK_DOCK;
4302758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        break;
4303758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_CAR:
4304758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_BT_CAR_DOCK;
4305758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        break;
430621e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                    case Intent.EXTRA_DOCK_STATE_LE_DESK:
430708ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                        config = AudioSystem.FORCE_ANALOG_DOCK;
430821e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        break;
430921e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                    case Intent.EXTRA_DOCK_STATE_HE_DESK:
431021e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        config = AudioSystem.FORCE_DIGITAL_DOCK;
431121e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        break;
4312758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4313758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    default:
4314758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_NONE;
4315758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                }
431608ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                // Low end docks have a menu to enable or disable audio
431708ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                // (see mDockAudioMediaEnabled)
431808ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
431908ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                      ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
432008ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                       (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
432108ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
432208ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                }
432308ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                mDockState = dockState;
432482aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh            } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
432559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
432682aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh                                               BluetoothProfile.STATE_DISCONNECTED);
4327ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
4328ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
4329a56d1c72190462aa9e377906583eceb58e0efcddNick Pelly                String address = null;
4330dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent
4331dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
4332dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (btDevice == null) {
4333dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    return;
4334dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                }
4335dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent
4336dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                address = btDevice.getAddress();
4337dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                BluetoothClass btClass = btDevice.getBluetoothClass();
4338dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (btClass != null) {
4339dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    switch (btClass.getDeviceClass()) {
4340dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
4341dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
4342ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                        outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
4343dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                        break;
4344dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
4345ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                        outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
4346dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                        break;
4347d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    }
4348d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                }
4349d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent
4350dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4351dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    address = "";
4352dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                }
4353d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent
435459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
4355ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                boolean success = handleDeviceConnection(connected, outDevice, address) &&
4356ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                                      handleDeviceConnection(connected, inDevice, address);
4357ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                if (success) {
43586bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mScoClients) {
435959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        if (connected) {
436059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                            mBluetoothHeadsetDevice = btDevice;
436159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        } else {
43626bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mBluetoothHeadsetDevice = null;
43636bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            resetBluetoothSco();
43646bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
436562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    }
4366a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
4367df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean            } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG)) {
4368df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                state = intent.getIntExtra("state", 0);
4369df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean
4370df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                int alsaCard = intent.getIntExtra("card", -1);
4371df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                int alsaDevice = intent.getIntExtra("device", -1);
4372df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean
4373df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
4374df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                                    : "card=" + alsaCard + ";device=" + alsaDevice);
4375df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean
4376df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                // Playback Device
4377ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                outDevice = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
4378ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                setWiredDeviceConnectionState(outDevice, state, params);
4379df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean            } else if (action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
438059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                state = intent.getIntExtra("state", 0);
4381c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
438259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int alsaCard = intent.getIntExtra("card", -1);
438359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int alsaDevice = intent.getIntExtra("device", -1);
4384c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                boolean hasPlayback = intent.getBooleanExtra("hasPlayback", false);
4385c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                boolean hasCapture = intent.getBooleanExtra("hasCapture", false);
4386c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                boolean hasMIDI = intent.getBooleanExtra("hasMIDI", false);
4387c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
43889841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
43899841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                                    : "card=" + alsaCard + ";device=" + alsaDevice);
4390c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
4391c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                // Playback Device
4392df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                if (hasPlayback) {
4393ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                    outDevice = AudioSystem.DEVICE_OUT_USB_DEVICE;
4394ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                    setWiredDeviceConnectionState(outDevice, state, params);
4395df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                }
4396c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
4397c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                // Capture Device
4398df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                if (hasCapture) {
4399ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                    inDevice = AudioSystem.DEVICE_IN_USB_DEVICE;
4400ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                    setWiredDeviceConnectionState(inDevice, state, params);
4401df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                }
4402df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
440362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                boolean broadcast = false;
440459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
44053def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                synchronized (mScoClients) {
440662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
4407dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // broadcast intent if the connection was initated by AudioService
4408dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (!mScoClients.isEmpty() &&
4409dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
4410dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                             mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
4411dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                             mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
441262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        broadcast = true;
441362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    }
441462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    switch (btState) {
441562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_CONNECTED:
441659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
4417dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4418dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4419dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
442062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
44213def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        }
442262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
442362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
442459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
442562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        mScoAudioState = SCO_STATE_INACTIVE;
4426d7454be47f4111c0478a502353e11dea401378bdEric Laurent                        clearAllScoClients(0, false);
442762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
442862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_CONNECTING:
4429dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4430dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4431dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
443262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
44333def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        }
443462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    default:
443562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        // do not broadcast CONNECTING or invalid state
443662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        broadcast = false;
443762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
44383def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
44393def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
444062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                if (broadcast) {
444159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                    broadcastScoConnectionState(scoAudioState);
4442dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    //FIXME: this is to maintain compatibility with deprecated intent
4443dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
444462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
444559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                    newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
44465ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn                    sendStickyBroadcastToAll(newIntent);
444762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                }
4448950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent            } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
4449950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent                AudioSystem.setParameters("screen_state=on");
4450950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
4451950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent                AudioSystem.setParameters("screen_state=off");
4452961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
4453f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                handleConfigurationChanged(context);
4454bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
4455f4a8eb22112c534f436357b50f231778c5c15c25Jean-Michel Trivi                // attempt to stop music playback for background user
44565bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                sendMsg(mAudioHandler,
44575bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
44585bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        SENDMSG_REPLACE,
44595bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0,
44605bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0,
44615bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        null,
44625bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0);
4463f4a8eb22112c534f436357b50f231778c5c15c25Jean-Michel Trivi                // the current audio focus owner is no longer valid
4464fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                mMediaFocusControl.discardAudioFocusOwner();
4465f4a8eb22112c534f436357b50f231778c5c15c25Jean-Michel Trivi
44665bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                // load volume settings for new user
4467bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                readAudioSettings(true /*userSwitch*/);
4468bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                // preserve STREAM_MUSIC volume from one user to the next.
4469bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                sendMsg(mAudioHandler,
4470bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        MSG_SET_ALL_VOLUMES,
4471bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        SENDMSG_QUEUE,
4472bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        0,
4473bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        0,
4474bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4475a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
4476a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        }
4477c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean    } // end class AudioServiceBroadcastReceiver
4478d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
4479d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    //==========================================================================================
4480fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    // RemoteControlDisplay / RemoteControlClient / Remote info
4481d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    //==========================================================================================
4482f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
4483f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            ComponentName listenerComp) {
4484f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
4485f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    }
4486f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
44877ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi    public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
4488f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
4489e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi    }
4490e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi
4491fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
4492fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
4493d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
4494d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
4495fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
4496fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
4497d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
4498d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
4499fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
4500fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            boolean wantsSync) {
4501fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
4502d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
4503d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
45043346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    @Override
4505fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void setRemoteStreamVolume(int index) {
45063346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        enforceSelfOrSystemUI("set the remote stream volume");
4507fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.setRemoteStreamVolume(index);
4508d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    }
4509d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
4510fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    //==========================================================================================
4511fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    // Audio Focus
4512fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    //==========================================================================================
4513fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb,
4514fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
4515fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return mMediaFocusControl.requestAudioFocus(mainStreamType, durationHint, cb, fd,
4516fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                clientId, callingPackageName);
45174294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    }
45184294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
4519fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId) {
4520fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return mMediaFocusControl.abandonAudioFocus(fd, clientId);
4521c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    }
4522c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
4523fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void unregisterAudioFocusClient(String clientId) {
4524fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.unregisterAudioFocusClient(clientId);
45253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
45263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
45272380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi    public int getCurrentAudioFocus() {
45282380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi        return mMediaFocusControl.getCurrentAudioFocus();
45292380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi    }
45302380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi
4531f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    //==========================================================================================
4532f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    // Device orientation
4533f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    //==========================================================================================
4534f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    /**
4535bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi     * Handles device configuration changes that may map to a change in the orientation
4536bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi     * or orientation.
4537bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi     * Monitoring orientation and rotation is optional, and is defined by the definition and value
4538bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi     * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
4539f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi     */
4540f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    private void handleConfigurationChanged(Context context) {
4541f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        try {
4542f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            // reading new orientation "safely" (i.e. under try catch) in case anything
4543f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            // goes wrong when obtaining resources and configuration
4544d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            Configuration config = context.getResources().getConfiguration();
4545bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            // TODO merge rotation and orientation
4546d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if (mMonitorOrientation) {
4547d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                int newOrientation = config.orientation;
4548d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                if (newOrientation != mDeviceOrientation) {
4549d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mDeviceOrientation = newOrientation;
4550d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    setOrientationForAudioSystem();
4551d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                }
4552f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            }
4553bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            if (mMonitorRotation) {
4554bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                int newRotation = ((WindowManager) context.getSystemService(
4555bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                        Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
4556bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                if (newRotation != mDeviceRotation) {
4557bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                    mDeviceRotation = newRotation;
4558bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                    setRotationForAudioSystem();
4559bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                }
4560bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            }
4561d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            sendMsg(mAudioHandler,
4562d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
4563d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    SENDMSG_REPLACE,
4564d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    0,
4565d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    0,
4566d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    null,
4567d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    0);
4568dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4569dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            boolean cameraSoundForced = mContext.getResources().getBoolean(
4570dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    com.android.internal.R.bool.config_camera_sound_forced);
4571dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            synchronized (mSettingsLock) {
4572dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                synchronized (mCameraSoundForced) {
4573dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    if (cameraSoundForced != mCameraSoundForced) {
4574dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        mCameraSoundForced = cameraSoundForced;
4575dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4576dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
4577dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        if (cameraSoundForced) {
4578dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                            s.setAllIndexesToMax();
4579dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                            mRingerModeAffectedStreams &=
4580dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                    ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4581dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        } else {
458242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
4583dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                            mRingerModeAffectedStreams |=
4584dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                    (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4585dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        }
4586dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        // take new state into account for streams muted by ringer mode
4587dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        setRingerModeInt(getRingerMode(), false);
4588dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4589dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        sendMsg(mAudioHandler,
4590dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                MSG_SET_FORCE_USE,
4591dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                SENDMSG_QUEUE,
4592dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                AudioSystem.FOR_SYSTEM,
4593dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                cameraSoundForced ?
4594dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                        AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
4595dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                null,
4596dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                0);
4597dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4598dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        sendMsg(mAudioHandler,
4599dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                MSG_SET_ALL_VOLUMES,
4600dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                SENDMSG_QUEUE,
4601dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                0,
4602dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                0,
4603dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
4604dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    }
4605dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                }
4606dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            }
46073346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            mVolumeController.setLayoutDirection(config.getLayoutDirection());
4608f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        } catch (Exception e) {
4609bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            Log.e(TAG, "Error handling configuration change: ", e);
4610f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        }
4611f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    }
4612f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
4613f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    private void setOrientationForAudioSystem() {
4614f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        switch (mDeviceOrientation) {
4615f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_LANDSCAPE:
4616f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is landscape");
4617f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=landscape");
4618f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
4619f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_PORTRAIT:
4620f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is portrait");
4621f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=portrait");
4622f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
4623f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_SQUARE:
4624f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is square");
4625f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=square");
4626f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
4627f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_UNDEFINED:
4628f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is undefined");
4629f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=undefined");
4630f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
4631f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            default:
4632f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                Log.e(TAG, "Unknown orientation");
4633f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        }
4634f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    }
4635f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
4636bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    private void setRotationForAudioSystem() {
4637bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        switch (mDeviceRotation) {
4638bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            case Surface.ROTATION_0:
4639bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                AudioSystem.setParameters("rotation=0");
4640bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                break;
4641bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            case Surface.ROTATION_90:
4642bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                AudioSystem.setParameters("rotation=90");
4643bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                break;
4644bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            case Surface.ROTATION_180:
4645bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                AudioSystem.setParameters("rotation=180");
4646bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                break;
4647bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            case Surface.ROTATION_270:
4648bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                AudioSystem.setParameters("rotation=270");
4649bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                break;
4650bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            default:
4651bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                Log.e(TAG, "Unknown device rotation");
4652bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        }
4653bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    }
4654bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi
4655f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
46567847211fb4699bf6018e29d214a918ed6657319bEric Laurent    // Handles request to override default use of A2DP for media.
46577847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public void setBluetoothA2dpOnInt(boolean on) {
46587847211fb4699bf6018e29d214a918ed6657319bEric Laurent        synchronized (mBluetoothA2dpEnabledLock) {
46597847211fb4699bf6018e29d214a918ed6657319bEric Laurent            mBluetoothA2dpEnabled = on;
4660c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
4661c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
4662c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
46637847211fb4699bf6018e29d214a918ed6657319bEric Laurent        }
46647847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
46657847211fb4699bf6018e29d214a918ed6657319bEric Laurent
4666d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    @Override
4667098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    public void setRingtonePlayer(IRingtonePlayer player) {
4668098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
4669098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        mRingtonePlayer = player;
4670098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    }
4671098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
4672098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    @Override
4673098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    public IRingtonePlayer getRingtonePlayer() {
4674098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        return mRingtonePlayer;
4675098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    }
4676098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
4677098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    @Override
4678632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
4679632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        synchronized (mCurAudioRoutes) {
4680632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
4681632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            mRoutesObservers.register(observer);
4682632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            return routes;
4683632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        }
4684632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    }
4685632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
4686c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4687c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    //==========================================================================================
4688c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // Safe media volume management.
4689c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // MUSIC stream volume level is limited when headphones are connected according to safety
4690c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // regulation. When the user attempts to raise the volume above the limit, a warning is
4691c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // displayed and the user has to acknowlegde before the volume is actually changed.
4692c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // The volume index corresponding to the limit is stored in config_safe_media_volume_index
4693c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // property. Platforms with a different limit must set this property accordingly in their
4694c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // overlay.
4695c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    //==========================================================================================
4696c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4697d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
4698d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
4699d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
4700d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
4701d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
4702d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // (when user opts out).
4703d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
4704d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private final int SAFE_MEDIA_VOLUME_DISABLED = 1;
4705d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private final int SAFE_MEDIA_VOLUME_INACTIVE = 2;
4706d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private final int SAFE_MEDIA_VOLUME_ACTIVE = 3;
4707d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private Integer mSafeMediaVolumeState;
4708d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent
4709d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private int mMcc = 0;
4710c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
4711d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private int mSafeMediaVolumeIndex;
4712c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
4713c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
4714c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                                                AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
4715c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
4716c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
4717c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
4718c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private int mMusicActiveMs;
4719c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
4720c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000;  // 1 minute polling interval
4721d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000;  // 30s after boot completed
4722c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4723c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private void setSafeMediaVolumeEnabled(boolean on) {
4724d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
4725d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
4726d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
4727d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
4728d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
4729d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    enforceSafeMediaVolume();
4730d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
4731d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
4732d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mMusicActiveMs = 0;
4733d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    sendMsg(mAudioHandler,
4734d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            MSG_CHECK_MUSIC_ACTIVE,
4735d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            SENDMSG_REPLACE,
4736d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            0,
4737d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            0,
4738d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            null,
4739d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            MUSIC_ACTIVE_POLL_PERIOD_MS);
4740d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                }
4741c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
4742c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
4743c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
4744c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4745c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private void enforceSafeMediaVolume() {
4746c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4747c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        int devices = mSafeMediaVolumeDevices;
4748c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        int i = 0;
4749c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4750c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        while (devices != 0) {
4751c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            int device = 1 << i++;
4752c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            if ((device & devices) == 0) {
4753c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                continue;
4754c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
475542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            int index = streamState.getIndex(device);
4756c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            if (index > mSafeMediaVolumeIndex) {
475742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                streamState.setIndex(mSafeMediaVolumeIndex, device);
475842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                sendMsg(mAudioHandler,
475942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        MSG_SET_DEVICE_VOLUME,
476042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        SENDMSG_QUEUE,
476142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        device,
476242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        0,
476342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        streamState,
476442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        0);
4765c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
4766c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            devices &= ~device;
4767c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
4768c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
4769c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4770c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private boolean checkSafeMediaVolume(int streamType, int index, int device) {
4771d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
4772d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
4773c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
4774c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    ((device & mSafeMediaVolumeDevices) != 0) &&
4775c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    (index > mSafeMediaVolumeIndex)) {
4776c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                return false;
4777c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
4778c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            return true;
4779c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
4780c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
4781c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
47823346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    @Override
4783c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    public void disableSafeMediaVolume() {
47843346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        enforceSelfOrSystemUI("disable the safe media volume");
4785d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
4786c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            setSafeMediaVolumeEnabled(false);
4787fde16d5879ea88a971004c984093409468b6139cEric Laurent            if (mPendingVolumeCommand != null) {
4788fde16d5879ea88a971004c984093409468b6139cEric Laurent                onSetStreamVolume(mPendingVolumeCommand.mStreamType,
4789fde16d5879ea88a971004c984093409468b6139cEric Laurent                                  mPendingVolumeCommand.mIndex,
4790fde16d5879ea88a971004c984093409468b6139cEric Laurent                                  mPendingVolumeCommand.mFlags,
4791fde16d5879ea88a971004c984093409468b6139cEric Laurent                                  mPendingVolumeCommand.mDevice);
4792fde16d5879ea88a971004c984093409468b6139cEric Laurent                mPendingVolumeCommand = null;
4793fde16d5879ea88a971004c984093409468b6139cEric Laurent            }
4794c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
4795c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
4796c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
479741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    //==========================================================================================
479841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    // Hdmi Cec system audio mode.
479941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    // If Hdmi Cec's system audio mode is on, audio service should notify volume change
480041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    // to HdmiControlService so that audio recevier can handle volume change.
480141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    //==========================================================================================
480241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang
480341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    // If HDMI-CEC system audio is supported
480441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    private boolean mHdmiSystemAudioSupported = false;
480541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    // Set only when device is tv.
480641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    private HdmiTvClient mHdmiTvClient;
480741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang
480841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    @Override
480912307ca810e8100981b2b60e3f2c6a7e451b9774Jungshik Jang    public int setHdmiSystemAudioSupported(boolean on) {
481041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang        if (mHdmiTvClient == null) {
481141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang            Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
48126f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang            return AudioSystem.DEVICE_NONE;
481341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang        }
481441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang
481541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang        synchronized (mHdmiTvClient) {
48166f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang            if (mHdmiSystemAudioSupported == on) {
48176f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang                return AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
48186f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang            }
481941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang            mHdmiSystemAudioSupported = on;
482012307ca810e8100981b2b60e3f2c6a7e451b9774Jungshik Jang            AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
482112307ca810e8100981b2b60e3f2c6a7e451b9774Jungshik Jang                    on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED : AudioSystem.FORCE_NONE);
48226f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang        }
48236f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang        return AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
48246f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang    }
48256f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang
4826dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    //==========================================================================================
4827dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // Camera shutter sound policy.
4828dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
4829dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // sound is forced (sound even if the device is in silent mode) or not. This option is false by
4830dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
4831dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    //==========================================================================================
4832dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4833dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // cached value of com.android.internal.R.bool.config_camera_sound_forced
4834dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    private Boolean mCameraSoundForced;
4835dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4836dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
4837dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    public boolean isCameraSoundForced() {
4838dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        synchronized (mCameraSoundForced) {
4839dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            return mCameraSoundForced;
4840dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        }
4841dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    }
4842dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4843dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    private static final String[] RINGER_MODE_NAMES = new String[] {
4844dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            "SILENT",
4845dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            "VIBRATE",
4846dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            "NORMAL"
4847dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    };
4848dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4849dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    private void dumpRingerMode(PrintWriter pw) {
4850dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println("\nRinger mode: ");
4851dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]);
4852dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.print("- ringer mode affected streams = 0x");
4853dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println(Integer.toHexString(mRingerModeAffectedStreams));
4854dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.print("- ringer mode muted streams = 0x");
4855dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println(Integer.toHexString(mRingerModeMutedStreams));
4856dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    }
4857dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4858632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    @Override
4859d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
4860eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
4861eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey
4862fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.dump(pw);
4863bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        dumpStreamStates(pw);
4864dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        dumpRingerMode(pw);
4865632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.println("\nAudio routes:");
4866632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
4867632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
48683346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        pw.print("  mVolumeController="); pw.println(mVolumeController);
4869d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
4870fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten
4871fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten    // Inform AudioFlinger of our device's low RAM attribute
4872fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten    private static void readAndSetLowRamDevice()
4873fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten    {
4874fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten        int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
4875fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten        if (status != 0) {
4876fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten            Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
4877fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten        }
4878fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten    }
48793346a802087f621c6441bc512dfcc17b07143fc6John Spurlock
48803346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    private void enforceSelfOrSystemUI(String action) {
48813346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
48823346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                "Only SystemUI can " + action);
48833346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    }
48843346a802087f621c6441bc512dfcc17b07143fc6John Spurlock
48853346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    @Override
48863346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    public void setVolumeController(final IVolumeController controller) {
48873346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        enforceSelfOrSystemUI("set the volume controller");
48883346a802087f621c6441bc512dfcc17b07143fc6John Spurlock
48893346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        // return early if things are not actually changing
48903346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        if (mVolumeController.isSameBinder(controller)) {
48913346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            return;
48923346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        }
48933346a802087f621c6441bc512dfcc17b07143fc6John Spurlock
48943346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        // dismiss the old volume controller
48953346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        mVolumeController.postDismiss();
48963346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        if (controller != null) {
48973346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            // we are about to register a new controller, listen for its death
48983346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            try {
48993346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                controller.asBinder().linkToDeath(new DeathRecipient() {
49003346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                    @Override
49013346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                    public void binderDied() {
49023346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                        if (mVolumeController.isSameBinder(controller)) {
49033346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                            Log.w(TAG, "Current remote volume controller died, unregistering");
49043346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                            setVolumeController(null);
49053346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                        }
49063346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                    }
49073346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                }, 0);
49083346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            } catch (RemoteException e) {
49093346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                // noop
49103346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            }
49113346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        }
49123346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        mVolumeController.setController(controller);
491333f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
491433f4e04e32fac42f158733d6a731e50490fa9951John Spurlock    }
491533f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
491633f4e04e32fac42f158733d6a731e50490fa9951John Spurlock    @Override
491733f4e04e32fac42f158733d6a731e50490fa9951John Spurlock    public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
491833f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        enforceSelfOrSystemUI("notify about volume controller visibility");
491933f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
492033f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        // return early if the controller is not current
492133f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        if (!mVolumeController.isSameBinder(controller)) {
492233f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            return;
492333f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        }
492433f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
492533f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        mVolumeController.setVisible(visible);
492633f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
49273346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    }
4928d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4929d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik    public static class VolumeController {
4930d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        private static final String TAG = "VolumeController";
4931d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4932d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        private IVolumeController mController;
493333f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        private boolean mVisible;
493433f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        private long mNextLongPress;
493533f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        private int mLongPressTimeout;
4936d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4937d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void setController(IVolumeController controller) {
4938d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            mController = controller;
493933f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            mVisible = false;
494033f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        }
494133f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
494233f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        public void loadSettings(ContentResolver cr) {
494333f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            mLongPressTimeout = Settings.Secure.getIntForUser(cr,
494433f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
494533f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        }
494633f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
494733f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        public boolean suppressAdjustment(int resolvedStream, int flags) {
494833f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            boolean suppress = false;
494933f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
495033f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                final long now = SystemClock.uptimeMillis();
495133f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
495233f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    // ui will become visible
495333f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    if (mNextLongPress < now) {
495433f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                        mNextLongPress = now + mLongPressTimeout;
495533f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    }
495633f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    suppress = true;
495733f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                } else if (mNextLongPress > 0) {  // in a long-press
495833f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    if (now > mNextLongPress) {
495933f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                        // long press triggered, no more suppression
496033f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                        mNextLongPress = 0;
496133f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    } else {
496233f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                        // keep suppressing until the long press triggers
496333f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                        suppress = true;
496433f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    }
496533f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                }
496633f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            }
496733f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            return suppress;
496833f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        }
496933f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
497033f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        public void setVisible(boolean visible) {
497133f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            mVisible = visible;
4972d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
4973d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4974d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public boolean isSameBinder(IVolumeController controller) {
4975d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            return Objects.equals(asBinder(), binder(controller));
4976d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
4977d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4978d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public IBinder asBinder() {
4979d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            return binder(mController);
4980d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
4981d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4982d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        private static IBinder binder(IVolumeController controller) {
4983d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            return controller == null ? null : controller.asBinder();
4984d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
4985d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4986d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        @Override
4987d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public String toString() {
498833f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
4989d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
4990d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4991d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void postDisplaySafeVolumeWarning(int flags) {
4992d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
4993d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
4994d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
4995d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.displaySafeVolumeWarning(flags);
4996d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
4997d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
4998d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
4999d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5000d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5001d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void postVolumeChanged(int streamType, int flags) {
5002d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
5003d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
5004d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
5005d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.volumeChanged(streamType, flags);
5006d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
5007d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling volumeChanged", e);
5008d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
5009d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5010d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5011d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void postMasterVolumeChanged(int flags) {
5012d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
5013d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
5014d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
5015d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.masterVolumeChanged(flags);
5016d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
5017d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling masterVolumeChanged", e);
5018d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
5019d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5020d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5021d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void postMasterMuteChanged(int flags) {
5022d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
5023d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
5024d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
5025d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.masterMuteChanged(flags);
5026d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
5027d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling masterMuteChanged", e);
5028d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
5029d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5030d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5031d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void setLayoutDirection(int layoutDirection) {
5032d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
5033d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
5034d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
5035d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.setLayoutDirection(layoutDirection);
5036d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
5037d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling setLayoutDirection", e);
5038d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
5039d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5040d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5041d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void postDismiss() {
5042d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
5043d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
5044d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
5045d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.dismiss();
5046d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
5047d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling dismiss", e);
5048d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
5049d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5050d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik    }
5051a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
5052a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    //==========================================================================================
5053a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    // Audio policy management
5054a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    //==========================================================================================
5055a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    public boolean registerAudioPolicy(AudioPolicyConfig policyConfig, IBinder cb) {
5056a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        //Log.v(TAG, "registerAudioPolicy for " + cb + " got policy:" + policyConfig);
5057a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        boolean hasPermissionForPolicy =
5058a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
5059a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                        android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5060a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        if (!hasPermissionForPolicy) {
5061a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
5062a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                    + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
5063a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            return false;
5064a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        }
5065a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        synchronized (mAudioPolicies) {
5066a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, cb);
5067a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            try {
5068a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                cb.linkToDeath(app, 0/*flags*/);
5069a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                mAudioPolicies.put(cb, app);
5070a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            } catch (RemoteException e) {
5071a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                // audio policy owner has already died!
5072a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                Slog.w(TAG, "Audio policy registration failed, could not link to " + cb +
5073a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                        " binder death", e);
5074a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                return false;
5075a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            }
5076a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        }
5077a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        // TODO implement registration with native audio policy (including permission check)
5078a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        return true;
5079a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    }
5080a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    public void unregisterAudioPolicyAsync(IBinder cb) {
5081a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        synchronized (mAudioPolicies) {
5082a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            AudioPolicyProxy app = mAudioPolicies.remove(cb);
5083a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            if (app == null) {
5084a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
5085a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                        + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
5086a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            } else {
5087a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                cb.unlinkToDeath(app, 0/*flags*/);
5088a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            }
5089a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        }
5090a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        // TODO implement registration with native audio policy
5091a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    }
5092a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
5093a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    public class AudioPolicyProxy implements IBinder.DeathRecipient {
5094a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        private static final String TAG = "AudioPolicyProxy";
5095a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        AudioPolicyConfig mConfig;
5096a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        IBinder mToken;
5097a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        AudioPolicyProxy(AudioPolicyConfig config, IBinder token) {
5098a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            mConfig = config;
5099a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            mToken = token;
5100a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        }
5101a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
5102a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        public void binderDied() {
5103a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            synchronized (mAudioPolicies) {
5104a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                Log.v(TAG, "audio policy " + mToken + " died");
5105a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                mAudioPolicies.remove(mToken);
5106a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            }
5107a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        }
5108a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    };
5109a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
5110a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
5111a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            new HashMap<IBinder, AudioPolicyProxy>();
51129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5113