blob: b6b24a4c76815d0fb2a1bcbf048b4833cf920163 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.media;
18
Jeff Sharkey098d5802012-04-26 17:30:34 -070019import static android.Manifest.permission.REMOTE_AUDIO_PLAYBACK;
Amith Yamasanic696a532011-10-28 17:02:37 -070020import static android.media.AudioManager.RINGER_MODE_NORMAL;
21import static android.media.AudioManager.RINGER_MODE_SILENT;
22import static android.media.AudioManager.RINGER_MODE_VIBRATE;
23
Glenn Kastenfd116ad2013-07-12 17:10:39 -070024import android.app.ActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.app.ActivityManagerNative;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -070026import android.app.AppOpsManager;
Amith Yamasani6243edd2011-12-05 19:58:48 -080027import android.app.KeyguardManager;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070028import android.bluetooth.BluetoothA2dp;
29import android.bluetooth.BluetoothAdapter;
30import android.bluetooth.BluetoothClass;
31import android.bluetooth.BluetoothDevice;
32import android.bluetooth.BluetoothHeadset;
33import android.bluetooth.BluetoothProfile;
Nick Pellybd022f42009-08-14 18:33:38 -070034import android.content.BroadcastReceiver;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070035import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.content.ContentResolver;
37import android.content.Context;
38import android.content.Intent;
Eric Laurenta553c252009-07-17 12:17:14 -070039import android.content.IntentFilter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.content.pm.PackageManager;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -070041import android.content.res.Configuration;
Eric Laurente78fced2013-03-15 16:03:47 -070042import android.content.res.Resources;
43import android.content.res.XmlResourceParser;
Jason Parekhb1096152009-03-24 17:48:25 -070044import android.database.ContentObserver;
Jungshik Jang41d97462014-06-30 22:26:29 +090045import android.hardware.hdmi.HdmiControlManager;
Eric Laurent212532b2014-07-21 15:43:18 -070046import android.hardware.hdmi.HdmiPlaybackClient;
Jungshik Jang41d97462014-06-30 22:26:29 +090047import android.hardware.hdmi.HdmiTvClient;
Paul McLeanc837a452014-04-09 09:04:43 -070048import android.hardware.usb.UsbManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.media.MediaPlayer.OnCompletionListener;
50import android.media.MediaPlayer.OnErrorListener;
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -070051import android.media.audiopolicy.AudioMix;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -080052import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070053import android.media.audiopolicy.AudioPolicyConfig;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.os.Binder;
Eric Laurentc18c9132013-04-12 17:24:56 -070055import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.os.Environment;
57import android.os.Handler;
58import android.os.IBinder;
59import android.os.Looper;
60import android.os.Message;
Jean-Michel Trivic6802222012-04-30 11:15:03 -070061import android.os.PowerManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070062import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.os.RemoteException;
John Spurlock33f4e042014-07-11 13:10:58 -040064import android.os.SystemClock;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070065import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070066import android.os.UserHandle;
Eric Laurentbffc3d12012-05-07 17:43:49 -070067import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068import android.provider.Settings;
John Spurlocke5b42d92014-10-15 12:03:48 -040069import android.provider.Settings.Global;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070import android.provider.Settings.System;
Tyler Gunnef9f6f92014-09-12 22:16:17 -070071import android.telecom.TelecomManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070072import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.util.Log;
John Spurlockaa5ee4d2014-07-25 13:05:12 -040074import android.util.MathUtils;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070075import android.util.Slog;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070076import android.view.KeyEvent;
RoboErik519c7742014-11-18 10:59:09 -080077import android.view.OrientationEventListener;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -070078import android.view.Surface;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -070079import android.view.WindowManager;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -070080import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081
Eric Laurente78fced2013-03-15 16:03:47 -070082import com.android.internal.util.XmlUtils;
RoboErik0dac35a2014-08-12 15:48:49 -070083import com.android.server.LocalServices;
Eric Laurente78fced2013-03-15 16:03:47 -070084
85import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -080087import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088import java.io.IOException;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -080089import java.io.PrintWriter;
Eric Laurente78fced2013-03-15 16:03:47 -070090import java.lang.reflect.Field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091import java.util.ArrayList;
Eric Laurentc42ac9d2009-07-29 08:53:03 -070092import java.util.HashMap;
93import java.util.Iterator;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -070094import java.util.List;
Eric Laurentc42ac9d2009-07-29 08:53:03 -070095import java.util.Map;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070096import java.util.NoSuchElementException;
RoboErikd09bd0c2014-06-24 17:45:19 -070097import java.util.Objects;
Eric Laurentc42ac9d2009-07-29 08:53:03 -070098import java.util.Set;
RoboErik519c7742014-11-18 10:59:09 -080099import java.util.concurrent.ConcurrentHashMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100
101/**
102 * The implementation of the volume manager service.
103 * <p>
104 * This implementation focuses on delivering a responsive UI. Most methods are
105 * asynchronous to external calls. For example, the task of setting a volume
106 * will update our internal state, but in a separate thread will set the system
107 * volume and later persist to the database. Similarly, setting the ringer mode
108 * will update the state and broadcast a change and in a separate thread later
109 * persist the ringer mode.
110 *
111 * @hide
112 */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700113public class AudioService extends IAudioService.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114
115 private static final String TAG = "AudioService";
116
Jean-Michel Trivi339567d2014-07-29 09:53:34 -0700117 /** Debug audio mode */
118 protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -0700119
120 /** Debug audio policy feature */
121 protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);
122
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700123 /** Debug volumes */
John Spurlockae641c92014-06-30 18:11:40 -0400124 protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700125
RoboErik430fc482014-06-12 15:49:20 -0700126 /** debug calls to media session apis */
John Spurlockae641c92014-06-30 18:11:40 -0400127 private static final boolean DEBUG_SESSIONS = Log.isLoggable(TAG + ".SESSIONS", Log.DEBUG);
RoboErik8a2cfc32014-05-16 11:19:38 -0700128
John Spurlock86005342014-05-23 11:58:00 -0400129 /** Allow volume changes to set ringer mode to silent? */
130 private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
131
John Spurlocka11b4af2014-06-01 11:52:23 -0400132 /** In silent mode, are volume adjustments (raises) prevented? */
133 private static final boolean PREVENT_VOLUME_ADJUSTMENT_IF_SILENT = true;
134
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 /** How long to delay before persisting a change in volume/ringer mode. */
RoboErik45edba12012-03-27 17:54:36 -0700136 private static final int PERSIST_DELAY = 500;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137
John Spurlock3346a802014-05-20 16:25:37 -0400138 /**
139 * The delay before playing a sound. This small period exists so the user
140 * can press another key (non-volume keys, too) to have it NOT be audible.
141 * <p>
142 * PhoneWindow will implement this part.
143 */
144 public static final int PLAY_SOUND_DELAY = 300;
145
John Spurlocka11b4af2014-06-01 11:52:23 -0400146 /**
147 * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
148 */
149 private static final int FLAG_ADJUST_VOLUME = 1;
150
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700151 private final Context mContext;
152 private final ContentResolver mContentResolver;
153 private final AppOpsManager mAppOps;
Eric Laurent212532b2014-07-21 15:43:18 -0700154
155 // the platform has no specific capabilities
156 private static final int PLATFORM_DEFAULT = 0;
157 // the platform is voice call capable (a phone)
158 private static final int PLATFORM_VOICE = 1;
159 // the platform is a television or a set-top box
160 private static final int PLATFORM_TELEVISION = 2;
161 // the platform type affects volume and silent mode behavior
162 private final int mPlatformType;
163
164 private boolean isPlatformVoice() {
165 return mPlatformType == PLATFORM_VOICE;
166 }
167
168 private boolean isPlatformTelevision() {
169 return mPlatformType == PLATFORM_TELEVISION;
170 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800171
John Spurlock3346a802014-05-20 16:25:37 -0400172 /** The controller for the volume UI. */
173 private final VolumeController mVolumeController = new VolumeController();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174
175 // sendMsg() flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176 /** If the msg is already queued, replace it with this one. */
177 private static final int SENDMSG_REPLACE = 0;
178 /** If the msg is already queued, ignore this one and leave the old. */
179 private static final int SENDMSG_NOOP = 1;
180 /** If the msg is already queued, queue this one and leave the old. */
181 private static final int SENDMSG_QUEUE = 2;
182
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700183 // AudioHandler messages
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800184 private static final int MSG_SET_DEVICE_VOLUME = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 private static final int MSG_PERSIST_VOLUME = 1;
Mike Lockwood5c55a052011-12-15 17:21:44 -0500186 private static final int MSG_PERSIST_MASTER_VOLUME = 2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 private static final int MSG_PERSIST_RINGER_MODE = 3;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700188 private static final int MSG_MEDIA_SERVER_DIED = 4;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700189 private static final int MSG_PLAY_SOUND_EFFECT = 5;
190 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
191 private static final int MSG_LOAD_SOUND_EFFECTS = 7;
192 private static final int MSG_SET_FORCE_USE = 8;
193 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
194 private static final int MSG_SET_ALL_VOLUMES = 10;
195 private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
196 private static final int MSG_REPORT_NEW_ROUTES = 12;
197 private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
198 private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
199 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
200 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
201 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
202 private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
203 private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
204 private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700205 private static final int MSG_SYSTEM_READY = 21;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400206 private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
Julia Reynoldsb53453f2014-08-22 11:42:43 -0400207 private static final int MSG_PERSIST_MICROPHONE_MUTE = 23;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700208 // start of messages handled under wakelock
209 // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
Jean-Michel Trivie12c39b2012-06-06 10:51:58 -0700210 // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700211 private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
Mike Lockwood0a40ec22014-05-21 10:08:50 -0700212 private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
213 private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700214 // end of messages handled under wakelock
Eric Laurentafbb0472011-12-15 09:04:23 -0800215
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -0700216 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
Eric Laurentdc03c612011-04-01 10:59:41 -0700217 // Timeout for connection to bluetooth headset service
218 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 /** @see AudioSystemThread */
221 private AudioSystemThread mAudioSystemThread;
222 /** @see AudioHandler */
223 private AudioHandler mAudioHandler;
224 /** @see VolumeStreamState */
225 private VolumeStreamState[] mStreamStates;
Jason Parekhb1096152009-03-24 17:48:25 -0700226 private SettingsObserver mSettingsObserver;
Eric Laurenta553c252009-07-17 12:17:14 -0700227
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700228 private int mMode = AudioSystem.MODE_NORMAL;
Glenn Kastenba195eb2011-12-13 09:30:40 -0800229 // protects mRingerMode
230 private final Object mSettingsLock = new Object();
Eric Laurent45c90ce2012-04-24 18:44:22 -0700231
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232 private SoundPool mSoundPool;
Glenn Kasten30c918c2011-11-10 17:56:41 -0800233 private final Object mSoundEffectsLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 private static final int NUM_SOUNDPOOL_CHANNELS = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235
Mike Lockwood47676902011-11-08 10:31:21 -0800236 // Internally master volume is a float in the 0.0 - 1.0 range,
237 // but to support integer based AudioManager API we translate it to 0 - 100
238 private static final int MAX_MASTER_VOLUME = 100;
239
Lei Zhang6c798972012-03-02 11:40:12 -0800240 // Maximum volume adjust steps allowed in a single batch call.
241 private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 /* Sound effect file names */
244 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
Eric Laurente78fced2013-03-15 16:03:47 -0700245 private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246
247 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
248 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
249 * uses soundpool (second column) */
Eric Laurente78fced2013-03-15 16:03:47 -0700250 private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251
Jared Suttles59820132009-08-13 21:50:52 -0500252 /** @hide Maximum volume index values for audio streams */
Eric Laurent91377de2014-10-10 15:24:04 -0700253 private static int[] MAX_STREAM_VOLUME = new int[] {
Eric Laurent6ee99522009-08-25 06:30:59 -0700254 5, // STREAM_VOICE_CALL
255 7, // STREAM_SYSTEM
256 7, // STREAM_RING
257 15, // STREAM_MUSIC
258 7, // STREAM_ALARM
259 7, // STREAM_NOTIFICATION
260 15, // STREAM_BLUETOOTH_SCO
261 7, // STREAM_SYSTEM_ENFORCED
262 15, // STREAM_DTMF
263 15 // STREAM_TTS
Jared Suttles59820132009-08-13 21:50:52 -0500264 };
Eric Laurent91377de2014-10-10 15:24:04 -0700265
266 private static int[] DEFAULT_STREAM_VOLUME = new int[] {
267 4, // STREAM_VOICE_CALL
268 7, // STREAM_SYSTEM
269 5, // STREAM_RING
270 11, // STREAM_MUSIC
271 6, // STREAM_ALARM
272 5, // STREAM_NOTIFICATION
273 7, // STREAM_BLUETOOTH_SCO
274 7, // STREAM_SYSTEM_ENFORCED
275 11, // STREAM_DTMF
276 11 // STREAM_TTS
277 };
278
Eric Laurent6d517662012-04-23 18:42:39 -0700279 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
Eric Laurenta553c252009-07-17 12:17:14 -0700280 * of another stream: This avoids multiplying the volume settings for hidden
281 * stream types that follow other stream behavior for volume settings
Eric Laurent6d517662012-04-23 18:42:39 -0700282 * NOTE: do not create loops in aliases!
283 * Some streams alias to different streams according to device category (phone or tablet) or
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700284 * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
Eric Laurent212532b2014-07-21 15:43:18 -0700285 * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
286 * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
287 * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
288 private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700289 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
290 AudioSystem.STREAM_RING, // STREAM_SYSTEM
291 AudioSystem.STREAM_RING, // STREAM_RING
292 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
293 AudioSystem.STREAM_ALARM, // STREAM_ALARM
294 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
295 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
296 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
297 AudioSystem.STREAM_RING, // STREAM_DTMF
298 AudioSystem.STREAM_MUSIC // STREAM_TTS
Eric Laurenta553c252009-07-17 12:17:14 -0700299 };
Eric Laurent212532b2014-07-21 15:43:18 -0700300 private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
301 AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL
302 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
303 AudioSystem.STREAM_MUSIC, // STREAM_RING
304 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
305 AudioSystem.STREAM_MUSIC, // STREAM_ALARM
306 AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
307 AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO
308 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
309 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
310 AudioSystem.STREAM_MUSIC // STREAM_TTS
311 };
312 private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700313 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
John Spurlock4f0f1202014-08-05 13:28:33 -0400314 AudioSystem.STREAM_RING, // STREAM_SYSTEM
Eric Laurent6d517662012-04-23 18:42:39 -0700315 AudioSystem.STREAM_RING, // STREAM_RING
316 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
317 AudioSystem.STREAM_ALARM, // STREAM_ALARM
318 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
319 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
John Spurlock4f0f1202014-08-05 13:28:33 -0400320 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
321 AudioSystem.STREAM_RING, // STREAM_DTMF
Eric Laurent6d517662012-04-23 18:42:39 -0700322 AudioSystem.STREAM_MUSIC // STREAM_TTS
323 };
324 private int[] mStreamVolumeAlias;
Eric Laurenta553c252009-07-17 12:17:14 -0700325
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700326 /**
327 * Map AudioSystem.STREAM_* constants to app ops. This should be used
328 * after mapping through mStreamVolumeAlias.
329 */
330 private static final int[] STEAM_VOLUME_OPS = new int[] {
331 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL
332 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM
333 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING
334 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC
335 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM
336 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION
337 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO
338 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED
339 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF
340 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS
341 };
342
Eric Laurent83a017b2013-03-19 18:15:31 -0700343 private final boolean mUseFixedVolume;
344
Eric Laurentbffc3d12012-05-07 17:43:49 -0700345 // stream names used by dumpStreamStates()
John Spurlock1af30c72014-03-10 08:33:35 -0400346 private static final String[] STREAM_NAMES = new String[] {
Eric Laurentbffc3d12012-05-07 17:43:49 -0700347 "STREAM_VOICE_CALL",
348 "STREAM_SYSTEM",
349 "STREAM_RING",
350 "STREAM_MUSIC",
351 "STREAM_ALARM",
352 "STREAM_NOTIFICATION",
353 "STREAM_BLUETOOTH_SCO",
354 "STREAM_SYSTEM_ENFORCED",
355 "STREAM_DTMF",
356 "STREAM_TTS"
357 };
358
Glenn Kasten30c918c2011-11-10 17:56:41 -0800359 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 public void onError(int error) {
361 switch (error) {
362 case AudioSystem.AUDIO_STATUS_SERVER_DIED:
Eric Laurentdfb881f2013-07-18 14:41:39 -0700363 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
364 SENDMSG_NOOP, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 break;
366 default:
367 break;
368 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700369 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 };
371
372 /**
373 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
374 * {@link AudioManager#RINGER_MODE_SILENT}, or
375 * {@link AudioManager#RINGER_MODE_VIBRATE}.
376 */
Glenn Kastenba195eb2011-12-13 09:30:40 -0800377 // protected by mSettingsLock
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 private int mRingerMode;
379
Eric Laurent9bcf4012009-06-12 06:09:28 -0700380 /** @see System#MODE_RINGER_STREAMS_AFFECTED */
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700381 private int mRingerModeAffectedStreams = 0;
Eric Laurent9bcf4012009-06-12 06:09:28 -0700382
Eric Laurent5b4e6542010-03-19 20:02:21 -0700383 // Streams currently muted by ringer mode
384 private int mRingerModeMutedStreams;
385
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 /** @see System#MUTE_STREAMS_AFFECTED */
387 private int mMuteAffectedStreams;
388
389 /**
Eric Laurentbffc3d12012-05-07 17:43:49 -0700390 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
391 * mVibrateSetting is just maintained during deprecation period but vibration policy is
392 * now only controlled by mHasVibrator and mRingerMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 */
394 private int mVibrateSetting;
395
Eric Laurentbffc3d12012-05-07 17:43:49 -0700396 // Is there a vibrator
397 private final boolean mHasVibrator;
398
Eric Laurenta553c252009-07-17 12:17:14 -0700399 // Broadcast receiver for device connections intent broadcasts
400 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
401
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700402 // Devices currently connected
Glenn Kasten30c918c2011-11-10 17:56:41 -0800403 private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700404
405 // Forced device usage for communications
406 private int mForcedUseForComm;
407
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500408 // True if we have master volume support
409 private final boolean mUseMasterVolume;
410
Mike Lockwood97606472012-02-09 11:24:10 -0800411 private final int[] mMasterVolumeRamp;
412
Eric Laurent9272b4b2010-01-23 17:12:59 -0800413 // List of binder death handlers for setMode() client processes.
414 // The last process to have called setMode() is at the top of the list.
Glenn Kasten30c918c2011-11-10 17:56:41 -0800415 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
Eric Laurenteb14a782009-12-17 03:12:59 -0800416
Eric Laurent3def1ee2010-03-17 23:26:26 -0700417 // List of clients having issued a SCO start request
Glenn Kasten30c918c2011-11-10 17:56:41 -0800418 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
Eric Laurent3def1ee2010-03-17 23:26:26 -0700419
420 // BluetoothHeadset API to control SCO connection
421 private BluetoothHeadset mBluetoothHeadset;
422
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700423 // Bluetooth headset device
424 private BluetoothDevice mBluetoothHeadsetDevice;
Eric Laurent3def1ee2010-03-17 23:26:26 -0700425
Eric Laurent62ef7672010-11-24 10:58:32 -0800426 // Indicate if SCO audio connection is currently active and if the initiator is
427 // audio service (internal) or bluetooth headset (external)
428 private int mScoAudioState;
429 // SCO audio state is not active
430 private static final int SCO_STATE_INACTIVE = 0;
Eric Laurentdc03c612011-04-01 10:59:41 -0700431 // SCO audio activation request waiting for headset service to connect
432 private static final int SCO_STATE_ACTIVATE_REQ = 1;
Eric Laurent25fc29b2013-04-05 12:13:54 -0700433 // SCO audio state is active or starting due to a request from AudioManager API
Eric Laurentdc03c612011-04-01 10:59:41 -0700434 private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
435 // SCO audio deactivation request waiting for headset service to connect
436 private static final int SCO_STATE_DEACTIVATE_REQ = 5;
437
Eric Laurent62ef7672010-11-24 10:58:32 -0800438 // SCO audio state is active due to an action in BT handsfree (either voice recognition or
439 // in call audio)
440 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
Eric Laurentdc03c612011-04-01 10:59:41 -0700441 // Deactivation request for all SCO connections (initiated by audio mode change)
442 // waiting for headset service to connect
443 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
444
Eric Laurentc18c9132013-04-12 17:24:56 -0700445 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
446 // originated from an app targeting an API version before JB MR2 and raw audio after that.
447 private int mScoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -0700448 // SCO audio mode is undefined
449 private static final int SCO_MODE_UNDEFINED = -1;
Eric Laurentc18c9132013-04-12 17:24:56 -0700450 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
451 private static final int SCO_MODE_VIRTUAL_CALL = 0;
452 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
453 private static final int SCO_MODE_RAW = 1;
Liejun Taof4e51d82014-07-16 11:18:29 -0700454 // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
455 private static final int SCO_MODE_VR = 2;
456
457 private static final int SCO_MODE_MAX = 2;
Eric Laurentc18c9132013-04-12 17:24:56 -0700458
Eric Laurentdc03c612011-04-01 10:59:41 -0700459 // Current connection state indicated by bluetooth headset
460 private int mScoConnectionState;
Eric Laurent62ef7672010-11-24 10:58:32 -0800461
Eric Laurenta60e2122010-12-28 16:49:07 -0800462 // true if boot sequence has been completed
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700463 private boolean mSystemReady;
Eric Laurenta60e2122010-12-28 16:49:07 -0800464 // listener for SoundPool sample load completion indication
465 private SoundPoolCallback mSoundPoolCallBack;
466 // thread for SoundPool listener
467 private SoundPoolListenerThread mSoundPoolListenerThread;
468 // message looper for SoundPool listener
469 private Looper mSoundPoolLooper = null;
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700470 // volume applied to sound played with playSoundEffect()
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700471 private static int sSoundEffectVolumeDb;
Eric Laurent25101b02011-02-02 09:33:30 -0800472 // previous volume adjustment direction received by checkForRingerModeChange()
473 private int mPrevVolDirection = AudioManager.ADJUST_SAME;
Amith Yamasani6243edd2011-12-05 19:58:48 -0800474 // Keyguard manager proxy
475 private KeyguardManager mKeyguardManager;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700476 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
477 // is controlled by Vol keys.
478 private int mVolumeControlStream = -1;
479 private final Object mForceControlStreamLock = new Object();
480 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
481 // server process so in theory it is not necessary to monitor the client death.
482 // However it is good to be ready for future evolutions.
483 private ForceControlStreamClient mForceControlStreamClient = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700484 // Used to play ringtones outside system_server
485 private volatile IRingtonePlayer mRingtonePlayer;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800486
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700487 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700488 private int mDeviceRotation = Surface.ROTATION_0;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700489
Eric Laurent78472112012-05-21 08:57:21 -0700490 // Request to override default use of A2DP for media.
491 private boolean mBluetoothA2dpEnabled;
492 private final Object mBluetoothA2dpEnabledLock = new Object();
493
Dianne Hackborn632ca412012-06-14 19:34:10 -0700494 // Monitoring of audio routes. Protected by mCurAudioRoutes.
495 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
496 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
497 = new RemoteCallbackList<IAudioRoutesObserver>();
498
Eric Laurent4bbcc652012-09-24 14:26:30 -0700499 // Devices for which the volume is fixed and VolumePanel slider should be disabled
Eric Laurent212532b2014-07-21 15:43:18 -0700500 int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700501 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Eric Laurent212532b2014-07-21 15:43:18 -0700502 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
503 AudioSystem.DEVICE_OUT_HDMI_ARC |
504 AudioSystem.DEVICE_OUT_SPDIF |
505 AudioSystem.DEVICE_OUT_AUX_LINE;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700506 int mFullVolumeDevices = 0;
Eric Laurent4bbcc652012-09-24 14:26:30 -0700507
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700508 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700509 private final boolean mMonitorOrientation;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700510 private final boolean mMonitorRotation;
Eric Laurentd640bd32012-09-28 18:01:48 -0700511
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700512 private boolean mDockAudioMediaEnabled = true;
513
Eric Laurent08ed1b92012-11-05 14:54:12 -0800514 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
515
Eric Laurentfde16d52012-12-03 14:42:39 -0800516 // Used when safe volume warning message display is requested by setStreamVolume(). In this
517 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
518 // and used later when/if disableSafeMediaVolume() is called.
519 private StreamVolumeCommand mPendingVolumeCommand;
520
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700521 private PowerManager.WakeLock mAudioEventWakeLock;
522
523 private final MediaFocusControl mMediaFocusControl;
524
John Du5a0cf7a2013-07-19 11:30:34 -0700525 // Reference to BluetoothA2dp to query for AbsoluteVolume.
526 private BluetoothA2dp mA2dp;
527 private final Object mA2dpAvrcpLock = new Object();
528 // If absolute volume is supported in AVRCP device
529 private boolean mAvrcpAbsVolSupported = false;
530
Jon Eklund318f0fe2014-01-23 17:53:48 -0600531 private AudioOrientationEventListener mOrientationListener;
532
Eric Laurentadbe8bf2014-11-03 18:26:32 -0800533 private static Long mLastDeviceConnectMsgTime = new Long(0);
534
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 ///////////////////////////////////////////////////////////////////////////
536 // Construction
537 ///////////////////////////////////////////////////////////////////////////
538
539 /** @hide */
540 public AudioService(Context context) {
541 mContext = context;
542 mContentResolver = context.getContentResolver();
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700543 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700544
545 if (mContext.getResources().getBoolean(
546 com.android.internal.R.bool.config_voice_capable)) {
547 mPlatformType = PLATFORM_VOICE;
548 } else if (context.getPackageManager().hasSystemFeature(
549 PackageManager.FEATURE_TELEVISION)) {
550 mPlatformType = PLATFORM_TELEVISION;
551 } else {
552 mPlatformType = PLATFORM_DEFAULT;
553 }
Jared Suttles59820132009-08-13 21:50:52 -0500554
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700555 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700556 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700557
Eric Laurentbffc3d12012-05-07 17:43:49 -0700558 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
559 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
560
Jared Suttles59820132009-08-13 21:50:52 -0500561 // Intialized volume
Eric Laurent91377de2014-10-10 15:24:04 -0700562 int maxVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps",
563 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
564 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
565 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
566 DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
567 }
568 maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
569 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
570 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
571 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
572 DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
573 }
Jared Suttles59820132009-08-13 21:50:52 -0500574
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700575 sSoundEffectVolumeDb = context.getResources().getInteger(
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700576 com.android.internal.R.integer.config_soundEffectVolumeDb);
Eric Laurent25101b02011-02-02 09:33:30 -0800577
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700578 mForcedUseForComm = AudioSystem.FORCE_NONE;
Eric Laurentdd45d012012-10-08 09:04:34 -0700579
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 createAudioSystemThread();
Eric Laurentdd45d012012-10-08 09:04:34 -0700581
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700582 mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
John Spurlock3346a802014-05-20 16:25:37 -0400583 mContext, mVolumeController, this);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700584
Eric Laurentdfb881f2013-07-18 14:41:39 -0700585 AudioSystem.setErrorCallback(mAudioSystemCallback);
586
Eric Laurentdd45d012012-10-08 09:04:34 -0700587 boolean cameraSoundForced = mContext.getResources().getBoolean(
588 com.android.internal.R.bool.config_camera_sound_forced);
589 mCameraSoundForced = new Boolean(cameraSoundForced);
590 sendMsg(mAudioHandler,
591 MSG_SET_FORCE_USE,
592 SENDMSG_QUEUE,
593 AudioSystem.FOR_SYSTEM,
594 cameraSoundForced ?
595 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
596 null,
597 0);
598
Eric Laurent05274f32012-11-29 12:48:18 -0800599 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
600 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
601 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
602 // The default safe volume index read here will be replaced by the actual value when
603 // the mcc is read by onConfigureSafeVolume()
604 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
605 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
606
Eric Laurent83a017b2013-03-19 18:15:31 -0700607 mUseFixedVolume = mContext.getResources().getBoolean(
608 com.android.internal.R.bool.config_useFixedVolume);
609
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700610 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
611 // array initialized by updateStreamVolumeAlias()
612 updateStreamVolumeAlias(false /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 readPersistedSettings();
Eric Laurentc1d41662011-07-19 11:21:13 -0700614 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700615 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700616
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700617 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700618
619 // Call setRingerModeInt() to apply correct mute
620 // state on streams affected by ringer mode.
621 mRingerModeMutedStreams = 0;
622 setRingerModeInt(getRingerMode(), false);
623
Eric Laurenta553c252009-07-17 12:17:14 -0700624 // Register for device connection intent broadcasts.
625 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700626 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700627 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
628 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700629 intentFilter.addAction(AudioManager.ACTION_USB_AUDIO_ACCESSORY_PLUG);
630 intentFilter.addAction(AudioManager.ACTION_USB_AUDIO_DEVICE_PLUG);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700631 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
632 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700633 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Paul McLeanc837a452014-04-09 09:04:43 -0700634 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700635
Eric Laurentd640bd32012-09-28 18:01:48 -0700636 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700637 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700638 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
639 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700640 Log.v(TAG, "monitoring device orientation");
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700641 // initialize orientation in AudioSystem
642 setOrientationForAudioSystem();
643 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700644 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
645 if (mMonitorRotation) {
646 mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
647 .getDefaultDisplay().getRotation();
648 Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
Jon Eklund318f0fe2014-01-23 17:53:48 -0600649
650 mOrientationListener = new AudioOrientationEventListener(mContext);
651 mOrientationListener.enable();
652
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700653 // initialize rotation in AudioSystem
654 setRotationForAudioSystem();
655 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700656
Eric Laurenta553c252009-07-17 12:17:14 -0700657 context.registerReceiver(mReceiver, intentFilter);
Jared Suttles59820132009-08-13 21:50:52 -0500658
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500659 mUseMasterVolume = context.getResources().getBoolean(
660 com.android.internal.R.bool.config_useMasterVolume);
Mike Lockwood90631542012-01-06 11:20:37 -0500661 restoreMasterVolume();
Mike Lockwood97606472012-02-09 11:24:10 -0800662
663 mMasterVolumeRamp = context.getResources().getIntArray(
664 com.android.internal.R.array.config_masterVolumeRamp);
Eric Laurent78472112012-05-21 08:57:21 -0700665
RoboErik0dac35a2014-08-12 15:48:49 -0700666 LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 }
668
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700669 public void systemReady() {
670 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
671 0, 0, null, 0);
672 }
673
674 public void onSystemReady() {
675 mSystemReady = true;
676 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
677 0, 0, null, 0);
678
679 mKeyguardManager =
680 (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
681 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
682 resetBluetoothSco();
683 getBluetoothHeadset();
684 //FIXME: this is to maintain compatibility with deprecated intent
685 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
686 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
687 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
688 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
689 sendStickyBroadcastToAll(newIntent);
690
691 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
692 if (adapter != null) {
693 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
694 BluetoothProfile.A2DP);
695 }
696
Eric Laurent212532b2014-07-21 15:43:18 -0700697 mHdmiManager =
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900698 (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700699 if (mHdmiManager != null) {
700 synchronized (mHdmiManager) {
701 mHdmiTvClient = mHdmiManager.getTvClient();
Jungshik Jangc9ff9682014-09-15 17:41:06 +0900702 if (mHdmiTvClient != null) {
703 mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
704 }
Eric Laurent212532b2014-07-21 15:43:18 -0700705 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
706 mHdmiCecSink = false;
707 }
708 }
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900709
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700710 sendMsg(mAudioHandler,
711 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
712 SENDMSG_REPLACE,
713 0,
714 0,
715 null,
716 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700717
718 StreamOverride.init(mContext);
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700719 }
720
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 private void createAudioSystemThread() {
722 mAudioSystemThread = new AudioSystemThread();
723 mAudioSystemThread.start();
724 waitForAudioHandlerCreation();
725 }
726
727 /** Waits for the volume handler to be created by the other thread. */
728 private void waitForAudioHandlerCreation() {
729 synchronized(this) {
730 while (mAudioHandler == null) {
731 try {
732 // Wait for mAudioHandler to be set by the other thread
733 wait();
734 } catch (InterruptedException e) {
735 Log.e(TAG, "Interrupted while waiting on volume handler.");
736 }
737 }
738 }
739 }
740
Eric Laurent24482012012-05-10 09:41:17 -0700741 private void checkAllAliasStreamVolumes() {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700742 synchronized (VolumeStreamState.class) {
743 int numStreamTypes = AudioSystem.getNumStreamTypes();
744 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
745 if (streamType != mStreamVolumeAlias[streamType]) {
746 mStreamStates[streamType].
Eric Laurent42b041e2013-03-29 11:36:03 -0700747 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700748 }
749 // apply stream volume
750 if (!mStreamStates[streamType].isMuted_syncVSS()) {
751 mStreamStates[streamType].applyAllVolumes();
752 }
Eric Laurent24482012012-05-10 09:41:17 -0700753 }
754 }
755 }
756
Eric Laurent212532b2014-07-21 15:43:18 -0700757 private void checkAllFixedVolumeDevices()
758 {
759 int numStreamTypes = AudioSystem.getNumStreamTypes();
760 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
761 mStreamStates[streamType].checkFixedVolumeDevices();
762 }
763 }
764
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700765 private void checkAllFixedVolumeDevices(int streamType) {
766 mStreamStates[streamType].checkFixedVolumeDevices();
767 }
768
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 int numStreamTypes = AudioSystem.getNumStreamTypes();
771 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
772
773 for (int i = 0; i < numStreamTypes; i++) {
Eric Laurent6d517662012-04-23 18:42:39 -0700774 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -0700775 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776
Eric Laurent212532b2014-07-21 15:43:18 -0700777 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -0700778 checkAllAliasStreamVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800779 }
780
Eric Laurentbffc3d12012-05-07 17:43:49 -0700781 private void dumpStreamStates(PrintWriter pw) {
782 pw.println("\nStream volumes (device: index)");
783 int numStreamTypes = AudioSystem.getNumStreamTypes();
784 for (int i = 0; i < numStreamTypes; i++) {
785 pw.println("- "+STREAM_NAMES[i]+":");
786 mStreamStates[i].dump(pw);
787 pw.println("");
788 }
Eric Laurentdd45d012012-10-08 09:04:34 -0700789 pw.print("\n- mute affected streams = 0x");
790 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -0700791 }
792
John Spurlock1af30c72014-03-10 08:33:35 -0400793 /** @hide */
794 public static String streamToString(int stream) {
795 if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream];
796 if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE";
797 return "UNKNOWN_STREAM_" + stream;
798 }
Eric Laurent6d517662012-04-23 18:42:39 -0700799
800 private void updateStreamVolumeAlias(boolean updateVolumes) {
801 int dtmfStreamAlias;
Eric Laurent212532b2014-07-21 15:43:18 -0700802
803 switch (mPlatformType) {
804 case PLATFORM_VOICE:
805 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
Eric Laurent6d517662012-04-23 18:42:39 -0700806 dtmfStreamAlias = AudioSystem.STREAM_RING;
Eric Laurent212532b2014-07-21 15:43:18 -0700807 break;
808 case PLATFORM_TELEVISION:
809 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
810 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
811 break;
812 default:
813 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
Eric Laurent6d517662012-04-23 18:42:39 -0700814 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
815 }
Eric Laurent212532b2014-07-21 15:43:18 -0700816
817 if (isPlatformTelevision()) {
818 mRingerModeAffectedStreams = 0;
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700819 } else {
Eric Laurent212532b2014-07-21 15:43:18 -0700820 if (isInCommunication()) {
821 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
822 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
823 } else {
824 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
825 }
Eric Laurent6d517662012-04-23 18:42:39 -0700826 }
Eric Laurent212532b2014-07-21 15:43:18 -0700827
Eric Laurent6d517662012-04-23 18:42:39 -0700828 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
829 if (updateVolumes) {
Eric Laurent42b041e2013-03-29 11:36:03 -0700830 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700831 // apply stream mute states according to new value of mRingerModeAffectedStreams
832 setRingerModeInt(getRingerMode(), false);
Eric Laurent6d517662012-04-23 18:42:39 -0700833 sendMsg(mAudioHandler,
834 MSG_SET_ALL_VOLUMES,
835 SENDMSG_QUEUE,
836 0,
837 0,
838 mStreamStates[AudioSystem.STREAM_DTMF], 0);
839 }
840 }
841
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700842 private void readDockAudioSettings(ContentResolver cr)
843 {
844 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -0700845 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700846
847 if (mDockAudioMediaEnabled) {
848 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
849 } else {
850 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
851 }
852
853 sendMsg(mAudioHandler,
854 MSG_SET_FORCE_USE,
855 SENDMSG_QUEUE,
856 AudioSystem.FOR_DOCK,
857 mDockAudioMediaEnabled ?
858 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
859 null,
860 0);
861 }
862
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800863 private void readPersistedSettings() {
864 final ContentResolver cr = mContentResolver;
865
Eric Laurentbffc3d12012-05-07 17:43:49 -0700866 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700867 Settings.Global.getInt(
868 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -0700869 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -0700870 // sanity check in case the settings are restored from a device with incompatible
871 // ringer modes
John Spurlock97559372014-10-24 16:27:36 -0400872 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -0800873 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700874 }
875 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
876 ringerMode = AudioManager.RINGER_MODE_SILENT;
877 }
878 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700879 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -0800880 }
Eric Laurent212532b2014-07-21 15:43:18 -0700881 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -0700882 ringerMode = AudioManager.RINGER_MODE_NORMAL;
883 }
Glenn Kastenba195eb2011-12-13 09:30:40 -0800884 synchronized(mSettingsLock) {
885 mRingerMode = ringerMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800886
Eric Laurentdd45d012012-10-08 09:04:34 -0700887 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
888 // are still needed while setVibrateSetting() and getVibrateSetting() are being
889 // deprecated.
890 mVibrateSetting = getValueForVibrateSetting(0,
891 AudioManager.VIBRATE_TYPE_NOTIFICATION,
892 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
893 : AudioManager.VIBRATE_SETTING_OFF);
894 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
895 AudioManager.VIBRATE_TYPE_RINGER,
896 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
897 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800898
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700899 updateRingerModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700900 readDockAudioSettings(cr);
Eric Laurent402f7f22011-02-04 12:30:32 -0800901 }
Eric Laurentc1d41662011-07-19 11:21:13 -0700902
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700903 mMuteAffectedStreams = System.getIntForUser(cr,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 System.MUTE_STREAMS_AFFECTED,
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700905 ((1 << AudioSystem.STREAM_MUSIC)|
906 (1 << AudioSystem.STREAM_RING)|
907 (1 << AudioSystem.STREAM_SYSTEM)),
908 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800909
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700910 boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
911 0, UserHandle.USER_CURRENT) == 1;
Eric Laurent83a017b2013-03-19 18:15:31 -0700912 if (mUseFixedVolume) {
913 masterMute = false;
914 AudioSystem.setMasterVolume(1.0f);
915 }
Justin Koh57978ed2012-04-03 17:37:58 -0700916 AudioSystem.setMasterMute(masterMute);
917 broadcastMasterMuteStatus(masterMute);
918
Julia Reynoldsb53453f2014-08-22 11:42:43 -0400919 boolean microphoneMute =
920 System.getIntForUser(cr, System.MICROPHONE_MUTE, 0, UserHandle.USER_CURRENT) == 1;
921 AudioSystem.muteMicrophone(microphoneMute);
922
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923 // Each stream will read its own persisted settings
924
925 // Broadcast the sticky intent
Glenn Kastenba195eb2011-12-13 09:30:40 -0800926 broadcastRingerMode(ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800927
928 // Broadcast vibrate settings
929 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
930 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -0700931
John Spurlock33f4e042014-07-11 13:10:58 -0400932 // Load settings for the volume controller
933 mVolumeController.loadSettings(cr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800934 }
935
Eric Laurenta553c252009-07-17 12:17:14 -0700936 private int rescaleIndex(int index, int srcStream, int dstStream) {
937 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
938 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800939
Jon Eklund318f0fe2014-01-23 17:53:48 -0600940 private class AudioOrientationEventListener
941 extends OrientationEventListener {
942 public AudioOrientationEventListener(Context context) {
943 super(context);
944 }
945
946 @Override
947 public void onOrientationChanged(int orientation) {
948 //Even though we're responding to phone orientation events,
949 //use display rotation so audio stays in sync with video/dialogs
950 int newRotation = ((WindowManager) mContext.getSystemService(
951 Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
952 if (newRotation != mDeviceRotation) {
953 mDeviceRotation = newRotation;
954 setRotationForAudioSystem();
955 }
956 }
957 }
958
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800959 ///////////////////////////////////////////////////////////////////////////
960 // IPC methods
961 ///////////////////////////////////////////////////////////////////////////
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962 /** @see AudioManager#adjustVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700963 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
964 String callingPackage) {
RoboErik272e1612014-09-05 11:39:29 -0700965 adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
966 Binder.getCallingUid());
967 }
968
969 private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
970 String callingPackage, int uid) {
John Spurlockae641c92014-06-30 18:11:40 -0400971 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType
972 + ", flags=" + flags);
Eric Laurent402f7f22011-02-04 12:30:32 -0800973 int streamType;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700974 if (mVolumeControlStream != -1) {
975 streamType = mVolumeControlStream;
Eric Laurent402f7f22011-02-04 12:30:32 -0800976 } else {
977 streamType = getActiveStreamType(suggestedStreamType);
978 }
John Spurlock33f4e042014-07-11 13:10:58 -0400979 final int resolvedStream = mStreamVolumeAlias[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980
RoboErik2811dd32014-08-12 09:48:13 -0700981 // Play sounds on STREAM_RING only.
982 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
John Spurlock33f4e042014-07-11 13:10:58 -0400983 resolvedStream != AudioSystem.STREAM_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 flags &= ~AudioManager.FLAG_PLAY_SOUND;
985 }
986
John Spurlock33f4e042014-07-11 13:10:58 -0400987 // For notifications/ring, show the ui before making any adjustments
988 if (mVolumeController.suppressAdjustment(resolvedStream, flags)) {
989 direction = 0;
990 flags &= ~AudioManager.FLAG_PLAY_SOUND;
991 flags &= ~AudioManager.FLAG_VIBRATE;
992 if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
993 }
994
RoboErik272e1612014-09-05 11:39:29 -0700995 adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 }
997
998 /** @see AudioManager#adjustStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700999 public void adjustStreamVolume(int streamType, int direction, int flags,
1000 String callingPackage) {
RoboErik0dac35a2014-08-12 15:48:49 -07001001 adjustStreamVolume(streamType, direction, flags, callingPackage, Binder.getCallingUid());
1002 }
1003
1004 private void adjustStreamVolume(int streamType, int direction, int flags,
1005 String callingPackage, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001006 if (mUseFixedVolume) {
1007 return;
1008 }
John Spurlockae641c92014-06-30 18:11:40 -04001009 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction
1010 + ", flags="+flags);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07001011
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 ensureValidDirection(direction);
1013 ensureValidStreamType(streamType);
1014
Eric Laurent96a33d12011-11-08 10:31:57 -08001015 // use stream type alias here so that streams with same alias have the same behavior,
1016 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
1017 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
Eric Laurent6d517662012-04-23 18:42:39 -07001018 int streamTypeAlias = mStreamVolumeAlias[streamType];
Eric Laurentb024c302011-10-14 17:19:27 -07001019 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001020
1021 final int device = getDeviceForStream(streamTypeAlias);
Eric Laurent3ef75492012-11-28 12:12:23 -08001022
Eric Laurent42b041e2013-03-29 11:36:03 -07001023 int aliasIndex = streamState.getIndex(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024 boolean adjustVolume = true;
Eric Laurent3ef75492012-11-28 12:12:23 -08001025 int step;
Eric Laurent24482012012-05-10 09:41:17 -07001026
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001027 // skip a2dp absolute volume control request when the device
1028 // is not an a2dp device
1029 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1030 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1031 return;
1032 }
1033
RoboErik0dac35a2014-08-12 15:48:49 -07001034 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
1035 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001036 return;
1037 }
1038
Eric Laurentfde16d52012-12-03 14:42:39 -08001039 // reset any pending volume command
1040 synchronized (mSafeMediaVolumeState) {
1041 mPendingVolumeCommand = null;
1042 }
1043
Eric Laurent3ef75492012-11-28 12:12:23 -08001044 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1045 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1046 ((device & mFixedVolumeDevices) != 0)) {
1047 flags |= AudioManager.FLAG_FIXED_VOLUME;
1048
1049 // Always toggle between max safe volume and 0 for fixed volume devices where safe
1050 // volume is enforced, and max and 0 for the others.
1051 // This is simulated by stepping by the full allowed volume range
1052 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1053 (device & mSafeMediaVolumeDevices) != 0) {
1054 step = mSafeMediaVolumeIndex;
1055 } else {
1056 step = streamState.getMaxIndex();
1057 }
1058 if (aliasIndex != 0) {
1059 aliasIndex = step;
1060 }
1061 } else {
1062 // convert one UI step (+/-1) into a number of internal units on the stream alias
1063 step = rescaleIndex(10, streamType, streamTypeAlias);
1064 }
1065
Eric Laurent42b041e2013-03-29 11:36:03 -07001066 // If either the client forces allowing ringer modes for this adjustment,
1067 // or the stream type is one that is affected by ringer modes
1068 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1069 (streamTypeAlias == getMasterStreamType())) {
1070 int ringerMode = getRingerMode();
1071 // do not vibrate if already in vibrate mode
1072 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
1073 flags &= ~AudioManager.FLAG_VIBRATE;
Eric Laurent3ef75492012-11-28 12:12:23 -08001074 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001075 // Check if the ringer mode changes with this volume adjustment. If
1076 // it does, it will handle adjusting the volume, so we won't below
John Spurlocka11b4af2014-06-01 11:52:23 -04001077 final int result = checkForRingerModeChange(aliasIndex, direction, step);
1078 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
1079 // If suppressing a volume adjustment in silent mode, display the UI hint
1080 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
1081 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
1082 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001083 }
Eric Laurent3ef75492012-11-28 12:12:23 -08001084
Eric Laurent42b041e2013-03-29 11:36:03 -07001085 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001086
Eric Laurent42b041e2013-03-29 11:36:03 -07001087 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001088
John Du5a0cf7a2013-07-19 11:30:34 -07001089 // Check if volume update should be send to AVRCP
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001090 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1091 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1092 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1093 synchronized (mA2dpAvrcpLock) {
1094 if (mA2dp != null && mAvrcpAbsVolSupported) {
1095 mA2dp.adjustAvrcpAbsoluteVolume(direction);
1096 }
John Du5a0cf7a2013-07-19 11:30:34 -07001097 }
1098 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001099
Eric Laurent42b041e2013-03-29 11:36:03 -07001100 if ((direction == AudioManager.ADJUST_RAISE) &&
1101 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
1102 Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -04001103 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurent42b041e2013-03-29 11:36:03 -07001104 } else if (streamState.adjustIndex(direction * step, device)) {
1105 // Post message to set system volume (it in turn will post a message
1106 // to persist). Do not change volume if stream is muted.
1107 sendMsg(mAudioHandler,
1108 MSG_SET_DEVICE_VOLUME,
1109 SENDMSG_QUEUE,
1110 device,
1111 0,
1112 streamState,
1113 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001114 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001115
1116 // Check if volume update should be send to Hdmi system audio.
1117 int newIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent212532b2014-07-21 15:43:18 -07001118 if (mHdmiManager != null) {
1119 synchronized (mHdmiManager) {
1120 if (mHdmiTvClient != null &&
1121 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1122 (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 &&
1123 oldIndex != newIndex) {
1124 int maxIndex = getStreamMaxVolume(streamType);
1125 synchronized (mHdmiTvClient) {
1126 if (mHdmiSystemAudioSupported) {
1127 mHdmiTvClient.setSystemAudioVolume(
1128 (oldIndex + 5) / 10, (newIndex + 5) / 10, maxIndex);
1129 }
1130 }
1131 }
1132 // mHdmiCecSink true => mHdmiPlaybackClient != null
1133 if (mHdmiCecSink &&
1134 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1135 oldIndex != newIndex) {
1136 synchronized (mHdmiPlaybackClient) {
1137 int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
1138 KeyEvent.KEYCODE_VOLUME_UP;
1139 mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1140 mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1141 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001142 }
1143 }
1144 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001145 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001146 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001147 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148 }
1149
Dianne Hackborn961cae92013-03-20 14:59:43 -07001150 /** @see AudioManager#adjustMasterVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001151 public void adjustMasterVolume(int steps, int flags, String callingPackage) {
RoboErik519c7742014-11-18 10:59:09 -08001152 adjustMasterVolume(steps, flags, callingPackage, Binder.getCallingUid());
1153 }
1154
1155 public void adjustMasterVolume(int steps, int flags, String callingPackage, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001156 if (mUseFixedVolume) {
1157 return;
1158 }
Lei Zhang6c798972012-03-02 11:40:12 -08001159 ensureValidSteps(steps);
Mike Lockwood97606472012-02-09 11:24:10 -08001160 int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1161 int delta = 0;
Lei Zhang6c798972012-03-02 11:40:12 -08001162 int numSteps = Math.abs(steps);
1163 int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
1164 for (int i = 0; i < numSteps; ++i) {
1165 delta = findVolumeDelta(direction, volume);
1166 volume += delta;
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001167 }
RoboErik24b082f2012-02-24 14:21:16 -08001168
Lei Zhang6c798972012-03-02 11:40:12 -08001169 //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
RoboErik519c7742014-11-18 10:59:09 -08001170 setMasterVolume(volume, flags, callingPackage, uid);
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001171 }
1172
Eric Laurentfde16d52012-12-03 14:42:39 -08001173 // StreamVolumeCommand contains the information needed to defer the process of
1174 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1175 class StreamVolumeCommand {
1176 public final int mStreamType;
1177 public final int mIndex;
1178 public final int mFlags;
1179 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001180
Eric Laurentfde16d52012-12-03 14:42:39 -08001181 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1182 mStreamType = streamType;
1183 mIndex = index;
1184 mFlags = flags;
1185 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001186 }
John Spurlock35134602014-07-24 18:10:48 -04001187
1188 @Override
1189 public String toString() {
1190 return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1191 .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1192 .append(mDevice).append('}').toString();
1193 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001194 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001195
Eric Laurentfde16d52012-12-03 14:42:39 -08001196 private void onSetStreamVolume(int streamType, int index, int flags, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001197 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
Eric Laurent3ef75492012-11-28 12:12:23 -08001198 // setting volume on master stream type also controls silent mode
1199 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1200 (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
1201 int newRingerMode;
1202 if (index == 0) {
1203 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlock86005342014-05-23 11:58:00 -04001204 : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
1205 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001206 } else {
1207 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1208 }
John Spurlocke5b42d92014-10-15 12:03:48 -04001209 setRingerMode(newRingerMode, false /*checkZen*/);
Eric Laurent3ef75492012-11-28 12:12:23 -08001210 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001211 }
1212
1213 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001214 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
RoboErik0dac35a2014-08-12 15:48:49 -07001215 setStreamVolume(streamType, index, flags, callingPackage, Binder.getCallingUid());
1216 }
1217
1218 private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
1219 int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001220 if (mUseFixedVolume) {
1221 return;
1222 }
1223
Eric Laurentfde16d52012-12-03 14:42:39 -08001224 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001225 int streamTypeAlias = mStreamVolumeAlias[streamType];
1226 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001227
1228 final int device = getDeviceForStream(streamType);
1229 int oldIndex;
1230
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001231 // skip a2dp absolute volume control request when the device
1232 // is not an a2dp device
1233 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1234 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1235 return;
1236 }
1237
RoboErik0dac35a2014-08-12 15:48:49 -07001238 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
1239 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001240 return;
1241 }
1242
Eric Laurentfde16d52012-12-03 14:42:39 -08001243 synchronized (mSafeMediaVolumeState) {
1244 // reset any pending volume command
1245 mPendingVolumeCommand = null;
1246
Eric Laurent42b041e2013-03-29 11:36:03 -07001247 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001248
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001249 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001250
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001251 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1252 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1253 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1254 synchronized (mA2dpAvrcpLock) {
1255 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001256 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001257 }
John Du5a0cf7a2013-07-19 11:30:34 -07001258 }
1259 }
1260
Eric Laurent212532b2014-07-21 15:43:18 -07001261 if (mHdmiManager != null) {
1262 synchronized (mHdmiManager) {
1263 if (mHdmiTvClient != null &&
1264 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1265 (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 &&
1266 oldIndex != index) {
1267 int maxIndex = getStreamMaxVolume(streamType);
1268 synchronized (mHdmiTvClient) {
1269 if (mHdmiSystemAudioSupported) {
1270 mHdmiTvClient.setSystemAudioVolume(
1271 (oldIndex + 5) / 10, (index + 5) / 10, maxIndex);
1272 }
1273 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001274 }
1275 }
1276 }
1277
Eric Laurentfde16d52012-12-03 14:42:39 -08001278 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001279 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001280 ((device & mFixedVolumeDevices) != 0)) {
1281 flags |= AudioManager.FLAG_FIXED_VOLUME;
1282
1283 // volume is either 0 or max allowed for fixed volume devices
1284 if (index != 0) {
1285 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1286 (device & mSafeMediaVolumeDevices) != 0) {
1287 index = mSafeMediaVolumeIndex;
1288 } else {
1289 index = streamState.getMaxIndex();
1290 }
1291 }
1292 }
1293
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001294 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001295 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001296 mPendingVolumeCommand = new StreamVolumeCommand(
1297 streamType, index, flags, device);
1298 } else {
1299 onSetStreamVolume(streamType, index, flags, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07001300 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001301 }
1302 }
Eric Laurent25101b02011-02-02 09:33:30 -08001303 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001304 }
1305
Eric Laurent45c90ce2012-04-24 18:44:22 -07001306 /** @see AudioManager#forceVolumeControlStream(int) */
1307 public void forceVolumeControlStream(int streamType, IBinder cb) {
1308 synchronized(mForceControlStreamLock) {
1309 mVolumeControlStream = streamType;
1310 if (mVolumeControlStream == -1) {
1311 if (mForceControlStreamClient != null) {
1312 mForceControlStreamClient.release();
1313 mForceControlStreamClient = null;
1314 }
1315 } else {
1316 mForceControlStreamClient = new ForceControlStreamClient(cb);
1317 }
1318 }
1319 }
1320
1321 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1322 private IBinder mCb; // To be notified of client's death
1323
1324 ForceControlStreamClient(IBinder cb) {
1325 if (cb != null) {
1326 try {
1327 cb.linkToDeath(this, 0);
1328 } catch (RemoteException e) {
1329 // Client has died!
1330 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1331 cb = null;
1332 }
1333 }
1334 mCb = cb;
1335 }
1336
1337 public void binderDied() {
1338 synchronized(mForceControlStreamLock) {
1339 Log.w(TAG, "SCO client died");
1340 if (mForceControlStreamClient != this) {
1341 Log.w(TAG, "unregistered control stream client died");
1342 } else {
1343 mForceControlStreamClient = null;
1344 mVolumeControlStream = -1;
1345 }
1346 }
1347 }
1348
1349 public void release() {
1350 if (mCb != null) {
1351 mCb.unlinkToDeath(this, 0);
1352 mCb = null;
1353 }
1354 }
1355 }
1356
Lei Zhang6c798972012-03-02 11:40:12 -08001357 private int findVolumeDelta(int direction, int volume) {
1358 int delta = 0;
1359 if (direction == AudioManager.ADJUST_RAISE) {
1360 if (volume == MAX_MASTER_VOLUME) {
1361 return 0;
1362 }
1363 // This is the default value if we make it to the end
1364 delta = mMasterVolumeRamp[1];
1365 // If we're raising the volume move down the ramp array until we
1366 // find the volume we're above and use that groups delta.
1367 for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
1368 if (volume >= mMasterVolumeRamp[i - 1]) {
1369 delta = mMasterVolumeRamp[i];
1370 break;
1371 }
1372 }
1373 } else if (direction == AudioManager.ADJUST_LOWER){
1374 if (volume == 0) {
1375 return 0;
1376 }
1377 int length = mMasterVolumeRamp.length;
1378 // This is the default value if we make it to the end
1379 delta = -mMasterVolumeRamp[length - 1];
1380 // If we're lowering the volume move up the ramp array until we
1381 // find the volume we're below and use the group below it's delta
1382 for (int i = 2; i < length; i += 2) {
1383 if (volume <= mMasterVolumeRamp[i]) {
1384 delta = -mMasterVolumeRamp[i - 1];
1385 break;
1386 }
1387 }
1388 }
1389 return delta;
1390 }
1391
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001392 private void sendBroadcastToAll(Intent intent) {
1393 final long ident = Binder.clearCallingIdentity();
1394 try {
1395 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1396 } finally {
1397 Binder.restoreCallingIdentity(ident);
1398 }
1399 }
1400
1401 private void sendStickyBroadcastToAll(Intent intent) {
1402 final long ident = Binder.clearCallingIdentity();
1403 try {
1404 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1405 } finally {
1406 Binder.restoreCallingIdentity(ident);
1407 }
1408 }
1409
Eric Laurent25101b02011-02-02 09:33:30 -08001410 // UI update and Broadcast Intent
1411 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
Eric Laurent212532b2014-07-21 15:43:18 -07001412 if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) {
Eric Laurent25101b02011-02-02 09:33:30 -08001413 streamType = AudioSystem.STREAM_NOTIFICATION;
1414 }
1415
Jungshik Jang1a6be6e2014-09-16 11:04:54 +09001416 // If Hdmi-CEC system audio mode is on, show volume bar
1417 // only when TV receives volume notification from Audio Receiver.
1418 if (mHdmiTvClient != null && streamType == AudioSystem.STREAM_MUSIC) {
1419 synchronized (mHdmiTvClient) {
1420 if (mHdmiSystemAudioSupported &&
1421 ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
1422 flags &= ~AudioManager.FLAG_SHOW_UI;
1423 }
1424 }
1425 }
John Spurlock3346a802014-05-20 16:25:37 -04001426 mVolumeController.postVolumeChanged(streamType, flags);
Eric Laurent25101b02011-02-02 09:33:30 -08001427
Eric Laurent4bbcc652012-09-24 14:26:30 -07001428 if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
1429 oldIndex = (oldIndex + 5) / 10;
1430 index = (index + 5) / 10;
1431 Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
1432 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
1433 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
1434 intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
1435 sendBroadcastToAll(intent);
1436 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001437 }
1438
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001439 // UI update and Broadcast Intent
1440 private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
John Spurlock3346a802014-05-20 16:25:37 -04001441 mVolumeController.postMasterVolumeChanged(flags);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001442
1443 Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
1444 intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
1445 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001446 sendBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001447 }
1448
1449 // UI update and Broadcast Intent
1450 private void sendMasterMuteUpdate(boolean muted, int flags) {
John Spurlock3346a802014-05-20 16:25:37 -04001451 mVolumeController.postMasterMuteChanged(flags);
Justin Koh57978ed2012-04-03 17:37:58 -07001452 broadcastMasterMuteStatus(muted);
1453 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001454
Justin Koh57978ed2012-04-03 17:37:58 -07001455 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001456 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1457 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001458 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1459 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001460 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001461 }
1462
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001463 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001464 * Sets the stream state's index, and posts a message to set system volume.
1465 * This will not call out to the UI. Assumes a valid stream type.
1466 *
1467 * @param streamType Type of the stream
1468 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001469 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001470 * @param force If true, set the volume even if the desired volume is same
1471 * as the current volume.
1472 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001473 private void setStreamVolumeInt(int streamType,
1474 int index,
1475 int device,
Eric Laurent42b041e2013-03-29 11:36:03 -07001476 boolean force) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001477 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07001478
Eric Laurent42b041e2013-03-29 11:36:03 -07001479 if (streamState.setIndex(index, device) || force) {
1480 // Post message to set system volume (it in turn will post a message
1481 // to persist).
1482 sendMsg(mAudioHandler,
1483 MSG_SET_DEVICE_VOLUME,
1484 SENDMSG_QUEUE,
1485 device,
1486 0,
1487 streamState,
1488 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 }
1490 }
1491
1492 /** @see AudioManager#setStreamSolo(int, boolean) */
1493 public void setStreamSolo(int streamType, boolean state, IBinder cb) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001494 if (mUseFixedVolume) {
1495 return;
1496 }
1497
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001498 for (int stream = 0; stream < mStreamStates.length; stream++) {
1499 if (!isStreamAffectedByMute(stream) || stream == streamType) continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001500 mStreamStates[stream].mute(cb, state);
1501 }
1502 }
1503
1504 /** @see AudioManager#setStreamMute(int, boolean) */
1505 public void setStreamMute(int streamType, boolean state, IBinder cb) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001506 if (mUseFixedVolume) {
1507 return;
1508 }
1509
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001510 if (isStreamAffectedByMute(streamType)) {
Eric Laurent212532b2014-07-21 15:43:18 -07001511 if (mHdmiManager != null) {
1512 synchronized (mHdmiManager) {
1513 if (streamType == AudioSystem.STREAM_MUSIC && mHdmiTvClient != null) {
1514 synchronized (mHdmiTvClient) {
1515 if (mHdmiSystemAudioSupported) {
1516 mHdmiTvClient.setSystemAudioMute(state);
1517 }
1518 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001519 }
1520 }
1521 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001522 mStreamStates[streamType].mute(cb, state);
1523 }
1524 }
1525
Eric Laurent25101b02011-02-02 09:33:30 -08001526 /** get stream mute state. */
1527 public boolean isStreamMute(int streamType) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001528 synchronized (VolumeStreamState.class) {
1529 return mStreamStates[streamType].isMuted_syncVSS();
1530 }
Eric Laurent25101b02011-02-02 09:33:30 -08001531 }
1532
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07001533 private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
1534 private IBinder mICallback; // To be notified of client's death
1535
1536 RmtSbmxFullVolDeathHandler(IBinder cb) {
1537 mICallback = cb;
1538 try {
1539 cb.linkToDeath(this, 0/*flags*/);
1540 } catch (RemoteException e) {
1541 Log.e(TAG, "can't link to death", e);
1542 }
1543 }
1544
1545 boolean isHandlerFor(IBinder cb) {
1546 return mICallback.equals(cb);
1547 }
1548
1549 void forget() {
1550 try {
1551 mICallback.unlinkToDeath(this, 0/*flags*/);
1552 } catch (NoSuchElementException e) {
1553 Log.e(TAG, "error unlinking to death", e);
1554 }
1555 }
1556
1557 public void binderDied() {
1558 Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
1559 forceRemoteSubmixFullVolume(false, mICallback);
1560 }
1561 }
1562
1563 /**
1564 * call must be synchronized on mRmtSbmxFullVolDeathHandlers
1565 * @return true if there is a registered death handler, false otherwise */
1566 private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1567 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1568 while (it.hasNext()) {
1569 final RmtSbmxFullVolDeathHandler handler = it.next();
1570 if (handler.isHandlerFor(cb)) {
1571 handler.forget();
1572 mRmtSbmxFullVolDeathHandlers.remove(handler);
1573 return true;
1574 }
1575 }
1576 return false;
1577 }
1578
1579 /** call synchronized on mRmtSbmxFullVolDeathHandlers */
1580 private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1581 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1582 while (it.hasNext()) {
1583 if (it.next().isHandlerFor(cb)) {
1584 return true;
1585 }
1586 }
1587 return false;
1588 }
1589
1590 private int mRmtSbmxFullVolRefCount = 0;
1591 private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
1592 new ArrayList<RmtSbmxFullVolDeathHandler>();
1593
1594 public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
1595 if (cb == null) {
1596 return;
1597 }
1598 if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
1599 android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
1600 Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
1601 return;
1602 }
1603 synchronized(mRmtSbmxFullVolDeathHandlers) {
1604 boolean applyRequired = false;
1605 if (startForcing) {
1606 if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
1607 mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
1608 if (mRmtSbmxFullVolRefCount == 0) {
1609 mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1610 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1611 applyRequired = true;
1612 }
1613 mRmtSbmxFullVolRefCount++;
1614 }
1615 } else {
1616 if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
1617 mRmtSbmxFullVolRefCount--;
1618 if (mRmtSbmxFullVolRefCount == 0) {
1619 mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1620 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1621 applyRequired = true;
1622 }
1623 }
1624 }
1625 if (applyRequired) {
1626 // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
1627 checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
1628 mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
1629 }
1630 }
1631 }
1632
Dianne Hackborn961cae92013-03-20 14:59:43 -07001633 /** @see AudioManager#setMasterMute(boolean, int) */
Julia Reynolds4a21b252014-06-04 11:11:43 -04001634 public void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001635 if (mUseFixedVolume) {
1636 return;
1637 }
Julia Reynolds4a21b252014-06-04 11:11:43 -04001638 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
1639 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1640 return;
1641 }
Jason Simmons1ce5b262012-02-02 13:00:17 -08001642 if (state != AudioSystem.getMasterMute()) {
1643 AudioSystem.setMasterMute(state);
Justin Koh57978ed2012-04-03 17:37:58 -07001644 // Post a persist master volume msg
Justin Koh75cf9e12012-04-04 15:27:37 -07001645 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001646 : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
Justin Koh0273af52012-04-04 18:29:50 -07001647 sendMasterMuteUpdate(state, flags);
Jason Simmons1ce5b262012-02-02 13:00:17 -08001648 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08001649 }
1650
1651 /** get master mute state. */
1652 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08001653 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001654 }
1655
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07001656 protected static int getMaxStreamVolume(int streamType) {
1657 return MAX_STREAM_VOLUME[streamType];
1658 }
1659
Eric Laurent91377de2014-10-10 15:24:04 -07001660 public static int getDefaultStreamVolume(int streamType) {
1661 return DEFAULT_STREAM_VOLUME[streamType];
1662 }
1663
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001664 /** @see AudioManager#getStreamVolume(int) */
1665 public int getStreamVolume(int streamType) {
1666 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001667 int device = getDeviceForStream(streamType);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001668 synchronized (VolumeStreamState.class) {
1669 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001670
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001671 // by convention getStreamVolume() returns 0 when a stream is muted.
1672 if (mStreamStates[streamType].isMuted_syncVSS()) {
1673 index = 0;
1674 }
1675 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
1676 (device & mFixedVolumeDevices) != 0) {
1677 index = mStreamStates[streamType].getMaxIndex();
1678 }
1679 return (index + 5) / 10;
Eric Laurent42b041e2013-03-29 11:36:03 -07001680 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001681 }
1682
RoboErik519c7742014-11-18 10:59:09 -08001683 @Override
Mike Lockwood47676902011-11-08 10:31:21 -08001684 public int getMasterVolume() {
Mike Lockwoodce952c82011-11-14 10:47:42 -08001685 if (isMasterMute()) return 0;
1686 return getLastAudibleMasterVolume();
Mike Lockwood8dc1dab2011-10-27 09:52:41 -04001687 }
1688
RoboErik519c7742014-11-18 10:59:09 -08001689 @Override
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001690 public void setMasterVolume(int volume, int flags, String callingPackage) {
RoboErik519c7742014-11-18 10:59:09 -08001691 setMasterVolume(volume, flags, callingPackage, Binder.getCallingUid());
1692 }
1693
1694 public void setMasterVolume(int volume, int flags, String callingPackage, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001695 if (mUseFixedVolume) {
1696 return;
1697 }
1698
RoboErik519c7742014-11-18 10:59:09 -08001699 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
1700 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001701 return;
1702 }
1703
Mike Lockwood97606472012-02-09 11:24:10 -08001704 if (volume < 0) {
1705 volume = 0;
1706 } else if (volume > MAX_MASTER_VOLUME) {
1707 volume = MAX_MASTER_VOLUME;
1708 }
Mike Lockwood5c55a052011-12-15 17:21:44 -05001709 doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
1710 }
1711
1712 private void doSetMasterVolume(float volume, int flags) {
1713 // don't allow changing master volume when muted
1714 if (!AudioSystem.getMasterMute()) {
1715 int oldVolume = getMasterVolume();
1716 AudioSystem.setMasterVolume(volume);
1717
1718 int newVolume = getMasterVolume();
1719 if (newVolume != oldVolume) {
1720 // Post a persist master volume msg
1721 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
1722 Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
Mike Lockwood5c55a052011-12-15 17:21:44 -05001723 }
Justin Koh3caba512012-04-02 15:32:18 -07001724 // Send the volume update regardless whether there was a change.
1725 sendMasterVolumeUpdate(flags, oldVolume, newVolume);
Mike Lockwood5c55a052011-12-15 17:21:44 -05001726 }
Mike Lockwood8dc1dab2011-10-27 09:52:41 -04001727 }
1728
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729 /** @see AudioManager#getStreamMaxVolume(int) */
1730 public int getStreamMaxVolume(int streamType) {
1731 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07001732 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001733 }
1734
Mike Lockwood47676902011-11-08 10:31:21 -08001735 public int getMasterMaxVolume() {
1736 return MAX_MASTER_VOLUME;
1737 }
Eric Laurent25101b02011-02-02 09:33:30 -08001738
1739 /** Get last audible volume before stream was muted. */
1740 public int getLastAudibleStreamVolume(int streamType) {
1741 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001742 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001743 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08001744 }
1745
Mike Lockwoodce952c82011-11-14 10:47:42 -08001746 /** Get last audible master volume before it was muted. */
1747 public int getLastAudibleMasterVolume() {
1748 return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1749 }
1750
Dianne Hackborn961cae92013-03-20 14:59:43 -07001751 /** @see AudioManager#getMasterStreamType() */
Eric Laurent6d517662012-04-23 18:42:39 -07001752 public int getMasterStreamType() {
John Spurlock4f0f1202014-08-05 13:28:33 -04001753 return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
Eric Laurent6d517662012-04-23 18:42:39 -07001754 }
1755
Emily Bernier22c921a2014-05-28 11:01:32 -04001756 /** @see AudioManager#setMicrophoneMute(boolean) */
1757 public void setMicrophoneMute(boolean on, String callingPackage) {
1758 if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(),
1759 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1760 return;
1761 }
Jean-Michel Trivi4a4fea02014-08-29 18:14:09 -07001762 if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
1763 return;
1764 }
Emily Bernier22c921a2014-05-28 11:01:32 -04001765
1766 AudioSystem.muteMicrophone(on);
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001767 // Post a persist microphone msg.
1768 sendMsg(mAudioHandler, MSG_PERSIST_MICROPHONE_MUTE, SENDMSG_REPLACE, on ? 1
1769 : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
Emily Bernier22c921a2014-05-28 11:01:32 -04001770 }
1771
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001772 /** @see AudioManager#getRingerMode() */
1773 public int getRingerMode() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001774 synchronized(mSettingsLock) {
1775 return mRingerMode;
1776 }
1777 }
1778
1779 private void ensureValidRingerMode(int ringerMode) {
John Spurlock97559372014-10-24 16:27:36 -04001780 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001781 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1782 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001783 }
1784
John Spurlock97559372014-10-24 16:27:36 -04001785 /** @see AudioManager#isValidRingerMode(int) */
1786 public boolean isValidRingerMode(int ringerMode) {
1787 return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
1788 }
1789
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001790 /** @see AudioManager#setRingerMode(int) */
John Spurlocke5b42d92014-10-15 12:03:48 -04001791 public void setRingerMode(int ringerMode, boolean checkZen) {
Eric Laurent212532b2014-07-21 15:43:18 -07001792 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001793 return;
1794 }
John Spurlock97559372014-10-24 16:27:36 -04001795 ensureValidRingerMode(ringerMode);
Eric Laurent24482012012-05-10 09:41:17 -07001796 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1797 ringerMode = AudioManager.RINGER_MODE_SILENT;
1798 }
John Spurlocke5b42d92014-10-15 12:03:48 -04001799 if (checkZen) {
1800 checkZen(ringerMode);
1801 }
Glenn Kastenba195eb2011-12-13 09:30:40 -08001802 if (ringerMode != getRingerMode()) {
1803 setRingerModeInt(ringerMode, true);
1804 // Send sticky broadcast
1805 broadcastRingerMode(ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001806 }
1807 }
1808
John Spurlocke5b42d92014-10-15 12:03:48 -04001809 private void checkZen(int ringerMode) {
1810 // leave zen when callers set ringer-mode = normal or vibrate
1811 final int zen = Global.getInt(mContentResolver, Global.ZEN_MODE, Global.ZEN_MODE_OFF);
1812 if (ringerMode != AudioManager.RINGER_MODE_SILENT && zen != Global.ZEN_MODE_OFF) {
1813 final long ident = Binder.clearCallingIdentity();
1814 try {
1815 Global.putInt(mContentResolver, Global.ZEN_MODE, Global.ZEN_MODE_OFF);
1816 } finally {
1817 Binder.restoreCallingIdentity(ident);
1818 }
1819 }
1820 }
1821
Eric Laurent4050c932009-07-08 02:52:14 -07001822 private void setRingerModeInt(int ringerMode, boolean persist) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001823 synchronized(mSettingsLock) {
1824 mRingerMode = ringerMode;
1825 }
Jason Parekhb1096152009-03-24 17:48:25 -07001826
Eric Laurent5b4e6542010-03-19 20:02:21 -07001827 // Mute stream if not previously muted by ringer mode and ringer mode
1828 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
1829 // Unmute stream if previously muted by ringer mode and ringer mode
1830 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07001831 int numStreamTypes = AudioSystem.getNumStreamTypes();
Eric Laurent5b4e6542010-03-19 20:02:21 -07001832 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
1833 if (isStreamMutedByRingerMode(streamType)) {
1834 if (!isStreamAffectedByRingerMode(streamType) ||
Glenn Kastenba195eb2011-12-13 09:30:40 -08001835 ringerMode == AudioManager.RINGER_MODE_NORMAL) {
Eric Laurentb024c302011-10-14 17:19:27 -07001836 // ring and notifications volume should never be 0 when not silenced
John Spurlock95ef08b2014-11-18 10:51:39 -05001837 // on voice capable devices or devices that support vibration
1838 if ((isPlatformVoice() || mHasVibrator) &&
Eric Laurent6d517662012-04-23 18:42:39 -07001839 mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001840 synchronized (VolumeStreamState.class) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001841 Set set = mStreamStates[streamType].mIndex.entrySet();
Eric Laurent3172d5e2012-05-09 11:38:16 -07001842 Iterator i = set.iterator();
1843 while (i.hasNext()) {
1844 Map.Entry entry = (Map.Entry)i.next();
1845 if ((Integer)entry.getValue() == 0) {
1846 entry.setValue(10);
1847 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001848 }
1849 }
Eric Laurentb024c302011-10-14 17:19:27 -07001850 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07001851 mStreamStates[streamType].mute(null, false);
1852 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent9bcf4012009-06-12 06:09:28 -07001853 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07001854 } else {
1855 if (isStreamAffectedByRingerMode(streamType) &&
Glenn Kastenba195eb2011-12-13 09:30:40 -08001856 ringerMode != AudioManager.RINGER_MODE_NORMAL) {
Eric Laurent5b4e6542010-03-19 20:02:21 -07001857 mStreamStates[streamType].mute(null, true);
1858 mRingerModeMutedStreams |= (1 << streamType);
1859 }
Jason Parekhb1096152009-03-24 17:48:25 -07001860 }
1861 }
Eric Laurenta553c252009-07-17 12:17:14 -07001862
Jason Parekhb1096152009-03-24 17:48:25 -07001863 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07001864 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08001865 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07001866 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
1867 }
Jason Parekhb1096152009-03-24 17:48:25 -07001868 }
1869
Mike Lockwood90631542012-01-06 11:20:37 -05001870 private void restoreMasterVolume() {
Eric Laurent83a017b2013-03-19 18:15:31 -07001871 if (mUseFixedVolume) {
1872 AudioSystem.setMasterVolume(1.0f);
1873 return;
1874 }
Mike Lockwood90631542012-01-06 11:20:37 -05001875 if (mUseMasterVolume) {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001876 float volume = Settings.System.getFloatForUser(mContentResolver,
1877 Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
Mike Lockwood90631542012-01-06 11:20:37 -05001878 if (volume >= 0.0f) {
1879 AudioSystem.setMasterVolume(volume);
1880 }
1881 }
1882 }
1883
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001884 /** @see AudioManager#shouldVibrate(int) */
1885 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001886 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001887
1888 switch (getVibrateSetting(vibrateType)) {
1889
1890 case AudioManager.VIBRATE_SETTING_ON:
Glenn Kastenba195eb2011-12-13 09:30:40 -08001891 return getRingerMode() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001892
1893 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
Glenn Kastenba195eb2011-12-13 09:30:40 -08001894 return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001895
1896 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04001897 // return false, even for incoming calls
1898 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001899
1900 default:
1901 return false;
1902 }
1903 }
1904
1905 /** @see AudioManager#getVibrateSetting(int) */
1906 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001907 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001908 return (mVibrateSetting >> (vibrateType * 2)) & 3;
1909 }
1910
1911 /** @see AudioManager#setVibrateSetting(int, int) */
1912 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
1913
Eric Laurentbffc3d12012-05-07 17:43:49 -07001914 if (!mHasVibrator) return;
1915
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001916 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
1917
1918 // Broadcast change
1919 broadcastVibrateSetting(vibrateType);
1920
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001921 }
1922
1923 /**
1924 * @see #setVibrateSetting(int, int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001925 */
1926 public static int getValueForVibrateSetting(int existingValue, int vibrateType,
1927 int vibrateSetting) {
1928
1929 // First clear the existing setting. Each vibrate type has two bits in
1930 // the value. Note '3' is '11' in binary.
1931 existingValue &= ~(3 << (vibrateType * 2));
1932
1933 // Set into the old value
1934 existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
1935
1936 return existingValue;
1937 }
1938
Eric Laurent9272b4b2010-01-23 17:12:59 -08001939 private class SetModeDeathHandler implements IBinder.DeathRecipient {
1940 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07001941 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001942 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
1943
Eric Laurent9f103de2011-09-08 15:04:23 -07001944 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08001945 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07001946 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001947 }
1948
1949 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07001950 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001951 synchronized(mSetModeDeathHandlers) {
1952 Log.w(TAG, "setMode() client died");
1953 int index = mSetModeDeathHandlers.indexOf(this);
1954 if (index < 0) {
1955 Log.w(TAG, "unregistered setMode() client died");
1956 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07001957 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
Eric Laurent9272b4b2010-01-23 17:12:59 -08001958 }
1959 }
Eric Laurent9f103de2011-09-08 15:04:23 -07001960 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1961 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07001962 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07001963 final long ident = Binder.clearCallingIdentity();
1964 disconnectBluetoothSco(newModeOwnerPid);
1965 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07001966 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08001967 }
1968
Marco Nelissenf1ddd512011-08-10 14:15:44 -07001969 public int getPid() {
1970 return mPid;
1971 }
1972
Eric Laurent9272b4b2010-01-23 17:12:59 -08001973 public void setMode(int mode) {
1974 mMode = mode;
1975 }
1976
1977 public int getMode() {
1978 return mMode;
1979 }
1980
1981 public IBinder getBinder() {
1982 return mCb;
1983 }
1984 }
1985
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001986 /** @see AudioManager#setMode(int) */
Eric Laurent9272b4b2010-01-23 17:12:59 -08001987 public void setMode(int mode, IBinder cb) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07001988 if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ")"); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001989 if (!checkAudioSettingsPermission("setMode()")) {
1990 return;
1991 }
Eric Laurenta553c252009-07-17 12:17:14 -07001992
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07001993 if ( (mode == AudioSystem.MODE_IN_CALL) &&
1994 (mContext.checkCallingOrSelfPermission(
1995 android.Manifest.permission.MODIFY_PHONE_STATE)
1996 != PackageManager.PERMISSION_GRANTED)) {
1997 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
1998 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
1999 return;
2000 }
2001
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08002002 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07002003 return;
2004 }
2005
Eric Laurentd7454be2011-09-14 08:45:58 -07002006 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002007 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07002008 if (mode == AudioSystem.MODE_CURRENT) {
2009 mode = mMode;
2010 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002011 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
Eric Laurent9f103de2011-09-08 15:04:23 -07002012 }
2013 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2014 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002015 if (newModeOwnerPid != 0) {
2016 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07002017 }
2018 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002019
Eric Laurent9f103de2011-09-08 15:04:23 -07002020 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07002021 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07002022 // any mode other than NORMAL.
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07002023 private int setModeInt(int mode, IBinder cb, int pid) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002024 if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ")"); }
Eric Laurentd7454be2011-09-14 08:45:58 -07002025 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002026 if (cb == null) {
2027 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07002028 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07002029 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002030
Eric Laurent9f103de2011-09-08 15:04:23 -07002031 SetModeDeathHandler hdlr = null;
2032 Iterator iter = mSetModeDeathHandlers.iterator();
2033 while (iter.hasNext()) {
2034 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
2035 if (h.getPid() == pid) {
2036 hdlr = h;
2037 // Remove from client list so that it is re-inserted at top of list
2038 iter.remove();
2039 hdlr.getBinder().unlinkToDeath(hdlr, 0);
2040 break;
2041 }
2042 }
2043 int status = AudioSystem.AUDIO_STATUS_OK;
2044 do {
2045 if (mode == AudioSystem.MODE_NORMAL) {
2046 // get new mode from client at top the list if any
2047 if (!mSetModeDeathHandlers.isEmpty()) {
2048 hdlr = mSetModeDeathHandlers.get(0);
2049 cb = hdlr.getBinder();
2050 mode = hdlr.getMode();
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002051 if (DEBUG_MODE) {
2052 Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
2053 + hdlr.mPid);
2054 }
Eric Laurentb9c9d262009-05-06 08:13:20 -07002055 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002056 } else {
2057 if (hdlr == null) {
2058 hdlr = new SetModeDeathHandler(cb, pid);
2059 }
2060 // Register for client death notification
2061 try {
2062 cb.linkToDeath(hdlr, 0);
2063 } catch (RemoteException e) {
2064 // Client has died!
2065 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
2066 }
2067
2068 // Last client to call setMode() is always at top of client list
2069 // as required by SetModeDeathHandler.binderDied()
2070 mSetModeDeathHandlers.add(0, hdlr);
2071 hdlr.setMode(mode);
2072 }
2073
2074 if (mode != mMode) {
2075 status = AudioSystem.setPhoneState(mode);
2076 if (status == AudioSystem.AUDIO_STATUS_OK) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002077 if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002078 mMode = mode;
2079 } else {
2080 if (hdlr != null) {
2081 mSetModeDeathHandlers.remove(hdlr);
2082 cb.unlinkToDeath(hdlr, 0);
2083 }
2084 // force reading new top of mSetModeDeathHandlers stack
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002085 if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002086 mode = AudioSystem.MODE_NORMAL;
2087 }
2088 } else {
2089 status = AudioSystem.AUDIO_STATUS_OK;
2090 }
2091 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
2092
2093 if (status == AudioSystem.AUDIO_STATUS_OK) {
2094 if (mode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002095 if (mSetModeDeathHandlers.isEmpty()) {
2096 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
2097 } else {
2098 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2099 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002100 }
2101 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002102 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07002103 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
2104 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
Eric Laurent6d517662012-04-23 18:42:39 -07002105
2106 updateStreamVolumeAlias(true /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002107 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002108 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002109 }
2110
2111 /** @see AudioManager#getMode() */
2112 public int getMode() {
2113 return mMode;
2114 }
2115
Eric Laurente78fced2013-03-15 16:03:47 -07002116 //==========================================================================================
2117 // Sound Effects
2118 //==========================================================================================
2119
2120 private static final String TAG_AUDIO_ASSETS = "audio_assets";
2121 private static final String ATTR_VERSION = "version";
2122 private static final String TAG_GROUP = "group";
2123 private static final String ATTR_GROUP_NAME = "name";
2124 private static final String TAG_ASSET = "asset";
2125 private static final String ATTR_ASSET_ID = "id";
2126 private static final String ATTR_ASSET_FILE = "file";
2127
2128 private static final String ASSET_FILE_VERSION = "1.0";
2129 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
2130
Glenn Kasten167d1a22013-07-23 16:24:41 -07002131 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002132
2133 class LoadSoundEffectReply {
2134 public int mStatus = 1;
2135 };
2136
Eric Laurente78fced2013-03-15 16:03:47 -07002137 private void loadTouchSoundAssetDefaults() {
2138 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
2139 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
2140 SOUND_EFFECT_FILES_MAP[i][0] = 0;
2141 SOUND_EFFECT_FILES_MAP[i][1] = -1;
2142 }
2143 }
2144
2145 private void loadTouchSoundAssets() {
2146 XmlResourceParser parser = null;
2147
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002148 // only load assets once.
2149 if (!SOUND_EFFECT_FILES.isEmpty()) {
2150 return;
2151 }
2152
Eric Laurente78fced2013-03-15 16:03:47 -07002153 loadTouchSoundAssetDefaults();
2154
2155 try {
2156 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
2157
2158 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
2159 String version = parser.getAttributeValue(null, ATTR_VERSION);
2160 boolean inTouchSoundsGroup = false;
2161
2162 if (ASSET_FILE_VERSION.equals(version)) {
2163 while (true) {
2164 XmlUtils.nextElement(parser);
2165 String element = parser.getName();
2166 if (element == null) {
2167 break;
2168 }
2169 if (element.equals(TAG_GROUP)) {
2170 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
2171 if (GROUP_TOUCH_SOUNDS.equals(name)) {
2172 inTouchSoundsGroup = true;
2173 break;
2174 }
2175 }
2176 }
2177 while (inTouchSoundsGroup) {
2178 XmlUtils.nextElement(parser);
2179 String element = parser.getName();
2180 if (element == null) {
2181 break;
2182 }
2183 if (element.equals(TAG_ASSET)) {
2184 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
2185 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
2186 int fx;
2187
2188 try {
2189 Field field = AudioManager.class.getField(id);
2190 fx = field.getInt(null);
2191 } catch (Exception e) {
2192 Log.w(TAG, "Invalid touch sound ID: "+id);
2193 continue;
2194 }
2195
2196 int i = SOUND_EFFECT_FILES.indexOf(file);
2197 if (i == -1) {
2198 i = SOUND_EFFECT_FILES.size();
2199 SOUND_EFFECT_FILES.add(file);
2200 }
2201 SOUND_EFFECT_FILES_MAP[fx][0] = i;
2202 } else {
2203 break;
2204 }
2205 }
2206 }
2207 } catch (Resources.NotFoundException e) {
2208 Log.w(TAG, "audio assets file not found", e);
2209 } catch (XmlPullParserException e) {
2210 Log.w(TAG, "XML parser exception reading touch sound assets", e);
2211 } catch (IOException e) {
2212 Log.w(TAG, "I/O exception reading touch sound assets", e);
2213 } finally {
2214 if (parser != null) {
2215 parser.close();
2216 }
2217 }
2218 }
2219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002220 /** @see AudioManager#playSoundEffect(int) */
2221 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002222 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002223 }
2224
2225 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002226 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07002227 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
2228 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
2229 return;
2230 }
2231
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002232 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002233 effectType, (int) (volume * 1000), null, 0);
2234 }
2235
2236 /**
2237 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08002238 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002239 */
2240 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002241 int attempts = 3;
2242 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08002243
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002244 synchronized (reply) {
2245 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
2246 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08002247 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07002248 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002249 } catch (InterruptedException e) {
2250 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08002251 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002252 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002253 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002254 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002255 }
2256
2257 /**
2258 * Unloads samples from the sound pool.
2259 * This method can be called to free some memory when
2260 * sound effects are disabled.
2261 */
2262 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002263 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002264 }
2265
Eric Laurenta60e2122010-12-28 16:49:07 -08002266 class SoundPoolListenerThread extends Thread {
2267 public SoundPoolListenerThread() {
2268 super("SoundPoolListenerThread");
2269 }
2270
2271 @Override
2272 public void run() {
2273
2274 Looper.prepare();
2275 mSoundPoolLooper = Looper.myLooper();
2276
2277 synchronized (mSoundEffectsLock) {
2278 if (mSoundPool != null) {
2279 mSoundPoolCallBack = new SoundPoolCallback();
2280 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2281 }
2282 mSoundEffectsLock.notify();
2283 }
2284 Looper.loop();
2285 }
2286 }
2287
2288 private final class SoundPoolCallback implements
2289 android.media.SoundPool.OnLoadCompleteListener {
2290
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002291 int mStatus = 1; // 1 means neither error nor last sample loaded yet
2292 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08002293
2294 public int status() {
2295 return mStatus;
2296 }
2297
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002298 public void setSamples(int[] samples) {
2299 for (int i = 0; i < samples.length; i++) {
2300 // do not wait ack for samples rejected upfront by SoundPool
2301 if (samples[i] > 0) {
2302 mSamples.add(samples[i]);
2303 }
2304 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002305 }
2306
2307 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2308 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002309 int i = mSamples.indexOf(sampleId);
2310 if (i >= 0) {
2311 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08002312 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002313 if ((status != 0) || mSamples. isEmpty()) {
2314 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08002315 mSoundEffectsLock.notify();
2316 }
2317 }
2318 }
2319 }
2320
Eric Laurent4050c932009-07-08 02:52:14 -07002321 /** @see AudioManager#reloadAudioSettings() */
2322 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002323 readAudioSettings(false /*userSwitch*/);
2324 }
2325
2326 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07002327 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2328 readPersistedSettings();
2329
2330 // restore volume settings
2331 int numStreamTypes = AudioSystem.getNumStreamTypes();
2332 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2333 VolumeStreamState streamState = mStreamStates[streamType];
2334
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002335 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2336 continue;
2337 }
2338
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002339 streamState.readSettings();
2340 synchronized (VolumeStreamState.class) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002341 // unmute stream that was muted but is not affect by mute anymore
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002342 if (streamState.isMuted_syncVSS() && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07002343 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002344 int size = streamState.mDeathHandlers.size();
2345 for (int i = 0; i < size; i++) {
2346 streamState.mDeathHandlers.get(i).mMuteCount = 1;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002347 streamState.mDeathHandlers.get(i).mute_syncVSS(false);
Eric Laurent3172d5e2012-05-09 11:38:16 -07002348 }
Eric Laurent4050c932009-07-08 02:52:14 -07002349 }
Eric Laurent4050c932009-07-08 02:52:14 -07002350 }
2351 }
2352
Eric Laurent33902db2012-10-07 16:15:07 -07002353 // apply new ringer mode before checking volume for alias streams so that streams
2354 // muted by ringer mode have the correct volume
2355 setRingerModeInt(getRingerMode(), false);
2356
Eric Laurent212532b2014-07-21 15:43:18 -07002357 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07002358 checkAllAliasStreamVolumes();
2359
Eric Laurentd640bd32012-09-28 18:01:48 -07002360 synchronized (mSafeMediaVolumeState) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002361 mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2362 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2363 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
Eric Laurentd640bd32012-09-28 18:01:48 -07002364 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07002365 enforceSafeMediaVolume();
2366 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07002367 }
Eric Laurent4050c932009-07-08 02:52:14 -07002368 }
2369
Dianne Hackborn961cae92013-03-20 14:59:43 -07002370 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002371 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002372 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2373 return;
2374 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002375
2376 if (on) {
2377 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2378 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2379 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
2380 }
2381 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2382 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2383 mForcedUseForComm = AudioSystem.FORCE_NONE;
2384 }
Eric Laurentfa640152011-03-12 15:59:51 -08002385
Eric Laurentafbb0472011-12-15 09:04:23 -08002386 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002387 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002388 }
2389
2390 /** @see AudioManager#isSpeakerphoneOn() */
2391 public boolean isSpeakerphoneOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002392 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002393 }
2394
Dianne Hackborn961cae92013-03-20 14:59:43 -07002395 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002396 public void setBluetoothScoOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002397 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2398 return;
2399 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002400
2401 if (on) {
2402 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2403 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2404 mForcedUseForComm = AudioSystem.FORCE_NONE;
2405 }
Eric Laurentfa640152011-03-12 15:59:51 -08002406
Eric Laurentafbb0472011-12-15 09:04:23 -08002407 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002408 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08002409 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002410 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002411 }
2412
2413 /** @see AudioManager#isBluetoothScoOn() */
2414 public boolean isBluetoothScoOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002415 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002416 }
2417
Dianne Hackborn961cae92013-03-20 14:59:43 -07002418 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07002419 public void setBluetoothA2dpOn(boolean on) {
Eric Laurentc390bed2012-07-03 12:24:05 -07002420 synchronized (mBluetoothA2dpEnabledLock) {
2421 mBluetoothA2dpEnabled = on;
2422 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2423 AudioSystem.FOR_MEDIA,
2424 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2425 null, 0);
2426 }
Eric Laurent78472112012-05-21 08:57:21 -07002427 }
2428
2429 /** @see AudioManager#isBluetoothA2dpOn() */
2430 public boolean isBluetoothA2dpOn() {
2431 synchronized (mBluetoothA2dpEnabledLock) {
2432 return mBluetoothA2dpEnabled;
2433 }
2434 }
2435
Eric Laurent3def1ee2010-03-17 23:26:26 -07002436 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07002437 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
2438 int scoAudioMode =
2439 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
Liejun Taof4e51d82014-07-16 11:18:29 -07002440 SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
Eric Laurent83900752014-05-15 15:14:22 -07002441 startBluetoothScoInt(cb, scoAudioMode);
2442 }
2443
2444 /** @see AudioManager#startBluetoothScoVirtualCall() */
2445 public void startBluetoothScoVirtualCall(IBinder cb) {
2446 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
2447 }
2448
2449 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07002450 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002451 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002452 return;
2453 }
Eric Laurent854938a2011-02-22 12:05:20 -08002454 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002455 // The calling identity must be cleared before calling ScoClient.incCount().
2456 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2457 // and this must be done on behalf of system server to make sure permissions are granted.
2458 // The caller identity must be cleared after getScoClient() because it is needed if a new
2459 // client is created.
2460 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07002461 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08002462 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002463 }
2464
2465 /** @see AudioManager#stopBluetoothSco() */
2466 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07002467 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002468 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002469 return;
2470 }
Eric Laurent854938a2011-02-22 12:05:20 -08002471 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002472 // The calling identity must be cleared before calling ScoClient.decCount().
2473 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2474 // and this must be done on behalf of system server to make sure permissions are granted.
2475 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08002476 if (client != null) {
2477 client.decCount();
2478 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08002479 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002480 }
2481
Eric Laurent78472112012-05-21 08:57:21 -07002482
Eric Laurent3def1ee2010-03-17 23:26:26 -07002483 private class ScoClient implements IBinder.DeathRecipient {
2484 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002485 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002486 private int mStartcount; // number of SCO connections started by this client
2487
2488 ScoClient(IBinder cb) {
2489 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002490 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002491 mStartcount = 0;
2492 }
2493
2494 public void binderDied() {
2495 synchronized(mScoClients) {
2496 Log.w(TAG, "SCO client died");
2497 int index = mScoClients.indexOf(this);
2498 if (index < 0) {
2499 Log.w(TAG, "unregistered SCO client died");
2500 } else {
2501 clearCount(true);
2502 mScoClients.remove(this);
2503 }
2504 }
2505 }
2506
Eric Laurent83900752014-05-15 15:14:22 -07002507 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002508 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07002509 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002510 if (mStartcount == 0) {
2511 try {
2512 mCb.linkToDeath(this, 0);
2513 } catch (RemoteException e) {
2514 // client has already died!
2515 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
2516 }
2517 }
2518 mStartcount++;
2519 }
2520 }
2521
2522 public void decCount() {
2523 synchronized(mScoClients) {
2524 if (mStartcount == 0) {
2525 Log.w(TAG, "ScoClient.decCount() already 0");
2526 } else {
2527 mStartcount--;
2528 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002529 try {
2530 mCb.unlinkToDeath(this, 0);
2531 } catch (NoSuchElementException e) {
2532 Log.w(TAG, "decCount() going to 0 but not registered to binder");
2533 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002534 }
Eric Laurentc18c9132013-04-12 17:24:56 -07002535 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002536 }
2537 }
2538 }
2539
2540 public void clearCount(boolean stopSco) {
2541 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002542 if (mStartcount != 0) {
2543 try {
2544 mCb.unlinkToDeath(this, 0);
2545 } catch (NoSuchElementException e) {
2546 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2547 }
2548 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002549 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002550 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002551 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002552 }
2553 }
2554 }
2555
2556 public int getCount() {
2557 return mStartcount;
2558 }
2559
2560 public IBinder getBinder() {
2561 return mCb;
2562 }
2563
Eric Laurentd7454be2011-09-14 08:45:58 -07002564 public int getPid() {
2565 return mCreatorPid;
2566 }
2567
Eric Laurent3def1ee2010-03-17 23:26:26 -07002568 public int totalCount() {
2569 synchronized(mScoClients) {
2570 int count = 0;
2571 int size = mScoClients.size();
2572 for (int i = 0; i < size; i++) {
2573 count += mScoClients.get(i).getCount();
2574 }
2575 return count;
2576 }
2577 }
2578
Eric Laurent83900752014-05-15 15:14:22 -07002579 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08002580 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07002581 if (totalCount() == 0) {
2582 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2583 // Make sure that the state transitions to CONNECTING even if we cannot initiate
2584 // the connection.
2585 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2586 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002587 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07002588 synchronized(mSetModeDeathHandlers) {
2589 if ((mSetModeDeathHandlers.isEmpty() ||
2590 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2591 (mScoAudioState == SCO_STATE_INACTIVE ||
2592 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2593 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07002594 mScoAudioMode = scoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -07002595 if (scoAudioMode == SCO_MODE_UNDEFINED) {
Andre Eisenbach570cc532014-10-28 17:03:18 -07002596 if (mBluetoothHeadsetDevice != null) {
2597 mScoAudioMode = new Integer(Settings.Global.getInt(
2598 mContentResolver,
2599 "bluetooth_sco_channel_"+
2600 mBluetoothHeadsetDevice.getAddress(),
2601 SCO_MODE_VIRTUAL_CALL));
2602 if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2603 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2604 }
2605 } else {
2606 mScoAudioMode = SCO_MODE_RAW;
Liejun Taof4e51d82014-07-16 11:18:29 -07002607 }
2608 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002609 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002610 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002611 if (mScoAudioMode == SCO_MODE_RAW) {
2612 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002613 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002614 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2615 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002616 } else if (mScoAudioMode == SCO_MODE_VR) {
2617 status = mBluetoothHeadset.startVoiceRecognition(
2618 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002619 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002620
Eric Laurentc18c9132013-04-12 17:24:56 -07002621 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07002622 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2623 } else {
2624 broadcastScoConnectionState(
2625 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2626 }
2627 } else if (getBluetoothHeadset()) {
2628 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07002629 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002630 } else {
2631 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2632 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002633 }
2634 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07002635 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002636 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002637 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002638 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002639 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2640 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2641 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07002642 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002643 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002644 if (mScoAudioMode == SCO_MODE_RAW) {
2645 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002646 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002647 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2648 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002649 } else if (mScoAudioMode == SCO_MODE_VR) {
2650 status = mBluetoothHeadset.stopVoiceRecognition(
2651 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002652 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002653
Eric Laurentc18c9132013-04-12 17:24:56 -07002654 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002655 mScoAudioState = SCO_STATE_INACTIVE;
2656 broadcastScoConnectionState(
2657 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2658 }
2659 } else if (getBluetoothHeadset()) {
2660 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2661 }
2662 } else {
2663 mScoAudioState = SCO_STATE_INACTIVE;
2664 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2665 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002666 }
2667 }
2668 }
2669 }
2670
Eric Laurent62ef7672010-11-24 10:58:32 -08002671 private void checkScoAudioState() {
2672 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002673 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08002674 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2675 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2676 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2677 }
2678 }
2679
Eric Laurent854938a2011-02-22 12:05:20 -08002680 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002681 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002682 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002683 int size = mScoClients.size();
2684 for (int i = 0; i < size; i++) {
2685 client = mScoClients.get(i);
2686 if (client.getBinder() == cb)
2687 return client;
2688 }
Eric Laurent854938a2011-02-22 12:05:20 -08002689 if (create) {
2690 client = new ScoClient(cb);
2691 mScoClients.add(client);
2692 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002693 return client;
2694 }
2695 }
2696
Eric Laurentd7454be2011-09-14 08:45:58 -07002697 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002698 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002699 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002700 int size = mScoClients.size();
2701 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08002702 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07002703 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08002704 cl.clearCount(stopSco);
2705 } else {
2706 savedClient = cl;
2707 }
2708 }
2709 mScoClients.clear();
2710 if (savedClient != null) {
2711 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002712 }
2713 }
2714 }
2715
Eric Laurentdc03c612011-04-01 10:59:41 -07002716 private boolean getBluetoothHeadset() {
2717 boolean result = false;
2718 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2719 if (adapter != null) {
2720 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2721 BluetoothProfile.HEADSET);
2722 }
2723 // If we could not get a bluetooth headset proxy, send a failure message
2724 // without delay to reset the SCO audio state and clear SCO clients.
2725 // If we could get a proxy, send a delayed failure message that will reset our state
2726 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08002727 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002728 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2729 return result;
2730 }
2731
Eric Laurentd7454be2011-09-14 08:45:58 -07002732 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002733 synchronized(mScoClients) {
2734 checkScoAudioState();
2735 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2736 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2737 if (mBluetoothHeadsetDevice != null) {
2738 if (mBluetoothHeadset != null) {
2739 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07002740 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002741 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002742 SENDMSG_REPLACE, 0, 0, null, 0);
2743 }
2744 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2745 getBluetoothHeadset()) {
2746 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2747 }
2748 }
2749 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07002750 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07002751 }
2752 }
2753 }
2754
2755 private void resetBluetoothSco() {
2756 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002757 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07002758 mScoAudioState = SCO_STATE_INACTIVE;
2759 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2760 }
2761 }
2762
2763 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08002764 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
2765 SENDMSG_QUEUE, state, 0, null, 0);
2766 }
2767
2768 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002769 if (state != mScoConnectionState) {
2770 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2771 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2772 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2773 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002774 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07002775 mScoConnectionState = state;
2776 }
2777 }
2778
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002779 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
2780 new BluetoothProfile.ServiceListener() {
2781 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002782 BluetoothDevice btDevice;
2783 List<BluetoothDevice> deviceList;
2784 switch(profile) {
2785 case BluetoothProfile.A2DP:
John Du5a0cf7a2013-07-19 11:30:34 -07002786 synchronized (mA2dpAvrcpLock) {
2787 mA2dp = (BluetoothA2dp) proxy;
2788 deviceList = mA2dp.getConnectedDevices();
2789 if (deviceList.size() > 0) {
2790 btDevice = deviceList.get(0);
2791 synchronized (mConnectedDevices) {
2792 int state = mA2dp.getConnectionState(btDevice);
2793 int delay = checkSendBecomingNoisyIntent(
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002794 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2795 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
John Du5a0cf7a2013-07-19 11:30:34 -07002796 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002797 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07002798 state,
2799 0,
2800 btDevice,
2801 delay);
2802 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002803 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002804 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002805 break;
2806
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002807 case BluetoothProfile.A2DP_SINK:
2808 deviceList = proxy.getConnectedDevices();
2809 if (deviceList.size() > 0) {
2810 btDevice = deviceList.get(0);
2811 synchronized (mConnectedDevices) {
2812 int state = proxy.getConnectionState(btDevice);
2813 queueMsgUnderWakeLock(mAudioHandler,
2814 MSG_SET_A2DP_SRC_CONNECTION_STATE,
2815 state,
2816 0,
2817 btDevice,
2818 0 /* delay */);
2819 }
2820 }
2821 break;
2822
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002823 case BluetoothProfile.HEADSET:
2824 synchronized (mScoClients) {
2825 // Discard timeout message
2826 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
2827 mBluetoothHeadset = (BluetoothHeadset) proxy;
2828 deviceList = mBluetoothHeadset.getConnectedDevices();
2829 if (deviceList.size() > 0) {
2830 mBluetoothHeadsetDevice = deviceList.get(0);
2831 } else {
2832 mBluetoothHeadsetDevice = null;
2833 }
2834 // Refresh SCO audio state
2835 checkScoAudioState();
2836 // Continue pending action if any
2837 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
2838 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
2839 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2840 boolean status = false;
2841 if (mBluetoothHeadsetDevice != null) {
2842 switch (mScoAudioState) {
2843 case SCO_STATE_ACTIVATE_REQ:
2844 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07002845 if (mScoAudioMode == SCO_MODE_RAW) {
2846 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002847 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002848 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2849 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002850 } else if (mScoAudioMode == SCO_MODE_VR) {
2851 status = mBluetoothHeadset.startVoiceRecognition(
2852 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002853 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002854 break;
2855 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07002856 if (mScoAudioMode == SCO_MODE_RAW) {
2857 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002858 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002859 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2860 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002861 } else if (mScoAudioMode == SCO_MODE_VR) {
2862 status = mBluetoothHeadset.stopVoiceRecognition(
2863 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002864 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002865 break;
2866 case SCO_STATE_DEACTIVATE_EXT_REQ:
2867 status = mBluetoothHeadset.stopVoiceRecognition(
2868 mBluetoothHeadsetDevice);
2869 }
2870 }
2871 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002872 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002873 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07002874 }
2875 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002876 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002877 break;
2878
2879 default:
2880 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002881 }
2882 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002883 public void onServiceDisconnected(int profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002884 switch(profile) {
2885 case BluetoothProfile.A2DP:
John Du5a0cf7a2013-07-19 11:30:34 -07002886 synchronized (mA2dpAvrcpLock) {
2887 mA2dp = null;
2888 synchronized (mConnectedDevices) {
2889 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
2890 makeA2dpDeviceUnavailableNow(
2891 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
2892 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002893 }
2894 }
2895 break;
2896
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002897 case BluetoothProfile.A2DP_SINK:
2898 synchronized (mConnectedDevices) {
2899 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) {
2900 makeA2dpSrcUnavailable(
2901 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP));
2902 }
2903 }
2904 break;
2905
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002906 case BluetoothProfile.HEADSET:
2907 synchronized (mScoClients) {
2908 mBluetoothHeadset = null;
2909 }
2910 break;
2911
2912 default:
2913 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002914 }
2915 }
2916 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08002917
Eric Laurentc34dcc12012-09-10 13:51:52 -07002918 private void onCheckMusicActive() {
Eric Laurentd640bd32012-09-28 18:01:48 -07002919 synchronized (mSafeMediaVolumeState) {
2920 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002921 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
2922
2923 if ((device & mSafeMediaVolumeDevices) != 0) {
2924 sendMsg(mAudioHandler,
2925 MSG_CHECK_MUSIC_ACTIVE,
2926 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07002927 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07002928 0,
2929 null,
2930 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07002931 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07002932 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
2933 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002934 // Approximate cumulative active music time
2935 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
2936 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
2937 setSafeMediaVolumeEnabled(true);
2938 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07002939 }
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002940 saveMusicActiveMs();
Eric Laurentc34dcc12012-09-10 13:51:52 -07002941 }
2942 }
2943 }
2944 }
2945 }
2946
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002947 private void saveMusicActiveMs() {
2948 mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
2949 }
2950
Eric Laurentd640bd32012-09-28 18:01:48 -07002951 private void onConfigureSafeVolume(boolean force) {
2952 synchronized (mSafeMediaVolumeState) {
2953 int mcc = mContext.getResources().getConfiguration().mcc;
2954 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
2955 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
2956 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
John Spurlock35134602014-07-24 18:10:48 -04002957 boolean safeMediaVolumeEnabled =
2958 SystemProperties.getBoolean("audio.safemedia.force", false)
2959 || mContext.getResources().getBoolean(
2960 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08002961
2962 // The persisted state is either "disabled" or "active": this is the state applied
2963 // next time we boot and cannot be "inactive"
2964 int persistedState;
Eric Laurentd640bd32012-09-28 18:01:48 -07002965 if (safeMediaVolumeEnabled) {
Eric Laurent05274f32012-11-29 12:48:18 -08002966 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
2967 // The state can already be "inactive" here if the user has forced it before
2968 // the 30 seconds timeout for forced configuration. In this case we don't reset
2969 // it to "active".
2970 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002971 if (mMusicActiveMs == 0) {
2972 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
2973 enforceSafeMediaVolume();
2974 } else {
2975 // We have existing playback time recorded, already confirmed.
2976 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
2977 }
Eric Laurent05274f32012-11-29 12:48:18 -08002978 }
Eric Laurentd640bd32012-09-28 18:01:48 -07002979 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08002980 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07002981 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
2982 }
2983 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08002984 sendMsg(mAudioHandler,
2985 MSG_PERSIST_SAFE_VOLUME_STATE,
2986 SENDMSG_QUEUE,
2987 persistedState,
2988 0,
2989 null,
2990 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07002991 }
2992 }
2993 }
2994
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002995 ///////////////////////////////////////////////////////////////////////////
2996 // Internal methods
2997 ///////////////////////////////////////////////////////////////////////////
2998
2999 /**
3000 * Checks if the adjustment should change ringer mode instead of just
3001 * adjusting volume. If so, this will set the proper ringer mode and volume
3002 * indices on the stream states.
3003 */
John Spurlocka11b4af2014-06-01 11:52:23 -04003004 private int checkForRingerModeChange(int oldIndex, int direction, int step) {
3005 int result = FLAG_ADJUST_VOLUME;
Glenn Kastenba195eb2011-12-13 09:30:40 -08003006 int ringerMode = getRingerMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003007
Eric Laurentbffc3d12012-05-07 17:43:49 -07003008 switch (ringerMode) {
3009 case RINGER_MODE_NORMAL:
3010 if (direction == AudioManager.ADJUST_LOWER) {
3011 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07003012 // "step" is the delta in internal index units corresponding to a
3013 // change of 1 in UI index units.
3014 // Because of rounding when rescaling from one stream index range to its alias
3015 // index range, we cannot simply test oldIndex == step:
3016 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
3017 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003018 ringerMode = RINGER_MODE_VIBRATE;
3019 }
3020 } else {
Eric Laurent24482012012-05-10 09:41:17 -07003021 // (oldIndex < step) is equivalent to (old UI index == 0)
John Spurlock86005342014-05-23 11:58:00 -04003022 if ((oldIndex < step)
3023 && VOLUME_SETS_RINGER_MODE_SILENT
3024 && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003025 ringerMode = RINGER_MODE_SILENT;
3026 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07003027 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003028 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003029 break;
3030 case RINGER_MODE_VIBRATE:
3031 if (!mHasVibrator) {
3032 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
3033 "but no vibrator is present");
3034 break;
3035 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003036 if ((direction == AudioManager.ADJUST_LOWER)) {
John Spurlock86005342014-05-23 11:58:00 -04003037 if (VOLUME_SETS_RINGER_MODE_SILENT
3038 && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003039 ringerMode = RINGER_MODE_SILENT;
Amith Yamasanic696a532011-10-28 17:02:37 -07003040 }
3041 } else if (direction == AudioManager.ADJUST_RAISE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003042 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07003043 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003044 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003045 break;
3046 case RINGER_MODE_SILENT:
Daniel Sandler6329bf72010-02-26 15:17:44 -05003047 if (direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003048 if (PREVENT_VOLUME_ADJUSTMENT_IF_SILENT) {
3049 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003050 } else {
John Spurlocka11b4af2014-06-01 11:52:23 -04003051 if (mHasVibrator) {
3052 ringerMode = RINGER_MODE_VIBRATE;
3053 } else {
3054 ringerMode = RINGER_MODE_NORMAL;
3055 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003056 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05003057 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003058 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003059 break;
3060 default:
3061 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
3062 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003063 }
3064
John Spurlocke5b42d92014-10-15 12:03:48 -04003065 setRingerMode(ringerMode, false /*checkZen*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003066
Eric Laurent25101b02011-02-02 09:33:30 -08003067 mPrevVolDirection = direction;
3068
John Spurlocka11b4af2014-06-01 11:52:23 -04003069 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003070 }
3071
John Spurlock3346a802014-05-20 16:25:37 -04003072 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003073 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07003074 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003075 }
3076
Eric Laurent5b4e6542010-03-19 20:02:21 -07003077 private boolean isStreamMutedByRingerMode(int streamType) {
3078 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
3079 }
3080
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003081 boolean updateRingerModeAffectedStreams() {
3082 int ringerModeAffectedStreams;
3083 // make sure settings for ringer mode are consistent with device type: non voice capable
3084 // devices (tablets) include media stream in silent mode whereas phones don't.
3085 ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
3086 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3087 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
3088 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
3089 UserHandle.USER_CURRENT);
3090
3091 // ringtone, notification and system streams are always affected by ringer mode
3092 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
3093 (1 << AudioSystem.STREAM_NOTIFICATION)|
3094 (1 << AudioSystem.STREAM_SYSTEM);
3095
Eric Laurent212532b2014-07-21 15:43:18 -07003096 switch (mPlatformType) {
Eric Laurent212532b2014-07-21 15:43:18 -07003097 case PLATFORM_TELEVISION:
3098 ringerModeAffectedStreams = 0;
3099 break;
3100 default:
John Spurlock77e54d92014-08-11 12:16:24 -04003101 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
Eric Laurent212532b2014-07-21 15:43:18 -07003102 break;
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003103 }
Eric Laurent212532b2014-07-21 15:43:18 -07003104
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003105 synchronized (mCameraSoundForced) {
3106 if (mCameraSoundForced) {
3107 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3108 } else {
3109 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3110 }
3111 }
3112 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
3113 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
3114 } else {
3115 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
3116 }
3117
3118 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3119 Settings.System.putIntForUser(mContentResolver,
3120 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3121 ringerModeAffectedStreams,
3122 UserHandle.USER_CURRENT);
3123 mRingerModeAffectedStreams = ringerModeAffectedStreams;
3124 return true;
3125 }
3126 return false;
3127 }
3128
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003129 public boolean isStreamAffectedByMute(int streamType) {
3130 return (mMuteAffectedStreams & (1 << streamType)) != 0;
3131 }
3132
3133 private void ensureValidDirection(int direction) {
3134 if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
3135 throw new IllegalArgumentException("Bad direction " + direction);
3136 }
3137 }
3138
Lei Zhang6c798972012-03-02 11:40:12 -08003139 private void ensureValidSteps(int steps) {
3140 if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
3141 throw new IllegalArgumentException("Bad volume adjust steps " + steps);
3142 }
3143 }
3144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003145 private void ensureValidStreamType(int streamType) {
3146 if (streamType < 0 || streamType >= mStreamStates.length) {
3147 throw new IllegalArgumentException("Bad stream type " + streamType);
3148 }
3149 }
3150
Eric Laurent6d517662012-04-23 18:42:39 -07003151 private boolean isInCommunication() {
Nancy Chen0eb1e402014-08-21 22:52:29 -07003152 boolean IsInCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003153
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003154 TelecomManager telecomManager =
3155 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
3156 IsInCall = telecomManager.isInCall();
Santos Cordon9eb45932014-06-27 12:28:43 -07003157
Nancy Chen0eb1e402014-08-21 22:52:29 -07003158 return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
Eric Laurent6d517662012-04-23 18:42:39 -07003159 }
Eric Laurent25101b02011-02-02 09:33:30 -08003160
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003161 /**
3162 * For code clarity for getActiveStreamType(int)
3163 * @param delay_ms max time since last STREAM_MUSIC activity to consider
3164 * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
3165 * in the last "delay_ms" ms.
3166 */
3167 private boolean isAfMusicActiveRecently(int delay_ms) {
3168 return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
3169 || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
3170 }
3171
Eric Laurent6d517662012-04-23 18:42:39 -07003172 private int getActiveStreamType(int suggestedStreamType) {
Eric Laurent212532b2014-07-21 15:43:18 -07003173 switch (mPlatformType) {
3174 case PLATFORM_VOICE:
Eric Laurent6d517662012-04-23 18:42:39 -07003175 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003176 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3177 == AudioSystem.FORCE_BT_SCO) {
3178 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
3179 return AudioSystem.STREAM_BLUETOOTH_SCO;
3180 } else {
3181 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
3182 return AudioSystem.STREAM_VOICE_CALL;
3183 }
Eric Laurent25101b02011-02-02 09:33:30 -08003184 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003185 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003186 if (DEBUG_VOL)
3187 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3188 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003189 } else {
3190 if (DEBUG_VOL)
3191 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
3192 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003193 }
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003194 } else if (isAfMusicActiveRecently(0)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003195 if (DEBUG_VOL)
3196 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3197 return AudioSystem.STREAM_MUSIC;
Eric Laurent25101b02011-02-02 09:33:30 -08003198 }
Eric Laurent212532b2014-07-21 15:43:18 -07003199 break;
3200 case PLATFORM_TELEVISION:
3201 if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
RoboErik2811dd32014-08-12 09:48:13 -07003202 // TV always defaults to STREAM_MUSIC
Eric Laurent212532b2014-07-21 15:43:18 -07003203 return AudioSystem.STREAM_MUSIC;
Eric Laurent212532b2014-07-21 15:43:18 -07003204 }
3205 break;
3206 default:
Eric Laurent6d517662012-04-23 18:42:39 -07003207 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003208 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3209 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003210 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08003211 return AudioSystem.STREAM_BLUETOOTH_SCO;
3212 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003213 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08003214 return AudioSystem.STREAM_VOICE_CALL;
3215 }
3216 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003217 StreamOverride.sDelayMs) ||
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003218 AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003219 StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003220 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08003221 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003222 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003223 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003224 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
3225 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003226 } else {
John Spurlockeb1d88d2014-07-19 14:49:19 -04003227 if (DEBUG_VOL) Log.v(TAG,
3228 "getActiveStreamType: using STREAM_NOTIFICATION as default");
3229 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003230 }
Joe Onoratoc7fcba42011-01-05 16:53:11 -08003231 }
Eric Laurent212532b2014-07-21 15:43:18 -07003232 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003233 }
Eric Laurent212532b2014-07-21 15:43:18 -07003234 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
3235 + suggestedStreamType);
3236 return suggestedStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003237 }
3238
Glenn Kastenba195eb2011-12-13 09:30:40 -08003239 private void broadcastRingerMode(int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003240 // Send sticky broadcast
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003241 Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION);
Glenn Kastenba195eb2011-12-13 09:30:40 -08003242 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003243 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
3244 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003245 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003246 }
3247
3248 private void broadcastVibrateSetting(int vibrateType) {
3249 // Send broadcast
3250 if (ActivityManagerNative.isSystemReady()) {
3251 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
3252 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
3253 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003254 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003255 }
3256 }
3257
3258 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003259 /**
3260 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
3261 * Note that the wake lock needs to be released after the message has been handled.
3262 */
3263 private void queueMsgUnderWakeLock(Handler handler, int msg,
3264 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003265 final long ident = Binder.clearCallingIdentity();
3266 // Always acquire the wake lock as AudioService because it is released by the
3267 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003268 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003269 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003270 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
3271 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003272
Eric Laurentafbb0472011-12-15 09:04:23 -08003273 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003274 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003275
3276 if (existingMsgPolicy == SENDMSG_REPLACE) {
3277 handler.removeMessages(msg);
3278 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
3279 return;
3280 }
Eric Laurentadbe8bf2014-11-03 18:26:32 -08003281 synchronized (mLastDeviceConnectMsgTime) {
3282 long time = SystemClock.uptimeMillis() + delay;
3283 handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
3284 if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
3285 msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
3286 msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
3287 mLastDeviceConnectMsgTime = time;
3288 }
3289 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003290 }
3291
3292 boolean checkAudioSettingsPermission(String method) {
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07003293 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003294 == PackageManager.PERMISSION_GRANTED) {
3295 return true;
3296 }
3297 String msg = "Audio Settings Permission Denial: " + method + " from pid="
3298 + Binder.getCallingPid()
3299 + ", uid=" + Binder.getCallingUid();
3300 Log.w(TAG, msg);
3301 return false;
3302 }
3303
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003304 private int getDeviceForStream(int stream) {
3305 int device = AudioSystem.getDevicesForStream(stream);
3306 if ((device & (device - 1)) != 0) {
3307 // Multiple device selection is either:
3308 // - speaker + one other device: give priority to speaker in this case.
3309 // - one A2DP device + another device: happens with duplicated output. In this case
3310 // retain the device on the A2DP output as the other must not correspond to an active
3311 // selection if not the speaker.
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003312 // - HDMI-CEC system audio mode only output: give priority to available item in order.
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003313 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
3314 device = AudioSystem.DEVICE_OUT_SPEAKER;
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003315 } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
3316 device = AudioSystem.DEVICE_OUT_HDMI_ARC;
3317 } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
3318 device = AudioSystem.DEVICE_OUT_SPDIF;
3319 } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
3320 device = AudioSystem.DEVICE_OUT_AUX_LINE;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003321 } else {
3322 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
3323 }
3324 }
3325 return device;
3326 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003327
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003328 public void setWiredDeviceConnectionState(int device, int state, String name) {
3329 synchronized (mConnectedDevices) {
3330 int delay = checkSendBecomingNoisyIntent(device, state);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003331 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003332 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003333 device,
3334 state,
3335 name,
3336 delay);
3337 }
3338 }
3339
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003340 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003341 {
3342 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003343 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
3344 throw new IllegalArgumentException("invalid profile " + profile);
3345 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003346 synchronized (mConnectedDevices) {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003347 if (profile == BluetoothProfile.A2DP) {
3348 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3349 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
3350 } else {
3351 delay = 0;
3352 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003353 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003354 (profile == BluetoothProfile.A2DP ?
3355 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003356 state,
3357 0,
3358 device,
3359 delay);
3360 }
3361 return delay;
3362 }
3363
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003364 ///////////////////////////////////////////////////////////////////////////
3365 // Inner classes
3366 ///////////////////////////////////////////////////////////////////////////
3367
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003368 // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
3369 // 1 mScoclient OR mSafeMediaVolumeState
3370 // 2 mSetModeDeathHandlers
3371 // 3 mSettingsLock
3372 // 4 VolumeStreamState.class
3373 // 5 mCameraSoundForced
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003374 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003375 private final int mStreamType;
3376
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003377 private String mVolumeIndexSettingName;
Eric Laurenta553c252009-07-17 12:17:14 -07003378 private int mIndexMax;
Eric Laurent3172d5e2012-05-09 11:38:16 -07003379 private final ConcurrentHashMap<Integer, Integer> mIndex =
3380 new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003381 private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003382
Eric Laurenta553c252009-07-17 12:17:14 -07003383 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003384
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003385 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003386
3387 mStreamType = streamType;
Jared Suttles59820132009-08-13 21:50:52 -05003388 mIndexMax = MAX_STREAM_VOLUME[streamType];
Eric Laurenta553c252009-07-17 12:17:14 -07003389 AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
3390 mIndexMax *= 10;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003391
Eric Laurent33902db2012-10-07 16:15:07 -07003392 // mDeathHandlers must be created before calling readSettings()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003393 mDeathHandlers = new ArrayList<VolumeDeathHandler>();
Eric Laurent33902db2012-10-07 16:15:07 -07003394
3395 readSettings();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003396 }
3397
Eric Laurent42b041e2013-03-29 11:36:03 -07003398 public String getSettingNameForDevice(int device) {
3399 String name = mVolumeIndexSettingName;
Eric Laurent948d3272014-05-16 15:18:45 -07003400 String suffix = AudioSystem.getOutputDeviceName(device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003401 if (suffix.isEmpty()) {
3402 return name;
3403 }
3404 return name + "_" + suffix;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003405 }
3406
Eric Laurentfdbee862014-05-12 15:26:12 -07003407 public void readSettings() {
3408 synchronized (VolumeStreamState.class) {
3409 // force maximum volume on all streams if fixed volume property is set
3410 if (mUseFixedVolume) {
3411 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
3412 return;
3413 }
3414 // do not read system stream volume from settings: this stream is always aliased
3415 // to another stream type and its volume is never persisted. Values in settings can
3416 // only be stale values
3417 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3418 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
Eric Laurent91377de2014-10-10 15:24:04 -07003419 int index = 10 * DEFAULT_STREAM_VOLUME[mStreamType];
Eric Laurentfdbee862014-05-12 15:26:12 -07003420 synchronized (mCameraSoundForced) {
3421 if (mCameraSoundForced) {
3422 index = mIndexMax;
3423 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003424 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003425 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
3426 return;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003427 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003428
Eric Laurentfdbee862014-05-12 15:26:12 -07003429 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
3430
3431 for (int i = 0; remainingDevices != 0; i++) {
3432 int device = (1 << i);
3433 if ((device & remainingDevices) == 0) {
3434 continue;
3435 }
3436 remainingDevices &= ~device;
3437
3438 // retrieve current volume for device
3439 String name = getSettingNameForDevice(device);
3440 // if no volume stored for current stream and device, use default volume if default
3441 // device, continue otherwise
3442 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
Eric Laurent91377de2014-10-10 15:24:04 -07003443 DEFAULT_STREAM_VOLUME[mStreamType] : -1;
Eric Laurentfdbee862014-05-12 15:26:12 -07003444 int index = Settings.System.getIntForUser(
3445 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3446 if (index == -1) {
3447 continue;
3448 }
3449
Eric Laurent212532b2014-07-21 15:43:18 -07003450 mIndex.put(device, getValidIndex(10 * index));
Eric Laurentdd45d012012-10-08 09:04:34 -07003451 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003452 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003453 }
3454
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003455 // must be called while synchronized VolumeStreamState.class
3456 public void applyDeviceVolume_syncVSS(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003457 int index;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003458 if (isMuted_syncVSS()) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003459 index = 0;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003460 } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported)
3461 || ((device & mFullVolumeDevices) != 0)) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003462 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07003463 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07003464 index = (getIndex(device) + 5)/10;
3465 }
3466 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003467 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003468
Eric Laurentfdbee862014-05-12 15:26:12 -07003469 public void applyAllVolumes() {
3470 synchronized (VolumeStreamState.class) {
3471 // apply default volume first: by convention this will reset all
3472 // devices volumes in audio policy manager to the supplied value
3473 int index;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003474 if (isMuted_syncVSS()) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003475 index = 0;
3476 } else {
3477 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3478 }
3479 AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3480 // then apply device specific volumes
3481 Set set = mIndex.entrySet();
3482 Iterator i = set.iterator();
3483 while (i.hasNext()) {
3484 Map.Entry entry = (Map.Entry)i.next();
3485 int device = ((Integer)entry.getKey()).intValue();
3486 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003487 if (isMuted_syncVSS()) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003488 index = 0;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003489 } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3490 mAvrcpAbsVolSupported)
3491 || ((device & mFullVolumeDevices) != 0))
3492 {
Eric Laurentfdbee862014-05-12 15:26:12 -07003493 index = (mIndexMax + 5)/10;
3494 } else {
3495 index = ((Integer)entry.getValue() + 5)/10;
3496 }
3497 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07003498 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003499 }
3500 }
3501 }
3502
3503 public boolean adjustIndex(int deltaIndex, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003504 return setIndex(getIndex(device) + deltaIndex,
3505 device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003506 }
3507
Eric Laurentfdbee862014-05-12 15:26:12 -07003508 public boolean setIndex(int index, int device) {
3509 synchronized (VolumeStreamState.class) {
3510 int oldIndex = getIndex(device);
3511 index = getValidIndex(index);
3512 synchronized (mCameraSoundForced) {
3513 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3514 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07003515 }
3516 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003517 mIndex.put(device, index);
3518
3519 if (oldIndex != index) {
3520 // Apply change to all streams using this one as alias
3521 // if changing volume of current device, also change volume of current
3522 // device on aliased stream
3523 boolean currentDevice = (device == getDeviceForStream(mStreamType));
3524 int numStreamTypes = AudioSystem.getNumStreamTypes();
3525 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3526 if (streamType != mStreamType &&
3527 mStreamVolumeAlias[streamType] == mStreamType) {
3528 int scaledIndex = rescaleIndex(index, mStreamType, streamType);
3529 mStreamStates[streamType].setIndex(scaledIndex,
3530 device);
3531 if (currentDevice) {
3532 mStreamStates[streamType].setIndex(scaledIndex,
3533 getDeviceForStream(streamType));
3534 }
3535 }
3536 }
3537 return true;
3538 } else {
3539 return false;
3540 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003541 }
3542 }
3543
Eric Laurentfdbee862014-05-12 15:26:12 -07003544 public int getIndex(int device) {
3545 synchronized (VolumeStreamState.class) {
3546 Integer index = mIndex.get(device);
3547 if (index == null) {
3548 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
3549 index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
3550 }
3551 return index.intValue();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003552 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07003553 }
3554
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003555 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07003556 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003557 }
3558
Eric Laurentfdbee862014-05-12 15:26:12 -07003559 public void setAllIndexes(VolumeStreamState srcStream) {
3560 synchronized (VolumeStreamState.class) {
3561 int srcStreamType = srcStream.getStreamType();
3562 // apply default device volume from source stream to all devices first in case
3563 // some devices are present in this stream state but not in source stream state
3564 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003565 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurentfdbee862014-05-12 15:26:12 -07003566 Set set = mIndex.entrySet();
3567 Iterator i = set.iterator();
3568 while (i.hasNext()) {
3569 Map.Entry entry = (Map.Entry)i.next();
3570 entry.setValue(index);
3571 }
3572 // Now apply actual volume for devices in source stream state
3573 set = srcStream.mIndex.entrySet();
3574 i = set.iterator();
3575 while (i.hasNext()) {
3576 Map.Entry entry = (Map.Entry)i.next();
3577 int device = ((Integer)entry.getKey()).intValue();
3578 index = ((Integer)entry.getValue()).intValue();
3579 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07003580
Eric Laurentfdbee862014-05-12 15:26:12 -07003581 setIndex(index, device);
3582 }
Eric Laurent6d517662012-04-23 18:42:39 -07003583 }
3584 }
3585
Eric Laurentfdbee862014-05-12 15:26:12 -07003586 public void setAllIndexesToMax() {
3587 synchronized (VolumeStreamState.class) {
3588 Set set = mIndex.entrySet();
3589 Iterator i = set.iterator();
3590 while (i.hasNext()) {
3591 Map.Entry entry = (Map.Entry)i.next();
3592 entry.setValue(mIndexMax);
3593 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003594 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003595 }
3596
Eric Laurentfdbee862014-05-12 15:26:12 -07003597 public void mute(IBinder cb, boolean state) {
3598 synchronized (VolumeStreamState.class) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003599 VolumeDeathHandler handler = getDeathHandler_syncVSS(cb, state);
Eric Laurentfdbee862014-05-12 15:26:12 -07003600 if (handler == null) {
3601 Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
3602 return;
3603 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003604 handler.mute_syncVSS(state);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003605 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003606 }
3607
Eric Laurent6d517662012-04-23 18:42:39 -07003608 public int getStreamType() {
3609 return mStreamType;
3610 }
3611
Eric Laurent212532b2014-07-21 15:43:18 -07003612 public void checkFixedVolumeDevices() {
3613 synchronized (VolumeStreamState.class) {
3614 // ignore settings for fixed volume devices: volume should always be at max or 0
3615 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
3616 Set set = mIndex.entrySet();
3617 Iterator i = set.iterator();
3618 while (i.hasNext()) {
3619 Map.Entry entry = (Map.Entry)i.next();
3620 int device = ((Integer)entry.getKey()).intValue();
3621 int index = ((Integer)entry.getValue()).intValue();
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003622 if (((device & mFullVolumeDevices) != 0)
3623 || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
Eric Laurent212532b2014-07-21 15:43:18 -07003624 entry.setValue(mIndexMax);
3625 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003626 applyDeviceVolume_syncVSS(device);
Eric Laurent212532b2014-07-21 15:43:18 -07003627 }
3628 }
3629 }
3630 }
3631
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003632 private int getValidIndex(int index) {
3633 if (index < 0) {
3634 return 0;
Eric Laurent83a017b2013-03-19 18:15:31 -07003635 } else if (mUseFixedVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07003636 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003637 }
3638
3639 return index;
3640 }
3641
3642 private class VolumeDeathHandler implements IBinder.DeathRecipient {
3643 private IBinder mICallback; // To be notified of client's death
3644 private int mMuteCount; // Number of active mutes for this client
3645
3646 VolumeDeathHandler(IBinder cb) {
3647 mICallback = cb;
3648 }
3649
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003650 // must be called while synchronized VolumeStreamState.class
3651 public void mute_syncVSS(boolean state) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003652 boolean updateVolume = false;
Eric Laurent3172d5e2012-05-09 11:38:16 -07003653 if (state) {
3654 if (mMuteCount == 0) {
3655 // Register for client death notification
3656 try {
3657 // mICallback can be 0 if muted by AudioService
3658 if (mICallback != null) {
3659 mICallback.linkToDeath(this, 0);
3660 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003661 VolumeStreamState.this.mDeathHandlers.add(this);
Eric Laurent3172d5e2012-05-09 11:38:16 -07003662 // If the stream is not yet muted by any client, set level to 0
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003663 if (!VolumeStreamState.this.isMuted_syncVSS()) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003664 updateVolume = true;
Eric Laurent3172d5e2012-05-09 11:38:16 -07003665 }
3666 } catch (RemoteException e) {
3667 // Client has died!
3668 binderDied();
3669 return;
3670 }
3671 } else {
3672 Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
3673 }
3674 mMuteCount++;
3675 } else {
3676 if (mMuteCount == 0) {
3677 Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
3678 } else {
3679 mMuteCount--;
3680 if (mMuteCount == 0) {
3681 // Unregister from client death notification
Eric Laurent42b041e2013-03-29 11:36:03 -07003682 VolumeStreamState.this.mDeathHandlers.remove(this);
Eric Laurent3172d5e2012-05-09 11:38:16 -07003683 // mICallback can be 0 if muted by AudioService
3684 if (mICallback != null) {
3685 mICallback.unlinkToDeath(this, 0);
3686 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003687 if (!VolumeStreamState.this.isMuted_syncVSS()) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003688 updateVolume = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003689 }
3690 }
3691 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003692 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003693 if (updateVolume) {
3694 sendMsg(mAudioHandler,
3695 MSG_SET_ALL_VOLUMES,
3696 SENDMSG_QUEUE,
3697 0,
3698 0,
3699 VolumeStreamState.this, 0);
3700 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003701 }
3702
3703 public void binderDied() {
3704 Log.w(TAG, "Volume service client died for stream: "+mStreamType);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003705 synchronized (VolumeStreamState.class) {
3706 if (mMuteCount != 0) {
3707 // Reset all active mute requests from this client.
3708 mMuteCount = 1;
3709 mute_syncVSS(false);
3710 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003711 }
3712 }
3713 }
3714
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003715 private int muteCount() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003716 int count = 0;
3717 int size = mDeathHandlers.size();
3718 for (int i = 0; i < size; i++) {
3719 count += mDeathHandlers.get(i).mMuteCount;
3720 }
3721 return count;
3722 }
3723
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003724 // must be called while synchronized VolumeStreamState.class
3725 private boolean isMuted_syncVSS() {
Eric Laurent42b041e2013-03-29 11:36:03 -07003726 return muteCount() != 0;
3727 }
3728
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003729 // must be called while synchronized VolumeStreamState.class
3730 private VolumeDeathHandler getDeathHandler_syncVSS(IBinder cb, boolean state) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07003731 VolumeDeathHandler handler;
3732 int size = mDeathHandlers.size();
3733 for (int i = 0; i < size; i++) {
3734 handler = mDeathHandlers.get(i);
3735 if (cb == handler.mICallback) {
3736 return handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003737 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003738 }
Eric Laurent3172d5e2012-05-09 11:38:16 -07003739 // If this is the first mute request for this client, create a new
3740 // client death handler. Otherwise, it is an out of sequence unmute request.
3741 if (state) {
3742 handler = new VolumeDeathHandler(cb);
3743 } else {
3744 Log.w(TAG, "stream was not muted by this client");
3745 handler = null;
3746 }
3747 return handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003748 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003749
3750 private void dump(PrintWriter pw) {
Eric Laurentdd45d012012-10-08 09:04:34 -07003751 pw.print(" Mute count: ");
3752 pw.println(muteCount());
John Spurlock2b29bc42014-08-26 16:40:35 -04003753 pw.print(" Max: ");
3754 pw.println((mIndexMax + 5) / 10);
Eric Laurentbffc3d12012-05-07 17:43:49 -07003755 pw.print(" Current: ");
3756 Set set = mIndex.entrySet();
3757 Iterator i = set.iterator();
3758 while (i.hasNext()) {
3759 Map.Entry entry = (Map.Entry)i.next();
John Spurlock2b29bc42014-08-26 16:40:35 -04003760 final int device = (Integer) entry.getKey();
3761 pw.print(Integer.toHexString(device));
3762 final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
3763 : AudioSystem.getOutputDeviceName(device);
3764 if (!deviceName.isEmpty()) {
3765 pw.print(" (");
3766 pw.print(deviceName);
3767 pw.print(")");
3768 }
3769 pw.print(": ");
3770 final int index = (((Integer) entry.getValue()) + 5) / 10;
3771 pw.print(index);
3772 if (i.hasNext()) {
3773 pw.print(", ");
3774 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003775 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003776 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003777 }
3778
3779 /** Thread that handles native AudioSystem control. */
3780 private class AudioSystemThread extends Thread {
3781 AudioSystemThread() {
3782 super("AudioService");
3783 }
3784
3785 @Override
3786 public void run() {
3787 // Set this thread up so the handler will work on it
3788 Looper.prepare();
3789
3790 synchronized(AudioService.this) {
3791 mAudioHandler = new AudioHandler();
3792
3793 // Notify that the handler has been created
3794 AudioService.this.notify();
3795 }
3796
3797 // Listen for volume change requests that are set by VolumePanel
3798 Looper.loop();
3799 }
3800 }
3801
3802 /** Handles internal volume messages in separate volume thread. */
3803 private class AudioHandler extends Handler {
3804
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003805 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003806
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003807 synchronized (VolumeStreamState.class) {
3808 // Apply volume
3809 streamState.applyDeviceVolume_syncVSS(device);
Eric Laurenta553c252009-07-17 12:17:14 -07003810
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003811 // Apply change to all streams using this one as alias
3812 int numStreamTypes = AudioSystem.getNumStreamTypes();
3813 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3814 if (streamType != streamState.mStreamType &&
3815 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
3816 // Make sure volume is also maxed out on A2DP device for aliased stream
3817 // that may have a different device selected
3818 int streamDevice = getDeviceForStream(streamType);
3819 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
3820 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
3821 mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
3822 }
3823 mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
Eric Laurentcd772d02013-10-30 18:31:07 -07003824 }
Eric Laurenta553c252009-07-17 12:17:14 -07003825 }
3826 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003827 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08003828 sendMsg(mAudioHandler,
3829 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08003830 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003831 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07003832 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08003833 streamState,
3834 PERSIST_DELAY);
3835
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003836 }
3837
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003838 private void setAllVolumes(VolumeStreamState streamState) {
3839
3840 // Apply volume
3841 streamState.applyAllVolumes();
3842
3843 // Apply change to all streams using this one as alias
3844 int numStreamTypes = AudioSystem.getNumStreamTypes();
3845 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3846 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07003847 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003848 mStreamStates[streamType].applyAllVolumes();
3849 }
3850 }
3851 }
3852
Eric Laurent42b041e2013-03-29 11:36:03 -07003853 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003854 if (mUseFixedVolume) {
3855 return;
3856 }
Eric Laurent212532b2014-07-21 15:43:18 -07003857 if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
3858 return;
3859 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003860 System.putIntForUser(mContentResolver,
3861 streamState.getSettingNameForDevice(device),
3862 (streamState.getIndex(device) + 5)/ 10,
3863 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003864 }
3865
Glenn Kastenba195eb2011-12-13 09:30:40 -08003866 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003867 if (mUseFixedVolume) {
3868 return;
3869 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07003870 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003871 }
3872
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003873 private boolean onLoadSoundEffects() {
3874 int status;
3875
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003876 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07003877 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003878 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
3879 return false;
3880 }
3881
3882 if (mSoundPool != null) {
3883 return true;
3884 }
3885
3886 loadTouchSoundAssets();
3887
Jean-Michel Trivi55a30c42014-07-20 17:56:11 -07003888 mSoundPool = new SoundPool.Builder()
3889 .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
3890 .setAudioAttributes(new AudioAttributes.Builder()
3891 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
3892 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
3893 .build())
3894 .build();
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003895 mSoundPoolCallBack = null;
3896 mSoundPoolListenerThread = new SoundPoolListenerThread();
3897 mSoundPoolListenerThread.start();
3898 int attempts = 3;
3899 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
3900 try {
3901 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07003902 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003903 } catch (InterruptedException e) {
3904 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
3905 }
3906 }
3907
3908 if (mSoundPoolCallBack == null) {
3909 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
3910 if (mSoundPoolLooper != null) {
3911 mSoundPoolLooper.quit();
3912 mSoundPoolLooper = null;
3913 }
3914 mSoundPoolListenerThread = null;
3915 mSoundPool.release();
3916 mSoundPool = null;
3917 return false;
3918 }
3919 /*
3920 * poolId table: The value -1 in this table indicates that corresponding
3921 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
3922 * Once loaded, the value in poolId is the sample ID and the same
3923 * sample can be reused for another effect using the same file.
3924 */
3925 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3926 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3927 poolId[fileIdx] = -1;
3928 }
3929 /*
3930 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
3931 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
3932 * this indicates we have a valid sample loaded for this effect.
3933 */
3934
3935 int numSamples = 0;
3936 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3937 // Do not load sample if this effect uses the MediaPlayer
3938 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
3939 continue;
3940 }
3941 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
3942 String filePath = Environment.getRootDirectory()
3943 + SOUND_EFFECTS_PATH
3944 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
3945 int sampleId = mSoundPool.load(filePath, 0);
3946 if (sampleId <= 0) {
3947 Log.w(TAG, "Soundpool could not load file: "+filePath);
3948 } else {
3949 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
3950 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
3951 numSamples++;
3952 }
3953 } else {
3954 SOUND_EFFECT_FILES_MAP[effect][1] =
3955 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
3956 }
3957 }
3958 // wait for all samples to be loaded
3959 if (numSamples > 0) {
3960 mSoundPoolCallBack.setSamples(poolId);
3961
3962 attempts = 3;
3963 status = 1;
3964 while ((status == 1) && (attempts-- > 0)) {
3965 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07003966 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003967 status = mSoundPoolCallBack.status();
3968 } catch (InterruptedException e) {
3969 Log.w(TAG, "Interrupted while waiting sound pool callback.");
3970 }
3971 }
3972 } else {
3973 status = -1;
3974 }
3975
3976 if (mSoundPoolLooper != null) {
3977 mSoundPoolLooper.quit();
3978 mSoundPoolLooper = null;
3979 }
3980 mSoundPoolListenerThread = null;
3981 if (status != 0) {
3982 Log.w(TAG,
3983 "onLoadSoundEffects(), Error "+status+ " while loading samples");
3984 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3985 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
3986 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3987 }
3988 }
3989
3990 mSoundPool.release();
3991 mSoundPool = null;
3992 }
3993 }
3994 return (status == 0);
3995 }
3996
3997 /**
3998 * Unloads samples from the sound pool.
3999 * This method can be called to free some memory when
4000 * sound effects are disabled.
4001 */
4002 private void onUnloadSoundEffects() {
4003 synchronized (mSoundEffectsLock) {
4004 if (mSoundPool == null) {
4005 return;
4006 }
4007
4008 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4009 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4010 poolId[fileIdx] = 0;
4011 }
4012
4013 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4014 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
4015 continue;
4016 }
4017 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
4018 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
4019 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4020 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
4021 }
4022 }
4023 mSoundPool.release();
4024 mSoundPool = null;
4025 }
4026 }
4027
4028 private void onPlaySoundEffect(int effectType, int volume) {
4029 synchronized (mSoundEffectsLock) {
4030
4031 onLoadSoundEffects();
4032
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004033 if (mSoundPool == null) {
4034 return;
4035 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004036 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08004037 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004038 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07004039 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004040 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07004041 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004042 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004043
4044 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004045 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
4046 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004047 } else {
4048 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004049 try {
Eric Laurente78fced2013-03-15 16:03:47 -07004050 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
4051 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004052 mediaPlayer.setDataSource(filePath);
4053 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
4054 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08004055 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004056 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
4057 public void onCompletion(MediaPlayer mp) {
4058 cleanupPlayer(mp);
4059 }
4060 });
4061 mediaPlayer.setOnErrorListener(new OnErrorListener() {
4062 public boolean onError(MediaPlayer mp, int what, int extra) {
4063 cleanupPlayer(mp);
4064 return true;
4065 }
4066 });
4067 mediaPlayer.start();
4068 } catch (IOException ex) {
4069 Log.w(TAG, "MediaPlayer IOException: "+ex);
4070 } catch (IllegalArgumentException ex) {
4071 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
4072 } catch (IllegalStateException ex) {
4073 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004074 }
4075 }
4076 }
4077 }
4078
4079 private void cleanupPlayer(MediaPlayer mp) {
4080 if (mp != null) {
4081 try {
4082 mp.stop();
4083 mp.release();
4084 } catch (IllegalStateException ex) {
4085 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
4086 }
4087 }
4088 }
4089
Eric Laurentfa640152011-03-12 15:59:51 -08004090 private void setForceUse(int usage, int config) {
4091 AudioSystem.setForceUse(usage, config);
4092 }
4093
Eric Laurent05274f32012-11-29 12:48:18 -08004094 private void onPersistSafeVolumeState(int state) {
4095 Settings.Global.putInt(mContentResolver,
4096 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
4097 state);
4098 }
4099
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004100 @Override
4101 public void handleMessage(Message msg) {
Eric Laurentafbb0472011-12-15 09:04:23 -08004102 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004103
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004104 case MSG_SET_DEVICE_VOLUME:
4105 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
4106 break;
4107
4108 case MSG_SET_ALL_VOLUMES:
4109 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004110 break;
4111
4112 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07004113 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004114 break;
4115
Mike Lockwood5c55a052011-12-15 17:21:44 -05004116 case MSG_PERSIST_MASTER_VOLUME:
Eric Laurent83a017b2013-03-19 18:15:31 -07004117 if (mUseFixedVolume) {
4118 return;
4119 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004120 Settings.System.putFloatForUser(mContentResolver,
4121 Settings.System.VOLUME_MASTER,
RoboErik8a2cfc32014-05-16 11:19:38 -07004122 msg.arg1 / (float)1000.0,
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004123 UserHandle.USER_CURRENT);
Mike Lockwood5c55a052011-12-15 17:21:44 -05004124 break;
4125
Justin Koh57978ed2012-04-03 17:37:58 -07004126 case MSG_PERSIST_MASTER_VOLUME_MUTE:
Eric Laurent83a017b2013-03-19 18:15:31 -07004127 if (mUseFixedVolume) {
4128 return;
4129 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004130 Settings.System.putIntForUser(mContentResolver,
4131 Settings.System.VOLUME_MASTER_MUTE,
4132 msg.arg1,
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004133 msg.arg2);
Justin Koh57978ed2012-04-03 17:37:58 -07004134 break;
4135
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004136 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08004137 // note that the value persisted is the current ringer mode, not the
4138 // value of ringer mode as of the time the request was made to persist
4139 persistRingerMode(getRingerMode());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004140 break;
4141
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004142 case MSG_MEDIA_SERVER_DIED:
Eric Laurenteb4b8a22014-07-21 13:10:07 -07004143 if (!mSystemReady ||
4144 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Eric Laurent89e74ba2009-09-30 18:26:36 -07004145 Log.e(TAG, "Media server died.");
Eric Laurentafbb0472011-12-15 09:04:23 -08004146 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent89e74ba2009-09-30 18:26:36 -07004147 null, 500);
Eric Laurentdfb881f2013-07-18 14:41:39 -07004148 break;
Eric Laurent89e74ba2009-09-30 18:26:36 -07004149 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004150 Log.e(TAG, "Media server started.");
Eric Laurentdfb881f2013-07-18 14:41:39 -07004151
Eric Laurent3c652ca2010-06-21 20:46:26 -07004152 // indicate to audio HAL that we start the reconfiguration phase after a media
4153 // server crash
Eric Laurentdfb881f2013-07-18 14:41:39 -07004154 // Note that we only execute this when the media server
Eric Laurent3c652ca2010-06-21 20:46:26 -07004155 // process restarts after a crash, not the first time it is started.
4156 AudioSystem.setParameters("restarting=true");
4157
Glenn Kastenfd116ad2013-07-12 17:10:39 -07004158 readAndSetLowRamDevice();
4159
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004160 // Restore device connection states
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004161 synchronized (mConnectedDevices) {
4162 Set set = mConnectedDevices.entrySet();
4163 Iterator i = set.iterator();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004164 while (i.hasNext()) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004165 Map.Entry device = (Map.Entry)i.next();
4166 AudioSystem.setDeviceConnectionState(
4167 ((Integer)device.getKey()).intValue(),
4168 AudioSystem.DEVICE_STATE_AVAILABLE,
4169 (String)device.getValue());
4170 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004171 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004172 // Restore call state
4173 AudioSystem.setPhoneState(mMode);
4174
Eric Laurentd5603c12009-08-06 08:49:39 -07004175 // Restore forced usage for communcations and record
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004176 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
Eric Laurentd5603c12009-08-06 08:49:39 -07004177 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
Eric Laurentdd45d012012-10-08 09:04:34 -07004178 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
4179 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004180
Eric Laurenta553c252009-07-17 12:17:14 -07004181 // Restore stream volumes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004182 int numStreamTypes = AudioSystem.getNumStreamTypes();
4183 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004184 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004185 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004186
4187 streamState.applyAllVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004188 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004189
4190 // Restore ringer mode
4191 setRingerModeInt(getRingerMode(), false);
Eric Laurent3c652ca2010-06-21 20:46:26 -07004192
Mike Lockwood90631542012-01-06 11:20:37 -05004193 // Restore master volume
4194 restoreMasterVolume();
4195
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004196 // Reset device orientation (if monitored for this device)
Eric Laurentd640bd32012-09-28 18:01:48 -07004197 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004198 setOrientationForAudioSystem();
4199 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004200 if (mMonitorRotation) {
4201 setRotationForAudioSystem();
4202 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004203
Eric Laurent78472112012-05-21 08:57:21 -07004204 synchronized (mBluetoothA2dpEnabledLock) {
4205 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
4206 mBluetoothA2dpEnabled ?
4207 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
4208 }
Eric Laurentbff5ca52012-11-02 16:48:26 -07004209
4210 synchronized (mSettingsLock) {
4211 AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
4212 mDockAudioMediaEnabled ?
4213 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
4214 }
Eric Laurent212532b2014-07-21 15:43:18 -07004215 if (mHdmiManager != null) {
4216 synchronized (mHdmiManager) {
4217 if (mHdmiTvClient != null) {
4218 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
4219 }
4220 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004221 }
Eric Laurent3c652ca2010-06-21 20:46:26 -07004222 // indicate the end of reconfiguration phase to audio HAL
4223 AudioSystem.setParameters("restarting=false");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004224 break;
4225
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004226 case MSG_UNLOAD_SOUND_EFFECTS:
4227 onUnloadSoundEffects();
4228 break;
4229
Eric Laurent117b7bb2011-01-16 17:07:27 -08004230 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004231 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
4232 // can take several dozens of milliseconds to complete
4233 boolean loaded = onLoadSoundEffects();
4234 if (msg.obj != null) {
4235 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
4236 synchronized (reply) {
4237 reply.mStatus = loaded ? 0 : -1;
4238 reply.notify();
4239 }
4240 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08004241 break;
4242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004243 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004244 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004245 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004246
4247 case MSG_BTA2DP_DOCK_TIMEOUT:
4248 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004249 synchronized (mConnectedDevices) {
4250 makeA2dpDeviceUnavailableNow( (String) msg.obj );
4251 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004252 break;
Eric Laurentfa640152011-03-12 15:59:51 -08004253
4254 case MSG_SET_FORCE_USE:
Eric Laurentc390bed2012-07-03 12:24:05 -07004255 case MSG_SET_FORCE_BT_A2DP_USE:
Eric Laurentfa640152011-03-12 15:59:51 -08004256 setForceUse(msg.arg1, msg.arg2);
4257 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07004258
Eric Laurentdc03c612011-04-01 10:59:41 -07004259 case MSG_BT_HEADSET_CNCT_FAILED:
4260 resetBluetoothSco();
4261 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004262
4263 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
4264 onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004265 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004266 break;
4267
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004268 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
4269 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
4270 mAudioEventWakeLock.release();
4271 break;
4272
4273 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
4274 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004275 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004276 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004277
4278 case MSG_REPORT_NEW_ROUTES: {
4279 int N = mRoutesObservers.beginBroadcast();
4280 if (N > 0) {
4281 AudioRoutesInfo routes;
4282 synchronized (mCurAudioRoutes) {
4283 routes = new AudioRoutesInfo(mCurAudioRoutes);
4284 }
4285 while (N > 0) {
4286 N--;
4287 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
4288 try {
4289 obs.dispatchAudioRoutesChanged(routes);
4290 } catch (RemoteException e) {
4291 }
4292 }
4293 }
4294 mRoutesObservers.finishBroadcast();
4295 break;
4296 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004297
Eric Laurentc34dcc12012-09-10 13:51:52 -07004298 case MSG_CHECK_MUSIC_ACTIVE:
4299 onCheckMusicActive();
4300 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004301
4302 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
4303 onSendBecomingNoisyIntent();
4304 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07004305
4306 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
4307 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
4308 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
4309 break;
Eric Laurent05274f32012-11-29 12:48:18 -08004310 case MSG_PERSIST_SAFE_VOLUME_STATE:
4311 onPersistSafeVolumeState(msg.arg1);
4312 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08004313
Eric Laurent2a57ca92013-03-07 17:29:27 -08004314 case MSG_BROADCAST_BT_CONNECTION_STATE:
4315 onBroadcastScoConnectionState(msg.arg1);
4316 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004317
4318 case MSG_SYSTEM_READY:
4319 onSystemReady();
4320 break;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004321
4322 case MSG_PERSIST_MUSIC_ACTIVE_MS:
4323 final int musicActiveMs = msg.arg1;
4324 Settings.Secure.putIntForUser(mContentResolver,
4325 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
4326 UserHandle.USER_CURRENT);
4327 break;
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004328 case MSG_PERSIST_MICROPHONE_MUTE:
4329 Settings.System.putIntForUser(mContentResolver,
4330 Settings.System.MICROPHONE_MUTE,
4331 msg.arg1,
4332 msg.arg2);
4333 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004334 }
4335 }
4336 }
4337
Jason Parekhb1096152009-03-24 17:48:25 -07004338 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07004339
Jason Parekhb1096152009-03-24 17:48:25 -07004340 SettingsObserver() {
4341 super(new Handler());
4342 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4343 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004344 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4345 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07004346 }
4347
4348 @Override
4349 public void onChange(boolean selfChange) {
4350 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08004351 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
4352 // However there appear to be some missing locks around mRingerModeMutedStreams
4353 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
4354 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07004355 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004356 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07004357 /*
4358 * Ensure all stream types that should be affected by ringer mode
4359 * are in the proper state.
4360 */
Eric Laurenta553c252009-07-17 12:17:14 -07004361 setRingerModeInt(getRingerMode(), false);
4362 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004363 readDockAudioSettings(mContentResolver);
Eric Laurenta553c252009-07-17 12:17:14 -07004364 }
Jason Parekhb1096152009-03-24 17:48:25 -07004365 }
Jason Parekhb1096152009-03-24 17:48:25 -07004366 }
Eric Laurenta553c252009-07-17 12:17:14 -07004367
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004368 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004369 private void makeA2dpDeviceAvailable(String address) {
Eric Laurent78472112012-05-21 08:57:21 -07004370 // enable A2DP before notifying A2DP connection to avoid unecessary processing in
4371 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004372 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4373 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4374 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Eric Laurent78472112012-05-21 08:57:21 -07004375 setBluetoothA2dpOnInt(true);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004376 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4377 AudioSystem.DEVICE_STATE_AVAILABLE,
4378 address);
4379 // Reset A2DP suspend state each time a new sink is connected
4380 AudioSystem.setParameters("A2dpSuspended=false");
4381 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
4382 address);
4383 }
4384
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004385 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004386 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07004387 }
4388
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004389 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004390 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004391 synchronized (mA2dpAvrcpLock) {
4392 mAvrcpAbsVolSupported = false;
4393 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004394 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4395 AudioSystem.DEVICE_STATE_UNAVAILABLE,
4396 address);
4397 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
RoboErik5535ea82014-09-25 14:53:16 -07004398 synchronized (mCurAudioRoutes) {
4399 // Remove A2DP routes as well
4400 if (mCurAudioRoutes.mBluetoothName != null) {
4401 mCurAudioRoutes.mBluetoothName = null;
4402 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4403 SENDMSG_NOOP, 0, 0, null, 0);
4404 }
4405 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004406 }
4407
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004408 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004409 private void makeA2dpDeviceUnavailableLater(String address) {
Eric Laurent3b591262010-04-20 07:01:00 -07004410 // prevent any activity on the A2DP audio output to avoid unwanted
4411 // reconnection of the sink.
4412 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004413 // the device will be made unavailable later, so consider it disconnected right away
4414 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
4415 // send the delayed message to make the device unavailable later
4416 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
4417 mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
4418
4419 }
4420
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004421 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004422 private void makeA2dpSrcAvailable(String address) {
4423 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
4424 AudioSystem.DEVICE_STATE_AVAILABLE,
4425 address);
4426 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
4427 address);
4428 }
4429
4430 // must be called synchronized on mConnectedDevices
4431 private void makeA2dpSrcUnavailable(String address) {
4432 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
4433 AudioSystem.DEVICE_STATE_UNAVAILABLE,
4434 address);
4435 mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
4436 }
4437
4438 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004439 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004440 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4441 }
4442
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004443 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004444 private boolean hasScheduledA2dpDockTimeout() {
4445 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4446 }
4447
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004448 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004449 {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004450 if (DEBUG_VOL) {
4451 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
4452 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004453 if (btDevice == null) {
4454 return;
4455 }
4456 String address = btDevice.getAddress();
4457 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4458 address = "";
4459 }
John Du5a0cf7a2013-07-19 11:30:34 -07004460
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004461 synchronized (mConnectedDevices) {
4462 boolean isConnected =
4463 (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
4464 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
4465
4466 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4467 if (btDevice.isBluetoothDock()) {
4468 if (state == BluetoothProfile.STATE_DISCONNECTED) {
4469 // introduction of a delay for transient disconnections of docks when
4470 // power is rapidly turned off/on, this message will be canceled if
4471 // we reconnect the dock under a preset delay
4472 makeA2dpDeviceUnavailableLater(address);
4473 // the next time isConnected is evaluated, it will be false for the dock
4474 }
4475 } else {
4476 makeA2dpDeviceUnavailableNow(address);
4477 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07004478 synchronized (mCurAudioRoutes) {
4479 if (mCurAudioRoutes.mBluetoothName != null) {
4480 mCurAudioRoutes.mBluetoothName = null;
4481 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4482 SENDMSG_NOOP, 0, 0, null, 0);
4483 }
4484 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004485 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4486 if (btDevice.isBluetoothDock()) {
4487 // this could be a reconnection after a transient disconnection
4488 cancelA2dpDeviceTimeout();
4489 mDockAddress = address;
4490 } else {
4491 // this could be a connection of another A2DP device before the timeout of
4492 // a dock: cancel the dock timeout, and make the dock unavailable now
4493 if(hasScheduledA2dpDockTimeout()) {
4494 cancelA2dpDeviceTimeout();
4495 makeA2dpDeviceUnavailableNow(mDockAddress);
4496 }
4497 }
4498 makeA2dpDeviceAvailable(address);
Dianne Hackborn632ca412012-06-14 19:34:10 -07004499 synchronized (mCurAudioRoutes) {
4500 String name = btDevice.getAliasName();
4501 if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
4502 mCurAudioRoutes.mBluetoothName = name;
4503 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4504 SENDMSG_NOOP, 0, 0, null, 0);
4505 }
4506 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004507 }
4508 }
4509 }
4510
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004511 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
4512 {
4513 if (DEBUG_VOL) {
4514 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
4515 }
4516 if (btDevice == null) {
4517 return;
4518 }
4519 String address = btDevice.getAddress();
4520 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4521 address = "";
4522 }
4523
4524 synchronized (mConnectedDevices) {
4525 boolean isConnected =
4526 (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
4527 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));
4528
4529 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4530 makeA2dpSrcUnavailable(address);
4531 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4532 makeA2dpSrcAvailable(address);
4533 }
4534 }
4535 }
4536
John Du5a0cf7a2013-07-19 11:30:34 -07004537 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
4538 // address is not used for now, but may be used when multiple a2dp devices are supported
4539 synchronized (mA2dpAvrcpLock) {
4540 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004541 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07004542 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4543 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4544 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4545 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4546 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07004547 }
4548 }
4549
Eric Laurent59f48272012-04-05 19:42:21 -07004550 private boolean handleDeviceConnection(boolean connected, int device, String params) {
4551 synchronized (mConnectedDevices) {
4552 boolean isConnected = (mConnectedDevices.containsKey(device) &&
Mike Lockwood98418182012-05-10 17:13:20 -07004553 (params.isEmpty() || mConnectedDevices.get(device).equals(params)));
Eric Laurent59f48272012-04-05 19:42:21 -07004554
4555 if (isConnected && !connected) {
4556 AudioSystem.setDeviceConnectionState(device,
4557 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Mike Lockwood98418182012-05-10 17:13:20 -07004558 mConnectedDevices.get(device));
Eric Laurent59f48272012-04-05 19:42:21 -07004559 mConnectedDevices.remove(device);
4560 return true;
4561 } else if (!isConnected && connected) {
4562 AudioSystem.setDeviceConnectionState(device,
4563 AudioSystem.DEVICE_STATE_AVAILABLE,
4564 params);
4565 mConnectedDevices.put(new Integer(device), params);
4566 return true;
4567 }
4568 }
4569 return false;
4570 }
4571
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004572 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4573 // sent if none of these devices is connected.
4574 int mBecomingNoisyIntentDevices =
4575 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07004576 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07004577 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004578 AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004579
4580 // must be called before removing the device from mConnectedDevices
4581 private int checkSendBecomingNoisyIntent(int device, int state) {
4582 int delay = 0;
4583 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4584 int devices = 0;
4585 for (int dev : mConnectedDevices.keySet()) {
Eric Laurent27c30e42014-08-27 12:36:33 -07004586 if (((dev & AudioSystem.DEVICE_BIT_IN) == 0) &&
4587 ((dev & mBecomingNoisyIntentDevices) != 0)) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004588 devices |= dev;
4589 }
4590 }
4591 if (devices == device) {
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004592 sendMsg(mAudioHandler,
4593 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4594 SENDMSG_REPLACE,
4595 0,
4596 0,
4597 null,
4598 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004599 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004600 }
4601 }
4602
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004603 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
4604 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004605 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004606 synchronized (mLastDeviceConnectMsgTime) {
4607 long time = SystemClock.uptimeMillis();
4608 if (mLastDeviceConnectMsgTime > time) {
4609 delay = (int)(mLastDeviceConnectMsgTime - time);
4610 }
4611 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004612 }
4613 return delay;
4614 }
4615
4616 private void sendDeviceConnectionIntent(int device, int state, String name)
4617 {
4618 Intent intent = new Intent();
4619
4620 intent.putExtra("state", state);
4621 intent.putExtra("name", name);
4622 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4623
Dianne Hackborn632ca412012-06-14 19:34:10 -07004624 int connType = 0;
4625
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004626 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004627 connType = AudioRoutesInfo.MAIN_HEADSET;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004628 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4629 intent.putExtra("microphone", 1);
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004630 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
4631 device == AudioSystem.DEVICE_OUT_LINE) {
4632 /*do apps care about line-out vs headphones?*/
Dianne Hackborn632ca412012-06-14 19:34:10 -07004633 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004634 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4635 intent.putExtra("microphone", 0);
4636 } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004637 connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004638 intent.setAction(AudioManager.ACTION_ANALOG_AUDIO_DOCK_PLUG);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004639 } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004640 connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004641 intent.setAction(AudioManager.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
Eric Laurent948d3272014-05-16 15:18:45 -07004642 } else if (device == AudioSystem.DEVICE_OUT_HDMI) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004643 connType = AudioRoutesInfo.MAIN_HDMI;
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004644 configureHdmiPlugIntent(intent, state);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004645 }
4646
Dianne Hackborn632ca412012-06-14 19:34:10 -07004647 synchronized (mCurAudioRoutes) {
4648 if (connType != 0) {
4649 int newConn = mCurAudioRoutes.mMainType;
4650 if (state != 0) {
4651 newConn |= connType;
4652 } else {
4653 newConn &= ~connType;
4654 }
4655 if (newConn != mCurAudioRoutes.mMainType) {
4656 mCurAudioRoutes.mMainType = newConn;
4657 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4658 SENDMSG_NOOP, 0, 0, null, 0);
4659 }
4660 }
4661 }
4662
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004663 final long ident = Binder.clearCallingIdentity();
4664 try {
4665 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
4666 } finally {
4667 Binder.restoreCallingIdentity(ident);
4668 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004669 }
4670
4671 private void onSetWiredDeviceConnectionState(int device, int state, String name)
4672 {
4673 synchronized (mConnectedDevices) {
4674 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004675 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4676 (device == AudioSystem.DEVICE_OUT_LINE))) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004677 setBluetoothA2dpOnInt(true);
4678 }
Eric Laurentae4506e2014-05-29 16:04:32 -07004679 boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
4680 (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
4681 ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
Mike Lockwooddb454842012-09-18 11:16:57 -07004682 handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
Eric Laurentf1a457d2012-09-20 16:27:23 -07004683 if (state != 0) {
4684 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004685 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4686 (device == AudioSystem.DEVICE_OUT_LINE)) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07004687 setBluetoothA2dpOnInt(false);
4688 }
4689 if ((device & mSafeMediaVolumeDevices) != 0) {
4690 sendMsg(mAudioHandler,
4691 MSG_CHECK_MUSIC_ACTIVE,
4692 SENDMSG_REPLACE,
4693 0,
4694 0,
4695 null,
4696 MUSIC_ACTIVE_POLL_PERIOD_MS);
4697 }
Eric Laurent212532b2014-07-21 15:43:18 -07004698 // Television devices without CEC service apply software volume on HDMI output
4699 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4700 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
4701 checkAllFixedVolumeDevices();
4702 if (mHdmiManager != null) {
4703 synchronized (mHdmiManager) {
4704 if (mHdmiPlaybackClient != null) {
4705 mHdmiCecSink = false;
4706 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
4707 }
4708 }
4709 }
4710 }
4711 } else {
4712 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4713 if (mHdmiManager != null) {
4714 synchronized (mHdmiManager) {
4715 mHdmiCecSink = false;
4716 }
4717 }
4718 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004719 }
Eric Laurentae4506e2014-05-29 16:04:32 -07004720 if (!isUsb && (device != AudioSystem.DEVICE_IN_WIRED_HEADSET)) {
Mike Lockwooddb454842012-09-18 11:16:57 -07004721 sendDeviceConnectionIntent(device, state, name);
4722 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004723 }
4724 }
4725
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004726 private void configureHdmiPlugIntent(Intent intent, int state) {
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004727 intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
4728 intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004729 if (state == 1) {
4730 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
4731 int[] portGeneration = new int[1];
4732 int status = AudioSystem.listAudioPorts(ports, portGeneration);
4733 if (status == AudioManager.SUCCESS) {
4734 for (AudioPort port : ports) {
4735 if (port instanceof AudioDevicePort) {
4736 final AudioDevicePort devicePort = (AudioDevicePort) port;
4737 if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI) {
4738 // format the list of supported encodings
4739 int[] formats = devicePort.formats();
4740 if (formats.length > 0) {
4741 ArrayList<Integer> encodingList = new ArrayList(1);
4742 for (int format : formats) {
4743 // a format in the list can be 0, skip it
4744 if (format != AudioFormat.ENCODING_INVALID) {
4745 encodingList.add(format);
4746 }
4747 }
4748 int[] encodingArray = new int[encodingList.size()];
4749 for (int i = 0 ; i < encodingArray.length ; i++) {
4750 encodingArray[i] = encodingList.get(i);
4751 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004752 intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004753 }
4754 // find the maximum supported number of channels
4755 int maxChannels = 0;
4756 for (int mask : devicePort.channelMasks()) {
4757 int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
4758 if (channelCount > maxChannels) {
4759 maxChannels = channelCount;
4760 }
4761 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004762 intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004763 }
4764 }
4765 }
4766 }
4767 }
4768 }
4769
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004770 /* cache of the address of the last dock the device was connected to */
4771 private String mDockAddress;
4772
Eric Laurenta553c252009-07-17 12:17:14 -07004773 /**
4774 * Receiver for misc intent broadcasts the Phone app cares about.
4775 */
4776 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4777 @Override
4778 public void onReceive(Context context, Intent intent) {
4779 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07004780 int outDevice;
4781 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07004782 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07004783
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004784 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4785 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4786 Intent.EXTRA_DOCK_STATE_UNDOCKED);
4787 int config;
4788 switch (dockState) {
4789 case Intent.EXTRA_DOCK_STATE_DESK:
4790 config = AudioSystem.FORCE_BT_DESK_DOCK;
4791 break;
4792 case Intent.EXTRA_DOCK_STATE_CAR:
4793 config = AudioSystem.FORCE_BT_CAR_DOCK;
4794 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004795 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08004796 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004797 break;
4798 case Intent.EXTRA_DOCK_STATE_HE_DESK:
4799 config = AudioSystem.FORCE_DIGITAL_DOCK;
4800 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004801 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4802 default:
4803 config = AudioSystem.FORCE_NONE;
4804 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08004805 // Low end docks have a menu to enable or disable audio
4806 // (see mDockAudioMediaEnabled)
4807 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
4808 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
4809 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
4810 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
4811 }
4812 mDockState = dockState;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004813 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
Eric Laurent59f48272012-04-05 19:42:21 -07004814 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004815 BluetoothProfile.STATE_DISCONNECTED);
Eric Laurentae4506e2014-05-29 16:04:32 -07004816 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
4817 inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
Nick Pellya56d1c72009-08-19 14:49:29 -07004818 String address = null;
Eric Laurentdca56b92011-09-02 14:20:56 -07004819
4820 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
4821 if (btDevice == null) {
4822 return;
4823 }
4824
4825 address = btDevice.getAddress();
4826 BluetoothClass btClass = btDevice.getBluetoothClass();
4827 if (btClass != null) {
4828 switch (btClass.getDeviceClass()) {
4829 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
4830 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
Eric Laurentae4506e2014-05-29 16:04:32 -07004831 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurentdca56b92011-09-02 14:20:56 -07004832 break;
4833 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
Eric Laurentae4506e2014-05-29 16:04:32 -07004834 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurentdca56b92011-09-02 14:20:56 -07004835 break;
Eric Laurentd5603c12009-08-06 08:49:39 -07004836 }
4837 }
4838
Eric Laurentdca56b92011-09-02 14:20:56 -07004839 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4840 address = "";
4841 }
Eric Laurentd5603c12009-08-06 08:49:39 -07004842
Eric Laurent59f48272012-04-05 19:42:21 -07004843 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
Eric Laurentae4506e2014-05-29 16:04:32 -07004844 boolean success = handleDeviceConnection(connected, outDevice, address) &&
4845 handleDeviceConnection(connected, inDevice, address);
4846 if (success) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004847 synchronized (mScoClients) {
Eric Laurent59f48272012-04-05 19:42:21 -07004848 if (connected) {
4849 mBluetoothHeadsetDevice = btDevice;
4850 } else {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004851 mBluetoothHeadsetDevice = null;
4852 resetBluetoothSco();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004853 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004854 }
Eric Laurenta553c252009-07-17 12:17:14 -07004855 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004856 } else if (action.equals(AudioManager.ACTION_USB_AUDIO_ACCESSORY_PLUG)) {
Paul McLeandf361462014-04-10 16:02:55 -07004857 state = intent.getIntExtra("state", 0);
4858
4859 int alsaCard = intent.getIntExtra("card", -1);
4860 int alsaDevice = intent.getIntExtra("device", -1);
4861
4862 String params = (alsaCard == -1 && alsaDevice == -1 ? ""
4863 : "card=" + alsaCard + ";device=" + alsaDevice);
4864
4865 // Playback Device
Eric Laurentae4506e2014-05-29 16:04:32 -07004866 outDevice = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
4867 setWiredDeviceConnectionState(outDevice, state, params);
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004868 } else if (action.equals(AudioManager.ACTION_USB_AUDIO_DEVICE_PLUG)) {
Glenn Kasten5f516352014-07-22 09:11:48 -07004869 // FIXME Does not yet handle the case where the setting is changed
4870 // after device connection. Ideally we should handle the settings change
4871 // in SettingsObserver. Here we should log that a USB device is connected
4872 // and disconnected with its address (card , device) and force the
4873 // connection or disconnection when the setting changes.
Glenn Kasten34cc4db2014-08-13 10:56:38 -07004874 int isDisabled = Settings.Secure.getInt(mContentResolver,
4875 Settings.Secure.USB_AUDIO_AUTOMATIC_ROUTING_DISABLED, 0);
Glenn Kasten5f516352014-07-22 09:11:48 -07004876 if (isDisabled != 0) {
4877 return;
4878 }
4879
Eric Laurent59f48272012-04-05 19:42:21 -07004880 state = intent.getIntExtra("state", 0);
Paul McLeanc837a452014-04-09 09:04:43 -07004881
Eric Laurent59f48272012-04-05 19:42:21 -07004882 int alsaCard = intent.getIntExtra("card", -1);
4883 int alsaDevice = intent.getIntExtra("device", -1);
Paul McLeanc837a452014-04-09 09:04:43 -07004884 boolean hasPlayback = intent.getBooleanExtra("hasPlayback", false);
4885 boolean hasCapture = intent.getBooleanExtra("hasCapture", false);
4886 boolean hasMIDI = intent.getBooleanExtra("hasMIDI", false);
4887
Mike Lockwood98418182012-05-10 17:13:20 -07004888 String params = (alsaCard == -1 && alsaDevice == -1 ? ""
4889 : "card=" + alsaCard + ";device=" + alsaDevice);
Paul McLeanc837a452014-04-09 09:04:43 -07004890
Paul McLeanc837a452014-04-09 09:04:43 -07004891 // Playback Device
Paul McLeandf361462014-04-10 16:02:55 -07004892 if (hasPlayback) {
Eric Laurentae4506e2014-05-29 16:04:32 -07004893 outDevice = AudioSystem.DEVICE_OUT_USB_DEVICE;
4894 setWiredDeviceConnectionState(outDevice, state, params);
Paul McLeandf361462014-04-10 16:02:55 -07004895 }
Paul McLeanc837a452014-04-09 09:04:43 -07004896
4897 // Capture Device
Paul McLeandf361462014-04-10 16:02:55 -07004898 if (hasCapture) {
Eric Laurentae4506e2014-05-29 16:04:32 -07004899 inDevice = AudioSystem.DEVICE_IN_USB_DEVICE;
4900 setWiredDeviceConnectionState(inDevice, state, params);
Paul McLeandf361462014-04-10 16:02:55 -07004901 }
4902 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004903 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07004904 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004905 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004906 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07004907 // broadcast intent if the connection was initated by AudioService
4908 if (!mScoClients.isEmpty() &&
4909 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
4910 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
4911 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004912 broadcast = true;
4913 }
4914 switch (btState) {
4915 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004916 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07004917 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4918 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4919 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004920 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004921 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004922 break;
4923 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004924 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08004925 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07004926 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08004927 break;
4928 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07004929 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4930 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4931 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004932 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004933 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004934 default:
4935 // do not broadcast CONNECTING or invalid state
4936 broadcast = false;
4937 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004938 }
4939 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004940 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07004941 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07004942 //FIXME: this is to maintain compatibility with deprecated intent
4943 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08004944 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07004945 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004946 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08004947 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004948 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06004949 if (mMonitorRotation) {
4950 mOrientationListener.onOrientationChanged(0); //argument is ignored anyway
4951 mOrientationListener.enable();
4952 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004953 AudioSystem.setParameters("screen_state=on");
4954 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06004955 if (mMonitorRotation) {
4956 //reduce wakeups (save current) by only listening when display is on
4957 mOrientationListener.disable();
4958 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004959 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07004960 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004961 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004962 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004963 // attempt to stop music playback for background user
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004964 sendMsg(mAudioHandler,
4965 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4966 SENDMSG_REPLACE,
4967 0,
4968 0,
4969 null,
4970 0);
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004971 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004972 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004973
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004974 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004975 readAudioSettings(true /*userSwitch*/);
4976 // preserve STREAM_MUSIC volume from one user to the next.
4977 sendMsg(mAudioHandler,
4978 MSG_SET_ALL_VOLUMES,
4979 SENDMSG_QUEUE,
4980 0,
4981 0,
4982 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Eric Laurenta553c252009-07-17 12:17:14 -07004983 }
4984 }
Paul McLeanc837a452014-04-09 09:04:43 -07004985 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004986
4987 //==========================================================================================
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004988 // RemoteControlDisplay / RemoteControlClient / Remote info
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004989 //==========================================================================================
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004990 public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
4991 ComponentName listenerComp) {
4992 return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
4993 }
4994
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004995 public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004996 return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004997 }
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004998
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004999 public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005000 mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005001 }
5002
5003 public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005004 mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005005 }
5006
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07005007 public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
5008 boolean wantsSync) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005009 mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
5010 }
5011
John Spurlock3346a802014-05-20 16:25:37 -04005012 @Override
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005013 public void setRemoteStreamVolume(int index) {
John Spurlock3346a802014-05-20 16:25:37 -04005014 enforceSelfOrSystemUI("set the remote stream volume");
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005015 mMediaFocusControl.setRemoteStreamVolume(index);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005016 }
5017
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005018 //==========================================================================================
5019 // Audio Focus
5020 //==========================================================================================
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005021 public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005022 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
5023 IBinder policyToken) {
5024 // permission checks
5025 if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
5026 if (mMediaFocusControl.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
5027 if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
5028 android.Manifest.permission.MODIFY_PHONE_STATE)) {
5029 Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
5030 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5031 }
5032 } else {
5033 // only a registered audio policy can be used to lock focus
5034 synchronized (mAudioPolicies) {
5035 if (!mAudioPolicies.containsKey(policyToken)) {
5036 Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus",
5037 new Exception());
5038 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5039 }
5040 }
5041 }
5042 }
5043
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005044 return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
5045 clientId, callingPackageName, flags);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005046 }
5047
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005048 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
5049 return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005050 }
5051
5052 public void unregisterAudioFocusClient(String clientId) {
5053 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005054 }
5055
Jean-Michel Trivi23805662013-07-31 14:19:18 -07005056 public int getCurrentAudioFocus() {
5057 return mMediaFocusControl.getCurrentAudioFocus();
5058 }
5059
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005060 //==========================================================================================
5061 // Device orientation
5062 //==========================================================================================
5063 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005064 * Handles device configuration changes that may map to a change in the orientation
5065 * or orientation.
5066 * Monitoring orientation and rotation is optional, and is defined by the definition and value
5067 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005068 */
5069 private void handleConfigurationChanged(Context context) {
5070 try {
5071 // reading new orientation "safely" (i.e. under try catch) in case anything
5072 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07005073 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005074 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07005075 if (mMonitorOrientation) {
5076 int newOrientation = config.orientation;
5077 if (newOrientation != mDeviceOrientation) {
5078 mDeviceOrientation = newOrientation;
5079 setOrientationForAudioSystem();
5080 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005081 }
Eric Laurentd640bd32012-09-28 18:01:48 -07005082 sendMsg(mAudioHandler,
5083 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
5084 SENDMSG_REPLACE,
5085 0,
5086 0,
5087 null,
5088 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07005089
5090 boolean cameraSoundForced = mContext.getResources().getBoolean(
5091 com.android.internal.R.bool.config_camera_sound_forced);
5092 synchronized (mSettingsLock) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005093 boolean cameraSoundForcedChanged = false;
Eric Laurentdd45d012012-10-08 09:04:34 -07005094 synchronized (mCameraSoundForced) {
5095 if (cameraSoundForced != mCameraSoundForced) {
5096 mCameraSoundForced = cameraSoundForced;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005097 cameraSoundForcedChanged = true;
Eric Laurentdd45d012012-10-08 09:04:34 -07005098 }
5099 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005100 if (cameraSoundForcedChanged) {
5101 if (!isPlatformTelevision()) {
5102 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
5103 if (cameraSoundForced) {
5104 s.setAllIndexesToMax();
5105 mRingerModeAffectedStreams &=
5106 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5107 } else {
5108 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
5109 mRingerModeAffectedStreams |=
5110 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5111 }
5112 // take new state into account for streams muted by ringer mode
5113 setRingerModeInt(getRingerMode(), false);
5114 }
5115
5116 sendMsg(mAudioHandler,
5117 MSG_SET_FORCE_USE,
5118 SENDMSG_QUEUE,
5119 AudioSystem.FOR_SYSTEM,
5120 cameraSoundForced ?
5121 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
5122 null,
5123 0);
5124
5125 sendMsg(mAudioHandler,
5126 MSG_SET_ALL_VOLUMES,
5127 SENDMSG_QUEUE,
5128 0,
5129 0,
5130 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
5131 }
Eric Laurentdd45d012012-10-08 09:04:34 -07005132 }
John Spurlock3346a802014-05-20 16:25:37 -04005133 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005134 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005135 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005136 }
5137 }
5138
5139 private void setOrientationForAudioSystem() {
5140 switch (mDeviceOrientation) {
5141 case Configuration.ORIENTATION_LANDSCAPE:
5142 //Log.i(TAG, "orientation is landscape");
5143 AudioSystem.setParameters("orientation=landscape");
5144 break;
5145 case Configuration.ORIENTATION_PORTRAIT:
5146 //Log.i(TAG, "orientation is portrait");
5147 AudioSystem.setParameters("orientation=portrait");
5148 break;
5149 case Configuration.ORIENTATION_SQUARE:
5150 //Log.i(TAG, "orientation is square");
5151 AudioSystem.setParameters("orientation=square");
5152 break;
5153 case Configuration.ORIENTATION_UNDEFINED:
5154 //Log.i(TAG, "orientation is undefined");
5155 AudioSystem.setParameters("orientation=undefined");
5156 break;
5157 default:
5158 Log.e(TAG, "Unknown orientation");
5159 }
5160 }
5161
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005162 private void setRotationForAudioSystem() {
5163 switch (mDeviceRotation) {
5164 case Surface.ROTATION_0:
5165 AudioSystem.setParameters("rotation=0");
5166 break;
5167 case Surface.ROTATION_90:
5168 AudioSystem.setParameters("rotation=90");
5169 break;
5170 case Surface.ROTATION_180:
5171 AudioSystem.setParameters("rotation=180");
5172 break;
5173 case Surface.ROTATION_270:
5174 AudioSystem.setParameters("rotation=270");
5175 break;
5176 default:
5177 Log.e(TAG, "Unknown device rotation");
5178 }
5179 }
5180
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005181
Eric Laurent78472112012-05-21 08:57:21 -07005182 // Handles request to override default use of A2DP for media.
5183 public void setBluetoothA2dpOnInt(boolean on) {
5184 synchronized (mBluetoothA2dpEnabledLock) {
5185 mBluetoothA2dpEnabled = on;
Eric Laurentc390bed2012-07-03 12:24:05 -07005186 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
5187 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
5188 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
Eric Laurent78472112012-05-21 08:57:21 -07005189 }
5190 }
5191
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005192 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07005193 public void setRingtonePlayer(IRingtonePlayer player) {
5194 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5195 mRingtonePlayer = player;
5196 }
5197
5198 @Override
5199 public IRingtonePlayer getRingtonePlayer() {
5200 return mRingtonePlayer;
5201 }
5202
5203 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07005204 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5205 synchronized (mCurAudioRoutes) {
5206 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5207 mRoutesObservers.register(observer);
5208 return routes;
5209 }
5210 }
5211
Eric Laurentc34dcc12012-09-10 13:51:52 -07005212
5213 //==========================================================================================
5214 // Safe media volume management.
5215 // MUSIC stream volume level is limited when headphones are connected according to safety
5216 // regulation. When the user attempts to raise the volume above the limit, a warning is
5217 // displayed and the user has to acknowlegde before the volume is actually changed.
5218 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
5219 // property. Platforms with a different limit must set this property accordingly in their
5220 // overlay.
5221 //==========================================================================================
5222
Eric Laurentd640bd32012-09-28 18:01:48 -07005223 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
5224 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
5225 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
5226 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
5227 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
5228 // (when user opts out).
John Spurlock35134602014-07-24 18:10:48 -04005229 private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
5230 private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
5231 private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed
5232 private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
Eric Laurentd640bd32012-09-28 18:01:48 -07005233 private Integer mSafeMediaVolumeState;
5234
5235 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005236 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07005237 private int mSafeMediaVolumeIndex;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005238 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
5239 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
5240 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
5241 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
5242 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
5243 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
5244 private int mMusicActiveMs;
5245 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
5246 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07005247 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07005248
5249 private void setSafeMediaVolumeEnabled(boolean on) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005250 synchronized (mSafeMediaVolumeState) {
5251 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
5252 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
5253 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
5254 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
5255 enforceSafeMediaVolume();
5256 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
5257 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005258 mMusicActiveMs = 1; // nonzero = confirmed
5259 saveMusicActiveMs();
Eric Laurentd640bd32012-09-28 18:01:48 -07005260 sendMsg(mAudioHandler,
5261 MSG_CHECK_MUSIC_ACTIVE,
5262 SENDMSG_REPLACE,
5263 0,
5264 0,
5265 null,
5266 MUSIC_ACTIVE_POLL_PERIOD_MS);
5267 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005268 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005269 }
5270 }
5271
5272 private void enforceSafeMediaVolume() {
5273 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07005274 int devices = mSafeMediaVolumeDevices;
5275 int i = 0;
5276
5277 while (devices != 0) {
5278 int device = 1 << i++;
5279 if ((device & devices) == 0) {
5280 continue;
5281 }
Eric Laurent42b041e2013-03-29 11:36:03 -07005282 int index = streamState.getIndex(device);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005283 if (index > mSafeMediaVolumeIndex) {
Eric Laurent42b041e2013-03-29 11:36:03 -07005284 streamState.setIndex(mSafeMediaVolumeIndex, device);
5285 sendMsg(mAudioHandler,
5286 MSG_SET_DEVICE_VOLUME,
5287 SENDMSG_QUEUE,
5288 device,
5289 0,
5290 streamState,
5291 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005292 }
5293 devices &= ~device;
5294 }
5295 }
5296
5297 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005298 synchronized (mSafeMediaVolumeState) {
5299 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07005300 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
5301 ((device & mSafeMediaVolumeDevices) != 0) &&
5302 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005303 return false;
5304 }
5305 return true;
5306 }
5307 }
5308
John Spurlock3346a802014-05-20 16:25:37 -04005309 @Override
Eric Laurentc34dcc12012-09-10 13:51:52 -07005310 public void disableSafeMediaVolume() {
John Spurlock3346a802014-05-20 16:25:37 -04005311 enforceSelfOrSystemUI("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07005312 synchronized (mSafeMediaVolumeState) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005313 setSafeMediaVolumeEnabled(false);
Eric Laurentfde16d52012-12-03 14:42:39 -08005314 if (mPendingVolumeCommand != null) {
5315 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
5316 mPendingVolumeCommand.mIndex,
5317 mPendingVolumeCommand.mFlags,
5318 mPendingVolumeCommand.mDevice);
5319 mPendingVolumeCommand = null;
5320 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005321 }
5322 }
5323
Jungshik Jang41d97462014-06-30 22:26:29 +09005324 //==========================================================================================
5325 // Hdmi Cec system audio mode.
5326 // If Hdmi Cec's system audio mode is on, audio service should notify volume change
5327 // to HdmiControlService so that audio recevier can handle volume change.
5328 //==========================================================================================
5329
Eric Laurent212532b2014-07-21 15:43:18 -07005330 private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
5331 public void onComplete(int status) {
5332 if (mHdmiManager != null) {
5333 synchronized (mHdmiManager) {
5334 mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
5335 // Television devices without CEC service apply software volume on HDMI output
5336 if (isPlatformTelevision() && !mHdmiCecSink) {
5337 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5338 }
5339 checkAllFixedVolumeDevices();
5340 }
5341 }
5342 }
5343 };
5344
Jungshik Jang41d97462014-06-30 22:26:29 +09005345 // If HDMI-CEC system audio is supported
5346 private boolean mHdmiSystemAudioSupported = false;
5347 // Set only when device is tv.
5348 private HdmiTvClient mHdmiTvClient;
Eric Laurent212532b2014-07-21 15:43:18 -07005349 // true if the device has system feature PackageManager.FEATURE_TELEVISION.
5350 // cached HdmiControlManager interface
5351 private HdmiControlManager mHdmiManager;
5352 // Set only when device is a set-top box.
5353 private HdmiPlaybackClient mHdmiPlaybackClient;
5354 // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5355 private boolean mHdmiCecSink;
5356
5357 private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
Jungshik Jang41d97462014-06-30 22:26:29 +09005358
5359 @Override
Jungshik Jang12307ca2014-07-15 19:27:56 +09005360 public int setHdmiSystemAudioSupported(boolean on) {
Eric Laurent212532b2014-07-21 15:43:18 -07005361 int device = AudioSystem.DEVICE_NONE;
5362 if (mHdmiManager != null) {
5363 synchronized (mHdmiManager) {
5364 if (mHdmiTvClient == null) {
5365 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5366 return device;
5367 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005368
Eric Laurent212532b2014-07-21 15:43:18 -07005369 synchronized (mHdmiTvClient) {
5370 if (mHdmiSystemAudioSupported != on) {
5371 mHdmiSystemAudioSupported = on;
5372 AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5373 on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5374 AudioSystem.FORCE_NONE);
5375 }
5376 device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
5377 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005378 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005379 }
Eric Laurent212532b2014-07-21 15:43:18 -07005380 return device;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005381 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005382
Terry Heoe7d6d972014-09-04 21:05:28 +09005383 @Override
5384 public boolean isHdmiSystemAudioSupported() {
5385 return mHdmiSystemAudioSupported;
5386 }
5387
Eric Laurentdd45d012012-10-08 09:04:34 -07005388 //==========================================================================================
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005389 // Accessibility: taking touch exploration into account for selecting the default
5390 // stream override timeout when adjusting volume
5391 //==========================================================================================
5392 private static class StreamOverride
5393 implements AccessibilityManager.TouchExplorationStateChangeListener {
5394
5395 // AudioService.getActiveStreamType() will return:
5396 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
5397 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
5398 // stopped
5399 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
5400 private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
5401
5402 static int sDelayMs;
5403
5404 static void init(Context ctxt) {
5405 AccessibilityManager accessibilityManager =
5406 (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
5407 updateDefaultStreamOverrideDelay(
5408 accessibilityManager.isTouchExplorationEnabled());
5409 accessibilityManager.addTouchExplorationStateChangeListener(
5410 new StreamOverride());
5411 }
5412
5413 @Override
5414 public void onTouchExplorationStateChanged(boolean enabled) {
5415 updateDefaultStreamOverrideDelay(enabled);
5416 }
5417
5418 private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
5419 if (touchExploreEnabled) {
5420 sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
5421 } else {
5422 sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
5423 }
5424 if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
5425 + " stream override delay is now " + sDelayMs + " ms");
5426 }
5427 }
5428
5429 //==========================================================================================
Eric Laurentdd45d012012-10-08 09:04:34 -07005430 // Camera shutter sound policy.
5431 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5432 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5433 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5434 //==========================================================================================
5435
5436 // cached value of com.android.internal.R.bool.config_camera_sound_forced
5437 private Boolean mCameraSoundForced;
5438
5439 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5440 public boolean isCameraSoundForced() {
5441 synchronized (mCameraSoundForced) {
5442 return mCameraSoundForced;
5443 }
5444 }
5445
5446 private static final String[] RINGER_MODE_NAMES = new String[] {
5447 "SILENT",
5448 "VIBRATE",
5449 "NORMAL"
5450 };
5451
5452 private void dumpRingerMode(PrintWriter pw) {
5453 pw.println("\nRinger mode: ");
5454 pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]);
5455 pw.print("- ringer mode affected streams = 0x");
5456 pw.println(Integer.toHexString(mRingerModeAffectedStreams));
5457 pw.print("- ringer mode muted streams = 0x");
5458 pw.println(Integer.toHexString(mRingerModeMutedStreams));
5459 }
5460
Dianne Hackborn632ca412012-06-14 19:34:10 -07005461 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005462 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07005463 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5464
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005465 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07005466 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07005467 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005468 pw.println("\nAudio routes:");
5469 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
5470 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
John Spurlock35134602014-07-24 18:10:48 -04005471
5472 pw.println("\nOther state:");
John Spurlock3346a802014-05-20 16:25:37 -04005473 pw.print(" mVolumeController="); pw.println(mVolumeController);
John Spurlock35134602014-07-24 18:10:48 -04005474 pw.print(" mSafeMediaVolumeState=");
5475 pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
5476 pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
5477 pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
5478 pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005479 pw.print(" mMcc="); pw.println(mMcc);
John Spurlock35134602014-07-24 18:10:48 -04005480 }
5481
5482 private static String safeMediaVolumeStateToString(Integer state) {
5483 switch(state) {
5484 case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
5485 case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
5486 case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
5487 case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
5488 }
5489 return null;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005490 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07005491
5492 // Inform AudioFlinger of our device's low RAM attribute
5493 private static void readAndSetLowRamDevice()
5494 {
5495 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
5496 if (status != 0) {
5497 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
5498 }
5499 }
John Spurlock3346a802014-05-20 16:25:37 -04005500
5501 private void enforceSelfOrSystemUI(String action) {
5502 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
5503 "Only SystemUI can " + action);
5504 }
5505
5506 @Override
5507 public void setVolumeController(final IVolumeController controller) {
5508 enforceSelfOrSystemUI("set the volume controller");
5509
5510 // return early if things are not actually changing
5511 if (mVolumeController.isSameBinder(controller)) {
5512 return;
5513 }
5514
5515 // dismiss the old volume controller
5516 mVolumeController.postDismiss();
5517 if (controller != null) {
5518 // we are about to register a new controller, listen for its death
5519 try {
5520 controller.asBinder().linkToDeath(new DeathRecipient() {
5521 @Override
5522 public void binderDied() {
5523 if (mVolumeController.isSameBinder(controller)) {
5524 Log.w(TAG, "Current remote volume controller died, unregistering");
5525 setVolumeController(null);
5526 }
5527 }
5528 }, 0);
5529 } catch (RemoteException e) {
5530 // noop
5531 }
5532 }
5533 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04005534 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
5535 }
5536
5537 @Override
5538 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
5539 enforceSelfOrSystemUI("notify about volume controller visibility");
5540
5541 // return early if the controller is not current
5542 if (!mVolumeController.isSameBinder(controller)) {
5543 return;
5544 }
5545
5546 mVolumeController.setVisible(visible);
5547 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04005548 }
RoboErikd09bd0c2014-06-24 17:45:19 -07005549
5550 public static class VolumeController {
5551 private static final String TAG = "VolumeController";
5552
5553 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04005554 private boolean mVisible;
5555 private long mNextLongPress;
5556 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07005557
5558 public void setController(IVolumeController controller) {
5559 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04005560 mVisible = false;
5561 }
5562
5563 public void loadSettings(ContentResolver cr) {
5564 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
5565 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
5566 }
5567
5568 public boolean suppressAdjustment(int resolvedStream, int flags) {
5569 boolean suppress = false;
5570 if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
5571 final long now = SystemClock.uptimeMillis();
5572 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
5573 // ui will become visible
5574 if (mNextLongPress < now) {
5575 mNextLongPress = now + mLongPressTimeout;
5576 }
5577 suppress = true;
5578 } else if (mNextLongPress > 0) { // in a long-press
5579 if (now > mNextLongPress) {
5580 // long press triggered, no more suppression
5581 mNextLongPress = 0;
5582 } else {
5583 // keep suppressing until the long press triggers
5584 suppress = true;
5585 }
5586 }
5587 }
5588 return suppress;
5589 }
5590
5591 public void setVisible(boolean visible) {
5592 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07005593 }
5594
5595 public boolean isSameBinder(IVolumeController controller) {
5596 return Objects.equals(asBinder(), binder(controller));
5597 }
5598
5599 public IBinder asBinder() {
5600 return binder(mController);
5601 }
5602
5603 private static IBinder binder(IVolumeController controller) {
5604 return controller == null ? null : controller.asBinder();
5605 }
5606
5607 @Override
5608 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04005609 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07005610 }
5611
5612 public void postDisplaySafeVolumeWarning(int flags) {
5613 if (mController == null)
5614 return;
5615 try {
5616 mController.displaySafeVolumeWarning(flags);
5617 } catch (RemoteException e) {
5618 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
5619 }
5620 }
5621
5622 public void postVolumeChanged(int streamType, int flags) {
5623 if (mController == null)
5624 return;
5625 try {
5626 mController.volumeChanged(streamType, flags);
5627 } catch (RemoteException e) {
5628 Log.w(TAG, "Error calling volumeChanged", e);
5629 }
5630 }
5631
5632 public void postMasterVolumeChanged(int flags) {
5633 if (mController == null)
5634 return;
5635 try {
5636 mController.masterVolumeChanged(flags);
5637 } catch (RemoteException e) {
5638 Log.w(TAG, "Error calling masterVolumeChanged", e);
5639 }
5640 }
5641
5642 public void postMasterMuteChanged(int flags) {
5643 if (mController == null)
5644 return;
5645 try {
5646 mController.masterMuteChanged(flags);
5647 } catch (RemoteException e) {
5648 Log.w(TAG, "Error calling masterMuteChanged", e);
5649 }
5650 }
5651
5652 public void setLayoutDirection(int layoutDirection) {
5653 if (mController == null)
5654 return;
5655 try {
5656 mController.setLayoutDirection(layoutDirection);
5657 } catch (RemoteException e) {
5658 Log.w(TAG, "Error calling setLayoutDirection", e);
5659 }
5660 }
5661
5662 public void postDismiss() {
5663 if (mController == null)
5664 return;
5665 try {
5666 mController.dismiss();
5667 } catch (RemoteException e) {
5668 Log.w(TAG, "Error calling dismiss", e);
5669 }
5670 }
5671 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005672
RoboErik0dac35a2014-08-12 15:48:49 -07005673 /**
5674 * Interface for system components to get some extra functionality through
5675 * LocalServices.
5676 */
5677 final class AudioServiceInternal extends AudioManagerInternal {
RoboErik272e1612014-09-05 11:39:29 -07005678
5679 @Override
5680 public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
5681 String callingPackage, int uid) {
5682 // direction and stream type swap here because the public
5683 // adjustSuggested has a different order than the other methods.
5684 adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage, uid);
5685 }
5686
RoboErik0dac35a2014-08-12 15:48:49 -07005687 @Override
5688 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
5689 String callingPackage, int uid) {
5690 adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
5691 }
5692
5693 @Override
5694 public void setStreamVolumeForUid(int streamType, int direction, int flags,
5695 String callingPackage, int uid) {
5696 setStreamVolume(streamType, direction, flags, callingPackage, uid);
5697 }
RoboErik519c7742014-11-18 10:59:09 -08005698
5699 @Override
5700 public void adjustMasterVolumeForUid(int steps, int flags, String callingPackage,
5701 int uid) {
5702 adjustMasterVolume(steps, flags, callingPackage, uid);
5703 }
RoboErik0dac35a2014-08-12 15:48:49 -07005704 }
5705
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005706 //==========================================================================================
5707 // Audio policy management
5708 //==========================================================================================
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005709 public String registerAudioPolicy(AudioPolicyConfig policyConfig, IBinder cb) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005710 //Log.v(TAG, "registerAudioPolicy for " + cb + " got policy:" + policyConfig);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005711 String regId = null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005712 boolean hasPermissionForPolicy =
5713 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
5714 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5715 if (!hasPermissionForPolicy) {
5716 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
5717 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005718 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005719 }
5720 synchronized (mAudioPolicies) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005721 try {
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005722 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, cb);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005723 cb.linkToDeath(app, 0/*flags*/);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005724 regId = app.connectMixes();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005725 mAudioPolicies.put(cb, app);
5726 } catch (RemoteException e) {
5727 // audio policy owner has already died!
5728 Slog.w(TAG, "Audio policy registration failed, could not link to " + cb +
5729 " binder death", e);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005730 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005731 }
5732 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005733 return regId;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005734 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005735
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005736 public void unregisterAudioPolicyAsync(IBinder cb) {
5737 synchronized (mAudioPolicies) {
5738 AudioPolicyProxy app = mAudioPolicies.remove(cb);
5739 if (app == null) {
5740 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
5741 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
5742 } else {
5743 cb.unlinkToDeath(app, 0/*flags*/);
5744 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005745 app.disconnectMixes();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005746 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005747 // TODO implement clearing mix attribute matching info in native audio policy
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005748 }
5749
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005750 //======================
5751 // Audio policy proxy
5752 //======================
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005753 /**
5754 * This internal class inherits from AudioPolicyConfig which contains all the mixes and
5755 * their configurations.
5756 */
5757 public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005758 private static final String TAG = "AudioPolicyProxy";
5759 AudioPolicyConfig mConfig;
5760 IBinder mToken;
5761 AudioPolicyProxy(AudioPolicyConfig config, IBinder token) {
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005762 super(config);
5763 setRegistration(new String(config.toString() + ":ap:" + mAudioPolicyCounter++));
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005764 mToken = token;
5765 }
5766
5767 public void binderDied() {
5768 synchronized (mAudioPolicies) {
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005769 Log.i(TAG, "audio policy " + mToken + " died");
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005770 disconnectMixes();
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005771 mAudioPolicies.remove(mToken);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005772 }
5773 }
5774
5775 String connectMixes() {
5776 updateMixes(AudioSystem.DEVICE_STATE_AVAILABLE);
5777 return mRegistrationId;
5778 }
5779
5780 void disconnectMixes() {
5781 updateMixes(AudioSystem.DEVICE_STATE_UNAVAILABLE);
5782 }
5783
5784 void updateMixes(int connectionState) {
5785 for (AudioMix mix : mMixes) {
5786 // TODO implement sending the mix attribute matching info to native audio policy
5787 if (DEBUG_AP) {
5788 Log.v(TAG, "AudioPolicyProxy connect mix state=" + connectionState
5789 + " addr=" + mix.getRegistration()); }
5790 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_REMOTE_SUBMIX,
5791 connectionState,
5792 mix.getRegistration());
5793 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_REMOTE_SUBMIX,
5794 connectionState,
5795 mix.getRegistration());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005796 }
5797 }
5798 };
5799
5800 private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
5801 new HashMap<IBinder, AudioPolicyProxy>();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005802 private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005803}