blob: 8dd2721ea55c2ebe8ed3692ffe25611f8539fbb0 [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;
Jean-Michel Trivif0cff042011-09-14 18:11:09 -070028import android.app.PendingIntent;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070029import android.bluetooth.BluetoothA2dp;
30import android.bluetooth.BluetoothAdapter;
31import android.bluetooth.BluetoothClass;
32import android.bluetooth.BluetoothDevice;
33import android.bluetooth.BluetoothHeadset;
34import android.bluetooth.BluetoothProfile;
Nick Pellybd022f42009-08-14 18:33:38 -070035import android.content.BroadcastReceiver;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070036import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.content.ContentResolver;
38import android.content.Context;
39import android.content.Intent;
Eric Laurenta553c252009-07-17 12:17:14 -070040import android.content.IntentFilter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.content.pm.PackageManager;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -070042import android.content.res.Configuration;
Eric Laurente78fced2013-03-15 16:03:47 -070043import android.content.res.Resources;
44import android.content.res.XmlResourceParser;
Jason Parekhb1096152009-03-24 17:48:25 -070045import android.database.ContentObserver;
Paul McLeanc837a452014-04-09 09:04:43 -070046import android.hardware.usb.UsbManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.media.MediaPlayer.OnCompletionListener;
48import android.media.MediaPlayer.OnErrorListener;
RoboErik8a2cfc32014-05-16 11:19:38 -070049import android.media.session.MediaSessionLegacyHelper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.os.Binder;
Eric Laurentc18c9132013-04-12 17:24:56 -070051import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.os.Environment;
53import android.os.Handler;
54import android.os.IBinder;
55import android.os.Looper;
56import android.os.Message;
Jean-Michel Trivic6802222012-04-30 11:15:03 -070057import android.os.PowerManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070058import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.os.RemoteException;
60import android.os.ServiceManager;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070061import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070062import android.os.UserHandle;
Eric Laurentbffc3d12012-05-07 17:43:49 -070063import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import android.provider.Settings;
65import android.provider.Settings.System;
Dianne Hackborn632ca412012-06-14 19:34:10 -070066import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import android.util.Log;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070068import android.view.KeyEvent;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -070069import android.view.Surface;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -070070import android.view.WindowManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071
72import com.android.internal.telephony.ITelephony;
Eric Laurente78fced2013-03-15 16:03:47 -070073import com.android.internal.util.XmlUtils;
74
75import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -080077import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078import java.io.IOException;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -080079import java.io.PrintWriter;
Eric Laurente78fced2013-03-15 16:03:47 -070080import java.lang.reflect.Field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081import java.util.ArrayList;
Eric Laurent3172d5e2012-05-09 11:38:16 -070082import java.util.concurrent.ConcurrentHashMap;
Eric Laurentc42ac9d2009-07-29 08:53:03 -070083import java.util.HashMap;
84import java.util.Iterator;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -070085import java.util.List;
Eric Laurentc42ac9d2009-07-29 08:53:03 -070086import java.util.Map;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070087import java.util.NoSuchElementException;
RoboErikd09bd0c2014-06-24 17:45:19 -070088import java.util.Objects;
Eric Laurentc42ac9d2009-07-29 08:53:03 -070089import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090
91/**
92 * The implementation of the volume manager service.
93 * <p>
94 * This implementation focuses on delivering a responsive UI. Most methods are
95 * asynchronous to external calls. For example, the task of setting a volume
96 * will update our internal state, but in a separate thread will set the system
97 * volume and later persist to the database. Similarly, setting the ringer mode
98 * will update the state and broadcast a change and in a separate thread later
99 * persist the ringer mode.
100 *
101 * @hide
102 */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700103public class AudioService extends IAudioService.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104
105 private static final String TAG = "AudioService";
106
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700107 /** Debug remote control client/display feature */
Jean-Michel Trivi7ff866e2011-10-13 18:09:26 -0700108 protected static final boolean DEBUG_RC = false;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700109 /** Debug volumes */
110 protected static final boolean DEBUG_VOL = false;
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700111
RoboErik430fc482014-06-12 15:49:20 -0700112 /** debug calls to media session apis */
RoboErik8a2cfc32014-05-16 11:19:38 -0700113 private static final boolean DEBUG_SESSIONS = true;
114
John Spurlock86005342014-05-23 11:58:00 -0400115 /** Allow volume changes to set ringer mode to silent? */
116 private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
117
John Spurlocka11b4af2014-06-01 11:52:23 -0400118 /** In silent mode, are volume adjustments (raises) prevented? */
119 private static final boolean PREVENT_VOLUME_ADJUSTMENT_IF_SILENT = true;
120
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 /** How long to delay before persisting a change in volume/ringer mode. */
RoboErik45edba12012-03-27 17:54:36 -0700122 private static final int PERSIST_DELAY = 500;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123
John Spurlock3346a802014-05-20 16:25:37 -0400124 /**
125 * The delay before playing a sound. This small period exists so the user
126 * can press another key (non-volume keys, too) to have it NOT be audible.
127 * <p>
128 * PhoneWindow will implement this part.
129 */
130 public static final int PLAY_SOUND_DELAY = 300;
131
John Spurlocka11b4af2014-06-01 11:52:23 -0400132 /**
133 * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
134 */
135 private static final int FLAG_ADJUST_VOLUME = 1;
136
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700137 private final Context mContext;
138 private final ContentResolver mContentResolver;
139 private final AppOpsManager mAppOps;
140 private final boolean mVoiceCapable;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800141
John Spurlock3346a802014-05-20 16:25:37 -0400142 /** The controller for the volume UI. */
143 private final VolumeController mVolumeController = new VolumeController();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144
145 // sendMsg() flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 /** If the msg is already queued, replace it with this one. */
147 private static final int SENDMSG_REPLACE = 0;
148 /** If the msg is already queued, ignore this one and leave the old. */
149 private static final int SENDMSG_NOOP = 1;
150 /** If the msg is already queued, queue this one and leave the old. */
151 private static final int SENDMSG_QUEUE = 2;
152
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700153 // AudioHandler messages
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800154 private static final int MSG_SET_DEVICE_VOLUME = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 private static final int MSG_PERSIST_VOLUME = 1;
Mike Lockwood5c55a052011-12-15 17:21:44 -0500156 private static final int MSG_PERSIST_MASTER_VOLUME = 2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 private static final int MSG_PERSIST_RINGER_MODE = 3;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700158 private static final int MSG_MEDIA_SERVER_DIED = 4;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700159 private static final int MSG_PLAY_SOUND_EFFECT = 5;
160 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
161 private static final int MSG_LOAD_SOUND_EFFECTS = 7;
162 private static final int MSG_SET_FORCE_USE = 8;
163 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
164 private static final int MSG_SET_ALL_VOLUMES = 10;
165 private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
166 private static final int MSG_REPORT_NEW_ROUTES = 12;
167 private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
168 private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
169 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
170 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
171 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
172 private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
173 private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
174 private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700175 private static final int MSG_SYSTEM_READY = 21;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700176 // start of messages handled under wakelock
177 // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
Jean-Michel Trivie12c39b2012-06-06 10:51:58 -0700178 // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700179 private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
Mike Lockwood0a40ec22014-05-21 10:08:50 -0700180 private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
181 private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700182 // end of messages handled under wakelock
Eric Laurentafbb0472011-12-15 09:04:23 -0800183
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -0700184 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
Eric Laurentdc03c612011-04-01 10:59:41 -0700185 // Timeout for connection to bluetooth headset service
186 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 /** @see AudioSystemThread */
189 private AudioSystemThread mAudioSystemThread;
190 /** @see AudioHandler */
191 private AudioHandler mAudioHandler;
192 /** @see VolumeStreamState */
193 private VolumeStreamState[] mStreamStates;
Jason Parekhb1096152009-03-24 17:48:25 -0700194 private SettingsObserver mSettingsObserver;
Eric Laurenta553c252009-07-17 12:17:14 -0700195
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700196 private int mMode = AudioSystem.MODE_NORMAL;
Glenn Kastenba195eb2011-12-13 09:30:40 -0800197 // protects mRingerMode
198 private final Object mSettingsLock = new Object();
Eric Laurent45c90ce2012-04-24 18:44:22 -0700199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 private SoundPool mSoundPool;
Glenn Kasten30c918c2011-11-10 17:56:41 -0800201 private final Object mSoundEffectsLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 private static final int NUM_SOUNDPOOL_CHANNELS = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203
Mike Lockwood47676902011-11-08 10:31:21 -0800204 // Internally master volume is a float in the 0.0 - 1.0 range,
205 // but to support integer based AudioManager API we translate it to 0 - 100
206 private static final int MAX_MASTER_VOLUME = 100;
207
Lei Zhang6c798972012-03-02 11:40:12 -0800208 // Maximum volume adjust steps allowed in a single batch call.
209 private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 /* Sound effect file names */
212 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
Eric Laurente78fced2013-03-15 16:03:47 -0700213 private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214
215 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
216 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
217 * uses soundpool (second column) */
Eric Laurente78fced2013-03-15 16:03:47 -0700218 private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219
Jared Suttles59820132009-08-13 21:50:52 -0500220 /** @hide Maximum volume index values for audio streams */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700221 private static final int[] MAX_STREAM_VOLUME = new int[] {
Eric Laurent6ee99522009-08-25 06:30:59 -0700222 5, // STREAM_VOICE_CALL
223 7, // STREAM_SYSTEM
224 7, // STREAM_RING
225 15, // STREAM_MUSIC
226 7, // STREAM_ALARM
227 7, // STREAM_NOTIFICATION
228 15, // STREAM_BLUETOOTH_SCO
229 7, // STREAM_SYSTEM_ENFORCED
230 15, // STREAM_DTMF
231 15 // STREAM_TTS
Jared Suttles59820132009-08-13 21:50:52 -0500232 };
Eric Laurent6d517662012-04-23 18:42:39 -0700233 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
Eric Laurenta553c252009-07-17 12:17:14 -0700234 * of another stream: This avoids multiplying the volume settings for hidden
235 * stream types that follow other stream behavior for volume settings
Eric Laurent6d517662012-04-23 18:42:39 -0700236 * NOTE: do not create loops in aliases!
237 * Some streams alias to different streams according to device category (phone or tablet) or
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700238 * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
Eric Laurent6d517662012-04-23 18:42:39 -0700239 * mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and
240 * STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/
Glenn Kasten30c918c2011-11-10 17:56:41 -0800241 private final int[] STREAM_VOLUME_ALIAS = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700242 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
243 AudioSystem.STREAM_RING, // STREAM_SYSTEM
244 AudioSystem.STREAM_RING, // STREAM_RING
245 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
246 AudioSystem.STREAM_ALARM, // STREAM_ALARM
247 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
248 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
249 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
250 AudioSystem.STREAM_RING, // STREAM_DTMF
251 AudioSystem.STREAM_MUSIC // STREAM_TTS
Eric Laurenta553c252009-07-17 12:17:14 -0700252 };
Eric Laurent6d517662012-04-23 18:42:39 -0700253 private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] {
254 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
255 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
256 AudioSystem.STREAM_RING, // STREAM_RING
257 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
258 AudioSystem.STREAM_ALARM, // STREAM_ALARM
259 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
260 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
261 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
262 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
263 AudioSystem.STREAM_MUSIC // STREAM_TTS
264 };
265 private int[] mStreamVolumeAlias;
Eric Laurenta553c252009-07-17 12:17:14 -0700266
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700267 /**
268 * Map AudioSystem.STREAM_* constants to app ops. This should be used
269 * after mapping through mStreamVolumeAlias.
270 */
271 private static final int[] STEAM_VOLUME_OPS = new int[] {
272 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL
273 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM
274 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING
275 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC
276 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM
277 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION
278 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO
279 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED
280 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF
281 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS
282 };
283
Eric Laurent83a017b2013-03-19 18:15:31 -0700284 private final boolean mUseFixedVolume;
285
Eric Laurentbffc3d12012-05-07 17:43:49 -0700286 // stream names used by dumpStreamStates()
John Spurlock1af30c72014-03-10 08:33:35 -0400287 private static final String[] STREAM_NAMES = new String[] {
Eric Laurentbffc3d12012-05-07 17:43:49 -0700288 "STREAM_VOICE_CALL",
289 "STREAM_SYSTEM",
290 "STREAM_RING",
291 "STREAM_MUSIC",
292 "STREAM_ALARM",
293 "STREAM_NOTIFICATION",
294 "STREAM_BLUETOOTH_SCO",
295 "STREAM_SYSTEM_ENFORCED",
296 "STREAM_DTMF",
297 "STREAM_TTS"
298 };
299
Glenn Kasten30c918c2011-11-10 17:56:41 -0800300 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 public void onError(int error) {
302 switch (error) {
303 case AudioSystem.AUDIO_STATUS_SERVER_DIED:
Eric Laurentdfb881f2013-07-18 14:41:39 -0700304 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
305 SENDMSG_NOOP, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 break;
307 default:
308 break;
309 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700310 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311 };
312
313 /**
314 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
315 * {@link AudioManager#RINGER_MODE_SILENT}, or
316 * {@link AudioManager#RINGER_MODE_VIBRATE}.
317 */
Glenn Kastenba195eb2011-12-13 09:30:40 -0800318 // protected by mSettingsLock
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 private int mRingerMode;
320
Eric Laurent9bcf4012009-06-12 06:09:28 -0700321 /** @see System#MODE_RINGER_STREAMS_AFFECTED */
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700322 private int mRingerModeAffectedStreams = 0;
Eric Laurent9bcf4012009-06-12 06:09:28 -0700323
Eric Laurent5b4e6542010-03-19 20:02:21 -0700324 // Streams currently muted by ringer mode
325 private int mRingerModeMutedStreams;
326
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327 /** @see System#MUTE_STREAMS_AFFECTED */
328 private int mMuteAffectedStreams;
329
330 /**
Eric Laurentbffc3d12012-05-07 17:43:49 -0700331 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
332 * mVibrateSetting is just maintained during deprecation period but vibration policy is
333 * now only controlled by mHasVibrator and mRingerMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 */
335 private int mVibrateSetting;
336
Eric Laurentbffc3d12012-05-07 17:43:49 -0700337 // Is there a vibrator
338 private final boolean mHasVibrator;
339
Eric Laurenta553c252009-07-17 12:17:14 -0700340 // Broadcast receiver for device connections intent broadcasts
341 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
342
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700343 // Devices currently connected
Glenn Kasten30c918c2011-11-10 17:56:41 -0800344 private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700345
346 // Forced device usage for communications
347 private int mForcedUseForComm;
348
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500349 // True if we have master volume support
350 private final boolean mUseMasterVolume;
351
Mike Lockwood97606472012-02-09 11:24:10 -0800352 private final int[] mMasterVolumeRamp;
353
Eric Laurent9272b4b2010-01-23 17:12:59 -0800354 // List of binder death handlers for setMode() client processes.
355 // The last process to have called setMode() is at the top of the list.
Glenn Kasten30c918c2011-11-10 17:56:41 -0800356 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
Eric Laurenteb14a782009-12-17 03:12:59 -0800357
Eric Laurent3def1ee2010-03-17 23:26:26 -0700358 // List of clients having issued a SCO start request
Glenn Kasten30c918c2011-11-10 17:56:41 -0800359 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
Eric Laurent3def1ee2010-03-17 23:26:26 -0700360
361 // BluetoothHeadset API to control SCO connection
362 private BluetoothHeadset mBluetoothHeadset;
363
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700364 // Bluetooth headset device
365 private BluetoothDevice mBluetoothHeadsetDevice;
Eric Laurent3def1ee2010-03-17 23:26:26 -0700366
Eric Laurent62ef7672010-11-24 10:58:32 -0800367 // Indicate if SCO audio connection is currently active and if the initiator is
368 // audio service (internal) or bluetooth headset (external)
369 private int mScoAudioState;
370 // SCO audio state is not active
371 private static final int SCO_STATE_INACTIVE = 0;
Eric Laurentdc03c612011-04-01 10:59:41 -0700372 // SCO audio activation request waiting for headset service to connect
373 private static final int SCO_STATE_ACTIVATE_REQ = 1;
Eric Laurent25fc29b2013-04-05 12:13:54 -0700374 // SCO audio state is active or starting due to a request from AudioManager API
Eric Laurentdc03c612011-04-01 10:59:41 -0700375 private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
376 // SCO audio deactivation request waiting for headset service to connect
377 private static final int SCO_STATE_DEACTIVATE_REQ = 5;
378
Eric Laurent62ef7672010-11-24 10:58:32 -0800379 // SCO audio state is active due to an action in BT handsfree (either voice recognition or
380 // in call audio)
381 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
Eric Laurentdc03c612011-04-01 10:59:41 -0700382 // Deactivation request for all SCO connections (initiated by audio mode change)
383 // waiting for headset service to connect
384 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
385
Eric Laurentc18c9132013-04-12 17:24:56 -0700386 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
387 // originated from an app targeting an API version before JB MR2 and raw audio after that.
388 private int mScoAudioMode;
389 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
390 private static final int SCO_MODE_VIRTUAL_CALL = 0;
391 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
392 private static final int SCO_MODE_RAW = 1;
393
Eric Laurentdc03c612011-04-01 10:59:41 -0700394 // Current connection state indicated by bluetooth headset
395 private int mScoConnectionState;
Eric Laurent62ef7672010-11-24 10:58:32 -0800396
Eric Laurenta60e2122010-12-28 16:49:07 -0800397 // true if boot sequence has been completed
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700398 private boolean mSystemReady;
Eric Laurenta60e2122010-12-28 16:49:07 -0800399 // listener for SoundPool sample load completion indication
400 private SoundPoolCallback mSoundPoolCallBack;
401 // thread for SoundPool listener
402 private SoundPoolListenerThread mSoundPoolListenerThread;
403 // message looper for SoundPool listener
404 private Looper mSoundPoolLooper = null;
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700405 // volume applied to sound played with playSoundEffect()
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700406 private static int sSoundEffectVolumeDb;
Eric Laurent9903e262012-09-21 18:10:32 -0700407 // getActiveStreamType() will return:
408 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
409 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
Eric Laurent25101b02011-02-02 09:33:30 -0800410 // stopped
Eric Laurent9903e262012-09-21 18:10:32 -0700411 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
Eric Laurent25101b02011-02-02 09:33:30 -0800412 // previous volume adjustment direction received by checkForRingerModeChange()
413 private int mPrevVolDirection = AudioManager.ADJUST_SAME;
Amith Yamasani6243edd2011-12-05 19:58:48 -0800414 // Keyguard manager proxy
415 private KeyguardManager mKeyguardManager;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700416 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
417 // is controlled by Vol keys.
418 private int mVolumeControlStream = -1;
419 private final Object mForceControlStreamLock = new Object();
420 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
421 // server process so in theory it is not necessary to monitor the client death.
422 // However it is good to be ready for future evolutions.
423 private ForceControlStreamClient mForceControlStreamClient = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700424 // Used to play ringtones outside system_server
425 private volatile IRingtonePlayer mRingtonePlayer;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800426
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700427 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700428 private int mDeviceRotation = Surface.ROTATION_0;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700429
Eric Laurent78472112012-05-21 08:57:21 -0700430 // Request to override default use of A2DP for media.
431 private boolean mBluetoothA2dpEnabled;
432 private final Object mBluetoothA2dpEnabledLock = new Object();
433
Dianne Hackborn632ca412012-06-14 19:34:10 -0700434 // Monitoring of audio routes. Protected by mCurAudioRoutes.
435 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
436 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
437 = new RemoteCallbackList<IAudioRoutesObserver>();
438
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700439 /**
440 * A fake stream type to match the notion of remote media playback
441 */
442 public final static int STREAM_REMOTE_MUSIC = -200;
443
Eric Laurent4bbcc652012-09-24 14:26:30 -0700444 // Devices for which the volume is fixed and VolumePanel slider should be disabled
Eric Laurent948d3272014-05-16 15:18:45 -0700445 final int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700446 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700447 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700448 AudioSystem.DEVICE_OUT_ALL_USB;
449
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700450 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700451 private final boolean mMonitorOrientation;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700452 private final boolean mMonitorRotation;
Eric Laurentd640bd32012-09-28 18:01:48 -0700453
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700454 private boolean mDockAudioMediaEnabled = true;
455
Eric Laurent08ed1b92012-11-05 14:54:12 -0800456 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
457
Eric Laurentfde16d52012-12-03 14:42:39 -0800458 // Used when safe volume warning message display is requested by setStreamVolume(). In this
459 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
460 // and used later when/if disableSafeMediaVolume() is called.
461 private StreamVolumeCommand mPendingVolumeCommand;
462
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700463 private PowerManager.WakeLock mAudioEventWakeLock;
464
465 private final MediaFocusControl mMediaFocusControl;
466
John Du5a0cf7a2013-07-19 11:30:34 -0700467 // Reference to BluetoothA2dp to query for AbsoluteVolume.
468 private BluetoothA2dp mA2dp;
469 private final Object mA2dpAvrcpLock = new Object();
470 // If absolute volume is supported in AVRCP device
471 private boolean mAvrcpAbsVolSupported = false;
472
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 ///////////////////////////////////////////////////////////////////////////
474 // Construction
475 ///////////////////////////////////////////////////////////////////////////
476
477 /** @hide */
478 public AudioService(Context context) {
479 mContext = context;
480 mContentResolver = context.getContentResolver();
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700481 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Joe Onoratoc7fcba42011-01-05 16:53:11 -0800482 mVoiceCapable = mContext.getResources().getBoolean(
483 com.android.internal.R.bool.config_voice_capable);
Jared Suttles59820132009-08-13 21:50:52 -0500484
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700485 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700486 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700487
Eric Laurentbffc3d12012-05-07 17:43:49 -0700488 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
489 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
490
Jared Suttles59820132009-08-13 21:50:52 -0500491 // Intialized volume
492 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt(
493 "ro.config.vc_call_vol_steps",
494 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
495
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700496 sSoundEffectVolumeDb = context.getResources().getInteger(
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700497 com.android.internal.R.integer.config_soundEffectVolumeDb);
Eric Laurent25101b02011-02-02 09:33:30 -0800498
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700499 mForcedUseForComm = AudioSystem.FORCE_NONE;
Eric Laurentdd45d012012-10-08 09:04:34 -0700500
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 createAudioSystemThread();
Eric Laurentdd45d012012-10-08 09:04:34 -0700502
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700503 mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
John Spurlock3346a802014-05-20 16:25:37 -0400504 mContext, mVolumeController, this);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700505
Eric Laurentdfb881f2013-07-18 14:41:39 -0700506 AudioSystem.setErrorCallback(mAudioSystemCallback);
507
Eric Laurentdd45d012012-10-08 09:04:34 -0700508 boolean cameraSoundForced = mContext.getResources().getBoolean(
509 com.android.internal.R.bool.config_camera_sound_forced);
510 mCameraSoundForced = new Boolean(cameraSoundForced);
511 sendMsg(mAudioHandler,
512 MSG_SET_FORCE_USE,
513 SENDMSG_QUEUE,
514 AudioSystem.FOR_SYSTEM,
515 cameraSoundForced ?
516 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
517 null,
518 0);
519
Eric Laurent05274f32012-11-29 12:48:18 -0800520 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
521 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
522 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
523 // The default safe volume index read here will be replaced by the actual value when
524 // the mcc is read by onConfigureSafeVolume()
525 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
526 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
527
Eric Laurent83a017b2013-03-19 18:15:31 -0700528 mUseFixedVolume = mContext.getResources().getBoolean(
529 com.android.internal.R.bool.config_useFixedVolume);
530
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700531 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
532 // array initialized by updateStreamVolumeAlias()
533 updateStreamVolumeAlias(false /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 readPersistedSettings();
Eric Laurentc1d41662011-07-19 11:21:13 -0700535 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700536 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700537
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700538 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700539
540 // Call setRingerModeInt() to apply correct mute
541 // state on streams affected by ringer mode.
542 mRingerModeMutedStreams = 0;
543 setRingerModeInt(getRingerMode(), false);
544
Eric Laurenta553c252009-07-17 12:17:14 -0700545 // Register for device connection intent broadcasts.
546 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700547 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700548 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
549 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Eric Laurent59f48272012-04-05 19:42:21 -0700550 intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
551 intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700552 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
553 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700554 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Paul McLeanc837a452014-04-09 09:04:43 -0700555 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700556
Eric Laurentd640bd32012-09-28 18:01:48 -0700557 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700558 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700559 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
560 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700561 Log.v(TAG, "monitoring device orientation");
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700562 // initialize orientation in AudioSystem
563 setOrientationForAudioSystem();
564 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700565 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
566 if (mMonitorRotation) {
567 mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
568 .getDefaultDisplay().getRotation();
569 Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
570 // initialize rotation in AudioSystem
571 setRotationForAudioSystem();
572 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700573
Eric Laurenta553c252009-07-17 12:17:14 -0700574 context.registerReceiver(mReceiver, intentFilter);
Jared Suttles59820132009-08-13 21:50:52 -0500575
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500576 mUseMasterVolume = context.getResources().getBoolean(
577 com.android.internal.R.bool.config_useMasterVolume);
Mike Lockwood90631542012-01-06 11:20:37 -0500578 restoreMasterVolume();
Mike Lockwood97606472012-02-09 11:24:10 -0800579
580 mMasterVolumeRamp = context.getResources().getIntArray(
581 com.android.internal.R.array.config_masterVolumeRamp);
Eric Laurent78472112012-05-21 08:57:21 -0700582
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 }
584
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700585 public void systemReady() {
586 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
587 0, 0, null, 0);
588 }
589
590 public void onSystemReady() {
591 mSystemReady = true;
592 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
593 0, 0, null, 0);
594
595 mKeyguardManager =
596 (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
597 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
598 resetBluetoothSco();
599 getBluetoothHeadset();
600 //FIXME: this is to maintain compatibility with deprecated intent
601 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
602 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
603 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
604 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
605 sendStickyBroadcastToAll(newIntent);
606
607 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
608 if (adapter != null) {
609 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
610 BluetoothProfile.A2DP);
611 }
612
613 sendMsg(mAudioHandler,
614 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
615 SENDMSG_REPLACE,
616 0,
617 0,
618 null,
619 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
620 }
621
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622 private void createAudioSystemThread() {
623 mAudioSystemThread = new AudioSystemThread();
624 mAudioSystemThread.start();
625 waitForAudioHandlerCreation();
626 }
627
628 /** Waits for the volume handler to be created by the other thread. */
629 private void waitForAudioHandlerCreation() {
630 synchronized(this) {
631 while (mAudioHandler == null) {
632 try {
633 // Wait for mAudioHandler to be set by the other thread
634 wait();
635 } catch (InterruptedException e) {
636 Log.e(TAG, "Interrupted while waiting on volume handler.");
637 }
638 }
639 }
640 }
641
Eric Laurent24482012012-05-10 09:41:17 -0700642 private void checkAllAliasStreamVolumes() {
643 int numStreamTypes = AudioSystem.getNumStreamTypes();
644 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
645 if (streamType != mStreamVolumeAlias[streamType]) {
646 mStreamStates[streamType].
Eric Laurent42b041e2013-03-29 11:36:03 -0700647 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
Eric Laurent24482012012-05-10 09:41:17 -0700648 }
649 // apply stream volume
Eric Laurent42b041e2013-03-29 11:36:03 -0700650 if (!mStreamStates[streamType].isMuted()) {
Eric Laurent24482012012-05-10 09:41:17 -0700651 mStreamStates[streamType].applyAllVolumes();
652 }
653 }
654 }
655
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800656 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800657 int numStreamTypes = AudioSystem.getNumStreamTypes();
658 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
659
660 for (int i = 0; i < numStreamTypes; i++) {
Eric Laurent6d517662012-04-23 18:42:39 -0700661 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -0700662 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800663
Eric Laurent24482012012-05-10 09:41:17 -0700664 checkAllAliasStreamVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 }
666
Eric Laurentbffc3d12012-05-07 17:43:49 -0700667 private void dumpStreamStates(PrintWriter pw) {
668 pw.println("\nStream volumes (device: index)");
669 int numStreamTypes = AudioSystem.getNumStreamTypes();
670 for (int i = 0; i < numStreamTypes; i++) {
671 pw.println("- "+STREAM_NAMES[i]+":");
672 mStreamStates[i].dump(pw);
673 pw.println("");
674 }
Eric Laurentdd45d012012-10-08 09:04:34 -0700675 pw.print("\n- mute affected streams = 0x");
676 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -0700677 }
678
John Spurlock1af30c72014-03-10 08:33:35 -0400679 /** @hide */
680 public static String streamToString(int stream) {
681 if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream];
682 if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE";
683 return "UNKNOWN_STREAM_" + stream;
684 }
Eric Laurent6d517662012-04-23 18:42:39 -0700685
686 private void updateStreamVolumeAlias(boolean updateVolumes) {
687 int dtmfStreamAlias;
688 if (mVoiceCapable) {
689 mStreamVolumeAlias = STREAM_VOLUME_ALIAS;
690 dtmfStreamAlias = AudioSystem.STREAM_RING;
691 } else {
692 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE;
693 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
694 }
695 if (isInCommunication()) {
696 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700697 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
698 } else {
699 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
Eric Laurent6d517662012-04-23 18:42:39 -0700700 }
701 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
702 if (updateVolumes) {
Eric Laurent42b041e2013-03-29 11:36:03 -0700703 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700704 // apply stream mute states according to new value of mRingerModeAffectedStreams
705 setRingerModeInt(getRingerMode(), false);
Eric Laurent6d517662012-04-23 18:42:39 -0700706 sendMsg(mAudioHandler,
707 MSG_SET_ALL_VOLUMES,
708 SENDMSG_QUEUE,
709 0,
710 0,
711 mStreamStates[AudioSystem.STREAM_DTMF], 0);
712 }
713 }
714
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700715 private void readDockAudioSettings(ContentResolver cr)
716 {
717 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -0700718 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700719
720 if (mDockAudioMediaEnabled) {
721 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
722 } else {
723 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
724 }
725
726 sendMsg(mAudioHandler,
727 MSG_SET_FORCE_USE,
728 SENDMSG_QUEUE,
729 AudioSystem.FOR_DOCK,
730 mDockAudioMediaEnabled ?
731 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
732 null,
733 0);
734 }
735
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 private void readPersistedSettings() {
737 final ContentResolver cr = mContentResolver;
738
Eric Laurentbffc3d12012-05-07 17:43:49 -0700739 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700740 Settings.Global.getInt(
741 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -0700742 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -0700743 // sanity check in case the settings are restored from a device with incompatible
744 // ringer modes
Glenn Kastenba195eb2011-12-13 09:30:40 -0800745 if (!AudioManager.isValidRingerMode(ringerMode)) {
746 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700747 }
748 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
749 ringerMode = AudioManager.RINGER_MODE_SILENT;
750 }
751 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700752 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -0800753 }
Eric Laurent83a017b2013-03-19 18:15:31 -0700754 if (mUseFixedVolume) {
755 ringerMode = AudioManager.RINGER_MODE_NORMAL;
756 }
Glenn Kastenba195eb2011-12-13 09:30:40 -0800757 synchronized(mSettingsLock) {
758 mRingerMode = ringerMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759
Eric Laurentdd45d012012-10-08 09:04:34 -0700760 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
761 // are still needed while setVibrateSetting() and getVibrateSetting() are being
762 // deprecated.
763 mVibrateSetting = getValueForVibrateSetting(0,
764 AudioManager.VIBRATE_TYPE_NOTIFICATION,
765 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
766 : AudioManager.VIBRATE_SETTING_OFF);
767 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
768 AudioManager.VIBRATE_TYPE_RINGER,
769 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
770 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700772 updateRingerModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700773 readDockAudioSettings(cr);
Eric Laurent402f7f22011-02-04 12:30:32 -0800774 }
Eric Laurentc1d41662011-07-19 11:21:13 -0700775
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700776 mMuteAffectedStreams = System.getIntForUser(cr,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 System.MUTE_STREAMS_AFFECTED,
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700778 ((1 << AudioSystem.STREAM_MUSIC)|
779 (1 << AudioSystem.STREAM_RING)|
780 (1 << AudioSystem.STREAM_SYSTEM)),
781 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700783 boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
784 0, UserHandle.USER_CURRENT) == 1;
Eric Laurent83a017b2013-03-19 18:15:31 -0700785 if (mUseFixedVolume) {
786 masterMute = false;
787 AudioSystem.setMasterVolume(1.0f);
788 }
Justin Koh57978ed2012-04-03 17:37:58 -0700789 AudioSystem.setMasterMute(masterMute);
790 broadcastMasterMuteStatus(masterMute);
791
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 // Each stream will read its own persisted settings
793
794 // Broadcast the sticky intent
Glenn Kastenba195eb2011-12-13 09:30:40 -0800795 broadcastRingerMode(ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796
797 // Broadcast vibrate settings
798 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
799 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -0700800
801 // Restore the default media button receiver from the system settings
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700802 mMediaFocusControl.restoreMediaButtonReceiver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 }
804
Eric Laurenta553c252009-07-17 12:17:14 -0700805 private int rescaleIndex(int index, int srcStream, int dstStream) {
806 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
807 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800808
809 ///////////////////////////////////////////////////////////////////////////
810 // IPC methods
811 ///////////////////////////////////////////////////////////////////////////
Jean-Michel Trivifca1e602013-10-10 18:12:59 -0700812 /** @see AudioManager#isLocalOrRemoteMusicActive() */
813 public boolean isLocalOrRemoteMusicActive() {
814 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
815 // local / wired / BT playback active
816 if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): local");
817 return true;
818 }
819 if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
820 // remote "cast-like" playback active
821 if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): has PLAYBACK_TYPE_REMOTE");
822 return true;
823 }
824 if (AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, 0)) {
825 // remote submix playback active
826 if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): remote submix");
827 return true;
828 }
829 if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): no");
830 return false;
831 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800832
833 /** @see AudioManager#adjustVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700834 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
835 String callingPackage) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700836 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType);
Eric Laurent402f7f22011-02-04 12:30:32 -0800837 int streamType;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700838 if (mVolumeControlStream != -1) {
839 streamType = mVolumeControlStream;
Eric Laurent402f7f22011-02-04 12:30:32 -0800840 } else {
841 streamType = getActiveStreamType(suggestedStreamType);
842 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843
Amith Yamasani6243edd2011-12-05 19:58:48 -0800844 // Play sounds on STREAM_RING only and if lock screen is not on.
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700845 if ((streamType != STREAM_REMOTE_MUSIC) &&
846 (flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
Eric Laurent6d517662012-04-23 18:42:39 -0700847 ((mStreamVolumeAlias[streamType] != AudioSystem.STREAM_RING)
Amith Yamasani6243edd2011-12-05 19:58:48 -0800848 || (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800849 flags &= ~AudioManager.FLAG_PLAY_SOUND;
850 }
851
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700852 if (streamType == STREAM_REMOTE_MUSIC) {
RoboErik19c95182014-06-23 15:38:48 -0700853 // TODO bounce it to MediaSessionService to find an appropriate
854 // session
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700855 } else {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700856 adjustStreamVolume(streamType, direction, flags, callingPackage);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700857 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858 }
859
860 /** @see AudioManager#adjustStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700861 public void adjustStreamVolume(int streamType, int direction, int flags,
862 String callingPackage) {
Eric Laurent83a017b2013-03-19 18:15:31 -0700863 if (mUseFixedVolume) {
864 return;
865 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700866 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction);
867
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868 ensureValidDirection(direction);
869 ensureValidStreamType(streamType);
870
Eric Laurent96a33d12011-11-08 10:31:57 -0800871 // use stream type alias here so that streams with same alias have the same behavior,
872 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
873 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
Eric Laurent6d517662012-04-23 18:42:39 -0700874 int streamTypeAlias = mStreamVolumeAlias[streamType];
Eric Laurentb024c302011-10-14 17:19:27 -0700875 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800876
877 final int device = getDeviceForStream(streamTypeAlias);
Eric Laurent3ef75492012-11-28 12:12:23 -0800878
Eric Laurent42b041e2013-03-29 11:36:03 -0700879 int aliasIndex = streamState.getIndex(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880 boolean adjustVolume = true;
Eric Laurent3ef75492012-11-28 12:12:23 -0800881 int step;
Eric Laurent24482012012-05-10 09:41:17 -0700882
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700883 // skip a2dp absolute volume control request when the device
884 // is not an a2dp device
885 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
886 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
887 return;
888 }
889
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700890 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
891 callingPackage) != AppOpsManager.MODE_ALLOWED) {
892 return;
893 }
894
Eric Laurentfde16d52012-12-03 14:42:39 -0800895 // reset any pending volume command
896 synchronized (mSafeMediaVolumeState) {
897 mPendingVolumeCommand = null;
898 }
899
Eric Laurent3ef75492012-11-28 12:12:23 -0800900 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
901 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
902 ((device & mFixedVolumeDevices) != 0)) {
903 flags |= AudioManager.FLAG_FIXED_VOLUME;
904
905 // Always toggle between max safe volume and 0 for fixed volume devices where safe
906 // volume is enforced, and max and 0 for the others.
907 // This is simulated by stepping by the full allowed volume range
908 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
909 (device & mSafeMediaVolumeDevices) != 0) {
910 step = mSafeMediaVolumeIndex;
911 } else {
912 step = streamState.getMaxIndex();
913 }
914 if (aliasIndex != 0) {
915 aliasIndex = step;
916 }
917 } else {
918 // convert one UI step (+/-1) into a number of internal units on the stream alias
919 step = rescaleIndex(10, streamType, streamTypeAlias);
920 }
921
Eric Laurent42b041e2013-03-29 11:36:03 -0700922 // If either the client forces allowing ringer modes for this adjustment,
923 // or the stream type is one that is affected by ringer modes
924 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
925 (streamTypeAlias == getMasterStreamType())) {
926 int ringerMode = getRingerMode();
927 // do not vibrate if already in vibrate mode
928 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
929 flags &= ~AudioManager.FLAG_VIBRATE;
Eric Laurent3ef75492012-11-28 12:12:23 -0800930 }
Eric Laurent42b041e2013-03-29 11:36:03 -0700931 // Check if the ringer mode changes with this volume adjustment. If
932 // it does, it will handle adjusting the volume, so we won't below
John Spurlocka11b4af2014-06-01 11:52:23 -0400933 final int result = checkForRingerModeChange(aliasIndex, direction, step);
934 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
935 // If suppressing a volume adjustment in silent mode, display the UI hint
936 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
937 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
938 }
Eric Laurent42b041e2013-03-29 11:36:03 -0700939 }
Eric Laurent3ef75492012-11-28 12:12:23 -0800940
Eric Laurent42b041e2013-03-29 11:36:03 -0700941 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -0800942
Eric Laurent42b041e2013-03-29 11:36:03 -0700943 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700944
John Du5a0cf7a2013-07-19 11:30:34 -0700945 // Check if volume update should be send to AVRCP
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700946 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
947 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
948 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
949 synchronized (mA2dpAvrcpLock) {
950 if (mA2dp != null && mAvrcpAbsVolSupported) {
951 mA2dp.adjustAvrcpAbsoluteVolume(direction);
952 }
John Du5a0cf7a2013-07-19 11:30:34 -0700953 }
954 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700955
Eric Laurent42b041e2013-03-29 11:36:03 -0700956 if ((direction == AudioManager.ADJUST_RAISE) &&
957 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
958 Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -0400959 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurent42b041e2013-03-29 11:36:03 -0700960 } else if (streamState.adjustIndex(direction * step, device)) {
961 // Post message to set system volume (it in turn will post a message
962 // to persist). Do not change volume if stream is muted.
963 sendMsg(mAudioHandler,
964 MSG_SET_DEVICE_VOLUME,
965 SENDMSG_QUEUE,
966 device,
967 0,
968 streamState,
969 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -0700970 }
971 }
Eric Laurent42b041e2013-03-29 11:36:03 -0700972 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -0800973 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974 }
975
Dianne Hackborn961cae92013-03-20 14:59:43 -0700976 /** @see AudioManager#adjustMasterVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700977 public void adjustMasterVolume(int steps, int flags, String callingPackage) {
Eric Laurent83a017b2013-03-19 18:15:31 -0700978 if (mUseFixedVolume) {
979 return;
980 }
Lei Zhang6c798972012-03-02 11:40:12 -0800981 ensureValidSteps(steps);
Mike Lockwood97606472012-02-09 11:24:10 -0800982 int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
983 int delta = 0;
Lei Zhang6c798972012-03-02 11:40:12 -0800984 int numSteps = Math.abs(steps);
985 int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
986 for (int i = 0; i < numSteps; ++i) {
987 delta = findVolumeDelta(direction, volume);
988 volume += delta;
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -0400989 }
RoboErik24b082f2012-02-24 14:21:16 -0800990
Lei Zhang6c798972012-03-02 11:40:12 -0800991 //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700992 setMasterVolume(volume, flags, callingPackage);
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -0400993 }
994
Eric Laurentfde16d52012-12-03 14:42:39 -0800995 // StreamVolumeCommand contains the information needed to defer the process of
996 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
997 class StreamVolumeCommand {
998 public final int mStreamType;
999 public final int mIndex;
1000 public final int mFlags;
1001 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001002
Eric Laurentfde16d52012-12-03 14:42:39 -08001003 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1004 mStreamType = streamType;
1005 mIndex = index;
1006 mFlags = flags;
1007 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001008 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001009 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001010
Eric Laurentfde16d52012-12-03 14:42:39 -08001011 private void onSetStreamVolume(int streamType, int index, int flags, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001012 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
Eric Laurent3ef75492012-11-28 12:12:23 -08001013 // setting volume on master stream type also controls silent mode
1014 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1015 (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
1016 int newRingerMode;
1017 if (index == 0) {
1018 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlock86005342014-05-23 11:58:00 -04001019 : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
1020 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001021 } else {
1022 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1023 }
1024 setRingerMode(newRingerMode);
1025 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001026 }
1027
1028 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001029 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001030 if (mUseFixedVolume) {
1031 return;
1032 }
1033
Eric Laurentfde16d52012-12-03 14:42:39 -08001034 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001035 int streamTypeAlias = mStreamVolumeAlias[streamType];
1036 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001037
1038 final int device = getDeviceForStream(streamType);
1039 int oldIndex;
1040
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001041 // skip a2dp absolute volume control request when the device
1042 // is not an a2dp device
1043 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1044 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1045 return;
1046 }
1047
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001048 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
1049 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1050 return;
1051 }
1052
Eric Laurentfde16d52012-12-03 14:42:39 -08001053 synchronized (mSafeMediaVolumeState) {
1054 // reset any pending volume command
1055 mPendingVolumeCommand = null;
1056
Eric Laurent42b041e2013-03-29 11:36:03 -07001057 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001058
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001059 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001060
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001061 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1062 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1063 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1064 synchronized (mA2dpAvrcpLock) {
1065 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001066 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001067 }
John Du5a0cf7a2013-07-19 11:30:34 -07001068 }
1069 }
1070
Eric Laurentfde16d52012-12-03 14:42:39 -08001071 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001072 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001073 ((device & mFixedVolumeDevices) != 0)) {
1074 flags |= AudioManager.FLAG_FIXED_VOLUME;
1075
1076 // volume is either 0 or max allowed for fixed volume devices
1077 if (index != 0) {
1078 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1079 (device & mSafeMediaVolumeDevices) != 0) {
1080 index = mSafeMediaVolumeIndex;
1081 } else {
1082 index = streamState.getMaxIndex();
1083 }
1084 }
1085 }
1086
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001087 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001088 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001089 mPendingVolumeCommand = new StreamVolumeCommand(
1090 streamType, index, flags, device);
1091 } else {
1092 onSetStreamVolume(streamType, index, flags, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07001093 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001094 }
1095 }
Eric Laurent25101b02011-02-02 09:33:30 -08001096 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097 }
1098
Eric Laurent45c90ce2012-04-24 18:44:22 -07001099 /** @see AudioManager#forceVolumeControlStream(int) */
1100 public void forceVolumeControlStream(int streamType, IBinder cb) {
1101 synchronized(mForceControlStreamLock) {
1102 mVolumeControlStream = streamType;
1103 if (mVolumeControlStream == -1) {
1104 if (mForceControlStreamClient != null) {
1105 mForceControlStreamClient.release();
1106 mForceControlStreamClient = null;
1107 }
1108 } else {
1109 mForceControlStreamClient = new ForceControlStreamClient(cb);
1110 }
1111 }
1112 }
1113
1114 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1115 private IBinder mCb; // To be notified of client's death
1116
1117 ForceControlStreamClient(IBinder cb) {
1118 if (cb != null) {
1119 try {
1120 cb.linkToDeath(this, 0);
1121 } catch (RemoteException e) {
1122 // Client has died!
1123 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1124 cb = null;
1125 }
1126 }
1127 mCb = cb;
1128 }
1129
1130 public void binderDied() {
1131 synchronized(mForceControlStreamLock) {
1132 Log.w(TAG, "SCO client died");
1133 if (mForceControlStreamClient != this) {
1134 Log.w(TAG, "unregistered control stream client died");
1135 } else {
1136 mForceControlStreamClient = null;
1137 mVolumeControlStream = -1;
1138 }
1139 }
1140 }
1141
1142 public void release() {
1143 if (mCb != null) {
1144 mCb.unlinkToDeath(this, 0);
1145 mCb = null;
1146 }
1147 }
1148 }
1149
Lei Zhang6c798972012-03-02 11:40:12 -08001150 private int findVolumeDelta(int direction, int volume) {
1151 int delta = 0;
1152 if (direction == AudioManager.ADJUST_RAISE) {
1153 if (volume == MAX_MASTER_VOLUME) {
1154 return 0;
1155 }
1156 // This is the default value if we make it to the end
1157 delta = mMasterVolumeRamp[1];
1158 // If we're raising the volume move down the ramp array until we
1159 // find the volume we're above and use that groups delta.
1160 for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
1161 if (volume >= mMasterVolumeRamp[i - 1]) {
1162 delta = mMasterVolumeRamp[i];
1163 break;
1164 }
1165 }
1166 } else if (direction == AudioManager.ADJUST_LOWER){
1167 if (volume == 0) {
1168 return 0;
1169 }
1170 int length = mMasterVolumeRamp.length;
1171 // This is the default value if we make it to the end
1172 delta = -mMasterVolumeRamp[length - 1];
1173 // If we're lowering the volume move up the ramp array until we
1174 // find the volume we're below and use the group below it's delta
1175 for (int i = 2; i < length; i += 2) {
1176 if (volume <= mMasterVolumeRamp[i]) {
1177 delta = -mMasterVolumeRamp[i - 1];
1178 break;
1179 }
1180 }
1181 }
1182 return delta;
1183 }
1184
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001185 private void sendBroadcastToAll(Intent intent) {
1186 final long ident = Binder.clearCallingIdentity();
1187 try {
1188 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1189 } finally {
1190 Binder.restoreCallingIdentity(ident);
1191 }
1192 }
1193
1194 private void sendStickyBroadcastToAll(Intent intent) {
1195 final long ident = Binder.clearCallingIdentity();
1196 try {
1197 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1198 } finally {
1199 Binder.restoreCallingIdentity(ident);
1200 }
1201 }
1202
Eric Laurent25101b02011-02-02 09:33:30 -08001203 // UI update and Broadcast Intent
1204 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
1205 if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) {
1206 streamType = AudioSystem.STREAM_NOTIFICATION;
1207 }
1208
John Spurlock3346a802014-05-20 16:25:37 -04001209 mVolumeController.postVolumeChanged(streamType, flags);
Eric Laurent25101b02011-02-02 09:33:30 -08001210
Eric Laurent4bbcc652012-09-24 14:26:30 -07001211 if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
1212 oldIndex = (oldIndex + 5) / 10;
1213 index = (index + 5) / 10;
1214 Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
1215 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
1216 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
1217 intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
1218 sendBroadcastToAll(intent);
1219 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001220 }
1221
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001222 // UI update and Broadcast Intent
1223 private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
John Spurlock3346a802014-05-20 16:25:37 -04001224 mVolumeController.postMasterVolumeChanged(flags);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001225
1226 Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
1227 intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
1228 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001229 sendBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001230 }
1231
1232 // UI update and Broadcast Intent
1233 private void sendMasterMuteUpdate(boolean muted, int flags) {
John Spurlock3346a802014-05-20 16:25:37 -04001234 mVolumeController.postMasterMuteChanged(flags);
Justin Koh57978ed2012-04-03 17:37:58 -07001235 broadcastMasterMuteStatus(muted);
1236 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001237
Justin Koh57978ed2012-04-03 17:37:58 -07001238 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001239 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1240 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001241 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1242 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001243 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001244 }
1245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001246 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001247 * Sets the stream state's index, and posts a message to set system volume.
1248 * This will not call out to the UI. Assumes a valid stream type.
1249 *
1250 * @param streamType Type of the stream
1251 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001252 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001253 * @param force If true, set the volume even if the desired volume is same
1254 * as the current volume.
1255 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001256 private void setStreamVolumeInt(int streamType,
1257 int index,
1258 int device,
Eric Laurent42b041e2013-03-29 11:36:03 -07001259 boolean force) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07001261
Eric Laurent42b041e2013-03-29 11:36:03 -07001262 if (streamState.setIndex(index, device) || force) {
1263 // Post message to set system volume (it in turn will post a message
1264 // to persist).
1265 sendMsg(mAudioHandler,
1266 MSG_SET_DEVICE_VOLUME,
1267 SENDMSG_QUEUE,
1268 device,
1269 0,
1270 streamState,
1271 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001272 }
1273 }
1274
1275 /** @see AudioManager#setStreamSolo(int, boolean) */
1276 public void setStreamSolo(int streamType, boolean state, IBinder cb) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001277 if (mUseFixedVolume) {
1278 return;
1279 }
1280
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001281 for (int stream = 0; stream < mStreamStates.length; stream++) {
1282 if (!isStreamAffectedByMute(stream) || stream == streamType) continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001283 mStreamStates[stream].mute(cb, state);
1284 }
1285 }
1286
1287 /** @see AudioManager#setStreamMute(int, boolean) */
1288 public void setStreamMute(int streamType, boolean state, IBinder cb) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001289 if (mUseFixedVolume) {
1290 return;
1291 }
1292
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001293 if (isStreamAffectedByMute(streamType)) {
1294 mStreamStates[streamType].mute(cb, state);
1295 }
1296 }
1297
Eric Laurent25101b02011-02-02 09:33:30 -08001298 /** get stream mute state. */
1299 public boolean isStreamMute(int streamType) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001300 return mStreamStates[streamType].isMuted();
Eric Laurent25101b02011-02-02 09:33:30 -08001301 }
1302
Dianne Hackborn961cae92013-03-20 14:59:43 -07001303 /** @see AudioManager#setMasterMute(boolean, int) */
Julia Reynolds4a21b252014-06-04 11:11:43 -04001304 public void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001305 if (mUseFixedVolume) {
1306 return;
1307 }
1308
Julia Reynolds4a21b252014-06-04 11:11:43 -04001309 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
1310 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1311 return;
1312 }
1313
Jason Simmons1ce5b262012-02-02 13:00:17 -08001314 if (state != AudioSystem.getMasterMute()) {
1315 AudioSystem.setMasterMute(state);
Justin Koh57978ed2012-04-03 17:37:58 -07001316 // Post a persist master volume msg
Justin Koh75cf9e12012-04-04 15:27:37 -07001317 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
Justin Koh57978ed2012-04-03 17:37:58 -07001318 : 0, 0, null, PERSIST_DELAY);
Justin Koh0273af52012-04-04 18:29:50 -07001319 sendMasterMuteUpdate(state, flags);
Jason Simmons1ce5b262012-02-02 13:00:17 -08001320 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08001321 }
1322
1323 /** get master mute state. */
1324 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08001325 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001326 }
1327
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07001328 protected static int getMaxStreamVolume(int streamType) {
1329 return MAX_STREAM_VOLUME[streamType];
1330 }
1331
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001332 /** @see AudioManager#getStreamVolume(int) */
1333 public int getStreamVolume(int streamType) {
1334 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001335 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001336 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001337
Eric Laurent42b041e2013-03-29 11:36:03 -07001338 // by convention getStreamVolume() returns 0 when a stream is muted.
1339 if (mStreamStates[streamType].isMuted()) {
1340 index = 0;
1341 }
Eric Laurent3ef75492012-11-28 12:12:23 -08001342 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
Eric Laurent4bbcc652012-09-24 14:26:30 -07001343 (device & mFixedVolumeDevices) != 0) {
1344 index = mStreamStates[streamType].getMaxIndex();
Eric Laurent4bbcc652012-09-24 14:26:30 -07001345 }
1346 return (index + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001347 }
1348
Mike Lockwood47676902011-11-08 10:31:21 -08001349 public int getMasterVolume() {
Mike Lockwoodce952c82011-11-14 10:47:42 -08001350 if (isMasterMute()) return 0;
1351 return getLastAudibleMasterVolume();
Mike Lockwood8dc1dab2011-10-27 09:52:41 -04001352 }
1353
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001354 public void setMasterVolume(int volume, int flags, String callingPackage) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001355 if (mUseFixedVolume) {
1356 return;
1357 }
1358
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001359 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
1360 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1361 return;
1362 }
1363
Mike Lockwood97606472012-02-09 11:24:10 -08001364 if (volume < 0) {
1365 volume = 0;
1366 } else if (volume > MAX_MASTER_VOLUME) {
1367 volume = MAX_MASTER_VOLUME;
1368 }
Mike Lockwood5c55a052011-12-15 17:21:44 -05001369 doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
1370 }
1371
1372 private void doSetMasterVolume(float volume, int flags) {
1373 // don't allow changing master volume when muted
1374 if (!AudioSystem.getMasterMute()) {
1375 int oldVolume = getMasterVolume();
1376 AudioSystem.setMasterVolume(volume);
1377
1378 int newVolume = getMasterVolume();
1379 if (newVolume != oldVolume) {
1380 // Post a persist master volume msg
1381 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
1382 Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
Mike Lockwood5c55a052011-12-15 17:21:44 -05001383 }
Justin Koh3caba512012-04-02 15:32:18 -07001384 // Send the volume update regardless whether there was a change.
1385 sendMasterVolumeUpdate(flags, oldVolume, newVolume);
Mike Lockwood5c55a052011-12-15 17:21:44 -05001386 }
Mike Lockwood8dc1dab2011-10-27 09:52:41 -04001387 }
1388
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001389 /** @see AudioManager#getStreamMaxVolume(int) */
1390 public int getStreamMaxVolume(int streamType) {
1391 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07001392 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001393 }
1394
Mike Lockwood47676902011-11-08 10:31:21 -08001395 public int getMasterMaxVolume() {
1396 return MAX_MASTER_VOLUME;
1397 }
Eric Laurent25101b02011-02-02 09:33:30 -08001398
1399 /** Get last audible volume before stream was muted. */
1400 public int getLastAudibleStreamVolume(int streamType) {
1401 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001402 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001403 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08001404 }
1405
Mike Lockwoodce952c82011-11-14 10:47:42 -08001406 /** Get last audible master volume before it was muted. */
1407 public int getLastAudibleMasterVolume() {
1408 return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1409 }
1410
Dianne Hackborn961cae92013-03-20 14:59:43 -07001411 /** @see AudioManager#getMasterStreamType() */
Eric Laurent6d517662012-04-23 18:42:39 -07001412 public int getMasterStreamType() {
1413 if (mVoiceCapable) {
1414 return AudioSystem.STREAM_RING;
1415 } else {
1416 return AudioSystem.STREAM_MUSIC;
1417 }
1418 }
1419
Emily Bernier22c921a2014-05-28 11:01:32 -04001420 /** @see AudioManager#setMicrophoneMute(boolean) */
1421 public void setMicrophoneMute(boolean on, String callingPackage) {
1422 if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(),
1423 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1424 return;
1425 }
1426
1427 AudioSystem.muteMicrophone(on);
1428 }
1429
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001430 /** @see AudioManager#getRingerMode() */
1431 public int getRingerMode() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001432 synchronized(mSettingsLock) {
1433 return mRingerMode;
1434 }
1435 }
1436
1437 private void ensureValidRingerMode(int ringerMode) {
1438 if (!AudioManager.isValidRingerMode(ringerMode)) {
1439 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1440 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001441 }
1442
1443 /** @see AudioManager#setRingerMode(int) */
1444 public void setRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001445 if (mUseFixedVolume) {
1446 return;
1447 }
1448
Eric Laurent24482012012-05-10 09:41:17 -07001449 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1450 ringerMode = AudioManager.RINGER_MODE_SILENT;
1451 }
Glenn Kastenba195eb2011-12-13 09:30:40 -08001452 if (ringerMode != getRingerMode()) {
1453 setRingerModeInt(ringerMode, true);
1454 // Send sticky broadcast
1455 broadcastRingerMode(ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001456 }
1457 }
1458
Eric Laurent4050c932009-07-08 02:52:14 -07001459 private void setRingerModeInt(int ringerMode, boolean persist) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001460 synchronized(mSettingsLock) {
1461 mRingerMode = ringerMode;
1462 }
Jason Parekhb1096152009-03-24 17:48:25 -07001463
Eric Laurent5b4e6542010-03-19 20:02:21 -07001464 // Mute stream if not previously muted by ringer mode and ringer mode
1465 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
1466 // Unmute stream if previously muted by ringer mode and ringer mode
1467 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07001468 int numStreamTypes = AudioSystem.getNumStreamTypes();
Eric Laurent5b4e6542010-03-19 20:02:21 -07001469 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
1470 if (isStreamMutedByRingerMode(streamType)) {
1471 if (!isStreamAffectedByRingerMode(streamType) ||
Glenn Kastenba195eb2011-12-13 09:30:40 -08001472 ringerMode == AudioManager.RINGER_MODE_NORMAL) {
Eric Laurentb024c302011-10-14 17:19:27 -07001473 // ring and notifications volume should never be 0 when not silenced
1474 // on voice capable devices
1475 if (mVoiceCapable &&
Eric Laurent6d517662012-04-23 18:42:39 -07001476 mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07001477 synchronized (mStreamStates[streamType]) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001478 Set set = mStreamStates[streamType].mIndex.entrySet();
Eric Laurent3172d5e2012-05-09 11:38:16 -07001479 Iterator i = set.iterator();
1480 while (i.hasNext()) {
1481 Map.Entry entry = (Map.Entry)i.next();
1482 if ((Integer)entry.getValue() == 0) {
1483 entry.setValue(10);
1484 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001485 }
1486 }
Eric Laurentb024c302011-10-14 17:19:27 -07001487 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07001488 mStreamStates[streamType].mute(null, false);
1489 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent9bcf4012009-06-12 06:09:28 -07001490 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07001491 } else {
1492 if (isStreamAffectedByRingerMode(streamType) &&
Glenn Kastenba195eb2011-12-13 09:30:40 -08001493 ringerMode != AudioManager.RINGER_MODE_NORMAL) {
Eric Laurent5b4e6542010-03-19 20:02:21 -07001494 mStreamStates[streamType].mute(null, true);
1495 mRingerModeMutedStreams |= (1 << streamType);
1496 }
Jason Parekhb1096152009-03-24 17:48:25 -07001497 }
1498 }
Eric Laurenta553c252009-07-17 12:17:14 -07001499
Jason Parekhb1096152009-03-24 17:48:25 -07001500 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07001501 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08001502 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07001503 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
1504 }
Jason Parekhb1096152009-03-24 17:48:25 -07001505 }
1506
Mike Lockwood90631542012-01-06 11:20:37 -05001507 private void restoreMasterVolume() {
Eric Laurent83a017b2013-03-19 18:15:31 -07001508 if (mUseFixedVolume) {
1509 AudioSystem.setMasterVolume(1.0f);
1510 return;
1511 }
Mike Lockwood90631542012-01-06 11:20:37 -05001512 if (mUseMasterVolume) {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001513 float volume = Settings.System.getFloatForUser(mContentResolver,
1514 Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
Mike Lockwood90631542012-01-06 11:20:37 -05001515 if (volume >= 0.0f) {
1516 AudioSystem.setMasterVolume(volume);
1517 }
1518 }
1519 }
1520
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001521 /** @see AudioManager#shouldVibrate(int) */
1522 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001523 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001524
1525 switch (getVibrateSetting(vibrateType)) {
1526
1527 case AudioManager.VIBRATE_SETTING_ON:
Glenn Kastenba195eb2011-12-13 09:30:40 -08001528 return getRingerMode() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001529
1530 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
Glenn Kastenba195eb2011-12-13 09:30:40 -08001531 return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001532
1533 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04001534 // return false, even for incoming calls
1535 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001536
1537 default:
1538 return false;
1539 }
1540 }
1541
1542 /** @see AudioManager#getVibrateSetting(int) */
1543 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001544 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001545 return (mVibrateSetting >> (vibrateType * 2)) & 3;
1546 }
1547
1548 /** @see AudioManager#setVibrateSetting(int, int) */
1549 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
1550
Eric Laurentbffc3d12012-05-07 17:43:49 -07001551 if (!mHasVibrator) return;
1552
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
1554
1555 // Broadcast change
1556 broadcastVibrateSetting(vibrateType);
1557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001558 }
1559
1560 /**
1561 * @see #setVibrateSetting(int, int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001562 */
1563 public static int getValueForVibrateSetting(int existingValue, int vibrateType,
1564 int vibrateSetting) {
1565
1566 // First clear the existing setting. Each vibrate type has two bits in
1567 // the value. Note '3' is '11' in binary.
1568 existingValue &= ~(3 << (vibrateType * 2));
1569
1570 // Set into the old value
1571 existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
1572
1573 return existingValue;
1574 }
1575
Eric Laurent9272b4b2010-01-23 17:12:59 -08001576 private class SetModeDeathHandler implements IBinder.DeathRecipient {
1577 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07001578 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001579 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
1580
Eric Laurent9f103de2011-09-08 15:04:23 -07001581 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08001582 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07001583 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001584 }
1585
1586 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07001587 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001588 synchronized(mSetModeDeathHandlers) {
1589 Log.w(TAG, "setMode() client died");
1590 int index = mSetModeDeathHandlers.indexOf(this);
1591 if (index < 0) {
1592 Log.w(TAG, "unregistered setMode() client died");
1593 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07001594 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
Eric Laurent9272b4b2010-01-23 17:12:59 -08001595 }
1596 }
Eric Laurent9f103de2011-09-08 15:04:23 -07001597 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1598 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07001599 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07001600 final long ident = Binder.clearCallingIdentity();
1601 disconnectBluetoothSco(newModeOwnerPid);
1602 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07001603 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08001604 }
1605
Marco Nelissenf1ddd512011-08-10 14:15:44 -07001606 public int getPid() {
1607 return mPid;
1608 }
1609
Eric Laurent9272b4b2010-01-23 17:12:59 -08001610 public void setMode(int mode) {
1611 mMode = mode;
1612 }
1613
1614 public int getMode() {
1615 return mMode;
1616 }
1617
1618 public IBinder getBinder() {
1619 return mCb;
1620 }
1621 }
1622
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001623 /** @see AudioManager#setMode(int) */
Eric Laurent9272b4b2010-01-23 17:12:59 -08001624 public void setMode(int mode, IBinder cb) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001625 if (!checkAudioSettingsPermission("setMode()")) {
1626 return;
1627 }
Eric Laurenta553c252009-07-17 12:17:14 -07001628
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08001629 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07001630 return;
1631 }
1632
Eric Laurentd7454be2011-09-14 08:45:58 -07001633 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07001634 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07001635 if (mode == AudioSystem.MODE_CURRENT) {
1636 mode = mMode;
1637 }
Eric Laurentd7454be2011-09-14 08:45:58 -07001638 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
Eric Laurent9f103de2011-09-08 15:04:23 -07001639 }
1640 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1641 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07001642 if (newModeOwnerPid != 0) {
1643 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07001644 }
1645 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08001646
Eric Laurent9f103de2011-09-08 15:04:23 -07001647 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07001648 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07001649 // any mode other than NORMAL.
Eric Laurentd7454be2011-09-14 08:45:58 -07001650 int setModeInt(int mode, IBinder cb, int pid) {
1651 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07001652 if (cb == null) {
1653 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07001654 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07001655 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08001656
Eric Laurent9f103de2011-09-08 15:04:23 -07001657 SetModeDeathHandler hdlr = null;
1658 Iterator iter = mSetModeDeathHandlers.iterator();
1659 while (iter.hasNext()) {
1660 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
1661 if (h.getPid() == pid) {
1662 hdlr = h;
1663 // Remove from client list so that it is re-inserted at top of list
1664 iter.remove();
1665 hdlr.getBinder().unlinkToDeath(hdlr, 0);
1666 break;
1667 }
1668 }
1669 int status = AudioSystem.AUDIO_STATUS_OK;
1670 do {
1671 if (mode == AudioSystem.MODE_NORMAL) {
1672 // get new mode from client at top the list if any
1673 if (!mSetModeDeathHandlers.isEmpty()) {
1674 hdlr = mSetModeDeathHandlers.get(0);
1675 cb = hdlr.getBinder();
1676 mode = hdlr.getMode();
Eric Laurentb9c9d262009-05-06 08:13:20 -07001677 }
Eric Laurent9f103de2011-09-08 15:04:23 -07001678 } else {
1679 if (hdlr == null) {
1680 hdlr = new SetModeDeathHandler(cb, pid);
1681 }
1682 // Register for client death notification
1683 try {
1684 cb.linkToDeath(hdlr, 0);
1685 } catch (RemoteException e) {
1686 // Client has died!
1687 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
1688 }
1689
1690 // Last client to call setMode() is always at top of client list
1691 // as required by SetModeDeathHandler.binderDied()
1692 mSetModeDeathHandlers.add(0, hdlr);
1693 hdlr.setMode(mode);
1694 }
1695
1696 if (mode != mMode) {
1697 status = AudioSystem.setPhoneState(mode);
1698 if (status == AudioSystem.AUDIO_STATUS_OK) {
Eric Laurent9f103de2011-09-08 15:04:23 -07001699 mMode = mode;
1700 } else {
1701 if (hdlr != null) {
1702 mSetModeDeathHandlers.remove(hdlr);
1703 cb.unlinkToDeath(hdlr, 0);
1704 }
1705 // force reading new top of mSetModeDeathHandlers stack
1706 mode = AudioSystem.MODE_NORMAL;
1707 }
1708 } else {
1709 status = AudioSystem.AUDIO_STATUS_OK;
1710 }
1711 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
1712
1713 if (status == AudioSystem.AUDIO_STATUS_OK) {
1714 if (mode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07001715 if (mSetModeDeathHandlers.isEmpty()) {
1716 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
1717 } else {
1718 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
1719 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001720 }
1721 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07001722 if (streamType == STREAM_REMOTE_MUSIC) {
1723 // here handle remote media playback the same way as local playback
1724 streamType = AudioManager.STREAM_MUSIC;
1725 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001726 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001727 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
1728 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
Eric Laurent6d517662012-04-23 18:42:39 -07001729
1730 updateStreamVolumeAlias(true /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001731 }
Eric Laurentd7454be2011-09-14 08:45:58 -07001732 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001733 }
1734
1735 /** @see AudioManager#getMode() */
1736 public int getMode() {
1737 return mMode;
1738 }
1739
Eric Laurente78fced2013-03-15 16:03:47 -07001740 //==========================================================================================
1741 // Sound Effects
1742 //==========================================================================================
1743
1744 private static final String TAG_AUDIO_ASSETS = "audio_assets";
1745 private static final String ATTR_VERSION = "version";
1746 private static final String TAG_GROUP = "group";
1747 private static final String ATTR_GROUP_NAME = "name";
1748 private static final String TAG_ASSET = "asset";
1749 private static final String ATTR_ASSET_ID = "id";
1750 private static final String ATTR_ASSET_FILE = "file";
1751
1752 private static final String ASSET_FILE_VERSION = "1.0";
1753 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
1754
Glenn Kasten167d1a22013-07-23 16:24:41 -07001755 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001756
1757 class LoadSoundEffectReply {
1758 public int mStatus = 1;
1759 };
1760
Eric Laurente78fced2013-03-15 16:03:47 -07001761 private void loadTouchSoundAssetDefaults() {
1762 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
1763 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
1764 SOUND_EFFECT_FILES_MAP[i][0] = 0;
1765 SOUND_EFFECT_FILES_MAP[i][1] = -1;
1766 }
1767 }
1768
1769 private void loadTouchSoundAssets() {
1770 XmlResourceParser parser = null;
1771
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001772 // only load assets once.
1773 if (!SOUND_EFFECT_FILES.isEmpty()) {
1774 return;
1775 }
1776
Eric Laurente78fced2013-03-15 16:03:47 -07001777 loadTouchSoundAssetDefaults();
1778
1779 try {
1780 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
1781
1782 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
1783 String version = parser.getAttributeValue(null, ATTR_VERSION);
1784 boolean inTouchSoundsGroup = false;
1785
1786 if (ASSET_FILE_VERSION.equals(version)) {
1787 while (true) {
1788 XmlUtils.nextElement(parser);
1789 String element = parser.getName();
1790 if (element == null) {
1791 break;
1792 }
1793 if (element.equals(TAG_GROUP)) {
1794 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
1795 if (GROUP_TOUCH_SOUNDS.equals(name)) {
1796 inTouchSoundsGroup = true;
1797 break;
1798 }
1799 }
1800 }
1801 while (inTouchSoundsGroup) {
1802 XmlUtils.nextElement(parser);
1803 String element = parser.getName();
1804 if (element == null) {
1805 break;
1806 }
1807 if (element.equals(TAG_ASSET)) {
1808 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
1809 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
1810 int fx;
1811
1812 try {
1813 Field field = AudioManager.class.getField(id);
1814 fx = field.getInt(null);
1815 } catch (Exception e) {
1816 Log.w(TAG, "Invalid touch sound ID: "+id);
1817 continue;
1818 }
1819
1820 int i = SOUND_EFFECT_FILES.indexOf(file);
1821 if (i == -1) {
1822 i = SOUND_EFFECT_FILES.size();
1823 SOUND_EFFECT_FILES.add(file);
1824 }
1825 SOUND_EFFECT_FILES_MAP[fx][0] = i;
1826 } else {
1827 break;
1828 }
1829 }
1830 }
1831 } catch (Resources.NotFoundException e) {
1832 Log.w(TAG, "audio assets file not found", e);
1833 } catch (XmlPullParserException e) {
1834 Log.w(TAG, "XML parser exception reading touch sound assets", e);
1835 } catch (IOException e) {
1836 Log.w(TAG, "I/O exception reading touch sound assets", e);
1837 } finally {
1838 if (parser != null) {
1839 parser.close();
1840 }
1841 }
1842 }
1843
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001844 /** @see AudioManager#playSoundEffect(int) */
1845 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001846 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001847 }
1848
1849 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07001851 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
1852 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
1853 return;
1854 }
1855
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001856 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001857 effectType, (int) (volume * 1000), null, 0);
1858 }
1859
1860 /**
1861 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08001862 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001863 */
1864 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001865 int attempts = 3;
1866 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08001867
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001868 synchronized (reply) {
1869 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
1870 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08001871 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07001872 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001873 } catch (InterruptedException e) {
1874 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08001875 }
Eric Laurenta60e2122010-12-28 16:49:07 -08001876 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001877 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001878 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001879 }
1880
1881 /**
1882 * Unloads samples from the sound pool.
1883 * This method can be called to free some memory when
1884 * sound effects are disabled.
1885 */
1886 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001887 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001888 }
1889
Eric Laurenta60e2122010-12-28 16:49:07 -08001890 class SoundPoolListenerThread extends Thread {
1891 public SoundPoolListenerThread() {
1892 super("SoundPoolListenerThread");
1893 }
1894
1895 @Override
1896 public void run() {
1897
1898 Looper.prepare();
1899 mSoundPoolLooper = Looper.myLooper();
1900
1901 synchronized (mSoundEffectsLock) {
1902 if (mSoundPool != null) {
1903 mSoundPoolCallBack = new SoundPoolCallback();
1904 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
1905 }
1906 mSoundEffectsLock.notify();
1907 }
1908 Looper.loop();
1909 }
1910 }
1911
1912 private final class SoundPoolCallback implements
1913 android.media.SoundPool.OnLoadCompleteListener {
1914
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001915 int mStatus = 1; // 1 means neither error nor last sample loaded yet
1916 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08001917
1918 public int status() {
1919 return mStatus;
1920 }
1921
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001922 public void setSamples(int[] samples) {
1923 for (int i = 0; i < samples.length; i++) {
1924 // do not wait ack for samples rejected upfront by SoundPool
1925 if (samples[i] > 0) {
1926 mSamples.add(samples[i]);
1927 }
1928 }
Eric Laurenta60e2122010-12-28 16:49:07 -08001929 }
1930
1931 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
1932 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001933 int i = mSamples.indexOf(sampleId);
1934 if (i >= 0) {
1935 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08001936 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001937 if ((status != 0) || mSamples. isEmpty()) {
1938 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08001939 mSoundEffectsLock.notify();
1940 }
1941 }
1942 }
1943 }
1944
Eric Laurent4050c932009-07-08 02:52:14 -07001945 /** @see AudioManager#reloadAudioSettings() */
1946 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001947 readAudioSettings(false /*userSwitch*/);
1948 }
1949
1950 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07001951 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
1952 readPersistedSettings();
1953
1954 // restore volume settings
1955 int numStreamTypes = AudioSystem.getNumStreamTypes();
1956 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
1957 VolumeStreamState streamState = mStreamStates[streamType];
1958
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001959 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
1960 continue;
1961 }
1962
Eric Laurent3172d5e2012-05-09 11:38:16 -07001963 synchronized (streamState) {
1964 streamState.readSettings();
Eric Laurenta553c252009-07-17 12:17:14 -07001965
Eric Laurent3172d5e2012-05-09 11:38:16 -07001966 // unmute stream that was muted but is not affect by mute anymore
Eric Laurent42b041e2013-03-29 11:36:03 -07001967 if (streamState.isMuted() && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07001968 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07001969 int size = streamState.mDeathHandlers.size();
1970 for (int i = 0; i < size; i++) {
1971 streamState.mDeathHandlers.get(i).mMuteCount = 1;
1972 streamState.mDeathHandlers.get(i).mute(false);
1973 }
Eric Laurent4050c932009-07-08 02:52:14 -07001974 }
Eric Laurent4050c932009-07-08 02:52:14 -07001975 }
1976 }
1977
Eric Laurent33902db2012-10-07 16:15:07 -07001978 // apply new ringer mode before checking volume for alias streams so that streams
1979 // muted by ringer mode have the correct volume
1980 setRingerModeInt(getRingerMode(), false);
1981
Eric Laurent24482012012-05-10 09:41:17 -07001982 checkAllAliasStreamVolumes();
1983
Eric Laurentd640bd32012-09-28 18:01:48 -07001984 synchronized (mSafeMediaVolumeState) {
1985 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07001986 enforceSafeMediaVolume();
1987 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07001988 }
Eric Laurent4050c932009-07-08 02:52:14 -07001989 }
1990
Dianne Hackborn961cae92013-03-20 14:59:43 -07001991 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001992 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07001993 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
1994 return;
1995 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01001996
1997 if (on) {
1998 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
1999 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2000 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
2001 }
2002 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2003 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2004 mForcedUseForComm = AudioSystem.FORCE_NONE;
2005 }
Eric Laurentfa640152011-03-12 15:59:51 -08002006
Eric Laurentafbb0472011-12-15 09:04:23 -08002007 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002008 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002009 }
2010
2011 /** @see AudioManager#isSpeakerphoneOn() */
2012 public boolean isSpeakerphoneOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002013 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002014 }
2015
Dianne Hackborn961cae92013-03-20 14:59:43 -07002016 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002017 public void setBluetoothScoOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002018 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2019 return;
2020 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002021
2022 if (on) {
2023 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2024 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2025 mForcedUseForComm = AudioSystem.FORCE_NONE;
2026 }
Eric Laurentfa640152011-03-12 15:59:51 -08002027
Eric Laurentafbb0472011-12-15 09:04:23 -08002028 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002029 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08002030 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002031 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002032 }
2033
2034 /** @see AudioManager#isBluetoothScoOn() */
2035 public boolean isBluetoothScoOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002036 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002037 }
2038
Dianne Hackborn961cae92013-03-20 14:59:43 -07002039 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07002040 public void setBluetoothA2dpOn(boolean on) {
Eric Laurentc390bed2012-07-03 12:24:05 -07002041 synchronized (mBluetoothA2dpEnabledLock) {
2042 mBluetoothA2dpEnabled = on;
2043 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2044 AudioSystem.FOR_MEDIA,
2045 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2046 null, 0);
2047 }
Eric Laurent78472112012-05-21 08:57:21 -07002048 }
2049
2050 /** @see AudioManager#isBluetoothA2dpOn() */
2051 public boolean isBluetoothA2dpOn() {
2052 synchronized (mBluetoothA2dpEnabledLock) {
2053 return mBluetoothA2dpEnabled;
2054 }
2055 }
2056
Eric Laurent3def1ee2010-03-17 23:26:26 -07002057 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07002058 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
2059 int scoAudioMode =
2060 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
2061 SCO_MODE_VIRTUAL_CALL : SCO_MODE_RAW;
2062 startBluetoothScoInt(cb, scoAudioMode);
2063 }
2064
2065 /** @see AudioManager#startBluetoothScoVirtualCall() */
2066 public void startBluetoothScoVirtualCall(IBinder cb) {
2067 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
2068 }
2069
2070 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07002071 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002072 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002073 return;
2074 }
Eric Laurent854938a2011-02-22 12:05:20 -08002075 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002076 // The calling identity must be cleared before calling ScoClient.incCount().
2077 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2078 // and this must be done on behalf of system server to make sure permissions are granted.
2079 // The caller identity must be cleared after getScoClient() because it is needed if a new
2080 // client is created.
2081 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07002082 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08002083 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002084 }
2085
2086 /** @see AudioManager#stopBluetoothSco() */
2087 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07002088 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002089 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002090 return;
2091 }
Eric Laurent854938a2011-02-22 12:05:20 -08002092 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002093 // The calling identity must be cleared before calling ScoClient.decCount().
2094 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2095 // and this must be done on behalf of system server to make sure permissions are granted.
2096 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08002097 if (client != null) {
2098 client.decCount();
2099 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08002100 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002101 }
2102
Eric Laurent78472112012-05-21 08:57:21 -07002103
Eric Laurent3def1ee2010-03-17 23:26:26 -07002104 private class ScoClient implements IBinder.DeathRecipient {
2105 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002106 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002107 private int mStartcount; // number of SCO connections started by this client
2108
2109 ScoClient(IBinder cb) {
2110 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002111 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002112 mStartcount = 0;
2113 }
2114
2115 public void binderDied() {
2116 synchronized(mScoClients) {
2117 Log.w(TAG, "SCO client died");
2118 int index = mScoClients.indexOf(this);
2119 if (index < 0) {
2120 Log.w(TAG, "unregistered SCO client died");
2121 } else {
2122 clearCount(true);
2123 mScoClients.remove(this);
2124 }
2125 }
2126 }
2127
Eric Laurent83900752014-05-15 15:14:22 -07002128 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002129 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07002130 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002131 if (mStartcount == 0) {
2132 try {
2133 mCb.linkToDeath(this, 0);
2134 } catch (RemoteException e) {
2135 // client has already died!
2136 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
2137 }
2138 }
2139 mStartcount++;
2140 }
2141 }
2142
2143 public void decCount() {
2144 synchronized(mScoClients) {
2145 if (mStartcount == 0) {
2146 Log.w(TAG, "ScoClient.decCount() already 0");
2147 } else {
2148 mStartcount--;
2149 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002150 try {
2151 mCb.unlinkToDeath(this, 0);
2152 } catch (NoSuchElementException e) {
2153 Log.w(TAG, "decCount() going to 0 but not registered to binder");
2154 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002155 }
Eric Laurentc18c9132013-04-12 17:24:56 -07002156 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002157 }
2158 }
2159 }
2160
2161 public void clearCount(boolean stopSco) {
2162 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002163 if (mStartcount != 0) {
2164 try {
2165 mCb.unlinkToDeath(this, 0);
2166 } catch (NoSuchElementException e) {
2167 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2168 }
2169 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002170 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002171 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002172 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002173 }
2174 }
2175 }
2176
2177 public int getCount() {
2178 return mStartcount;
2179 }
2180
2181 public IBinder getBinder() {
2182 return mCb;
2183 }
2184
Eric Laurentd7454be2011-09-14 08:45:58 -07002185 public int getPid() {
2186 return mCreatorPid;
2187 }
2188
Eric Laurent3def1ee2010-03-17 23:26:26 -07002189 public int totalCount() {
2190 synchronized(mScoClients) {
2191 int count = 0;
2192 int size = mScoClients.size();
2193 for (int i = 0; i < size; i++) {
2194 count += mScoClients.get(i).getCount();
2195 }
2196 return count;
2197 }
2198 }
2199
Eric Laurent83900752014-05-15 15:14:22 -07002200 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08002201 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07002202 if (totalCount() == 0) {
2203 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2204 // Make sure that the state transitions to CONNECTING even if we cannot initiate
2205 // the connection.
2206 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2207 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002208 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07002209 synchronized(mSetModeDeathHandlers) {
2210 if ((mSetModeDeathHandlers.isEmpty() ||
2211 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2212 (mScoAudioState == SCO_STATE_INACTIVE ||
2213 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2214 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07002215 mScoAudioMode = scoAudioMode;
Eric Laurent9f103de2011-09-08 15:04:23 -07002216 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002217 boolean status;
2218 if (mScoAudioMode == SCO_MODE_RAW) {
2219 status = mBluetoothHeadset.connectAudio();
2220 } else {
2221 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2222 mBluetoothHeadsetDevice);
2223 }
2224 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07002225 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2226 } else {
2227 broadcastScoConnectionState(
2228 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2229 }
2230 } else if (getBluetoothHeadset()) {
2231 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07002232 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002233 } else {
2234 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2235 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002236 }
2237 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07002238 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002239 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002240 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002241 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002242 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2243 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2244 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07002245 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002246 boolean status;
2247 if (mScoAudioMode == SCO_MODE_RAW) {
2248 status = mBluetoothHeadset.disconnectAudio();
2249 } else {
2250 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2251 mBluetoothHeadsetDevice);
2252 }
2253 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002254 mScoAudioState = SCO_STATE_INACTIVE;
2255 broadcastScoConnectionState(
2256 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2257 }
2258 } else if (getBluetoothHeadset()) {
2259 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2260 }
2261 } else {
2262 mScoAudioState = SCO_STATE_INACTIVE;
2263 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2264 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002265 }
2266 }
2267 }
2268 }
2269
Eric Laurent62ef7672010-11-24 10:58:32 -08002270 private void checkScoAudioState() {
2271 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002272 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08002273 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2274 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2275 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2276 }
2277 }
2278
Eric Laurent854938a2011-02-22 12:05:20 -08002279 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002280 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002281 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002282 int size = mScoClients.size();
2283 for (int i = 0; i < size; i++) {
2284 client = mScoClients.get(i);
2285 if (client.getBinder() == cb)
2286 return client;
2287 }
Eric Laurent854938a2011-02-22 12:05:20 -08002288 if (create) {
2289 client = new ScoClient(cb);
2290 mScoClients.add(client);
2291 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002292 return client;
2293 }
2294 }
2295
Eric Laurentd7454be2011-09-14 08:45:58 -07002296 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002297 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002298 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002299 int size = mScoClients.size();
2300 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08002301 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07002302 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08002303 cl.clearCount(stopSco);
2304 } else {
2305 savedClient = cl;
2306 }
2307 }
2308 mScoClients.clear();
2309 if (savedClient != null) {
2310 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002311 }
2312 }
2313 }
2314
Eric Laurentdc03c612011-04-01 10:59:41 -07002315 private boolean getBluetoothHeadset() {
2316 boolean result = false;
2317 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2318 if (adapter != null) {
2319 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2320 BluetoothProfile.HEADSET);
2321 }
2322 // If we could not get a bluetooth headset proxy, send a failure message
2323 // without delay to reset the SCO audio state and clear SCO clients.
2324 // If we could get a proxy, send a delayed failure message that will reset our state
2325 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08002326 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002327 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2328 return result;
2329 }
2330
Eric Laurentd7454be2011-09-14 08:45:58 -07002331 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002332 synchronized(mScoClients) {
2333 checkScoAudioState();
2334 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2335 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2336 if (mBluetoothHeadsetDevice != null) {
2337 if (mBluetoothHeadset != null) {
2338 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07002339 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002340 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002341 SENDMSG_REPLACE, 0, 0, null, 0);
2342 }
2343 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2344 getBluetoothHeadset()) {
2345 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2346 }
2347 }
2348 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07002349 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07002350 }
2351 }
2352 }
2353
2354 private void resetBluetoothSco() {
2355 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002356 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07002357 mScoAudioState = SCO_STATE_INACTIVE;
2358 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2359 }
2360 }
2361
2362 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08002363 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
2364 SENDMSG_QUEUE, state, 0, null, 0);
2365 }
2366
2367 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002368 if (state != mScoConnectionState) {
2369 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2370 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2371 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2372 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002373 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07002374 mScoConnectionState = state;
2375 }
2376 }
2377
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002378 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
2379 new BluetoothProfile.ServiceListener() {
2380 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002381 BluetoothDevice btDevice;
2382 List<BluetoothDevice> deviceList;
2383 switch(profile) {
2384 case BluetoothProfile.A2DP:
John Du5a0cf7a2013-07-19 11:30:34 -07002385 synchronized (mA2dpAvrcpLock) {
2386 mA2dp = (BluetoothA2dp) proxy;
2387 deviceList = mA2dp.getConnectedDevices();
2388 if (deviceList.size() > 0) {
2389 btDevice = deviceList.get(0);
2390 synchronized (mConnectedDevices) {
2391 int state = mA2dp.getConnectionState(btDevice);
2392 int delay = checkSendBecomingNoisyIntent(
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002393 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2394 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
John Du5a0cf7a2013-07-19 11:30:34 -07002395 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002396 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07002397 state,
2398 0,
2399 btDevice,
2400 delay);
2401 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002402 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002403 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002404 break;
2405
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002406 case BluetoothProfile.A2DP_SINK:
2407 deviceList = proxy.getConnectedDevices();
2408 if (deviceList.size() > 0) {
2409 btDevice = deviceList.get(0);
2410 synchronized (mConnectedDevices) {
2411 int state = proxy.getConnectionState(btDevice);
2412 queueMsgUnderWakeLock(mAudioHandler,
2413 MSG_SET_A2DP_SRC_CONNECTION_STATE,
2414 state,
2415 0,
2416 btDevice,
2417 0 /* delay */);
2418 }
2419 }
2420 break;
2421
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002422 case BluetoothProfile.HEADSET:
2423 synchronized (mScoClients) {
2424 // Discard timeout message
2425 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
2426 mBluetoothHeadset = (BluetoothHeadset) proxy;
2427 deviceList = mBluetoothHeadset.getConnectedDevices();
2428 if (deviceList.size() > 0) {
2429 mBluetoothHeadsetDevice = deviceList.get(0);
2430 } else {
2431 mBluetoothHeadsetDevice = null;
2432 }
2433 // Refresh SCO audio state
2434 checkScoAudioState();
2435 // Continue pending action if any
2436 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
2437 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
2438 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2439 boolean status = false;
2440 if (mBluetoothHeadsetDevice != null) {
2441 switch (mScoAudioState) {
2442 case SCO_STATE_ACTIVATE_REQ:
2443 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07002444 if (mScoAudioMode == SCO_MODE_RAW) {
2445 status = mBluetoothHeadset.connectAudio();
2446 } else {
2447 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2448 mBluetoothHeadsetDevice);
2449 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002450 break;
2451 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07002452 if (mScoAudioMode == SCO_MODE_RAW) {
2453 status = mBluetoothHeadset.disconnectAudio();
2454 } else {
2455 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2456 mBluetoothHeadsetDevice);
2457 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002458 break;
2459 case SCO_STATE_DEACTIVATE_EXT_REQ:
2460 status = mBluetoothHeadset.stopVoiceRecognition(
2461 mBluetoothHeadsetDevice);
2462 }
2463 }
2464 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002465 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002466 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07002467 }
2468 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002469 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002470 break;
2471
2472 default:
2473 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002474 }
2475 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002476 public void onServiceDisconnected(int profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002477 switch(profile) {
2478 case BluetoothProfile.A2DP:
John Du5a0cf7a2013-07-19 11:30:34 -07002479 synchronized (mA2dpAvrcpLock) {
2480 mA2dp = null;
2481 synchronized (mConnectedDevices) {
2482 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
2483 makeA2dpDeviceUnavailableNow(
2484 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
2485 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002486 }
2487 }
2488 break;
2489
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002490 case BluetoothProfile.A2DP_SINK:
2491 synchronized (mConnectedDevices) {
2492 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) {
2493 makeA2dpSrcUnavailable(
2494 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP));
2495 }
2496 }
2497 break;
2498
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002499 case BluetoothProfile.HEADSET:
2500 synchronized (mScoClients) {
2501 mBluetoothHeadset = null;
2502 }
2503 break;
2504
2505 default:
2506 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002507 }
2508 }
2509 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08002510
Eric Laurentc34dcc12012-09-10 13:51:52 -07002511 private void onCheckMusicActive() {
Eric Laurentd640bd32012-09-28 18:01:48 -07002512 synchronized (mSafeMediaVolumeState) {
2513 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002514 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
2515
2516 if ((device & mSafeMediaVolumeDevices) != 0) {
2517 sendMsg(mAudioHandler,
2518 MSG_CHECK_MUSIC_ACTIVE,
2519 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07002520 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07002521 0,
2522 null,
2523 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07002524 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07002525 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
2526 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002527 // Approximate cumulative active music time
2528 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
2529 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
2530 setSafeMediaVolumeEnabled(true);
2531 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07002532 }
2533 }
2534 }
2535 }
2536 }
2537 }
2538
Eric Laurentd640bd32012-09-28 18:01:48 -07002539 private void onConfigureSafeVolume(boolean force) {
2540 synchronized (mSafeMediaVolumeState) {
2541 int mcc = mContext.getResources().getConfiguration().mcc;
2542 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
2543 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
2544 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
2545 boolean safeMediaVolumeEnabled = mContext.getResources().getBoolean(
2546 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08002547
2548 // The persisted state is either "disabled" or "active": this is the state applied
2549 // next time we boot and cannot be "inactive"
2550 int persistedState;
Eric Laurentd640bd32012-09-28 18:01:48 -07002551 if (safeMediaVolumeEnabled) {
Eric Laurent05274f32012-11-29 12:48:18 -08002552 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
2553 // The state can already be "inactive" here if the user has forced it before
2554 // the 30 seconds timeout for forced configuration. In this case we don't reset
2555 // it to "active".
2556 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
2557 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
2558 enforceSafeMediaVolume();
2559 }
Eric Laurentd640bd32012-09-28 18:01:48 -07002560 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08002561 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07002562 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
2563 }
2564 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08002565 sendMsg(mAudioHandler,
2566 MSG_PERSIST_SAFE_VOLUME_STATE,
2567 SENDMSG_QUEUE,
2568 persistedState,
2569 0,
2570 null,
2571 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07002572 }
2573 }
2574 }
2575
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002576 ///////////////////////////////////////////////////////////////////////////
2577 // Internal methods
2578 ///////////////////////////////////////////////////////////////////////////
2579
2580 /**
2581 * Checks if the adjustment should change ringer mode instead of just
2582 * adjusting volume. If so, this will set the proper ringer mode and volume
2583 * indices on the stream states.
2584 */
John Spurlocka11b4af2014-06-01 11:52:23 -04002585 private int checkForRingerModeChange(int oldIndex, int direction, int step) {
2586 int result = FLAG_ADJUST_VOLUME;
Glenn Kastenba195eb2011-12-13 09:30:40 -08002587 int ringerMode = getRingerMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002588
Eric Laurentbffc3d12012-05-07 17:43:49 -07002589 switch (ringerMode) {
2590 case RINGER_MODE_NORMAL:
2591 if (direction == AudioManager.ADJUST_LOWER) {
2592 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07002593 // "step" is the delta in internal index units corresponding to a
2594 // change of 1 in UI index units.
2595 // Because of rounding when rescaling from one stream index range to its alias
2596 // index range, we cannot simply test oldIndex == step:
2597 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
2598 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002599 ringerMode = RINGER_MODE_VIBRATE;
2600 }
2601 } else {
Eric Laurent24482012012-05-10 09:41:17 -07002602 // (oldIndex < step) is equivalent to (old UI index == 0)
John Spurlock86005342014-05-23 11:58:00 -04002603 if ((oldIndex < step)
2604 && VOLUME_SETS_RINGER_MODE_SILENT
2605 && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002606 ringerMode = RINGER_MODE_SILENT;
2607 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07002608 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002609 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07002610 break;
2611 case RINGER_MODE_VIBRATE:
2612 if (!mHasVibrator) {
2613 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
2614 "but no vibrator is present");
2615 break;
2616 }
Amith Yamasanic696a532011-10-28 17:02:37 -07002617 if ((direction == AudioManager.ADJUST_LOWER)) {
John Spurlock86005342014-05-23 11:58:00 -04002618 if (VOLUME_SETS_RINGER_MODE_SILENT
2619 && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002620 ringerMode = RINGER_MODE_SILENT;
Amith Yamasanic696a532011-10-28 17:02:37 -07002621 }
2622 } else if (direction == AudioManager.ADJUST_RAISE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002623 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07002624 }
John Spurlocka11b4af2014-06-01 11:52:23 -04002625 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07002626 break;
2627 case RINGER_MODE_SILENT:
Daniel Sandler6329bf72010-02-26 15:17:44 -05002628 if (direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04002629 if (PREVENT_VOLUME_ADJUSTMENT_IF_SILENT) {
2630 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07002631 } else {
John Spurlocka11b4af2014-06-01 11:52:23 -04002632 if (mHasVibrator) {
2633 ringerMode = RINGER_MODE_VIBRATE;
2634 } else {
2635 ringerMode = RINGER_MODE_NORMAL;
2636 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07002637 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05002638 }
John Spurlocka11b4af2014-06-01 11:52:23 -04002639 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07002640 break;
2641 default:
2642 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
2643 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002644 }
2645
Eric Laurentbffc3d12012-05-07 17:43:49 -07002646 setRingerMode(ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002647
Eric Laurent25101b02011-02-02 09:33:30 -08002648 mPrevVolDirection = direction;
2649
John Spurlocka11b4af2014-06-01 11:52:23 -04002650 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002651 }
2652
John Spurlock3346a802014-05-20 16:25:37 -04002653 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002654 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07002655 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002656 }
2657
Eric Laurent5b4e6542010-03-19 20:02:21 -07002658 private boolean isStreamMutedByRingerMode(int streamType) {
2659 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
2660 }
2661
Eric Laurent24e0d9b2013-10-03 18:15:07 -07002662 boolean updateRingerModeAffectedStreams() {
2663 int ringerModeAffectedStreams;
2664 // make sure settings for ringer mode are consistent with device type: non voice capable
2665 // devices (tablets) include media stream in silent mode whereas phones don't.
2666 ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
2667 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
2668 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
2669 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
2670 UserHandle.USER_CURRENT);
2671
2672 // ringtone, notification and system streams are always affected by ringer mode
2673 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
2674 (1 << AudioSystem.STREAM_NOTIFICATION)|
2675 (1 << AudioSystem.STREAM_SYSTEM);
2676
2677 if (mVoiceCapable) {
2678 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
2679 } else {
2680 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
2681 }
2682 synchronized (mCameraSoundForced) {
2683 if (mCameraSoundForced) {
2684 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
2685 } else {
2686 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
2687 }
2688 }
2689 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
2690 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
2691 } else {
2692 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
2693 }
2694
2695 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
2696 Settings.System.putIntForUser(mContentResolver,
2697 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
2698 ringerModeAffectedStreams,
2699 UserHandle.USER_CURRENT);
2700 mRingerModeAffectedStreams = ringerModeAffectedStreams;
2701 return true;
2702 }
2703 return false;
2704 }
2705
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002706 public boolean isStreamAffectedByMute(int streamType) {
2707 return (mMuteAffectedStreams & (1 << streamType)) != 0;
2708 }
2709
2710 private void ensureValidDirection(int direction) {
2711 if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
2712 throw new IllegalArgumentException("Bad direction " + direction);
2713 }
2714 }
2715
Lei Zhang6c798972012-03-02 11:40:12 -08002716 private void ensureValidSteps(int steps) {
2717 if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
2718 throw new IllegalArgumentException("Bad volume adjust steps " + steps);
2719 }
2720 }
2721
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002722 private void ensureValidStreamType(int streamType) {
2723 if (streamType < 0 || streamType >= mStreamStates.length) {
2724 throw new IllegalArgumentException("Bad stream type " + streamType);
2725 }
2726 }
2727
Eric Laurent6d517662012-04-23 18:42:39 -07002728 private boolean isInCommunication() {
2729 boolean isOffhook = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002730
Eric Laurent25101b02011-02-02 09:33:30 -08002731 if (mVoiceCapable) {
Eric Laurent25101b02011-02-02 09:33:30 -08002732 try {
2733 ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
2734 if (phone != null) isOffhook = phone.isOffhook();
2735 } catch (RemoteException e) {
2736 Log.w(TAG, "Couldn't connect to phone service", e);
2737 }
Eric Laurent6d517662012-04-23 18:42:39 -07002738 }
2739 return (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION);
2740 }
Eric Laurent25101b02011-02-02 09:33:30 -08002741
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002742 /**
2743 * For code clarity for getActiveStreamType(int)
2744 * @param delay_ms max time since last STREAM_MUSIC activity to consider
2745 * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
2746 * in the last "delay_ms" ms.
2747 */
2748 private boolean isAfMusicActiveRecently(int delay_ms) {
2749 return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
2750 || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
2751 }
2752
Eric Laurent6d517662012-04-23 18:42:39 -07002753 private int getActiveStreamType(int suggestedStreamType) {
2754 if (mVoiceCapable) {
2755 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08002756 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
2757 == AudioSystem.FORCE_BT_SCO) {
2758 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
2759 return AudioSystem.STREAM_BLUETOOTH_SCO;
2760 } else {
2761 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
2762 return AudioSystem.STREAM_VOICE_CALL;
2763 }
Eric Laurent25101b02011-02-02 09:33:30 -08002764 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002765 if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002766 if (DEBUG_VOL)
2767 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
2768 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002769 } else
2770 if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC))
2771 {
2772 if (DEBUG_VOL)
2773 Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
2774 return STREAM_REMOTE_MUSIC;
2775 } else {
2776 if (DEBUG_VOL)
2777 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
2778 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002779 }
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002780 } else if (isAfMusicActiveRecently(0)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002781 if (DEBUG_VOL)
2782 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
2783 return AudioSystem.STREAM_MUSIC;
Joe Onoratoc7fcba42011-01-05 16:53:11 -08002784 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002785 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
2786 + suggestedStreamType);
Eric Laurent25101b02011-02-02 09:33:30 -08002787 return suggestedStreamType;
2788 }
2789 } else {
Eric Laurent6d517662012-04-23 18:42:39 -07002790 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08002791 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
2792 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002793 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08002794 return AudioSystem.STREAM_BLUETOOTH_SCO;
2795 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002796 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08002797 return AudioSystem.STREAM_VOICE_CALL;
2798 }
2799 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
Eric Laurent9903e262012-09-21 18:10:32 -07002800 DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS) ||
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002801 AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
Eric Laurent9903e262012-09-21 18:10:32 -07002802 DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002803 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08002804 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002805 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002806 if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
2807 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
2808 return AudioSystem.STREAM_MUSIC;
2809 } else
2810 if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC))
2811 {
2812 if (DEBUG_VOL)
2813 Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
2814 return STREAM_REMOTE_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002815 } else {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002816 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default");
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002817 return AudioSystem.STREAM_MUSIC;
2818 }
Eric Laurent25101b02011-02-02 09:33:30 -08002819 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002820 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
2821 + suggestedStreamType);
Eric Laurent25101b02011-02-02 09:33:30 -08002822 return suggestedStreamType;
Joe Onoratoc7fcba42011-01-05 16:53:11 -08002823 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002824 }
2825 }
2826
Glenn Kastenba195eb2011-12-13 09:30:40 -08002827 private void broadcastRingerMode(int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002828 // Send sticky broadcast
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08002829 Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION);
Glenn Kastenba195eb2011-12-13 09:30:40 -08002830 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08002831 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
2832 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002833 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002834 }
2835
2836 private void broadcastVibrateSetting(int vibrateType) {
2837 // Send broadcast
2838 if (ActivityManagerNative.isSystemReady()) {
2839 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
2840 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
2841 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002842 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002843 }
2844 }
2845
2846 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07002847 /**
2848 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
2849 * Note that the wake lock needs to be released after the message has been handled.
2850 */
2851 private void queueMsgUnderWakeLock(Handler handler, int msg,
2852 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07002853 final long ident = Binder.clearCallingIdentity();
2854 // Always acquire the wake lock as AudioService because it is released by the
2855 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07002856 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07002857 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07002858 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
2859 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002860
Eric Laurentafbb0472011-12-15 09:04:23 -08002861 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002862 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002863
2864 if (existingMsgPolicy == SENDMSG_REPLACE) {
2865 handler.removeMessages(msg);
2866 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
2867 return;
2868 }
2869
Eric Laurentafbb0472011-12-15 09:04:23 -08002870 handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002871 }
2872
2873 boolean checkAudioSettingsPermission(String method) {
2874 if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS")
2875 == PackageManager.PERMISSION_GRANTED) {
2876 return true;
2877 }
2878 String msg = "Audio Settings Permission Denial: " + method + " from pid="
2879 + Binder.getCallingPid()
2880 + ", uid=" + Binder.getCallingUid();
2881 Log.w(TAG, msg);
2882 return false;
2883 }
2884
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002885 private int getDeviceForStream(int stream) {
2886 int device = AudioSystem.getDevicesForStream(stream);
2887 if ((device & (device - 1)) != 0) {
2888 // Multiple device selection is either:
2889 // - speaker + one other device: give priority to speaker in this case.
2890 // - one A2DP device + another device: happens with duplicated output. In this case
2891 // retain the device on the A2DP output as the other must not correspond to an active
2892 // selection if not the speaker.
2893 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
2894 device = AudioSystem.DEVICE_OUT_SPEAKER;
2895 } else {
2896 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
2897 }
2898 }
2899 return device;
2900 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002901
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002902 public void setWiredDeviceConnectionState(int device, int state, String name) {
2903 synchronized (mConnectedDevices) {
2904 int delay = checkSendBecomingNoisyIntent(device, state);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07002905 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002906 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002907 device,
2908 state,
2909 name,
2910 delay);
2911 }
2912 }
2913
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002914 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002915 {
2916 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002917 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
2918 throw new IllegalArgumentException("invalid profile " + profile);
2919 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002920 synchronized (mConnectedDevices) {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002921 if (profile == BluetoothProfile.A2DP) {
2922 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2923 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
2924 } else {
2925 delay = 0;
2926 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07002927 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002928 (profile == BluetoothProfile.A2DP ?
2929 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002930 state,
2931 0,
2932 device,
2933 delay);
2934 }
2935 return delay;
2936 }
2937
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002938 ///////////////////////////////////////////////////////////////////////////
2939 // Inner classes
2940 ///////////////////////////////////////////////////////////////////////////
2941
2942 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002943 private final int mStreamType;
2944
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07002945 private String mVolumeIndexSettingName;
Eric Laurenta553c252009-07-17 12:17:14 -07002946 private int mIndexMax;
Eric Laurent3172d5e2012-05-09 11:38:16 -07002947 private final ConcurrentHashMap<Integer, Integer> mIndex =
2948 new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002949 private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002950
Eric Laurenta553c252009-07-17 12:17:14 -07002951 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002952
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002953 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002954
2955 mStreamType = streamType;
Jared Suttles59820132009-08-13 21:50:52 -05002956 mIndexMax = MAX_STREAM_VOLUME[streamType];
Eric Laurenta553c252009-07-17 12:17:14 -07002957 AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
2958 mIndexMax *= 10;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002959
Eric Laurent33902db2012-10-07 16:15:07 -07002960 // mDeathHandlers must be created before calling readSettings()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002961 mDeathHandlers = new ArrayList<VolumeDeathHandler>();
Eric Laurent33902db2012-10-07 16:15:07 -07002962
2963 readSettings();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002964 }
2965
Eric Laurent42b041e2013-03-29 11:36:03 -07002966 public String getSettingNameForDevice(int device) {
2967 String name = mVolumeIndexSettingName;
Eric Laurent948d3272014-05-16 15:18:45 -07002968 String suffix = AudioSystem.getOutputDeviceName(device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002969 if (suffix.isEmpty()) {
2970 return name;
2971 }
2972 return name + "_" + suffix;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07002973 }
2974
Eric Laurentfdbee862014-05-12 15:26:12 -07002975 public void readSettings() {
2976 synchronized (VolumeStreamState.class) {
2977 // force maximum volume on all streams if fixed volume property is set
2978 if (mUseFixedVolume) {
2979 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
2980 return;
2981 }
2982 // do not read system stream volume from settings: this stream is always aliased
2983 // to another stream type and its volume is never persisted. Values in settings can
2984 // only be stale values
2985 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
2986 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
2987 int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
2988 synchronized (mCameraSoundForced) {
2989 if (mCameraSoundForced) {
2990 index = mIndexMax;
2991 }
Eric Laurentdd45d012012-10-08 09:04:34 -07002992 }
Eric Laurentfdbee862014-05-12 15:26:12 -07002993 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
2994 return;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002995 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002996
Eric Laurentfdbee862014-05-12 15:26:12 -07002997 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
2998
2999 for (int i = 0; remainingDevices != 0; i++) {
3000 int device = (1 << i);
3001 if ((device & remainingDevices) == 0) {
3002 continue;
3003 }
3004 remainingDevices &= ~device;
3005
3006 // retrieve current volume for device
3007 String name = getSettingNameForDevice(device);
3008 // if no volume stored for current stream and device, use default volume if default
3009 // device, continue otherwise
3010 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
3011 AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
3012 int index = Settings.System.getIntForUser(
3013 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3014 if (index == -1) {
3015 continue;
3016 }
3017
3018 // ignore settings for fixed volume devices: volume should always be at max or 0
3019 if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) &&
3020 ((device & mFixedVolumeDevices) != 0)) {
3021 mIndex.put(device, (index != 0) ? mIndexMax : 0);
3022 } else {
3023 mIndex.put(device, getValidIndex(10 * index));
3024 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003025 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003026 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003027 }
3028
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003029 public void applyDeviceVolume(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003030 int index;
3031 if (isMuted()) {
3032 index = 0;
Eric Laurentcd772d02013-10-30 18:31:07 -07003033 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003034 mAvrcpAbsVolSupported) {
3035 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07003036 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07003037 index = (getIndex(device) + 5)/10;
3038 }
3039 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003040 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003041
Eric Laurentfdbee862014-05-12 15:26:12 -07003042 public void applyAllVolumes() {
3043 synchronized (VolumeStreamState.class) {
3044 // apply default volume first: by convention this will reset all
3045 // devices volumes in audio policy manager to the supplied value
3046 int index;
3047 if (isMuted()) {
3048 index = 0;
3049 } else {
3050 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3051 }
3052 AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3053 // then apply device specific volumes
3054 Set set = mIndex.entrySet();
3055 Iterator i = set.iterator();
3056 while (i.hasNext()) {
3057 Map.Entry entry = (Map.Entry)i.next();
3058 int device = ((Integer)entry.getKey()).intValue();
3059 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
3060 if (isMuted()) {
3061 index = 0;
3062 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3063 mAvrcpAbsVolSupported) {
3064 index = (mIndexMax + 5)/10;
3065 } else {
3066 index = ((Integer)entry.getValue() + 5)/10;
3067 }
3068 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07003069 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003070 }
3071 }
3072 }
3073
3074 public boolean adjustIndex(int deltaIndex, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003075 return setIndex(getIndex(device) + deltaIndex,
3076 device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003077 }
3078
Eric Laurentfdbee862014-05-12 15:26:12 -07003079 public boolean setIndex(int index, int device) {
3080 synchronized (VolumeStreamState.class) {
3081 int oldIndex = getIndex(device);
3082 index = getValidIndex(index);
3083 synchronized (mCameraSoundForced) {
3084 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3085 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07003086 }
3087 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003088 mIndex.put(device, index);
3089
3090 if (oldIndex != index) {
3091 // Apply change to all streams using this one as alias
3092 // if changing volume of current device, also change volume of current
3093 // device on aliased stream
3094 boolean currentDevice = (device == getDeviceForStream(mStreamType));
3095 int numStreamTypes = AudioSystem.getNumStreamTypes();
3096 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3097 if (streamType != mStreamType &&
3098 mStreamVolumeAlias[streamType] == mStreamType) {
3099 int scaledIndex = rescaleIndex(index, mStreamType, streamType);
3100 mStreamStates[streamType].setIndex(scaledIndex,
3101 device);
3102 if (currentDevice) {
3103 mStreamStates[streamType].setIndex(scaledIndex,
3104 getDeviceForStream(streamType));
3105 }
3106 }
3107 }
3108 return true;
3109 } else {
3110 return false;
3111 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003112 }
3113 }
3114
Eric Laurentfdbee862014-05-12 15:26:12 -07003115 public int getIndex(int device) {
3116 synchronized (VolumeStreamState.class) {
3117 Integer index = mIndex.get(device);
3118 if (index == null) {
3119 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
3120 index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
3121 }
3122 return index.intValue();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003123 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07003124 }
3125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003126 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07003127 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003128 }
3129
Eric Laurentfdbee862014-05-12 15:26:12 -07003130 public void setAllIndexes(VolumeStreamState srcStream) {
3131 synchronized (VolumeStreamState.class) {
3132 int srcStreamType = srcStream.getStreamType();
3133 // apply default device volume from source stream to all devices first in case
3134 // some devices are present in this stream state but not in source stream state
3135 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003136 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurentfdbee862014-05-12 15:26:12 -07003137 Set set = mIndex.entrySet();
3138 Iterator i = set.iterator();
3139 while (i.hasNext()) {
3140 Map.Entry entry = (Map.Entry)i.next();
3141 entry.setValue(index);
3142 }
3143 // Now apply actual volume for devices in source stream state
3144 set = srcStream.mIndex.entrySet();
3145 i = set.iterator();
3146 while (i.hasNext()) {
3147 Map.Entry entry = (Map.Entry)i.next();
3148 int device = ((Integer)entry.getKey()).intValue();
3149 index = ((Integer)entry.getValue()).intValue();
3150 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07003151
Eric Laurentfdbee862014-05-12 15:26:12 -07003152 setIndex(index, device);
3153 }
Eric Laurent6d517662012-04-23 18:42:39 -07003154 }
3155 }
3156
Eric Laurentfdbee862014-05-12 15:26:12 -07003157 public void setAllIndexesToMax() {
3158 synchronized (VolumeStreamState.class) {
3159 Set set = mIndex.entrySet();
3160 Iterator i = set.iterator();
3161 while (i.hasNext()) {
3162 Map.Entry entry = (Map.Entry)i.next();
3163 entry.setValue(mIndexMax);
3164 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003165 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003166 }
3167
Eric Laurentfdbee862014-05-12 15:26:12 -07003168 public void mute(IBinder cb, boolean state) {
3169 synchronized (VolumeStreamState.class) {
3170 VolumeDeathHandler handler = getDeathHandler(cb, state);
3171 if (handler == null) {
3172 Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
3173 return;
3174 }
3175 handler.mute(state);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003176 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003177 }
3178
Eric Laurent6d517662012-04-23 18:42:39 -07003179 public int getStreamType() {
3180 return mStreamType;
3181 }
3182
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003183 private int getValidIndex(int index) {
3184 if (index < 0) {
3185 return 0;
Eric Laurent83a017b2013-03-19 18:15:31 -07003186 } else if (mUseFixedVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07003187 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003188 }
3189
3190 return index;
3191 }
3192
3193 private class VolumeDeathHandler implements IBinder.DeathRecipient {
3194 private IBinder mICallback; // To be notified of client's death
3195 private int mMuteCount; // Number of active mutes for this client
3196
3197 VolumeDeathHandler(IBinder cb) {
3198 mICallback = cb;
3199 }
3200
Eric Laurent3172d5e2012-05-09 11:38:16 -07003201 // must be called while synchronized on parent VolumeStreamState
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003202 public void mute(boolean state) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003203 boolean updateVolume = false;
Eric Laurent3172d5e2012-05-09 11:38:16 -07003204 if (state) {
3205 if (mMuteCount == 0) {
3206 // Register for client death notification
3207 try {
3208 // mICallback can be 0 if muted by AudioService
3209 if (mICallback != null) {
3210 mICallback.linkToDeath(this, 0);
3211 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003212 VolumeStreamState.this.mDeathHandlers.add(this);
Eric Laurent3172d5e2012-05-09 11:38:16 -07003213 // If the stream is not yet muted by any client, set level to 0
Eric Laurent42b041e2013-03-29 11:36:03 -07003214 if (!VolumeStreamState.this.isMuted()) {
3215 updateVolume = true;
Eric Laurent3172d5e2012-05-09 11:38:16 -07003216 }
3217 } catch (RemoteException e) {
3218 // Client has died!
3219 binderDied();
3220 return;
3221 }
3222 } else {
3223 Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
3224 }
3225 mMuteCount++;
3226 } else {
3227 if (mMuteCount == 0) {
3228 Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
3229 } else {
3230 mMuteCount--;
3231 if (mMuteCount == 0) {
3232 // Unregister from client death notification
Eric Laurent42b041e2013-03-29 11:36:03 -07003233 VolumeStreamState.this.mDeathHandlers.remove(this);
Eric Laurent3172d5e2012-05-09 11:38:16 -07003234 // mICallback can be 0 if muted by AudioService
3235 if (mICallback != null) {
3236 mICallback.unlinkToDeath(this, 0);
3237 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003238 if (!VolumeStreamState.this.isMuted()) {
3239 updateVolume = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003240 }
3241 }
3242 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003243 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003244 if (updateVolume) {
3245 sendMsg(mAudioHandler,
3246 MSG_SET_ALL_VOLUMES,
3247 SENDMSG_QUEUE,
3248 0,
3249 0,
3250 VolumeStreamState.this, 0);
3251 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003252 }
3253
3254 public void binderDied() {
3255 Log.w(TAG, "Volume service client died for stream: "+mStreamType);
3256 if (mMuteCount != 0) {
3257 // Reset all active mute requests from this client.
3258 mMuteCount = 1;
3259 mute(false);
3260 }
3261 }
3262 }
3263
Eric Laurent3172d5e2012-05-09 11:38:16 -07003264 private synchronized int muteCount() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003265 int count = 0;
3266 int size = mDeathHandlers.size();
3267 for (int i = 0; i < size; i++) {
3268 count += mDeathHandlers.get(i).mMuteCount;
3269 }
3270 return count;
3271 }
3272
Eric Laurent42b041e2013-03-29 11:36:03 -07003273 private synchronized boolean isMuted() {
3274 return muteCount() != 0;
3275 }
3276
Eric Laurent3172d5e2012-05-09 11:38:16 -07003277 // only called by mute() which is already synchronized
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003278 private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07003279 VolumeDeathHandler handler;
3280 int size = mDeathHandlers.size();
3281 for (int i = 0; i < size; i++) {
3282 handler = mDeathHandlers.get(i);
3283 if (cb == handler.mICallback) {
3284 return handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003285 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003286 }
Eric Laurent3172d5e2012-05-09 11:38:16 -07003287 // If this is the first mute request for this client, create a new
3288 // client death handler. Otherwise, it is an out of sequence unmute request.
3289 if (state) {
3290 handler = new VolumeDeathHandler(cb);
3291 } else {
3292 Log.w(TAG, "stream was not muted by this client");
3293 handler = null;
3294 }
3295 return handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003296 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003297
3298 private void dump(PrintWriter pw) {
Eric Laurentdd45d012012-10-08 09:04:34 -07003299 pw.print(" Mute count: ");
3300 pw.println(muteCount());
Eric Laurentbffc3d12012-05-07 17:43:49 -07003301 pw.print(" Current: ");
3302 Set set = mIndex.entrySet();
3303 Iterator i = set.iterator();
3304 while (i.hasNext()) {
3305 Map.Entry entry = (Map.Entry)i.next();
3306 pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue())
3307 + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", ");
3308 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003309 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003310 }
3311
3312 /** Thread that handles native AudioSystem control. */
3313 private class AudioSystemThread extends Thread {
3314 AudioSystemThread() {
3315 super("AudioService");
3316 }
3317
3318 @Override
3319 public void run() {
3320 // Set this thread up so the handler will work on it
3321 Looper.prepare();
3322
3323 synchronized(AudioService.this) {
3324 mAudioHandler = new AudioHandler();
3325
3326 // Notify that the handler has been created
3327 AudioService.this.notify();
3328 }
3329
3330 // Listen for volume change requests that are set by VolumePanel
3331 Looper.loop();
3332 }
3333 }
3334
3335 /** Handles internal volume messages in separate volume thread. */
3336 private class AudioHandler extends Handler {
3337
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003338 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003339
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003340 // Apply volume
3341 streamState.applyDeviceVolume(device);
Eric Laurenta553c252009-07-17 12:17:14 -07003342
3343 // Apply change to all streams using this one as alias
3344 int numStreamTypes = AudioSystem.getNumStreamTypes();
3345 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3346 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07003347 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurentcd772d02013-10-30 18:31:07 -07003348 // Make sure volume is also maxed out on A2DP device for aliased stream
3349 // that may have a different device selected
3350 int streamDevice = getDeviceForStream(streamType);
3351 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
3352 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
3353 mStreamStates[streamType].applyDeviceVolume(device);
3354 }
3355 mStreamStates[streamType].applyDeviceVolume(streamDevice);
Eric Laurenta553c252009-07-17 12:17:14 -07003356 }
3357 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003358
3359 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08003360 sendMsg(mAudioHandler,
3361 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08003362 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003363 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07003364 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08003365 streamState,
3366 PERSIST_DELAY);
3367
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003368 }
3369
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003370 private void setAllVolumes(VolumeStreamState streamState) {
3371
3372 // Apply volume
3373 streamState.applyAllVolumes();
3374
3375 // Apply change to all streams using this one as alias
3376 int numStreamTypes = AudioSystem.getNumStreamTypes();
3377 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3378 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07003379 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003380 mStreamStates[streamType].applyAllVolumes();
3381 }
3382 }
3383 }
3384
Eric Laurent42b041e2013-03-29 11:36:03 -07003385 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003386 if (mUseFixedVolume) {
3387 return;
3388 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003389 System.putIntForUser(mContentResolver,
3390 streamState.getSettingNameForDevice(device),
3391 (streamState.getIndex(device) + 5)/ 10,
3392 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003393 }
3394
Glenn Kastenba195eb2011-12-13 09:30:40 -08003395 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003396 if (mUseFixedVolume) {
3397 return;
3398 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07003399 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003400 }
3401
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003402 private boolean onLoadSoundEffects() {
3403 int status;
3404
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003405 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07003406 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003407 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
3408 return false;
3409 }
3410
3411 if (mSoundPool != null) {
3412 return true;
3413 }
3414
3415 loadTouchSoundAssets();
3416
3417 mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0);
3418 mSoundPoolCallBack = null;
3419 mSoundPoolListenerThread = new SoundPoolListenerThread();
3420 mSoundPoolListenerThread.start();
3421 int attempts = 3;
3422 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
3423 try {
3424 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07003425 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003426 } catch (InterruptedException e) {
3427 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
3428 }
3429 }
3430
3431 if (mSoundPoolCallBack == null) {
3432 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
3433 if (mSoundPoolLooper != null) {
3434 mSoundPoolLooper.quit();
3435 mSoundPoolLooper = null;
3436 }
3437 mSoundPoolListenerThread = null;
3438 mSoundPool.release();
3439 mSoundPool = null;
3440 return false;
3441 }
3442 /*
3443 * poolId table: The value -1 in this table indicates that corresponding
3444 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
3445 * Once loaded, the value in poolId is the sample ID and the same
3446 * sample can be reused for another effect using the same file.
3447 */
3448 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3449 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3450 poolId[fileIdx] = -1;
3451 }
3452 /*
3453 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
3454 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
3455 * this indicates we have a valid sample loaded for this effect.
3456 */
3457
3458 int numSamples = 0;
3459 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3460 // Do not load sample if this effect uses the MediaPlayer
3461 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
3462 continue;
3463 }
3464 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
3465 String filePath = Environment.getRootDirectory()
3466 + SOUND_EFFECTS_PATH
3467 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
3468 int sampleId = mSoundPool.load(filePath, 0);
3469 if (sampleId <= 0) {
3470 Log.w(TAG, "Soundpool could not load file: "+filePath);
3471 } else {
3472 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
3473 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
3474 numSamples++;
3475 }
3476 } else {
3477 SOUND_EFFECT_FILES_MAP[effect][1] =
3478 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
3479 }
3480 }
3481 // wait for all samples to be loaded
3482 if (numSamples > 0) {
3483 mSoundPoolCallBack.setSamples(poolId);
3484
3485 attempts = 3;
3486 status = 1;
3487 while ((status == 1) && (attempts-- > 0)) {
3488 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07003489 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003490 status = mSoundPoolCallBack.status();
3491 } catch (InterruptedException e) {
3492 Log.w(TAG, "Interrupted while waiting sound pool callback.");
3493 }
3494 }
3495 } else {
3496 status = -1;
3497 }
3498
3499 if (mSoundPoolLooper != null) {
3500 mSoundPoolLooper.quit();
3501 mSoundPoolLooper = null;
3502 }
3503 mSoundPoolListenerThread = null;
3504 if (status != 0) {
3505 Log.w(TAG,
3506 "onLoadSoundEffects(), Error "+status+ " while loading samples");
3507 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3508 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
3509 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3510 }
3511 }
3512
3513 mSoundPool.release();
3514 mSoundPool = null;
3515 }
3516 }
3517 return (status == 0);
3518 }
3519
3520 /**
3521 * Unloads samples from the sound pool.
3522 * This method can be called to free some memory when
3523 * sound effects are disabled.
3524 */
3525 private void onUnloadSoundEffects() {
3526 synchronized (mSoundEffectsLock) {
3527 if (mSoundPool == null) {
3528 return;
3529 }
3530
3531 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3532 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3533 poolId[fileIdx] = 0;
3534 }
3535
3536 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3537 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
3538 continue;
3539 }
3540 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
3541 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
3542 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3543 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
3544 }
3545 }
3546 mSoundPool.release();
3547 mSoundPool = null;
3548 }
3549 }
3550
3551 private void onPlaySoundEffect(int effectType, int volume) {
3552 synchronized (mSoundEffectsLock) {
3553
3554 onLoadSoundEffects();
3555
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003556 if (mSoundPool == null) {
3557 return;
3558 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003559 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08003560 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003561 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07003562 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003563 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07003564 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003565 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003566
3567 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003568 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
3569 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003570 } else {
3571 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003572 try {
Eric Laurente78fced2013-03-15 16:03:47 -07003573 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
3574 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003575 mediaPlayer.setDataSource(filePath);
3576 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
3577 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08003578 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003579 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
3580 public void onCompletion(MediaPlayer mp) {
3581 cleanupPlayer(mp);
3582 }
3583 });
3584 mediaPlayer.setOnErrorListener(new OnErrorListener() {
3585 public boolean onError(MediaPlayer mp, int what, int extra) {
3586 cleanupPlayer(mp);
3587 return true;
3588 }
3589 });
3590 mediaPlayer.start();
3591 } catch (IOException ex) {
3592 Log.w(TAG, "MediaPlayer IOException: "+ex);
3593 } catch (IllegalArgumentException ex) {
3594 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
3595 } catch (IllegalStateException ex) {
3596 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003597 }
3598 }
3599 }
3600 }
3601
3602 private void cleanupPlayer(MediaPlayer mp) {
3603 if (mp != null) {
3604 try {
3605 mp.stop();
3606 mp.release();
3607 } catch (IllegalStateException ex) {
3608 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
3609 }
3610 }
3611 }
3612
Eric Laurentfa640152011-03-12 15:59:51 -08003613 private void setForceUse(int usage, int config) {
3614 AudioSystem.setForceUse(usage, config);
3615 }
3616
Eric Laurent05274f32012-11-29 12:48:18 -08003617 private void onPersistSafeVolumeState(int state) {
3618 Settings.Global.putInt(mContentResolver,
3619 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
3620 state);
3621 }
3622
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003623 @Override
3624 public void handleMessage(Message msg) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003625
Eric Laurentafbb0472011-12-15 09:04:23 -08003626 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003627
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003628 case MSG_SET_DEVICE_VOLUME:
3629 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
3630 break;
3631
3632 case MSG_SET_ALL_VOLUMES:
3633 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003634 break;
3635
3636 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07003637 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003638 break;
3639
Mike Lockwood5c55a052011-12-15 17:21:44 -05003640 case MSG_PERSIST_MASTER_VOLUME:
Eric Laurent83a017b2013-03-19 18:15:31 -07003641 if (mUseFixedVolume) {
3642 return;
3643 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07003644 Settings.System.putFloatForUser(mContentResolver,
3645 Settings.System.VOLUME_MASTER,
RoboErik8a2cfc32014-05-16 11:19:38 -07003646 msg.arg1 / (float)1000.0,
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07003647 UserHandle.USER_CURRENT);
Mike Lockwood5c55a052011-12-15 17:21:44 -05003648 break;
3649
Justin Koh57978ed2012-04-03 17:37:58 -07003650 case MSG_PERSIST_MASTER_VOLUME_MUTE:
Eric Laurent83a017b2013-03-19 18:15:31 -07003651 if (mUseFixedVolume) {
3652 return;
3653 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07003654 Settings.System.putIntForUser(mContentResolver,
3655 Settings.System.VOLUME_MASTER_MUTE,
3656 msg.arg1,
3657 UserHandle.USER_CURRENT);
Justin Koh57978ed2012-04-03 17:37:58 -07003658 break;
3659
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003660 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08003661 // note that the value persisted is the current ringer mode, not the
3662 // value of ringer mode as of the time the request was made to persist
3663 persistRingerMode(getRingerMode());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003664 break;
3665
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003666 case MSG_MEDIA_SERVER_DIED:
Eric Laurentdfb881f2013-07-18 14:41:39 -07003667 if (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK) {
Eric Laurent89e74ba2009-09-30 18:26:36 -07003668 Log.e(TAG, "Media server died.");
Eric Laurentafbb0472011-12-15 09:04:23 -08003669 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent89e74ba2009-09-30 18:26:36 -07003670 null, 500);
Eric Laurentdfb881f2013-07-18 14:41:39 -07003671 break;
Eric Laurent89e74ba2009-09-30 18:26:36 -07003672 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003673 Log.e(TAG, "Media server started.");
Eric Laurentdfb881f2013-07-18 14:41:39 -07003674
Eric Laurent3c652ca2010-06-21 20:46:26 -07003675 // indicate to audio HAL that we start the reconfiguration phase after a media
3676 // server crash
Eric Laurentdfb881f2013-07-18 14:41:39 -07003677 // Note that we only execute this when the media server
Eric Laurent3c652ca2010-06-21 20:46:26 -07003678 // process restarts after a crash, not the first time it is started.
3679 AudioSystem.setParameters("restarting=true");
3680
Glenn Kastenfd116ad2013-07-12 17:10:39 -07003681 readAndSetLowRamDevice();
3682
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003683 // Restore device connection states
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003684 synchronized (mConnectedDevices) {
3685 Set set = mConnectedDevices.entrySet();
3686 Iterator i = set.iterator();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003687 while (i.hasNext()) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003688 Map.Entry device = (Map.Entry)i.next();
3689 AudioSystem.setDeviceConnectionState(
3690 ((Integer)device.getKey()).intValue(),
3691 AudioSystem.DEVICE_STATE_AVAILABLE,
3692 (String)device.getValue());
3693 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003694 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003695 // Restore call state
3696 AudioSystem.setPhoneState(mMode);
3697
Eric Laurentd5603c12009-08-06 08:49:39 -07003698 // Restore forced usage for communcations and record
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003699 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
Eric Laurentd5603c12009-08-06 08:49:39 -07003700 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
Eric Laurentdd45d012012-10-08 09:04:34 -07003701 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
3702 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003703
Eric Laurenta553c252009-07-17 12:17:14 -07003704 // Restore stream volumes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003705 int numStreamTypes = AudioSystem.getNumStreamTypes();
3706 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003707 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003708 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003709
3710 streamState.applyAllVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003711 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003712
3713 // Restore ringer mode
3714 setRingerModeInt(getRingerMode(), false);
Eric Laurent3c652ca2010-06-21 20:46:26 -07003715
Mike Lockwood90631542012-01-06 11:20:37 -05003716 // Restore master volume
3717 restoreMasterVolume();
3718
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07003719 // Reset device orientation (if monitored for this device)
Eric Laurentd640bd32012-09-28 18:01:48 -07003720 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07003721 setOrientationForAudioSystem();
3722 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07003723 if (mMonitorRotation) {
3724 setRotationForAudioSystem();
3725 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07003726
Eric Laurent78472112012-05-21 08:57:21 -07003727 synchronized (mBluetoothA2dpEnabledLock) {
3728 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
3729 mBluetoothA2dpEnabled ?
3730 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
3731 }
Eric Laurentbff5ca52012-11-02 16:48:26 -07003732
3733 synchronized (mSettingsLock) {
3734 AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
3735 mDockAudioMediaEnabled ?
3736 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
3737 }
3738
Eric Laurent3c652ca2010-06-21 20:46:26 -07003739 // indicate the end of reconfiguration phase to audio HAL
3740 AudioSystem.setParameters("restarting=false");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003741 break;
3742
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003743 case MSG_UNLOAD_SOUND_EFFECTS:
3744 onUnloadSoundEffects();
3745 break;
3746
Eric Laurent117b7bb2011-01-16 17:07:27 -08003747 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003748 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
3749 // can take several dozens of milliseconds to complete
3750 boolean loaded = onLoadSoundEffects();
3751 if (msg.obj != null) {
3752 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
3753 synchronized (reply) {
3754 reply.mStatus = loaded ? 0 : -1;
3755 reply.notify();
3756 }
3757 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08003758 break;
3759
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003760 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003761 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003762 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003763
3764 case MSG_BTA2DP_DOCK_TIMEOUT:
3765 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003766 synchronized (mConnectedDevices) {
3767 makeA2dpDeviceUnavailableNow( (String) msg.obj );
3768 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003769 break;
Eric Laurentfa640152011-03-12 15:59:51 -08003770
3771 case MSG_SET_FORCE_USE:
Eric Laurentc390bed2012-07-03 12:24:05 -07003772 case MSG_SET_FORCE_BT_A2DP_USE:
Eric Laurentfa640152011-03-12 15:59:51 -08003773 setForceUse(msg.arg1, msg.arg2);
3774 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07003775
Eric Laurentdc03c612011-04-01 10:59:41 -07003776 case MSG_BT_HEADSET_CNCT_FAILED:
3777 resetBluetoothSco();
3778 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003779
3780 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
3781 onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003782 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003783 break;
3784
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003785 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
3786 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
3787 mAudioEventWakeLock.release();
3788 break;
3789
3790 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
3791 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003792 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003793 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07003794
3795 case MSG_REPORT_NEW_ROUTES: {
3796 int N = mRoutesObservers.beginBroadcast();
3797 if (N > 0) {
3798 AudioRoutesInfo routes;
3799 synchronized (mCurAudioRoutes) {
3800 routes = new AudioRoutesInfo(mCurAudioRoutes);
3801 }
3802 while (N > 0) {
3803 N--;
3804 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
3805 try {
3806 obs.dispatchAudioRoutesChanged(routes);
3807 } catch (RemoteException e) {
3808 }
3809 }
3810 }
3811 mRoutesObservers.finishBroadcast();
3812 break;
3813 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003814
Eric Laurentc34dcc12012-09-10 13:51:52 -07003815 case MSG_CHECK_MUSIC_ACTIVE:
3816 onCheckMusicActive();
3817 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07003818
3819 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
3820 onSendBecomingNoisyIntent();
3821 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07003822
3823 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
3824 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
3825 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
3826 break;
Eric Laurent05274f32012-11-29 12:48:18 -08003827 case MSG_PERSIST_SAFE_VOLUME_STATE:
3828 onPersistSafeVolumeState(msg.arg1);
3829 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08003830
Eric Laurent2a57ca92013-03-07 17:29:27 -08003831 case MSG_BROADCAST_BT_CONNECTION_STATE:
3832 onBroadcastScoConnectionState(msg.arg1);
3833 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07003834
3835 case MSG_SYSTEM_READY:
3836 onSystemReady();
3837 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003838 }
3839 }
3840 }
3841
Jason Parekhb1096152009-03-24 17:48:25 -07003842 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07003843
Jason Parekhb1096152009-03-24 17:48:25 -07003844 SettingsObserver() {
3845 super(new Handler());
3846 mContentResolver.registerContentObserver(Settings.System.getUriFor(
3847 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07003848 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
3849 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07003850 }
3851
3852 @Override
3853 public void onChange(boolean selfChange) {
3854 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08003855 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
3856 // However there appear to be some missing locks around mRingerModeMutedStreams
3857 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
3858 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07003859 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003860 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07003861 /*
3862 * Ensure all stream types that should be affected by ringer mode
3863 * are in the proper state.
3864 */
Eric Laurenta553c252009-07-17 12:17:14 -07003865 setRingerModeInt(getRingerMode(), false);
3866 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07003867 readDockAudioSettings(mContentResolver);
Eric Laurenta553c252009-07-17 12:17:14 -07003868 }
Jason Parekhb1096152009-03-24 17:48:25 -07003869 }
Jason Parekhb1096152009-03-24 17:48:25 -07003870 }
Eric Laurenta553c252009-07-17 12:17:14 -07003871
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003872 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003873 private void makeA2dpDeviceAvailable(String address) {
Eric Laurent78472112012-05-21 08:57:21 -07003874 // enable A2DP before notifying A2DP connection to avoid unecessary processing in
3875 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003876 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
3877 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
3878 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Eric Laurent78472112012-05-21 08:57:21 -07003879 setBluetoothA2dpOnInt(true);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003880 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3881 AudioSystem.DEVICE_STATE_AVAILABLE,
3882 address);
3883 // Reset A2DP suspend state each time a new sink is connected
3884 AudioSystem.setParameters("A2dpSuspended=false");
3885 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
3886 address);
3887 }
3888
Eric Laurent5bfaeae2012-09-21 18:44:48 -07003889 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003890 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07003891 }
3892
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003893 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003894 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003895 synchronized (mA2dpAvrcpLock) {
3896 mAvrcpAbsVolSupported = false;
3897 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003898 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3899 AudioSystem.DEVICE_STATE_UNAVAILABLE,
3900 address);
3901 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
3902 }
3903
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003904 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003905 private void makeA2dpDeviceUnavailableLater(String address) {
Eric Laurent3b591262010-04-20 07:01:00 -07003906 // prevent any activity on the A2DP audio output to avoid unwanted
3907 // reconnection of the sink.
3908 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003909 // the device will be made unavailable later, so consider it disconnected right away
3910 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
3911 // send the delayed message to make the device unavailable later
3912 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
3913 mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
3914
3915 }
3916
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003917 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003918 private void makeA2dpSrcAvailable(String address) {
3919 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
3920 AudioSystem.DEVICE_STATE_AVAILABLE,
3921 address);
3922 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
3923 address);
3924 }
3925
3926 // must be called synchronized on mConnectedDevices
3927 private void makeA2dpSrcUnavailable(String address) {
3928 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
3929 AudioSystem.DEVICE_STATE_UNAVAILABLE,
3930 address);
3931 mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
3932 }
3933
3934 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07003935 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003936 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
3937 }
3938
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003939 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07003940 private boolean hasScheduledA2dpDockTimeout() {
3941 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
3942 }
3943
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003944 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003945 {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003946 if (DEBUG_VOL) {
3947 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
3948 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003949 if (btDevice == null) {
3950 return;
3951 }
3952 String address = btDevice.getAddress();
3953 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
3954 address = "";
3955 }
John Du5a0cf7a2013-07-19 11:30:34 -07003956
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003957 synchronized (mConnectedDevices) {
3958 boolean isConnected =
3959 (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
3960 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
3961
3962 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
3963 if (btDevice.isBluetoothDock()) {
3964 if (state == BluetoothProfile.STATE_DISCONNECTED) {
3965 // introduction of a delay for transient disconnections of docks when
3966 // power is rapidly turned off/on, this message will be canceled if
3967 // we reconnect the dock under a preset delay
3968 makeA2dpDeviceUnavailableLater(address);
3969 // the next time isConnected is evaluated, it will be false for the dock
3970 }
3971 } else {
3972 makeA2dpDeviceUnavailableNow(address);
3973 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07003974 synchronized (mCurAudioRoutes) {
3975 if (mCurAudioRoutes.mBluetoothName != null) {
3976 mCurAudioRoutes.mBluetoothName = null;
3977 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3978 SENDMSG_NOOP, 0, 0, null, 0);
3979 }
3980 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003981 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
3982 if (btDevice.isBluetoothDock()) {
3983 // this could be a reconnection after a transient disconnection
3984 cancelA2dpDeviceTimeout();
3985 mDockAddress = address;
3986 } else {
3987 // this could be a connection of another A2DP device before the timeout of
3988 // a dock: cancel the dock timeout, and make the dock unavailable now
3989 if(hasScheduledA2dpDockTimeout()) {
3990 cancelA2dpDeviceTimeout();
3991 makeA2dpDeviceUnavailableNow(mDockAddress);
3992 }
3993 }
3994 makeA2dpDeviceAvailable(address);
Dianne Hackborn632ca412012-06-14 19:34:10 -07003995 synchronized (mCurAudioRoutes) {
3996 String name = btDevice.getAliasName();
3997 if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
3998 mCurAudioRoutes.mBluetoothName = name;
3999 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4000 SENDMSG_NOOP, 0, 0, null, 0);
4001 }
4002 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004003 }
4004 }
4005 }
4006
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004007 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
4008 {
4009 if (DEBUG_VOL) {
4010 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
4011 }
4012 if (btDevice == null) {
4013 return;
4014 }
4015 String address = btDevice.getAddress();
4016 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4017 address = "";
4018 }
4019
4020 synchronized (mConnectedDevices) {
4021 boolean isConnected =
4022 (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
4023 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));
4024
4025 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4026 makeA2dpSrcUnavailable(address);
4027 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4028 makeA2dpSrcAvailable(address);
4029 }
4030 }
4031 }
4032
John Du5a0cf7a2013-07-19 11:30:34 -07004033 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
4034 // address is not used for now, but may be used when multiple a2dp devices are supported
4035 synchronized (mA2dpAvrcpLock) {
4036 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004037 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07004038 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4039 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4040 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4041 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4042 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07004043 }
4044 }
4045
Eric Laurent59f48272012-04-05 19:42:21 -07004046 private boolean handleDeviceConnection(boolean connected, int device, String params) {
4047 synchronized (mConnectedDevices) {
4048 boolean isConnected = (mConnectedDevices.containsKey(device) &&
Mike Lockwood98418182012-05-10 17:13:20 -07004049 (params.isEmpty() || mConnectedDevices.get(device).equals(params)));
Eric Laurent59f48272012-04-05 19:42:21 -07004050
4051 if (isConnected && !connected) {
4052 AudioSystem.setDeviceConnectionState(device,
4053 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Mike Lockwood98418182012-05-10 17:13:20 -07004054 mConnectedDevices.get(device));
Eric Laurent59f48272012-04-05 19:42:21 -07004055 mConnectedDevices.remove(device);
4056 return true;
4057 } else if (!isConnected && connected) {
4058 AudioSystem.setDeviceConnectionState(device,
4059 AudioSystem.DEVICE_STATE_AVAILABLE,
4060 params);
4061 mConnectedDevices.put(new Integer(device), params);
4062 return true;
4063 }
4064 }
4065 return false;
4066 }
4067
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004068 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4069 // sent if none of these devices is connected.
4070 int mBecomingNoisyIntentDevices =
4071 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07004072 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07004073 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
4074 AudioSystem.DEVICE_OUT_ALL_USB;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004075
4076 // must be called before removing the device from mConnectedDevices
4077 private int checkSendBecomingNoisyIntent(int device, int state) {
4078 int delay = 0;
4079 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4080 int devices = 0;
4081 for (int dev : mConnectedDevices.keySet()) {
4082 if ((dev & mBecomingNoisyIntentDevices) != 0) {
4083 devices |= dev;
4084 }
4085 }
4086 if (devices == device) {
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004087 sendMsg(mAudioHandler,
4088 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4089 SENDMSG_REPLACE,
4090 0,
4091 0,
4092 null,
4093 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004094 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004095 }
4096 }
4097
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004098 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
4099 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004100 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
4101 delay = 1000;
4102 }
4103 return delay;
4104 }
4105
4106 private void sendDeviceConnectionIntent(int device, int state, String name)
4107 {
4108 Intent intent = new Intent();
4109
4110 intent.putExtra("state", state);
4111 intent.putExtra("name", name);
4112 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4113
Dianne Hackborn632ca412012-06-14 19:34:10 -07004114 int connType = 0;
4115
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004116 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004117 connType = AudioRoutesInfo.MAIN_HEADSET;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004118 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4119 intent.putExtra("microphone", 1);
4120 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004121 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004122 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4123 intent.putExtra("microphone", 0);
4124 } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004125 connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004126 intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
4127 } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004128 connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004129 intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
Eric Laurent948d3272014-05-16 15:18:45 -07004130 } else if (device == AudioSystem.DEVICE_OUT_HDMI) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004131 connType = AudioRoutesInfo.MAIN_HDMI;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004132 intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);
4133 }
4134
Dianne Hackborn632ca412012-06-14 19:34:10 -07004135 synchronized (mCurAudioRoutes) {
4136 if (connType != 0) {
4137 int newConn = mCurAudioRoutes.mMainType;
4138 if (state != 0) {
4139 newConn |= connType;
4140 } else {
4141 newConn &= ~connType;
4142 }
4143 if (newConn != mCurAudioRoutes.mMainType) {
4144 mCurAudioRoutes.mMainType = newConn;
4145 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4146 SENDMSG_NOOP, 0, 0, null, 0);
4147 }
4148 }
4149 }
4150
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004151 final long ident = Binder.clearCallingIdentity();
4152 try {
4153 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
4154 } finally {
4155 Binder.restoreCallingIdentity(ident);
4156 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004157 }
4158
4159 private void onSetWiredDeviceConnectionState(int device, int state, String name)
4160 {
4161 synchronized (mConnectedDevices) {
4162 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
4163 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) {
4164 setBluetoothA2dpOnInt(true);
4165 }
Eric Laurentae4506e2014-05-29 16:04:32 -07004166 boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
4167 (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
4168 ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
Mike Lockwooddb454842012-09-18 11:16:57 -07004169 handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
Eric Laurentf1a457d2012-09-20 16:27:23 -07004170 if (state != 0) {
4171 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
4172 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE)) {
4173 setBluetoothA2dpOnInt(false);
4174 }
4175 if ((device & mSafeMediaVolumeDevices) != 0) {
4176 sendMsg(mAudioHandler,
4177 MSG_CHECK_MUSIC_ACTIVE,
4178 SENDMSG_REPLACE,
4179 0,
4180 0,
4181 null,
4182 MUSIC_ACTIVE_POLL_PERIOD_MS);
4183 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004184 }
Eric Laurentae4506e2014-05-29 16:04:32 -07004185 if (!isUsb && (device != AudioSystem.DEVICE_IN_WIRED_HEADSET)) {
Mike Lockwooddb454842012-09-18 11:16:57 -07004186 sendDeviceConnectionIntent(device, state, name);
4187 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004188 }
4189 }
4190
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004191 /* cache of the address of the last dock the device was connected to */
4192 private String mDockAddress;
4193
Eric Laurenta553c252009-07-17 12:17:14 -07004194 /**
4195 * Receiver for misc intent broadcasts the Phone app cares about.
4196 */
4197 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4198 @Override
4199 public void onReceive(Context context, Intent intent) {
4200 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07004201 int outDevice;
4202 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07004203 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07004204
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004205 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4206 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4207 Intent.EXTRA_DOCK_STATE_UNDOCKED);
4208 int config;
4209 switch (dockState) {
4210 case Intent.EXTRA_DOCK_STATE_DESK:
4211 config = AudioSystem.FORCE_BT_DESK_DOCK;
4212 break;
4213 case Intent.EXTRA_DOCK_STATE_CAR:
4214 config = AudioSystem.FORCE_BT_CAR_DOCK;
4215 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004216 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08004217 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004218 break;
4219 case Intent.EXTRA_DOCK_STATE_HE_DESK:
4220 config = AudioSystem.FORCE_DIGITAL_DOCK;
4221 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004222 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4223 default:
4224 config = AudioSystem.FORCE_NONE;
4225 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08004226 // Low end docks have a menu to enable or disable audio
4227 // (see mDockAudioMediaEnabled)
4228 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
4229 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
4230 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
4231 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
4232 }
4233 mDockState = dockState;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004234 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
Eric Laurent59f48272012-04-05 19:42:21 -07004235 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004236 BluetoothProfile.STATE_DISCONNECTED);
Eric Laurentae4506e2014-05-29 16:04:32 -07004237 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
4238 inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
Nick Pellya56d1c72009-08-19 14:49:29 -07004239 String address = null;
Eric Laurentdca56b92011-09-02 14:20:56 -07004240
4241 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
4242 if (btDevice == null) {
4243 return;
4244 }
4245
4246 address = btDevice.getAddress();
4247 BluetoothClass btClass = btDevice.getBluetoothClass();
4248 if (btClass != null) {
4249 switch (btClass.getDeviceClass()) {
4250 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
4251 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
Eric Laurentae4506e2014-05-29 16:04:32 -07004252 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurentdca56b92011-09-02 14:20:56 -07004253 break;
4254 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
Eric Laurentae4506e2014-05-29 16:04:32 -07004255 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurentdca56b92011-09-02 14:20:56 -07004256 break;
Eric Laurentd5603c12009-08-06 08:49:39 -07004257 }
4258 }
4259
Eric Laurentdca56b92011-09-02 14:20:56 -07004260 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4261 address = "";
4262 }
Eric Laurentd5603c12009-08-06 08:49:39 -07004263
Eric Laurent59f48272012-04-05 19:42:21 -07004264 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
Eric Laurentae4506e2014-05-29 16:04:32 -07004265 boolean success = handleDeviceConnection(connected, outDevice, address) &&
4266 handleDeviceConnection(connected, inDevice, address);
4267 if (success) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004268 synchronized (mScoClients) {
Eric Laurent59f48272012-04-05 19:42:21 -07004269 if (connected) {
4270 mBluetoothHeadsetDevice = btDevice;
4271 } else {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004272 mBluetoothHeadsetDevice = null;
4273 resetBluetoothSco();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004274 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004275 }
Eric Laurenta553c252009-07-17 12:17:14 -07004276 }
Paul McLeandf361462014-04-10 16:02:55 -07004277 } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG)) {
4278 state = intent.getIntExtra("state", 0);
4279
4280 int alsaCard = intent.getIntExtra("card", -1);
4281 int alsaDevice = intent.getIntExtra("device", -1);
4282
4283 String params = (alsaCard == -1 && alsaDevice == -1 ? ""
4284 : "card=" + alsaCard + ";device=" + alsaDevice);
4285
4286 // Playback Device
Eric Laurentae4506e2014-05-29 16:04:32 -07004287 outDevice = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
4288 setWiredDeviceConnectionState(outDevice, state, params);
Paul McLeandf361462014-04-10 16:02:55 -07004289 } else if (action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
Eric Laurent59f48272012-04-05 19:42:21 -07004290 state = intent.getIntExtra("state", 0);
Paul McLeanc837a452014-04-09 09:04:43 -07004291
Eric Laurent59f48272012-04-05 19:42:21 -07004292 int alsaCard = intent.getIntExtra("card", -1);
4293 int alsaDevice = intent.getIntExtra("device", -1);
Paul McLeanc837a452014-04-09 09:04:43 -07004294 boolean hasPlayback = intent.getBooleanExtra("hasPlayback", false);
4295 boolean hasCapture = intent.getBooleanExtra("hasCapture", false);
4296 boolean hasMIDI = intent.getBooleanExtra("hasMIDI", false);
4297
Mike Lockwood98418182012-05-10 17:13:20 -07004298 String params = (alsaCard == -1 && alsaDevice == -1 ? ""
4299 : "card=" + alsaCard + ";device=" + alsaDevice);
Paul McLeanc837a452014-04-09 09:04:43 -07004300
Paul McLeanc837a452014-04-09 09:04:43 -07004301 // Playback Device
Paul McLeandf361462014-04-10 16:02:55 -07004302 if (hasPlayback) {
Eric Laurentae4506e2014-05-29 16:04:32 -07004303 outDevice = AudioSystem.DEVICE_OUT_USB_DEVICE;
4304 setWiredDeviceConnectionState(outDevice, state, params);
Paul McLeandf361462014-04-10 16:02:55 -07004305 }
Paul McLeanc837a452014-04-09 09:04:43 -07004306
4307 // Capture Device
Paul McLeandf361462014-04-10 16:02:55 -07004308 if (hasCapture) {
Eric Laurentae4506e2014-05-29 16:04:32 -07004309 inDevice = AudioSystem.DEVICE_IN_USB_DEVICE;
4310 setWiredDeviceConnectionState(inDevice, state, params);
Paul McLeandf361462014-04-10 16:02:55 -07004311 }
4312 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004313 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07004314 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004315 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004316 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07004317 // broadcast intent if the connection was initated by AudioService
4318 if (!mScoClients.isEmpty() &&
4319 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
4320 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
4321 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004322 broadcast = true;
4323 }
4324 switch (btState) {
4325 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004326 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07004327 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4328 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4329 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004330 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004331 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004332 break;
4333 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004334 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08004335 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07004336 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08004337 break;
4338 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07004339 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4340 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4341 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004342 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004343 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004344 default:
4345 // do not broadcast CONNECTING or invalid state
4346 broadcast = false;
4347 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004348 }
4349 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004350 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07004351 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07004352 //FIXME: this is to maintain compatibility with deprecated intent
4353 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08004354 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07004355 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004356 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08004357 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004358 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
4359 AudioSystem.setParameters("screen_state=on");
4360 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
4361 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07004362 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004363 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004364 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004365 // attempt to stop music playback for background user
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004366 sendMsg(mAudioHandler,
4367 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4368 SENDMSG_REPLACE,
4369 0,
4370 0,
4371 null,
4372 0);
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004373 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004374 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004375
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004376 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004377 readAudioSettings(true /*userSwitch*/);
4378 // preserve STREAM_MUSIC volume from one user to the next.
4379 sendMsg(mAudioHandler,
4380 MSG_SET_ALL_VOLUMES,
4381 SENDMSG_QUEUE,
4382 0,
4383 0,
4384 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Eric Laurenta553c252009-07-17 12:17:14 -07004385 }
4386 }
Paul McLeanc837a452014-04-09 09:04:43 -07004387 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004388
4389 //==========================================================================================
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004390 // RemoteControlDisplay / RemoteControlClient / Remote info
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004391 //==========================================================================================
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004392 public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
4393 ComponentName listenerComp) {
4394 return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
4395 }
4396
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004397 public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004398 return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004399 }
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004400
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004401 public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004402 mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004403 }
4404
4405 public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004406 mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004407 }
4408
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07004409 public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
4410 boolean wantsSync) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004411 mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
4412 }
4413
John Spurlock3346a802014-05-20 16:25:37 -04004414 @Override
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004415 public void setRemoteStreamVolume(int index) {
John Spurlock3346a802014-05-20 16:25:37 -04004416 enforceSelfOrSystemUI("set the remote stream volume");
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004417 mMediaFocusControl.setRemoteStreamVolume(index);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004418 }
4419
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004420 //==========================================================================================
4421 // Audio Focus
4422 //==========================================================================================
4423 public int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb,
4424 IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
4425 return mMediaFocusControl.requestAudioFocus(mainStreamType, durationHint, cb, fd,
4426 clientId, callingPackageName);
4427 }
4428
4429 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId) {
4430 return mMediaFocusControl.abandonAudioFocus(fd, clientId);
4431 }
4432
4433 public void unregisterAudioFocusClient(String clientId) {
4434 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004435 }
4436
Jean-Michel Trivi23805662013-07-31 14:19:18 -07004437 public int getCurrentAudioFocus() {
4438 return mMediaFocusControl.getCurrentAudioFocus();
4439 }
4440
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004441 //==========================================================================================
4442 // Device orientation
4443 //==========================================================================================
4444 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004445 * Handles device configuration changes that may map to a change in the orientation
4446 * or orientation.
4447 * Monitoring orientation and rotation is optional, and is defined by the definition and value
4448 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004449 */
4450 private void handleConfigurationChanged(Context context) {
4451 try {
4452 // reading new orientation "safely" (i.e. under try catch) in case anything
4453 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07004454 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004455 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07004456 if (mMonitorOrientation) {
4457 int newOrientation = config.orientation;
4458 if (newOrientation != mDeviceOrientation) {
4459 mDeviceOrientation = newOrientation;
4460 setOrientationForAudioSystem();
4461 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004462 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004463 if (mMonitorRotation) {
4464 int newRotation = ((WindowManager) context.getSystemService(
4465 Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
4466 if (newRotation != mDeviceRotation) {
4467 mDeviceRotation = newRotation;
4468 setRotationForAudioSystem();
4469 }
4470 }
Eric Laurentd640bd32012-09-28 18:01:48 -07004471 sendMsg(mAudioHandler,
4472 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
4473 SENDMSG_REPLACE,
4474 0,
4475 0,
4476 null,
4477 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07004478
4479 boolean cameraSoundForced = mContext.getResources().getBoolean(
4480 com.android.internal.R.bool.config_camera_sound_forced);
4481 synchronized (mSettingsLock) {
4482 synchronized (mCameraSoundForced) {
4483 if (cameraSoundForced != mCameraSoundForced) {
4484 mCameraSoundForced = cameraSoundForced;
4485
4486 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
4487 if (cameraSoundForced) {
4488 s.setAllIndexesToMax();
4489 mRingerModeAffectedStreams &=
4490 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4491 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07004492 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
Eric Laurentdd45d012012-10-08 09:04:34 -07004493 mRingerModeAffectedStreams |=
4494 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4495 }
4496 // take new state into account for streams muted by ringer mode
4497 setRingerModeInt(getRingerMode(), false);
4498
4499 sendMsg(mAudioHandler,
4500 MSG_SET_FORCE_USE,
4501 SENDMSG_QUEUE,
4502 AudioSystem.FOR_SYSTEM,
4503 cameraSoundForced ?
4504 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
4505 null,
4506 0);
4507
4508 sendMsg(mAudioHandler,
4509 MSG_SET_ALL_VOLUMES,
4510 SENDMSG_QUEUE,
4511 0,
4512 0,
4513 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
4514 }
4515 }
4516 }
John Spurlock3346a802014-05-20 16:25:37 -04004517 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004518 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004519 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004520 }
4521 }
4522
4523 private void setOrientationForAudioSystem() {
4524 switch (mDeviceOrientation) {
4525 case Configuration.ORIENTATION_LANDSCAPE:
4526 //Log.i(TAG, "orientation is landscape");
4527 AudioSystem.setParameters("orientation=landscape");
4528 break;
4529 case Configuration.ORIENTATION_PORTRAIT:
4530 //Log.i(TAG, "orientation is portrait");
4531 AudioSystem.setParameters("orientation=portrait");
4532 break;
4533 case Configuration.ORIENTATION_SQUARE:
4534 //Log.i(TAG, "orientation is square");
4535 AudioSystem.setParameters("orientation=square");
4536 break;
4537 case Configuration.ORIENTATION_UNDEFINED:
4538 //Log.i(TAG, "orientation is undefined");
4539 AudioSystem.setParameters("orientation=undefined");
4540 break;
4541 default:
4542 Log.e(TAG, "Unknown orientation");
4543 }
4544 }
4545
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004546 private void setRotationForAudioSystem() {
4547 switch (mDeviceRotation) {
4548 case Surface.ROTATION_0:
4549 AudioSystem.setParameters("rotation=0");
4550 break;
4551 case Surface.ROTATION_90:
4552 AudioSystem.setParameters("rotation=90");
4553 break;
4554 case Surface.ROTATION_180:
4555 AudioSystem.setParameters("rotation=180");
4556 break;
4557 case Surface.ROTATION_270:
4558 AudioSystem.setParameters("rotation=270");
4559 break;
4560 default:
4561 Log.e(TAG, "Unknown device rotation");
4562 }
4563 }
4564
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004565
Eric Laurent78472112012-05-21 08:57:21 -07004566 // Handles request to override default use of A2DP for media.
4567 public void setBluetoothA2dpOnInt(boolean on) {
4568 synchronized (mBluetoothA2dpEnabledLock) {
4569 mBluetoothA2dpEnabled = on;
Eric Laurentc390bed2012-07-03 12:24:05 -07004570 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
4571 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
4572 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
Eric Laurent78472112012-05-21 08:57:21 -07004573 }
4574 }
4575
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004576 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07004577 public void setRingtonePlayer(IRingtonePlayer player) {
4578 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
4579 mRingtonePlayer = player;
4580 }
4581
4582 @Override
4583 public IRingtonePlayer getRingtonePlayer() {
4584 return mRingtonePlayer;
4585 }
4586
4587 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07004588 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
4589 synchronized (mCurAudioRoutes) {
4590 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
4591 mRoutesObservers.register(observer);
4592 return routes;
4593 }
4594 }
4595
Eric Laurentc34dcc12012-09-10 13:51:52 -07004596
4597 //==========================================================================================
4598 // Safe media volume management.
4599 // MUSIC stream volume level is limited when headphones are connected according to safety
4600 // regulation. When the user attempts to raise the volume above the limit, a warning is
4601 // displayed and the user has to acknowlegde before the volume is actually changed.
4602 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
4603 // property. Platforms with a different limit must set this property accordingly in their
4604 // overlay.
4605 //==========================================================================================
4606
Eric Laurentd640bd32012-09-28 18:01:48 -07004607 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
4608 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
4609 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
4610 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
4611 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
4612 // (when user opts out).
4613 private final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
4614 private final int SAFE_MEDIA_VOLUME_DISABLED = 1;
4615 private final int SAFE_MEDIA_VOLUME_INACTIVE = 2;
4616 private final int SAFE_MEDIA_VOLUME_ACTIVE = 3;
4617 private Integer mSafeMediaVolumeState;
4618
4619 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07004620 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07004621 private int mSafeMediaVolumeIndex;
Eric Laurentc34dcc12012-09-10 13:51:52 -07004622 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
4623 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
4624 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
4625 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
4626 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
4627 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
4628 private int mMusicActiveMs;
4629 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
4630 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07004631 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07004632
4633 private void setSafeMediaVolumeEnabled(boolean on) {
Eric Laurentd640bd32012-09-28 18:01:48 -07004634 synchronized (mSafeMediaVolumeState) {
4635 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
4636 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
4637 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
4638 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
4639 enforceSafeMediaVolume();
4640 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
4641 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
4642 mMusicActiveMs = 0;
4643 sendMsg(mAudioHandler,
4644 MSG_CHECK_MUSIC_ACTIVE,
4645 SENDMSG_REPLACE,
4646 0,
4647 0,
4648 null,
4649 MUSIC_ACTIVE_POLL_PERIOD_MS);
4650 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07004651 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07004652 }
4653 }
4654
4655 private void enforceSafeMediaVolume() {
4656 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07004657 int devices = mSafeMediaVolumeDevices;
4658 int i = 0;
4659
4660 while (devices != 0) {
4661 int device = 1 << i++;
4662 if ((device & devices) == 0) {
4663 continue;
4664 }
Eric Laurent42b041e2013-03-29 11:36:03 -07004665 int index = streamState.getIndex(device);
Eric Laurentc34dcc12012-09-10 13:51:52 -07004666 if (index > mSafeMediaVolumeIndex) {
Eric Laurent42b041e2013-03-29 11:36:03 -07004667 streamState.setIndex(mSafeMediaVolumeIndex, device);
4668 sendMsg(mAudioHandler,
4669 MSG_SET_DEVICE_VOLUME,
4670 SENDMSG_QUEUE,
4671 device,
4672 0,
4673 streamState,
4674 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07004675 }
4676 devices &= ~device;
4677 }
4678 }
4679
4680 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07004681 synchronized (mSafeMediaVolumeState) {
4682 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07004683 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
4684 ((device & mSafeMediaVolumeDevices) != 0) &&
4685 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07004686 return false;
4687 }
4688 return true;
4689 }
4690 }
4691
John Spurlock3346a802014-05-20 16:25:37 -04004692 @Override
Eric Laurentc34dcc12012-09-10 13:51:52 -07004693 public void disableSafeMediaVolume() {
John Spurlock3346a802014-05-20 16:25:37 -04004694 enforceSelfOrSystemUI("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07004695 synchronized (mSafeMediaVolumeState) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07004696 setSafeMediaVolumeEnabled(false);
Eric Laurentfde16d52012-12-03 14:42:39 -08004697 if (mPendingVolumeCommand != null) {
4698 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
4699 mPendingVolumeCommand.mIndex,
4700 mPendingVolumeCommand.mFlags,
4701 mPendingVolumeCommand.mDevice);
4702 mPendingVolumeCommand = null;
4703 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07004704 }
4705 }
4706
4707
Eric Laurentdd45d012012-10-08 09:04:34 -07004708 //==========================================================================================
4709 // Camera shutter sound policy.
4710 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
4711 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
4712 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
4713 //==========================================================================================
4714
4715 // cached value of com.android.internal.R.bool.config_camera_sound_forced
4716 private Boolean mCameraSoundForced;
4717
4718 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
4719 public boolean isCameraSoundForced() {
4720 synchronized (mCameraSoundForced) {
4721 return mCameraSoundForced;
4722 }
4723 }
4724
4725 private static final String[] RINGER_MODE_NAMES = new String[] {
4726 "SILENT",
4727 "VIBRATE",
4728 "NORMAL"
4729 };
4730
4731 private void dumpRingerMode(PrintWriter pw) {
4732 pw.println("\nRinger mode: ");
4733 pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]);
4734 pw.print("- ringer mode affected streams = 0x");
4735 pw.println(Integer.toHexString(mRingerModeAffectedStreams));
4736 pw.print("- ringer mode muted streams = 0x");
4737 pw.println(Integer.toHexString(mRingerModeMutedStreams));
4738 }
4739
Dianne Hackborn632ca412012-06-14 19:34:10 -07004740 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004741 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07004742 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
4743
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004744 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07004745 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07004746 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07004747 pw.println("\nAudio routes:");
4748 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
4749 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
John Spurlock3346a802014-05-20 16:25:37 -04004750 pw.print(" mVolumeController="); pw.println(mVolumeController);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004751 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07004752
4753 // Inform AudioFlinger of our device's low RAM attribute
4754 private static void readAndSetLowRamDevice()
4755 {
4756 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
4757 if (status != 0) {
4758 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
4759 }
4760 }
John Spurlock3346a802014-05-20 16:25:37 -04004761
4762 private void enforceSelfOrSystemUI(String action) {
4763 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
4764 "Only SystemUI can " + action);
4765 }
4766
4767 @Override
4768 public void setVolumeController(final IVolumeController controller) {
4769 enforceSelfOrSystemUI("set the volume controller");
4770
4771 // return early if things are not actually changing
4772 if (mVolumeController.isSameBinder(controller)) {
4773 return;
4774 }
4775
4776 // dismiss the old volume controller
4777 mVolumeController.postDismiss();
4778 if (controller != null) {
4779 // we are about to register a new controller, listen for its death
4780 try {
4781 controller.asBinder().linkToDeath(new DeathRecipient() {
4782 @Override
4783 public void binderDied() {
4784 if (mVolumeController.isSameBinder(controller)) {
4785 Log.w(TAG, "Current remote volume controller died, unregistering");
4786 setVolumeController(null);
4787 }
4788 }
4789 }, 0);
4790 } catch (RemoteException e) {
4791 // noop
4792 }
4793 }
4794 mVolumeController.setController(controller);
4795 }
RoboErikd09bd0c2014-06-24 17:45:19 -07004796
4797 public static class VolumeController {
4798 private static final String TAG = "VolumeController";
4799
4800 private IVolumeController mController;
4801
4802 public void setController(IVolumeController controller) {
4803 mController = controller;
4804 }
4805
4806 public boolean isSameBinder(IVolumeController controller) {
4807 return Objects.equals(asBinder(), binder(controller));
4808 }
4809
4810 public IBinder asBinder() {
4811 return binder(mController);
4812 }
4813
4814 private static IBinder binder(IVolumeController controller) {
4815 return controller == null ? null : controller.asBinder();
4816 }
4817
4818 @Override
4819 public String toString() {
4820 return "VolumeController(" + asBinder() + ")";
4821 }
4822
4823 public void postDisplaySafeVolumeWarning(int flags) {
4824 if (mController == null)
4825 return;
4826 try {
4827 mController.displaySafeVolumeWarning(flags);
4828 } catch (RemoteException e) {
4829 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
4830 }
4831 }
4832
4833 public void postVolumeChanged(int streamType, int flags) {
4834 if (mController == null)
4835 return;
4836 try {
4837 mController.volumeChanged(streamType, flags);
4838 } catch (RemoteException e) {
4839 Log.w(TAG, "Error calling volumeChanged", e);
4840 }
4841 }
4842
4843 public void postMasterVolumeChanged(int flags) {
4844 if (mController == null)
4845 return;
4846 try {
4847 mController.masterVolumeChanged(flags);
4848 } catch (RemoteException e) {
4849 Log.w(TAG, "Error calling masterVolumeChanged", e);
4850 }
4851 }
4852
4853 public void postMasterMuteChanged(int flags) {
4854 if (mController == null)
4855 return;
4856 try {
4857 mController.masterMuteChanged(flags);
4858 } catch (RemoteException e) {
4859 Log.w(TAG, "Error calling masterMuteChanged", e);
4860 }
4861 }
4862
4863 public void setLayoutDirection(int layoutDirection) {
4864 if (mController == null)
4865 return;
4866 try {
4867 mController.setLayoutDirection(layoutDirection);
4868 } catch (RemoteException e) {
4869 Log.w(TAG, "Error calling setLayoutDirection", e);
4870 }
4871 }
4872
4873 public void postDismiss() {
4874 if (mController == null)
4875 return;
4876 try {
4877 mController.dismiss();
4878 } catch (RemoteException e) {
4879 Log.w(TAG, "Error calling dismiss", e);
4880 }
4881 }
4882 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004883}