blob: ae7c50130c899cd9b0b16f7f2a7939457caa2177 [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;
Jungshik Jang41d97462014-06-30 22:26:29 +090046import android.hardware.hdmi.HdmiControlManager;
Eric Laurent212532b2014-07-21 15:43:18 -070047import android.hardware.hdmi.HdmiPlaybackClient;
Jungshik Jang41d97462014-06-30 22:26:29 +090048import android.hardware.hdmi.HdmiTvClient;
Paul McLeanc837a452014-04-09 09:04:43 -070049import android.hardware.usb.UsbManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.media.MediaPlayer.OnCompletionListener;
51import android.media.MediaPlayer.OnErrorListener;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070052import android.media.audiopolicy.AudioPolicyConfig;
RoboErik8a2cfc32014-05-16 11:19:38 -070053import android.media.session.MediaSessionLegacyHelper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.os.Binder;
Eric Laurentc18c9132013-04-12 17:24:56 -070055import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.os.Environment;
57import android.os.Handler;
58import android.os.IBinder;
59import android.os.Looper;
60import android.os.Message;
Jean-Michel Trivic6802222012-04-30 11:15:03 -070061import android.os.PowerManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070062import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.os.RemoteException;
64import android.os.ServiceManager;
John Spurlock33f4e042014-07-11 13:10:58 -040065import android.os.SystemClock;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070066import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070067import android.os.UserHandle;
Eric Laurentbffc3d12012-05-07 17:43:49 -070068import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069import android.provider.Settings;
70import android.provider.Settings.System;
Santos Cordon9eb45932014-06-27 12:28:43 -070071import android.telecomm.TelecommManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070072import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.util.Log;
John Spurlockaa5ee4d2014-07-25 13:05:12 -040074import android.util.MathUtils;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070075import android.util.Slog;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070076import android.view.KeyEvent;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -070077import android.view.Surface;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -070078import android.view.WindowManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079
80import com.android.internal.telephony.ITelephony;
Eric Laurente78fced2013-03-15 16:03:47 -070081import com.android.internal.util.XmlUtils;
82
83import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -080085import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086import java.io.IOException;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -080087import java.io.PrintWriter;
Eric Laurente78fced2013-03-15 16:03:47 -070088import java.lang.reflect.Field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089import java.util.ArrayList;
Eric Laurent3172d5e2012-05-09 11:38:16 -070090import java.util.concurrent.ConcurrentHashMap;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +090091import java.util.Arrays;
Eric Laurentc42ac9d2009-07-29 08:53:03 -070092import java.util.HashMap;
93import java.util.Iterator;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -070094import java.util.List;
Eric Laurentc42ac9d2009-07-29 08:53:03 -070095import java.util.Map;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070096import java.util.NoSuchElementException;
RoboErikd09bd0c2014-06-24 17:45:19 -070097import java.util.Objects;
Eric Laurentc42ac9d2009-07-29 08:53:03 -070098import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099
100/**
101 * The implementation of the volume manager service.
102 * <p>
103 * This implementation focuses on delivering a responsive UI. Most methods are
104 * asynchronous to external calls. For example, the task of setting a volume
105 * will update our internal state, but in a separate thread will set the system
106 * volume and later persist to the database. Similarly, setting the ringer mode
107 * will update the state and broadcast a change and in a separate thread later
108 * persist the ringer mode.
109 *
110 * @hide
111 */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700112public class AudioService extends IAudioService.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113
114 private static final String TAG = "AudioService";
115
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700116 /** Debug remote control client/display feature */
John Spurlockae641c92014-06-30 18:11:40 -0400117 protected static final boolean DEBUG_RC = Log.isLoggable(TAG + ".RC", Log.DEBUG);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700118 /** Debug volumes */
John Spurlockae641c92014-06-30 18:11:40 -0400119 protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700120
RoboErik430fc482014-06-12 15:49:20 -0700121 /** debug calls to media session apis */
John Spurlockae641c92014-06-30 18:11:40 -0400122 private static final boolean DEBUG_SESSIONS = Log.isLoggable(TAG + ".SESSIONS", Log.DEBUG);
RoboErik8a2cfc32014-05-16 11:19:38 -0700123
John Spurlock86005342014-05-23 11:58:00 -0400124 /** Allow volume changes to set ringer mode to silent? */
125 private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
126
John Spurlocka11b4af2014-06-01 11:52:23 -0400127 /** In silent mode, are volume adjustments (raises) prevented? */
128 private static final boolean PREVENT_VOLUME_ADJUSTMENT_IF_SILENT = true;
129
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 /** How long to delay before persisting a change in volume/ringer mode. */
RoboErik45edba12012-03-27 17:54:36 -0700131 private static final int PERSIST_DELAY = 500;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132
John Spurlock3346a802014-05-20 16:25:37 -0400133 /**
134 * The delay before playing a sound. This small period exists so the user
135 * can press another key (non-volume keys, too) to have it NOT be audible.
136 * <p>
137 * PhoneWindow will implement this part.
138 */
139 public static final int PLAY_SOUND_DELAY = 300;
140
John Spurlocka11b4af2014-06-01 11:52:23 -0400141 /**
142 * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
143 */
144 private static final int FLAG_ADJUST_VOLUME = 1;
145
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700146 private final Context mContext;
147 private final ContentResolver mContentResolver;
148 private final AppOpsManager mAppOps;
Eric Laurent212532b2014-07-21 15:43:18 -0700149
150 // the platform has no specific capabilities
151 private static final int PLATFORM_DEFAULT = 0;
152 // the platform is voice call capable (a phone)
153 private static final int PLATFORM_VOICE = 1;
154 // the platform is a television or a set-top box
155 private static final int PLATFORM_TELEVISION = 2;
156 // the platform type affects volume and silent mode behavior
157 private final int mPlatformType;
158
159 private boolean isPlatformVoice() {
160 return mPlatformType == PLATFORM_VOICE;
161 }
162
163 private boolean isPlatformTelevision() {
164 return mPlatformType == PLATFORM_TELEVISION;
165 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800166
John Spurlock3346a802014-05-20 16:25:37 -0400167 /** The controller for the volume UI. */
168 private final VolumeController mVolumeController = new VolumeController();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169
170 // sendMsg() flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 /** If the msg is already queued, replace it with this one. */
172 private static final int SENDMSG_REPLACE = 0;
173 /** If the msg is already queued, ignore this one and leave the old. */
174 private static final int SENDMSG_NOOP = 1;
175 /** If the msg is already queued, queue this one and leave the old. */
176 private static final int SENDMSG_QUEUE = 2;
177
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700178 // AudioHandler messages
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800179 private static final int MSG_SET_DEVICE_VOLUME = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 private static final int MSG_PERSIST_VOLUME = 1;
Mike Lockwood5c55a052011-12-15 17:21:44 -0500181 private static final int MSG_PERSIST_MASTER_VOLUME = 2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 private static final int MSG_PERSIST_RINGER_MODE = 3;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700183 private static final int MSG_MEDIA_SERVER_DIED = 4;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700184 private static final int MSG_PLAY_SOUND_EFFECT = 5;
185 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
186 private static final int MSG_LOAD_SOUND_EFFECTS = 7;
187 private static final int MSG_SET_FORCE_USE = 8;
188 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
189 private static final int MSG_SET_ALL_VOLUMES = 10;
190 private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
191 private static final int MSG_REPORT_NEW_ROUTES = 12;
192 private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
193 private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
194 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
195 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
196 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
197 private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
198 private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
199 private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700200 private static final int MSG_SYSTEM_READY = 21;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400201 private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700202 // start of messages handled under wakelock
203 // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
Jean-Michel Trivie12c39b2012-06-06 10:51:58 -0700204 // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700205 private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
Mike Lockwood0a40ec22014-05-21 10:08:50 -0700206 private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
207 private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700208 // end of messages handled under wakelock
Eric Laurentafbb0472011-12-15 09:04:23 -0800209
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -0700210 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
Eric Laurentdc03c612011-04-01 10:59:41 -0700211 // Timeout for connection to bluetooth headset service
212 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 /** @see AudioSystemThread */
215 private AudioSystemThread mAudioSystemThread;
216 /** @see AudioHandler */
217 private AudioHandler mAudioHandler;
218 /** @see VolumeStreamState */
219 private VolumeStreamState[] mStreamStates;
Jason Parekhb1096152009-03-24 17:48:25 -0700220 private SettingsObserver mSettingsObserver;
Eric Laurenta553c252009-07-17 12:17:14 -0700221
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700222 private int mMode = AudioSystem.MODE_NORMAL;
Glenn Kastenba195eb2011-12-13 09:30:40 -0800223 // protects mRingerMode
224 private final Object mSettingsLock = new Object();
Eric Laurent45c90ce2012-04-24 18:44:22 -0700225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 private SoundPool mSoundPool;
Glenn Kasten30c918c2011-11-10 17:56:41 -0800227 private final Object mSoundEffectsLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 private static final int NUM_SOUNDPOOL_CHANNELS = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229
Mike Lockwood47676902011-11-08 10:31:21 -0800230 // Internally master volume is a float in the 0.0 - 1.0 range,
231 // but to support integer based AudioManager API we translate it to 0 - 100
232 private static final int MAX_MASTER_VOLUME = 100;
233
Lei Zhang6c798972012-03-02 11:40:12 -0800234 // Maximum volume adjust steps allowed in a single batch call.
235 private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 /* Sound effect file names */
238 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
Eric Laurente78fced2013-03-15 16:03:47 -0700239 private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240
241 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
242 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
243 * uses soundpool (second column) */
Eric Laurente78fced2013-03-15 16:03:47 -0700244 private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245
Jared Suttles59820132009-08-13 21:50:52 -0500246 /** @hide Maximum volume index values for audio streams */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700247 private static final int[] MAX_STREAM_VOLUME = new int[] {
Eric Laurent6ee99522009-08-25 06:30:59 -0700248 5, // STREAM_VOICE_CALL
249 7, // STREAM_SYSTEM
250 7, // STREAM_RING
251 15, // STREAM_MUSIC
252 7, // STREAM_ALARM
253 7, // STREAM_NOTIFICATION
254 15, // STREAM_BLUETOOTH_SCO
255 7, // STREAM_SYSTEM_ENFORCED
256 15, // STREAM_DTMF
257 15 // STREAM_TTS
Jared Suttles59820132009-08-13 21:50:52 -0500258 };
Eric Laurent6d517662012-04-23 18:42:39 -0700259 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
Eric Laurenta553c252009-07-17 12:17:14 -0700260 * of another stream: This avoids multiplying the volume settings for hidden
261 * stream types that follow other stream behavior for volume settings
Eric Laurent6d517662012-04-23 18:42:39 -0700262 * NOTE: do not create loops in aliases!
263 * Some streams alias to different streams according to device category (phone or tablet) or
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700264 * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
Eric Laurent212532b2014-07-21 15:43:18 -0700265 * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
266 * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
267 * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
268 private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700269 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
270 AudioSystem.STREAM_RING, // STREAM_SYSTEM
271 AudioSystem.STREAM_RING, // STREAM_RING
272 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
273 AudioSystem.STREAM_ALARM, // STREAM_ALARM
274 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
275 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
276 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
277 AudioSystem.STREAM_RING, // STREAM_DTMF
278 AudioSystem.STREAM_MUSIC // STREAM_TTS
Eric Laurenta553c252009-07-17 12:17:14 -0700279 };
Eric Laurent212532b2014-07-21 15:43:18 -0700280 private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
281 AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL
282 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
283 AudioSystem.STREAM_MUSIC, // STREAM_RING
284 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
285 AudioSystem.STREAM_MUSIC, // STREAM_ALARM
286 AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
287 AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO
288 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
289 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
290 AudioSystem.STREAM_MUSIC // STREAM_TTS
291 };
292 private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700293 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
294 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
295 AudioSystem.STREAM_RING, // STREAM_RING
296 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
297 AudioSystem.STREAM_ALARM, // STREAM_ALARM
298 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
299 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
300 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
301 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
302 AudioSystem.STREAM_MUSIC // STREAM_TTS
303 };
304 private int[] mStreamVolumeAlias;
Eric Laurenta553c252009-07-17 12:17:14 -0700305
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700306 /**
307 * Map AudioSystem.STREAM_* constants to app ops. This should be used
308 * after mapping through mStreamVolumeAlias.
309 */
310 private static final int[] STEAM_VOLUME_OPS = new int[] {
311 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL
312 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM
313 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING
314 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC
315 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM
316 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION
317 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO
318 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED
319 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF
320 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS
321 };
322
Eric Laurent83a017b2013-03-19 18:15:31 -0700323 private final boolean mUseFixedVolume;
324
Eric Laurentbffc3d12012-05-07 17:43:49 -0700325 // stream names used by dumpStreamStates()
John Spurlock1af30c72014-03-10 08:33:35 -0400326 private static final String[] STREAM_NAMES = new String[] {
Eric Laurentbffc3d12012-05-07 17:43:49 -0700327 "STREAM_VOICE_CALL",
328 "STREAM_SYSTEM",
329 "STREAM_RING",
330 "STREAM_MUSIC",
331 "STREAM_ALARM",
332 "STREAM_NOTIFICATION",
333 "STREAM_BLUETOOTH_SCO",
334 "STREAM_SYSTEM_ENFORCED",
335 "STREAM_DTMF",
336 "STREAM_TTS"
337 };
338
Glenn Kasten30c918c2011-11-10 17:56:41 -0800339 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340 public void onError(int error) {
341 switch (error) {
342 case AudioSystem.AUDIO_STATUS_SERVER_DIED:
Eric Laurentdfb881f2013-07-18 14:41:39 -0700343 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
344 SENDMSG_NOOP, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 break;
346 default:
347 break;
348 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700349 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 };
351
352 /**
353 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
354 * {@link AudioManager#RINGER_MODE_SILENT}, or
355 * {@link AudioManager#RINGER_MODE_VIBRATE}.
356 */
Glenn Kastenba195eb2011-12-13 09:30:40 -0800357 // protected by mSettingsLock
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 private int mRingerMode;
359
Eric Laurent9bcf4012009-06-12 06:09:28 -0700360 /** @see System#MODE_RINGER_STREAMS_AFFECTED */
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700361 private int mRingerModeAffectedStreams = 0;
Eric Laurent9bcf4012009-06-12 06:09:28 -0700362
Eric Laurent5b4e6542010-03-19 20:02:21 -0700363 // Streams currently muted by ringer mode
364 private int mRingerModeMutedStreams;
365
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 /** @see System#MUTE_STREAMS_AFFECTED */
367 private int mMuteAffectedStreams;
368
369 /**
Eric Laurentbffc3d12012-05-07 17:43:49 -0700370 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
371 * mVibrateSetting is just maintained during deprecation period but vibration policy is
372 * now only controlled by mHasVibrator and mRingerMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 */
374 private int mVibrateSetting;
375
Eric Laurentbffc3d12012-05-07 17:43:49 -0700376 // Is there a vibrator
377 private final boolean mHasVibrator;
378
Eric Laurenta553c252009-07-17 12:17:14 -0700379 // Broadcast receiver for device connections intent broadcasts
380 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
381
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700382 // Devices currently connected
Glenn Kasten30c918c2011-11-10 17:56:41 -0800383 private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700384
385 // Forced device usage for communications
386 private int mForcedUseForComm;
387
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500388 // True if we have master volume support
389 private final boolean mUseMasterVolume;
390
Mike Lockwood97606472012-02-09 11:24:10 -0800391 private final int[] mMasterVolumeRamp;
392
Eric Laurent9272b4b2010-01-23 17:12:59 -0800393 // List of binder death handlers for setMode() client processes.
394 // The last process to have called setMode() is at the top of the list.
Glenn Kasten30c918c2011-11-10 17:56:41 -0800395 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
Eric Laurenteb14a782009-12-17 03:12:59 -0800396
Eric Laurent3def1ee2010-03-17 23:26:26 -0700397 // List of clients having issued a SCO start request
Glenn Kasten30c918c2011-11-10 17:56:41 -0800398 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
Eric Laurent3def1ee2010-03-17 23:26:26 -0700399
400 // BluetoothHeadset API to control SCO connection
401 private BluetoothHeadset mBluetoothHeadset;
402
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700403 // Bluetooth headset device
404 private BluetoothDevice mBluetoothHeadsetDevice;
Eric Laurent3def1ee2010-03-17 23:26:26 -0700405
Eric Laurent62ef7672010-11-24 10:58:32 -0800406 // Indicate if SCO audio connection is currently active and if the initiator is
407 // audio service (internal) or bluetooth headset (external)
408 private int mScoAudioState;
409 // SCO audio state is not active
410 private static final int SCO_STATE_INACTIVE = 0;
Eric Laurentdc03c612011-04-01 10:59:41 -0700411 // SCO audio activation request waiting for headset service to connect
412 private static final int SCO_STATE_ACTIVATE_REQ = 1;
Eric Laurent25fc29b2013-04-05 12:13:54 -0700413 // SCO audio state is active or starting due to a request from AudioManager API
Eric Laurentdc03c612011-04-01 10:59:41 -0700414 private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
415 // SCO audio deactivation request waiting for headset service to connect
416 private static final int SCO_STATE_DEACTIVATE_REQ = 5;
417
Eric Laurent62ef7672010-11-24 10:58:32 -0800418 // SCO audio state is active due to an action in BT handsfree (either voice recognition or
419 // in call audio)
420 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
Eric Laurentdc03c612011-04-01 10:59:41 -0700421 // Deactivation request for all SCO connections (initiated by audio mode change)
422 // waiting for headset service to connect
423 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
424
Eric Laurentc18c9132013-04-12 17:24:56 -0700425 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
426 // originated from an app targeting an API version before JB MR2 and raw audio after that.
427 private int mScoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -0700428 // SCO audio mode is undefined
429 private static final int SCO_MODE_UNDEFINED = -1;
Eric Laurentc18c9132013-04-12 17:24:56 -0700430 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
431 private static final int SCO_MODE_VIRTUAL_CALL = 0;
432 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
433 private static final int SCO_MODE_RAW = 1;
Liejun Taof4e51d82014-07-16 11:18:29 -0700434 // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
435 private static final int SCO_MODE_VR = 2;
436
437 private static final int SCO_MODE_MAX = 2;
Eric Laurentc18c9132013-04-12 17:24:56 -0700438
Eric Laurentdc03c612011-04-01 10:59:41 -0700439 // Current connection state indicated by bluetooth headset
440 private int mScoConnectionState;
Eric Laurent62ef7672010-11-24 10:58:32 -0800441
Eric Laurenta60e2122010-12-28 16:49:07 -0800442 // true if boot sequence has been completed
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700443 private boolean mSystemReady;
Eric Laurenta60e2122010-12-28 16:49:07 -0800444 // listener for SoundPool sample load completion indication
445 private SoundPoolCallback mSoundPoolCallBack;
446 // thread for SoundPool listener
447 private SoundPoolListenerThread mSoundPoolListenerThread;
448 // message looper for SoundPool listener
449 private Looper mSoundPoolLooper = null;
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700450 // volume applied to sound played with playSoundEffect()
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700451 private static int sSoundEffectVolumeDb;
Eric Laurent9903e262012-09-21 18:10:32 -0700452 // getActiveStreamType() will return:
453 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
454 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
Eric Laurent25101b02011-02-02 09:33:30 -0800455 // stopped
Eric Laurent9903e262012-09-21 18:10:32 -0700456 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
Eric Laurent25101b02011-02-02 09:33:30 -0800457 // previous volume adjustment direction received by checkForRingerModeChange()
458 private int mPrevVolDirection = AudioManager.ADJUST_SAME;
Amith Yamasani6243edd2011-12-05 19:58:48 -0800459 // Keyguard manager proxy
460 private KeyguardManager mKeyguardManager;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700461 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
462 // is controlled by Vol keys.
463 private int mVolumeControlStream = -1;
464 private final Object mForceControlStreamLock = new Object();
465 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
466 // server process so in theory it is not necessary to monitor the client death.
467 // However it is good to be ready for future evolutions.
468 private ForceControlStreamClient mForceControlStreamClient = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700469 // Used to play ringtones outside system_server
470 private volatile IRingtonePlayer mRingtonePlayer;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800471
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700472 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700473 private int mDeviceRotation = Surface.ROTATION_0;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700474
Eric Laurent78472112012-05-21 08:57:21 -0700475 // Request to override default use of A2DP for media.
476 private boolean mBluetoothA2dpEnabled;
477 private final Object mBluetoothA2dpEnabledLock = new Object();
478
Dianne Hackborn632ca412012-06-14 19:34:10 -0700479 // Monitoring of audio routes. Protected by mCurAudioRoutes.
480 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
481 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
482 = new RemoteCallbackList<IAudioRoutesObserver>();
483
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700484 /**
485 * A fake stream type to match the notion of remote media playback
486 */
487 public final static int STREAM_REMOTE_MUSIC = -200;
488
Eric Laurent4bbcc652012-09-24 14:26:30 -0700489 // Devices for which the volume is fixed and VolumePanel slider should be disabled
Eric Laurent212532b2014-07-21 15:43:18 -0700490 int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700491 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Eric Laurent212532b2014-07-21 15:43:18 -0700492 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
493 AudioSystem.DEVICE_OUT_HDMI_ARC |
494 AudioSystem.DEVICE_OUT_SPDIF |
495 AudioSystem.DEVICE_OUT_AUX_LINE;
Eric Laurent4bbcc652012-09-24 14:26:30 -0700496
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700497 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700498 private final boolean mMonitorOrientation;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700499 private final boolean mMonitorRotation;
Eric Laurentd640bd32012-09-28 18:01:48 -0700500
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700501 private boolean mDockAudioMediaEnabled = true;
502
Eric Laurent08ed1b92012-11-05 14:54:12 -0800503 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
504
Eric Laurentfde16d52012-12-03 14:42:39 -0800505 // Used when safe volume warning message display is requested by setStreamVolume(). In this
506 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
507 // and used later when/if disableSafeMediaVolume() is called.
508 private StreamVolumeCommand mPendingVolumeCommand;
509
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700510 private PowerManager.WakeLock mAudioEventWakeLock;
511
512 private final MediaFocusControl mMediaFocusControl;
513
John Du5a0cf7a2013-07-19 11:30:34 -0700514 // Reference to BluetoothA2dp to query for AbsoluteVolume.
515 private BluetoothA2dp mA2dp;
516 private final Object mA2dpAvrcpLock = new Object();
517 // If absolute volume is supported in AVRCP device
518 private boolean mAvrcpAbsVolSupported = false;
519
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 ///////////////////////////////////////////////////////////////////////////
521 // Construction
522 ///////////////////////////////////////////////////////////////////////////
523
524 /** @hide */
525 public AudioService(Context context) {
526 mContext = context;
527 mContentResolver = context.getContentResolver();
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700528 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700529
530 if (mContext.getResources().getBoolean(
531 com.android.internal.R.bool.config_voice_capable)) {
532 mPlatformType = PLATFORM_VOICE;
533 } else if (context.getPackageManager().hasSystemFeature(
534 PackageManager.FEATURE_TELEVISION)) {
535 mPlatformType = PLATFORM_TELEVISION;
536 } else {
537 mPlatformType = PLATFORM_DEFAULT;
538 }
Jared Suttles59820132009-08-13 21:50:52 -0500539
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700540 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700541 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700542
Eric Laurentbffc3d12012-05-07 17:43:49 -0700543 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
544 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
545
Jared Suttles59820132009-08-13 21:50:52 -0500546 // Intialized volume
547 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt(
548 "ro.config.vc_call_vol_steps",
549 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
550
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700551 sSoundEffectVolumeDb = context.getResources().getInteger(
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700552 com.android.internal.R.integer.config_soundEffectVolumeDb);
Eric Laurent25101b02011-02-02 09:33:30 -0800553
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700554 mForcedUseForComm = AudioSystem.FORCE_NONE;
Eric Laurentdd45d012012-10-08 09:04:34 -0700555
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800556 createAudioSystemThread();
Eric Laurentdd45d012012-10-08 09:04:34 -0700557
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700558 mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
John Spurlock3346a802014-05-20 16:25:37 -0400559 mContext, mVolumeController, this);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700560
Eric Laurentdfb881f2013-07-18 14:41:39 -0700561 AudioSystem.setErrorCallback(mAudioSystemCallback);
562
Eric Laurentdd45d012012-10-08 09:04:34 -0700563 boolean cameraSoundForced = mContext.getResources().getBoolean(
564 com.android.internal.R.bool.config_camera_sound_forced);
565 mCameraSoundForced = new Boolean(cameraSoundForced);
566 sendMsg(mAudioHandler,
567 MSG_SET_FORCE_USE,
568 SENDMSG_QUEUE,
569 AudioSystem.FOR_SYSTEM,
570 cameraSoundForced ?
571 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
572 null,
573 0);
574
Eric Laurent05274f32012-11-29 12:48:18 -0800575 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
576 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
577 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
578 // The default safe volume index read here will be replaced by the actual value when
579 // the mcc is read by onConfigureSafeVolume()
580 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
581 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
582
Eric Laurent83a017b2013-03-19 18:15:31 -0700583 mUseFixedVolume = mContext.getResources().getBoolean(
584 com.android.internal.R.bool.config_useFixedVolume);
585
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700586 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
587 // array initialized by updateStreamVolumeAlias()
588 updateStreamVolumeAlias(false /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589 readPersistedSettings();
Eric Laurentc1d41662011-07-19 11:21:13 -0700590 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700591 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700592
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700593 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700594
595 // Call setRingerModeInt() to apply correct mute
596 // state on streams affected by ringer mode.
597 mRingerModeMutedStreams = 0;
598 setRingerModeInt(getRingerMode(), false);
599
Eric Laurenta553c252009-07-17 12:17:14 -0700600 // Register for device connection intent broadcasts.
601 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700602 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700603 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
604 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Eric Laurent59f48272012-04-05 19:42:21 -0700605 intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
606 intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700607 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
608 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700609 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Paul McLeanc837a452014-04-09 09:04:43 -0700610 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700611
Eric Laurentd640bd32012-09-28 18:01:48 -0700612 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700613 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700614 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
615 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700616 Log.v(TAG, "monitoring device orientation");
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700617 // initialize orientation in AudioSystem
618 setOrientationForAudioSystem();
619 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700620 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
621 if (mMonitorRotation) {
622 mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
623 .getDefaultDisplay().getRotation();
624 Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
625 // initialize rotation in AudioSystem
626 setRotationForAudioSystem();
627 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700628
Eric Laurenta553c252009-07-17 12:17:14 -0700629 context.registerReceiver(mReceiver, intentFilter);
Jared Suttles59820132009-08-13 21:50:52 -0500630
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500631 mUseMasterVolume = context.getResources().getBoolean(
632 com.android.internal.R.bool.config_useMasterVolume);
Mike Lockwood90631542012-01-06 11:20:37 -0500633 restoreMasterVolume();
Mike Lockwood97606472012-02-09 11:24:10 -0800634
635 mMasterVolumeRamp = context.getResources().getIntArray(
636 com.android.internal.R.array.config_masterVolumeRamp);
Eric Laurent78472112012-05-21 08:57:21 -0700637
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800638 }
639
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700640 public void systemReady() {
641 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
642 0, 0, null, 0);
643 }
644
645 public void onSystemReady() {
646 mSystemReady = true;
647 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
648 0, 0, null, 0);
649
650 mKeyguardManager =
651 (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
652 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
653 resetBluetoothSco();
654 getBluetoothHeadset();
655 //FIXME: this is to maintain compatibility with deprecated intent
656 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
657 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
658 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
659 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
660 sendStickyBroadcastToAll(newIntent);
661
662 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
663 if (adapter != null) {
664 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
665 BluetoothProfile.A2DP);
666 }
667
Eric Laurent212532b2014-07-21 15:43:18 -0700668 mHdmiManager =
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900669 (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700670 if (mHdmiManager != null) {
671 synchronized (mHdmiManager) {
672 mHdmiTvClient = mHdmiManager.getTvClient();
673 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
674 mHdmiCecSink = false;
675 }
676 }
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900677
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700678 sendMsg(mAudioHandler,
679 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
680 SENDMSG_REPLACE,
681 0,
682 0,
683 null,
684 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
685 }
686
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687 private void createAudioSystemThread() {
688 mAudioSystemThread = new AudioSystemThread();
689 mAudioSystemThread.start();
690 waitForAudioHandlerCreation();
691 }
692
693 /** Waits for the volume handler to be created by the other thread. */
694 private void waitForAudioHandlerCreation() {
695 synchronized(this) {
696 while (mAudioHandler == null) {
697 try {
698 // Wait for mAudioHandler to be set by the other thread
699 wait();
700 } catch (InterruptedException e) {
701 Log.e(TAG, "Interrupted while waiting on volume handler.");
702 }
703 }
704 }
705 }
706
Eric Laurent24482012012-05-10 09:41:17 -0700707 private void checkAllAliasStreamVolumes() {
708 int numStreamTypes = AudioSystem.getNumStreamTypes();
709 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
710 if (streamType != mStreamVolumeAlias[streamType]) {
711 mStreamStates[streamType].
Eric Laurent42b041e2013-03-29 11:36:03 -0700712 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
Eric Laurent24482012012-05-10 09:41:17 -0700713 }
714 // apply stream volume
Eric Laurent42b041e2013-03-29 11:36:03 -0700715 if (!mStreamStates[streamType].isMuted()) {
Eric Laurent24482012012-05-10 09:41:17 -0700716 mStreamStates[streamType].applyAllVolumes();
717 }
718 }
719 }
720
Eric Laurent212532b2014-07-21 15:43:18 -0700721 private void checkAllFixedVolumeDevices()
722 {
723 int numStreamTypes = AudioSystem.getNumStreamTypes();
724 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
725 mStreamStates[streamType].checkFixedVolumeDevices();
726 }
727 }
728
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 int numStreamTypes = AudioSystem.getNumStreamTypes();
731 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
732
733 for (int i = 0; i < numStreamTypes; i++) {
Eric Laurent6d517662012-04-23 18:42:39 -0700734 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -0700735 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736
Eric Laurent212532b2014-07-21 15:43:18 -0700737 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -0700738 checkAllAliasStreamVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739 }
740
Eric Laurentbffc3d12012-05-07 17:43:49 -0700741 private void dumpStreamStates(PrintWriter pw) {
742 pw.println("\nStream volumes (device: index)");
743 int numStreamTypes = AudioSystem.getNumStreamTypes();
744 for (int i = 0; i < numStreamTypes; i++) {
745 pw.println("- "+STREAM_NAMES[i]+":");
746 mStreamStates[i].dump(pw);
747 pw.println("");
748 }
Eric Laurentdd45d012012-10-08 09:04:34 -0700749 pw.print("\n- mute affected streams = 0x");
750 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -0700751 }
752
John Spurlock1af30c72014-03-10 08:33:35 -0400753 /** @hide */
754 public static String streamToString(int stream) {
755 if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream];
756 if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE";
757 return "UNKNOWN_STREAM_" + stream;
758 }
Eric Laurent6d517662012-04-23 18:42:39 -0700759
760 private void updateStreamVolumeAlias(boolean updateVolumes) {
761 int dtmfStreamAlias;
Eric Laurent212532b2014-07-21 15:43:18 -0700762
763 switch (mPlatformType) {
764 case PLATFORM_VOICE:
765 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
Eric Laurent6d517662012-04-23 18:42:39 -0700766 dtmfStreamAlias = AudioSystem.STREAM_RING;
Eric Laurent212532b2014-07-21 15:43:18 -0700767 break;
768 case PLATFORM_TELEVISION:
769 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
770 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
771 break;
772 default:
773 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
Eric Laurent6d517662012-04-23 18:42:39 -0700774 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
775 }
Eric Laurent212532b2014-07-21 15:43:18 -0700776
777 if (isPlatformTelevision()) {
778 mRingerModeAffectedStreams = 0;
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700779 } else {
Eric Laurent212532b2014-07-21 15:43:18 -0700780 if (isInCommunication()) {
781 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
782 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
783 } else {
784 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
785 }
Eric Laurent6d517662012-04-23 18:42:39 -0700786 }
Eric Laurent212532b2014-07-21 15:43:18 -0700787
Eric Laurent6d517662012-04-23 18:42:39 -0700788 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
789 if (updateVolumes) {
Eric Laurent42b041e2013-03-29 11:36:03 -0700790 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700791 // apply stream mute states according to new value of mRingerModeAffectedStreams
792 setRingerModeInt(getRingerMode(), false);
Eric Laurent6d517662012-04-23 18:42:39 -0700793 sendMsg(mAudioHandler,
794 MSG_SET_ALL_VOLUMES,
795 SENDMSG_QUEUE,
796 0,
797 0,
798 mStreamStates[AudioSystem.STREAM_DTMF], 0);
799 }
800 }
801
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700802 private void readDockAudioSettings(ContentResolver cr)
803 {
804 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -0700805 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700806
807 if (mDockAudioMediaEnabled) {
808 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
809 } else {
810 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
811 }
812
813 sendMsg(mAudioHandler,
814 MSG_SET_FORCE_USE,
815 SENDMSG_QUEUE,
816 AudioSystem.FOR_DOCK,
817 mDockAudioMediaEnabled ?
818 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
819 null,
820 0);
821 }
822
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 private void readPersistedSettings() {
824 final ContentResolver cr = mContentResolver;
825
Eric Laurentbffc3d12012-05-07 17:43:49 -0700826 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700827 Settings.Global.getInt(
828 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -0700829 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -0700830 // sanity check in case the settings are restored from a device with incompatible
831 // ringer modes
Glenn Kastenba195eb2011-12-13 09:30:40 -0800832 if (!AudioManager.isValidRingerMode(ringerMode)) {
833 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700834 }
835 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
836 ringerMode = AudioManager.RINGER_MODE_SILENT;
837 }
838 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700839 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -0800840 }
Eric Laurent212532b2014-07-21 15:43:18 -0700841 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -0700842 ringerMode = AudioManager.RINGER_MODE_NORMAL;
843 }
Glenn Kastenba195eb2011-12-13 09:30:40 -0800844 synchronized(mSettingsLock) {
845 mRingerMode = ringerMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846
Eric Laurentdd45d012012-10-08 09:04:34 -0700847 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
848 // are still needed while setVibrateSetting() and getVibrateSetting() are being
849 // deprecated.
850 mVibrateSetting = getValueForVibrateSetting(0,
851 AudioManager.VIBRATE_TYPE_NOTIFICATION,
852 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
853 : AudioManager.VIBRATE_SETTING_OFF);
854 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
855 AudioManager.VIBRATE_TYPE_RINGER,
856 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
857 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700859 updateRingerModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700860 readDockAudioSettings(cr);
Eric Laurent402f7f22011-02-04 12:30:32 -0800861 }
Eric Laurentc1d41662011-07-19 11:21:13 -0700862
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700863 mMuteAffectedStreams = System.getIntForUser(cr,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 System.MUTE_STREAMS_AFFECTED,
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700865 ((1 << AudioSystem.STREAM_MUSIC)|
866 (1 << AudioSystem.STREAM_RING)|
867 (1 << AudioSystem.STREAM_SYSTEM)),
868 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800869
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700870 boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
871 0, UserHandle.USER_CURRENT) == 1;
Eric Laurent83a017b2013-03-19 18:15:31 -0700872 if (mUseFixedVolume) {
873 masterMute = false;
874 AudioSystem.setMasterVolume(1.0f);
875 }
Justin Koh57978ed2012-04-03 17:37:58 -0700876 AudioSystem.setMasterMute(masterMute);
877 broadcastMasterMuteStatus(masterMute);
878
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879 // Each stream will read its own persisted settings
880
881 // Broadcast the sticky intent
Glenn Kastenba195eb2011-12-13 09:30:40 -0800882 broadcastRingerMode(ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883
884 // Broadcast vibrate settings
885 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
886 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -0700887
John Spurlock33f4e042014-07-11 13:10:58 -0400888 // Load settings for the volume controller
889 mVolumeController.loadSettings(cr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800890 }
891
Eric Laurenta553c252009-07-17 12:17:14 -0700892 private int rescaleIndex(int index, int srcStream, int dstStream) {
893 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
894 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800895
896 ///////////////////////////////////////////////////////////////////////////
897 // IPC methods
898 ///////////////////////////////////////////////////////////////////////////
Jean-Michel Trivifca1e602013-10-10 18:12:59 -0700899 /** @see AudioManager#isLocalOrRemoteMusicActive() */
900 public boolean isLocalOrRemoteMusicActive() {
901 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
902 // local / wired / BT playback active
903 if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): local");
904 return true;
905 }
906 if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
907 // remote "cast-like" playback active
908 if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): has PLAYBACK_TYPE_REMOTE");
909 return true;
910 }
911 if (AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, 0)) {
912 // remote submix playback active
913 if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): remote submix");
914 return true;
915 }
916 if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): no");
917 return false;
918 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800919
920 /** @see AudioManager#adjustVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700921 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
922 String callingPackage) {
John Spurlockae641c92014-06-30 18:11:40 -0400923 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType
924 + ", flags=" + flags);
Eric Laurent402f7f22011-02-04 12:30:32 -0800925 int streamType;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700926 if (mVolumeControlStream != -1) {
927 streamType = mVolumeControlStream;
Eric Laurent402f7f22011-02-04 12:30:32 -0800928 } else {
929 streamType = getActiveStreamType(suggestedStreamType);
930 }
John Spurlock33f4e042014-07-11 13:10:58 -0400931 final int resolvedStream = mStreamVolumeAlias[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932
John Spurlock6bd096c2014-07-10 09:39:04 -0400933 // Play sounds on STREAM_RING and STREAM_REMOTE_MUSIC only.
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700934 if ((streamType != STREAM_REMOTE_MUSIC) &&
935 (flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
John Spurlock33f4e042014-07-11 13:10:58 -0400936 resolvedStream != AudioSystem.STREAM_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 flags &= ~AudioManager.FLAG_PLAY_SOUND;
938 }
939
John Spurlock33f4e042014-07-11 13:10:58 -0400940 // For notifications/ring, show the ui before making any adjustments
941 if (mVolumeController.suppressAdjustment(resolvedStream, flags)) {
942 direction = 0;
943 flags &= ~AudioManager.FLAG_PLAY_SOUND;
944 flags &= ~AudioManager.FLAG_VIBRATE;
945 if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
946 }
947
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700948 if (streamType == STREAM_REMOTE_MUSIC) {
RoboErik19c95182014-06-23 15:38:48 -0700949 // TODO bounce it to MediaSessionService to find an appropriate
950 // session
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700951 } else {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700952 adjustStreamVolume(streamType, direction, flags, callingPackage);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700953 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 }
955
956 /** @see AudioManager#adjustStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700957 public void adjustStreamVolume(int streamType, int direction, int flags,
958 String callingPackage) {
Eric Laurent83a017b2013-03-19 18:15:31 -0700959 if (mUseFixedVolume) {
960 return;
961 }
John Spurlockae641c92014-06-30 18:11:40 -0400962 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction
963 + ", flags="+flags);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700964
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 ensureValidDirection(direction);
966 ensureValidStreamType(streamType);
967
Eric Laurent96a33d12011-11-08 10:31:57 -0800968 // use stream type alias here so that streams with same alias have the same behavior,
969 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
970 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
Eric Laurent6d517662012-04-23 18:42:39 -0700971 int streamTypeAlias = mStreamVolumeAlias[streamType];
Eric Laurentb024c302011-10-14 17:19:27 -0700972 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800973
974 final int device = getDeviceForStream(streamTypeAlias);
Eric Laurent3ef75492012-11-28 12:12:23 -0800975
Eric Laurent42b041e2013-03-29 11:36:03 -0700976 int aliasIndex = streamState.getIndex(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800977 boolean adjustVolume = true;
Eric Laurent3ef75492012-11-28 12:12:23 -0800978 int step;
Eric Laurent24482012012-05-10 09:41:17 -0700979
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700980 // skip a2dp absolute volume control request when the device
981 // is not an a2dp device
982 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
983 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
984 return;
985 }
986
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700987 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
988 callingPackage) != AppOpsManager.MODE_ALLOWED) {
989 return;
990 }
991
Eric Laurentfde16d52012-12-03 14:42:39 -0800992 // reset any pending volume command
993 synchronized (mSafeMediaVolumeState) {
994 mPendingVolumeCommand = null;
995 }
996
Eric Laurent3ef75492012-11-28 12:12:23 -0800997 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
998 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
999 ((device & mFixedVolumeDevices) != 0)) {
1000 flags |= AudioManager.FLAG_FIXED_VOLUME;
1001
1002 // Always toggle between max safe volume and 0 for fixed volume devices where safe
1003 // volume is enforced, and max and 0 for the others.
1004 // This is simulated by stepping by the full allowed volume range
1005 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1006 (device & mSafeMediaVolumeDevices) != 0) {
1007 step = mSafeMediaVolumeIndex;
1008 } else {
1009 step = streamState.getMaxIndex();
1010 }
1011 if (aliasIndex != 0) {
1012 aliasIndex = step;
1013 }
1014 } else {
1015 // convert one UI step (+/-1) into a number of internal units on the stream alias
1016 step = rescaleIndex(10, streamType, streamTypeAlias);
1017 }
1018
Eric Laurent42b041e2013-03-29 11:36:03 -07001019 // If either the client forces allowing ringer modes for this adjustment,
1020 // or the stream type is one that is affected by ringer modes
1021 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1022 (streamTypeAlias == getMasterStreamType())) {
1023 int ringerMode = getRingerMode();
1024 // do not vibrate if already in vibrate mode
1025 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
1026 flags &= ~AudioManager.FLAG_VIBRATE;
Eric Laurent3ef75492012-11-28 12:12:23 -08001027 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001028 // Check if the ringer mode changes with this volume adjustment. If
1029 // it does, it will handle adjusting the volume, so we won't below
John Spurlocka11b4af2014-06-01 11:52:23 -04001030 final int result = checkForRingerModeChange(aliasIndex, direction, step);
1031 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
1032 // If suppressing a volume adjustment in silent mode, display the UI hint
1033 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
1034 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
1035 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001036 }
Eric Laurent3ef75492012-11-28 12:12:23 -08001037
Eric Laurent42b041e2013-03-29 11:36:03 -07001038 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001039
Eric Laurent42b041e2013-03-29 11:36:03 -07001040 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001041
John Du5a0cf7a2013-07-19 11:30:34 -07001042 // Check if volume update should be send to AVRCP
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001043 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1044 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1045 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1046 synchronized (mA2dpAvrcpLock) {
1047 if (mA2dp != null && mAvrcpAbsVolSupported) {
1048 mA2dp.adjustAvrcpAbsoluteVolume(direction);
1049 }
John Du5a0cf7a2013-07-19 11:30:34 -07001050 }
1051 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001052
Eric Laurent42b041e2013-03-29 11:36:03 -07001053 if ((direction == AudioManager.ADJUST_RAISE) &&
1054 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
1055 Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -04001056 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurent42b041e2013-03-29 11:36:03 -07001057 } else if (streamState.adjustIndex(direction * step, device)) {
1058 // Post message to set system volume (it in turn will post a message
1059 // to persist). Do not change volume if stream is muted.
1060 sendMsg(mAudioHandler,
1061 MSG_SET_DEVICE_VOLUME,
1062 SENDMSG_QUEUE,
1063 device,
1064 0,
1065 streamState,
1066 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001067 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001068
1069 // Check if volume update should be send to Hdmi system audio.
1070 int newIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent212532b2014-07-21 15:43:18 -07001071 if (mHdmiManager != null) {
1072 synchronized (mHdmiManager) {
1073 if (mHdmiTvClient != null &&
1074 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1075 (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 &&
1076 oldIndex != newIndex) {
1077 int maxIndex = getStreamMaxVolume(streamType);
1078 synchronized (mHdmiTvClient) {
1079 if (mHdmiSystemAudioSupported) {
1080 mHdmiTvClient.setSystemAudioVolume(
1081 (oldIndex + 5) / 10, (newIndex + 5) / 10, maxIndex);
1082 }
1083 }
1084 }
1085 // mHdmiCecSink true => mHdmiPlaybackClient != null
1086 if (mHdmiCecSink &&
1087 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1088 oldIndex != newIndex) {
1089 synchronized (mHdmiPlaybackClient) {
1090 int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
1091 KeyEvent.KEYCODE_VOLUME_UP;
1092 mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1093 mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1094 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001095 }
1096 }
1097 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001098 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001099 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001100 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 }
1102
Dianne Hackborn961cae92013-03-20 14:59:43 -07001103 /** @see AudioManager#adjustMasterVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001104 public void adjustMasterVolume(int steps, int flags, String callingPackage) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001105 if (mUseFixedVolume) {
1106 return;
1107 }
Lei Zhang6c798972012-03-02 11:40:12 -08001108 ensureValidSteps(steps);
Mike Lockwood97606472012-02-09 11:24:10 -08001109 int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1110 int delta = 0;
Lei Zhang6c798972012-03-02 11:40:12 -08001111 int numSteps = Math.abs(steps);
1112 int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
1113 for (int i = 0; i < numSteps; ++i) {
1114 delta = findVolumeDelta(direction, volume);
1115 volume += delta;
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001116 }
RoboErik24b082f2012-02-24 14:21:16 -08001117
Lei Zhang6c798972012-03-02 11:40:12 -08001118 //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001119 setMasterVolume(volume, flags, callingPackage);
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001120 }
1121
Eric Laurentfde16d52012-12-03 14:42:39 -08001122 // StreamVolumeCommand contains the information needed to defer the process of
1123 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1124 class StreamVolumeCommand {
1125 public final int mStreamType;
1126 public final int mIndex;
1127 public final int mFlags;
1128 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001129
Eric Laurentfde16d52012-12-03 14:42:39 -08001130 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1131 mStreamType = streamType;
1132 mIndex = index;
1133 mFlags = flags;
1134 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001135 }
John Spurlock35134602014-07-24 18:10:48 -04001136
1137 @Override
1138 public String toString() {
1139 return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1140 .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1141 .append(mDevice).append('}').toString();
1142 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001143 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001144
Eric Laurentfde16d52012-12-03 14:42:39 -08001145 private void onSetStreamVolume(int streamType, int index, int flags, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001146 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
Eric Laurent3ef75492012-11-28 12:12:23 -08001147 // setting volume on master stream type also controls silent mode
1148 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1149 (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
1150 int newRingerMode;
1151 if (index == 0) {
1152 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlock86005342014-05-23 11:58:00 -04001153 : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
1154 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001155 } else {
1156 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1157 }
1158 setRingerMode(newRingerMode);
1159 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001160 }
1161
1162 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001163 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001164 if (mUseFixedVolume) {
1165 return;
1166 }
1167
Eric Laurentfde16d52012-12-03 14:42:39 -08001168 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001169 int streamTypeAlias = mStreamVolumeAlias[streamType];
1170 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001171
1172 final int device = getDeviceForStream(streamType);
1173 int oldIndex;
1174
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001175 // skip a2dp absolute volume control request when the device
1176 // is not an a2dp device
1177 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1178 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1179 return;
1180 }
1181
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001182 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
1183 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1184 return;
1185 }
1186
Eric Laurentfde16d52012-12-03 14:42:39 -08001187 synchronized (mSafeMediaVolumeState) {
1188 // reset any pending volume command
1189 mPendingVolumeCommand = null;
1190
Eric Laurent42b041e2013-03-29 11:36:03 -07001191 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001192
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001193 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001194
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001195 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1196 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1197 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1198 synchronized (mA2dpAvrcpLock) {
1199 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001200 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001201 }
John Du5a0cf7a2013-07-19 11:30:34 -07001202 }
1203 }
1204
Eric Laurent212532b2014-07-21 15:43:18 -07001205 if (mHdmiManager != null) {
1206 synchronized (mHdmiManager) {
1207 if (mHdmiTvClient != null &&
1208 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1209 (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 &&
1210 oldIndex != index) {
1211 int maxIndex = getStreamMaxVolume(streamType);
1212 synchronized (mHdmiTvClient) {
1213 if (mHdmiSystemAudioSupported) {
1214 mHdmiTvClient.setSystemAudioVolume(
1215 (oldIndex + 5) / 10, (index + 5) / 10, maxIndex);
1216 }
1217 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001218 }
1219 }
1220 }
1221
Eric Laurentfde16d52012-12-03 14:42:39 -08001222 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001223 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001224 ((device & mFixedVolumeDevices) != 0)) {
1225 flags |= AudioManager.FLAG_FIXED_VOLUME;
1226
1227 // volume is either 0 or max allowed for fixed volume devices
1228 if (index != 0) {
1229 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1230 (device & mSafeMediaVolumeDevices) != 0) {
1231 index = mSafeMediaVolumeIndex;
1232 } else {
1233 index = streamState.getMaxIndex();
1234 }
1235 }
1236 }
1237
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001238 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001239 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001240 mPendingVolumeCommand = new StreamVolumeCommand(
1241 streamType, index, flags, device);
1242 } else {
1243 onSetStreamVolume(streamType, index, flags, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07001244 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001245 }
1246 }
Eric Laurent25101b02011-02-02 09:33:30 -08001247 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001248 }
1249
Eric Laurent45c90ce2012-04-24 18:44:22 -07001250 /** @see AudioManager#forceVolumeControlStream(int) */
1251 public void forceVolumeControlStream(int streamType, IBinder cb) {
1252 synchronized(mForceControlStreamLock) {
1253 mVolumeControlStream = streamType;
1254 if (mVolumeControlStream == -1) {
1255 if (mForceControlStreamClient != null) {
1256 mForceControlStreamClient.release();
1257 mForceControlStreamClient = null;
1258 }
1259 } else {
1260 mForceControlStreamClient = new ForceControlStreamClient(cb);
1261 }
1262 }
1263 }
1264
1265 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1266 private IBinder mCb; // To be notified of client's death
1267
1268 ForceControlStreamClient(IBinder cb) {
1269 if (cb != null) {
1270 try {
1271 cb.linkToDeath(this, 0);
1272 } catch (RemoteException e) {
1273 // Client has died!
1274 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1275 cb = null;
1276 }
1277 }
1278 mCb = cb;
1279 }
1280
1281 public void binderDied() {
1282 synchronized(mForceControlStreamLock) {
1283 Log.w(TAG, "SCO client died");
1284 if (mForceControlStreamClient != this) {
1285 Log.w(TAG, "unregistered control stream client died");
1286 } else {
1287 mForceControlStreamClient = null;
1288 mVolumeControlStream = -1;
1289 }
1290 }
1291 }
1292
1293 public void release() {
1294 if (mCb != null) {
1295 mCb.unlinkToDeath(this, 0);
1296 mCb = null;
1297 }
1298 }
1299 }
1300
Lei Zhang6c798972012-03-02 11:40:12 -08001301 private int findVolumeDelta(int direction, int volume) {
1302 int delta = 0;
1303 if (direction == AudioManager.ADJUST_RAISE) {
1304 if (volume == MAX_MASTER_VOLUME) {
1305 return 0;
1306 }
1307 // This is the default value if we make it to the end
1308 delta = mMasterVolumeRamp[1];
1309 // If we're raising the volume move down the ramp array until we
1310 // find the volume we're above and use that groups delta.
1311 for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
1312 if (volume >= mMasterVolumeRamp[i - 1]) {
1313 delta = mMasterVolumeRamp[i];
1314 break;
1315 }
1316 }
1317 } else if (direction == AudioManager.ADJUST_LOWER){
1318 if (volume == 0) {
1319 return 0;
1320 }
1321 int length = mMasterVolumeRamp.length;
1322 // This is the default value if we make it to the end
1323 delta = -mMasterVolumeRamp[length - 1];
1324 // If we're lowering the volume move up the ramp array until we
1325 // find the volume we're below and use the group below it's delta
1326 for (int i = 2; i < length; i += 2) {
1327 if (volume <= mMasterVolumeRamp[i]) {
1328 delta = -mMasterVolumeRamp[i - 1];
1329 break;
1330 }
1331 }
1332 }
1333 return delta;
1334 }
1335
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001336 private void sendBroadcastToAll(Intent intent) {
1337 final long ident = Binder.clearCallingIdentity();
1338 try {
1339 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1340 } finally {
1341 Binder.restoreCallingIdentity(ident);
1342 }
1343 }
1344
1345 private void sendStickyBroadcastToAll(Intent intent) {
1346 final long ident = Binder.clearCallingIdentity();
1347 try {
1348 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1349 } finally {
1350 Binder.restoreCallingIdentity(ident);
1351 }
1352 }
1353
Eric Laurent25101b02011-02-02 09:33:30 -08001354 // UI update and Broadcast Intent
1355 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
Eric Laurent212532b2014-07-21 15:43:18 -07001356 if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) {
Eric Laurent25101b02011-02-02 09:33:30 -08001357 streamType = AudioSystem.STREAM_NOTIFICATION;
1358 }
1359
John Spurlock3346a802014-05-20 16:25:37 -04001360 mVolumeController.postVolumeChanged(streamType, flags);
Eric Laurent25101b02011-02-02 09:33:30 -08001361
Eric Laurent4bbcc652012-09-24 14:26:30 -07001362 if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
1363 oldIndex = (oldIndex + 5) / 10;
1364 index = (index + 5) / 10;
1365 Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
1366 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
1367 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
1368 intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
1369 sendBroadcastToAll(intent);
1370 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371 }
1372
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001373 // UI update and Broadcast Intent
1374 private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
John Spurlock3346a802014-05-20 16:25:37 -04001375 mVolumeController.postMasterVolumeChanged(flags);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001376
1377 Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
1378 intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
1379 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001380 sendBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001381 }
1382
1383 // UI update and Broadcast Intent
1384 private void sendMasterMuteUpdate(boolean muted, int flags) {
John Spurlock3346a802014-05-20 16:25:37 -04001385 mVolumeController.postMasterMuteChanged(flags);
Justin Koh57978ed2012-04-03 17:37:58 -07001386 broadcastMasterMuteStatus(muted);
1387 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001388
Justin Koh57978ed2012-04-03 17:37:58 -07001389 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001390 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1391 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001392 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1393 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001394 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001395 }
1396
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001397 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398 * Sets the stream state's index, and posts a message to set system volume.
1399 * This will not call out to the UI. Assumes a valid stream type.
1400 *
1401 * @param streamType Type of the stream
1402 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001403 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 * @param force If true, set the volume even if the desired volume is same
1405 * as the current volume.
1406 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001407 private void setStreamVolumeInt(int streamType,
1408 int index,
1409 int device,
Eric Laurent42b041e2013-03-29 11:36:03 -07001410 boolean force) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001411 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07001412
Eric Laurent42b041e2013-03-29 11:36:03 -07001413 if (streamState.setIndex(index, device) || force) {
1414 // Post message to set system volume (it in turn will post a message
1415 // to persist).
1416 sendMsg(mAudioHandler,
1417 MSG_SET_DEVICE_VOLUME,
1418 SENDMSG_QUEUE,
1419 device,
1420 0,
1421 streamState,
1422 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001423 }
1424 }
1425
1426 /** @see AudioManager#setStreamSolo(int, boolean) */
1427 public void setStreamSolo(int streamType, boolean state, IBinder cb) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001428 if (mUseFixedVolume) {
1429 return;
1430 }
1431
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001432 for (int stream = 0; stream < mStreamStates.length; stream++) {
1433 if (!isStreamAffectedByMute(stream) || stream == streamType) continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001434 mStreamStates[stream].mute(cb, state);
1435 }
1436 }
1437
1438 /** @see AudioManager#setStreamMute(int, boolean) */
1439 public void setStreamMute(int streamType, boolean state, IBinder cb) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001440 if (mUseFixedVolume) {
1441 return;
1442 }
1443
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001444 if (isStreamAffectedByMute(streamType)) {
Eric Laurent212532b2014-07-21 15:43:18 -07001445 if (mHdmiManager != null) {
1446 synchronized (mHdmiManager) {
1447 if (streamType == AudioSystem.STREAM_MUSIC && mHdmiTvClient != null) {
1448 synchronized (mHdmiTvClient) {
1449 if (mHdmiSystemAudioSupported) {
1450 mHdmiTvClient.setSystemAudioMute(state);
1451 }
1452 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001453 }
1454 }
1455 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001456 mStreamStates[streamType].mute(cb, state);
1457 }
1458 }
1459
Eric Laurent25101b02011-02-02 09:33:30 -08001460 /** get stream mute state. */
1461 public boolean isStreamMute(int streamType) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001462 return mStreamStates[streamType].isMuted();
Eric Laurent25101b02011-02-02 09:33:30 -08001463 }
1464
Dianne Hackborn961cae92013-03-20 14:59:43 -07001465 /** @see AudioManager#setMasterMute(boolean, int) */
Julia Reynolds4a21b252014-06-04 11:11:43 -04001466 public void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001467 if (mUseFixedVolume) {
1468 return;
1469 }
1470
Julia Reynolds4a21b252014-06-04 11:11:43 -04001471 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
1472 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1473 return;
1474 }
1475
Jason Simmons1ce5b262012-02-02 13:00:17 -08001476 if (state != AudioSystem.getMasterMute()) {
1477 AudioSystem.setMasterMute(state);
Justin Koh57978ed2012-04-03 17:37:58 -07001478 // Post a persist master volume msg
Justin Koh75cf9e12012-04-04 15:27:37 -07001479 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
Justin Koh57978ed2012-04-03 17:37:58 -07001480 : 0, 0, null, PERSIST_DELAY);
Justin Koh0273af52012-04-04 18:29:50 -07001481 sendMasterMuteUpdate(state, flags);
Jason Simmons1ce5b262012-02-02 13:00:17 -08001482 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08001483 }
1484
1485 /** get master mute state. */
1486 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08001487 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001488 }
1489
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07001490 protected static int getMaxStreamVolume(int streamType) {
1491 return MAX_STREAM_VOLUME[streamType];
1492 }
1493
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001494 /** @see AudioManager#getStreamVolume(int) */
1495 public int getStreamVolume(int streamType) {
1496 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001497 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001498 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001499
Eric Laurent42b041e2013-03-29 11:36:03 -07001500 // by convention getStreamVolume() returns 0 when a stream is muted.
1501 if (mStreamStates[streamType].isMuted()) {
1502 index = 0;
1503 }
Eric Laurent3ef75492012-11-28 12:12:23 -08001504 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
Eric Laurent4bbcc652012-09-24 14:26:30 -07001505 (device & mFixedVolumeDevices) != 0) {
1506 index = mStreamStates[streamType].getMaxIndex();
Eric Laurent4bbcc652012-09-24 14:26:30 -07001507 }
1508 return (index + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001509 }
1510
Mike Lockwood47676902011-11-08 10:31:21 -08001511 public int getMasterVolume() {
Mike Lockwoodce952c82011-11-14 10:47:42 -08001512 if (isMasterMute()) return 0;
1513 return getLastAudibleMasterVolume();
Mike Lockwood8dc1dab2011-10-27 09:52:41 -04001514 }
1515
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001516 public void setMasterVolume(int volume, int flags, String callingPackage) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001517 if (mUseFixedVolume) {
1518 return;
1519 }
1520
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001521 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
1522 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1523 return;
1524 }
1525
Mike Lockwood97606472012-02-09 11:24:10 -08001526 if (volume < 0) {
1527 volume = 0;
1528 } else if (volume > MAX_MASTER_VOLUME) {
1529 volume = MAX_MASTER_VOLUME;
1530 }
Mike Lockwood5c55a052011-12-15 17:21:44 -05001531 doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
1532 }
1533
1534 private void doSetMasterVolume(float volume, int flags) {
1535 // don't allow changing master volume when muted
1536 if (!AudioSystem.getMasterMute()) {
1537 int oldVolume = getMasterVolume();
1538 AudioSystem.setMasterVolume(volume);
1539
1540 int newVolume = getMasterVolume();
1541 if (newVolume != oldVolume) {
1542 // Post a persist master volume msg
1543 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
1544 Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
Mike Lockwood5c55a052011-12-15 17:21:44 -05001545 }
Justin Koh3caba512012-04-02 15:32:18 -07001546 // Send the volume update regardless whether there was a change.
1547 sendMasterVolumeUpdate(flags, oldVolume, newVolume);
Mike Lockwood5c55a052011-12-15 17:21:44 -05001548 }
Mike Lockwood8dc1dab2011-10-27 09:52:41 -04001549 }
1550
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001551 /** @see AudioManager#getStreamMaxVolume(int) */
1552 public int getStreamMaxVolume(int streamType) {
1553 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07001554 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001555 }
1556
Mike Lockwood47676902011-11-08 10:31:21 -08001557 public int getMasterMaxVolume() {
1558 return MAX_MASTER_VOLUME;
1559 }
Eric Laurent25101b02011-02-02 09:33:30 -08001560
1561 /** Get last audible volume before stream was muted. */
1562 public int getLastAudibleStreamVolume(int streamType) {
1563 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001564 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001565 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08001566 }
1567
Mike Lockwoodce952c82011-11-14 10:47:42 -08001568 /** Get last audible master volume before it was muted. */
1569 public int getLastAudibleMasterVolume() {
1570 return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1571 }
1572
Dianne Hackborn961cae92013-03-20 14:59:43 -07001573 /** @see AudioManager#getMasterStreamType() */
Eric Laurent6d517662012-04-23 18:42:39 -07001574 public int getMasterStreamType() {
Eric Laurent212532b2014-07-21 15:43:18 -07001575 switch (mPlatformType) {
1576 case PLATFORM_VOICE:
1577 return AudioSystem.STREAM_RING;
1578 case PLATFORM_TELEVISION:
1579 return AudioSystem.STREAM_MUSIC;
1580 default:
1581 break;
Eric Laurent6d517662012-04-23 18:42:39 -07001582 }
Eric Laurent212532b2014-07-21 15:43:18 -07001583 return AudioSystem.STREAM_NOTIFICATION;
Eric Laurent6d517662012-04-23 18:42:39 -07001584 }
1585
Emily Bernier22c921a2014-05-28 11:01:32 -04001586 /** @see AudioManager#setMicrophoneMute(boolean) */
1587 public void setMicrophoneMute(boolean on, String callingPackage) {
1588 if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(),
1589 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1590 return;
1591 }
1592
1593 AudioSystem.muteMicrophone(on);
1594 }
1595
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001596 /** @see AudioManager#getRingerMode() */
1597 public int getRingerMode() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001598 synchronized(mSettingsLock) {
1599 return mRingerMode;
1600 }
1601 }
1602
1603 private void ensureValidRingerMode(int ringerMode) {
1604 if (!AudioManager.isValidRingerMode(ringerMode)) {
1605 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1606 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607 }
1608
1609 /** @see AudioManager#setRingerMode(int) */
1610 public void setRingerMode(int ringerMode) {
Eric Laurent212532b2014-07-21 15:43:18 -07001611 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001612 return;
1613 }
1614
Eric Laurent24482012012-05-10 09:41:17 -07001615 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1616 ringerMode = AudioManager.RINGER_MODE_SILENT;
1617 }
Glenn Kastenba195eb2011-12-13 09:30:40 -08001618 if (ringerMode != getRingerMode()) {
1619 setRingerModeInt(ringerMode, true);
1620 // Send sticky broadcast
1621 broadcastRingerMode(ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001622 }
1623 }
1624
Eric Laurent4050c932009-07-08 02:52:14 -07001625 private void setRingerModeInt(int ringerMode, boolean persist) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001626 synchronized(mSettingsLock) {
1627 mRingerMode = ringerMode;
1628 }
Jason Parekhb1096152009-03-24 17:48:25 -07001629
Eric Laurent5b4e6542010-03-19 20:02:21 -07001630 // Mute stream if not previously muted by ringer mode and ringer mode
1631 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
1632 // Unmute stream if previously muted by ringer mode and ringer mode
1633 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07001634 int numStreamTypes = AudioSystem.getNumStreamTypes();
Eric Laurent5b4e6542010-03-19 20:02:21 -07001635 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
1636 if (isStreamMutedByRingerMode(streamType)) {
1637 if (!isStreamAffectedByRingerMode(streamType) ||
Glenn Kastenba195eb2011-12-13 09:30:40 -08001638 ringerMode == AudioManager.RINGER_MODE_NORMAL) {
Eric Laurentb024c302011-10-14 17:19:27 -07001639 // ring and notifications volume should never be 0 when not silenced
1640 // on voice capable devices
Eric Laurent212532b2014-07-21 15:43:18 -07001641 if (isPlatformVoice() &&
Eric Laurent6d517662012-04-23 18:42:39 -07001642 mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07001643 synchronized (mStreamStates[streamType]) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001644 Set set = mStreamStates[streamType].mIndex.entrySet();
Eric Laurent3172d5e2012-05-09 11:38:16 -07001645 Iterator i = set.iterator();
1646 while (i.hasNext()) {
1647 Map.Entry entry = (Map.Entry)i.next();
1648 if ((Integer)entry.getValue() == 0) {
1649 entry.setValue(10);
1650 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001651 }
1652 }
Eric Laurentb024c302011-10-14 17:19:27 -07001653 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07001654 mStreamStates[streamType].mute(null, false);
1655 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent9bcf4012009-06-12 06:09:28 -07001656 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07001657 } else {
1658 if (isStreamAffectedByRingerMode(streamType) &&
Glenn Kastenba195eb2011-12-13 09:30:40 -08001659 ringerMode != AudioManager.RINGER_MODE_NORMAL) {
Eric Laurent5b4e6542010-03-19 20:02:21 -07001660 mStreamStates[streamType].mute(null, true);
1661 mRingerModeMutedStreams |= (1 << streamType);
1662 }
Jason Parekhb1096152009-03-24 17:48:25 -07001663 }
1664 }
Eric Laurenta553c252009-07-17 12:17:14 -07001665
Jason Parekhb1096152009-03-24 17:48:25 -07001666 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07001667 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08001668 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07001669 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
1670 }
Jason Parekhb1096152009-03-24 17:48:25 -07001671 }
1672
Mike Lockwood90631542012-01-06 11:20:37 -05001673 private void restoreMasterVolume() {
Eric Laurent83a017b2013-03-19 18:15:31 -07001674 if (mUseFixedVolume) {
1675 AudioSystem.setMasterVolume(1.0f);
1676 return;
1677 }
Mike Lockwood90631542012-01-06 11:20:37 -05001678 if (mUseMasterVolume) {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001679 float volume = Settings.System.getFloatForUser(mContentResolver,
1680 Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
Mike Lockwood90631542012-01-06 11:20:37 -05001681 if (volume >= 0.0f) {
1682 AudioSystem.setMasterVolume(volume);
1683 }
1684 }
1685 }
1686
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001687 /** @see AudioManager#shouldVibrate(int) */
1688 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001689 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690
1691 switch (getVibrateSetting(vibrateType)) {
1692
1693 case AudioManager.VIBRATE_SETTING_ON:
Glenn Kastenba195eb2011-12-13 09:30:40 -08001694 return getRingerMode() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001695
1696 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
Glenn Kastenba195eb2011-12-13 09:30:40 -08001697 return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001698
1699 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04001700 // return false, even for incoming calls
1701 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001702
1703 default:
1704 return false;
1705 }
1706 }
1707
1708 /** @see AudioManager#getVibrateSetting(int) */
1709 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001710 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001711 return (mVibrateSetting >> (vibrateType * 2)) & 3;
1712 }
1713
1714 /** @see AudioManager#setVibrateSetting(int, int) */
1715 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
1716
Eric Laurentbffc3d12012-05-07 17:43:49 -07001717 if (!mHasVibrator) return;
1718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
1720
1721 // Broadcast change
1722 broadcastVibrateSetting(vibrateType);
1723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001724 }
1725
1726 /**
1727 * @see #setVibrateSetting(int, int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001728 */
1729 public static int getValueForVibrateSetting(int existingValue, int vibrateType,
1730 int vibrateSetting) {
1731
1732 // First clear the existing setting. Each vibrate type has two bits in
1733 // the value. Note '3' is '11' in binary.
1734 existingValue &= ~(3 << (vibrateType * 2));
1735
1736 // Set into the old value
1737 existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
1738
1739 return existingValue;
1740 }
1741
Eric Laurent9272b4b2010-01-23 17:12:59 -08001742 private class SetModeDeathHandler implements IBinder.DeathRecipient {
1743 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07001744 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001745 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
1746
Eric Laurent9f103de2011-09-08 15:04:23 -07001747 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08001748 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07001749 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001750 }
1751
1752 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07001753 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001754 synchronized(mSetModeDeathHandlers) {
1755 Log.w(TAG, "setMode() client died");
1756 int index = mSetModeDeathHandlers.indexOf(this);
1757 if (index < 0) {
1758 Log.w(TAG, "unregistered setMode() client died");
1759 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07001760 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
Eric Laurent9272b4b2010-01-23 17:12:59 -08001761 }
1762 }
Eric Laurent9f103de2011-09-08 15:04:23 -07001763 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1764 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07001765 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07001766 final long ident = Binder.clearCallingIdentity();
1767 disconnectBluetoothSco(newModeOwnerPid);
1768 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07001769 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08001770 }
1771
Marco Nelissenf1ddd512011-08-10 14:15:44 -07001772 public int getPid() {
1773 return mPid;
1774 }
1775
Eric Laurent9272b4b2010-01-23 17:12:59 -08001776 public void setMode(int mode) {
1777 mMode = mode;
1778 }
1779
1780 public int getMode() {
1781 return mMode;
1782 }
1783
1784 public IBinder getBinder() {
1785 return mCb;
1786 }
1787 }
1788
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001789 /** @see AudioManager#setMode(int) */
Eric Laurent9272b4b2010-01-23 17:12:59 -08001790 public void setMode(int mode, IBinder cb) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001791 if (!checkAudioSettingsPermission("setMode()")) {
1792 return;
1793 }
Eric Laurenta553c252009-07-17 12:17:14 -07001794
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08001795 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07001796 return;
1797 }
1798
Eric Laurentd7454be2011-09-14 08:45:58 -07001799 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07001800 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07001801 if (mode == AudioSystem.MODE_CURRENT) {
1802 mode = mMode;
1803 }
Eric Laurentd7454be2011-09-14 08:45:58 -07001804 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
Eric Laurent9f103de2011-09-08 15:04:23 -07001805 }
1806 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1807 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07001808 if (newModeOwnerPid != 0) {
1809 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07001810 }
1811 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08001812
Eric Laurent9f103de2011-09-08 15:04:23 -07001813 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07001814 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07001815 // any mode other than NORMAL.
Eric Laurentd7454be2011-09-14 08:45:58 -07001816 int setModeInt(int mode, IBinder cb, int pid) {
1817 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07001818 if (cb == null) {
1819 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07001820 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07001821 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08001822
Eric Laurent9f103de2011-09-08 15:04:23 -07001823 SetModeDeathHandler hdlr = null;
1824 Iterator iter = mSetModeDeathHandlers.iterator();
1825 while (iter.hasNext()) {
1826 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
1827 if (h.getPid() == pid) {
1828 hdlr = h;
1829 // Remove from client list so that it is re-inserted at top of list
1830 iter.remove();
1831 hdlr.getBinder().unlinkToDeath(hdlr, 0);
1832 break;
1833 }
1834 }
1835 int status = AudioSystem.AUDIO_STATUS_OK;
1836 do {
1837 if (mode == AudioSystem.MODE_NORMAL) {
1838 // get new mode from client at top the list if any
1839 if (!mSetModeDeathHandlers.isEmpty()) {
1840 hdlr = mSetModeDeathHandlers.get(0);
1841 cb = hdlr.getBinder();
1842 mode = hdlr.getMode();
Eric Laurentb9c9d262009-05-06 08:13:20 -07001843 }
Eric Laurent9f103de2011-09-08 15:04:23 -07001844 } else {
1845 if (hdlr == null) {
1846 hdlr = new SetModeDeathHandler(cb, pid);
1847 }
1848 // Register for client death notification
1849 try {
1850 cb.linkToDeath(hdlr, 0);
1851 } catch (RemoteException e) {
1852 // Client has died!
1853 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
1854 }
1855
1856 // Last client to call setMode() is always at top of client list
1857 // as required by SetModeDeathHandler.binderDied()
1858 mSetModeDeathHandlers.add(0, hdlr);
1859 hdlr.setMode(mode);
1860 }
1861
1862 if (mode != mMode) {
1863 status = AudioSystem.setPhoneState(mode);
1864 if (status == AudioSystem.AUDIO_STATUS_OK) {
Eric Laurent9f103de2011-09-08 15:04:23 -07001865 mMode = mode;
1866 } else {
1867 if (hdlr != null) {
1868 mSetModeDeathHandlers.remove(hdlr);
1869 cb.unlinkToDeath(hdlr, 0);
1870 }
1871 // force reading new top of mSetModeDeathHandlers stack
1872 mode = AudioSystem.MODE_NORMAL;
1873 }
1874 } else {
1875 status = AudioSystem.AUDIO_STATUS_OK;
1876 }
1877 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
1878
1879 if (status == AudioSystem.AUDIO_STATUS_OK) {
1880 if (mode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07001881 if (mSetModeDeathHandlers.isEmpty()) {
1882 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
1883 } else {
1884 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
1885 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001886 }
1887 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07001888 if (streamType == STREAM_REMOTE_MUSIC) {
1889 // here handle remote media playback the same way as local playback
1890 streamType = AudioManager.STREAM_MUSIC;
1891 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001892 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001893 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
1894 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
Eric Laurent6d517662012-04-23 18:42:39 -07001895
1896 updateStreamVolumeAlias(true /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001897 }
Eric Laurentd7454be2011-09-14 08:45:58 -07001898 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001899 }
1900
1901 /** @see AudioManager#getMode() */
1902 public int getMode() {
1903 return mMode;
1904 }
1905
Eric Laurente78fced2013-03-15 16:03:47 -07001906 //==========================================================================================
1907 // Sound Effects
1908 //==========================================================================================
1909
1910 private static final String TAG_AUDIO_ASSETS = "audio_assets";
1911 private static final String ATTR_VERSION = "version";
1912 private static final String TAG_GROUP = "group";
1913 private static final String ATTR_GROUP_NAME = "name";
1914 private static final String TAG_ASSET = "asset";
1915 private static final String ATTR_ASSET_ID = "id";
1916 private static final String ATTR_ASSET_FILE = "file";
1917
1918 private static final String ASSET_FILE_VERSION = "1.0";
1919 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
1920
Glenn Kasten167d1a22013-07-23 16:24:41 -07001921 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001922
1923 class LoadSoundEffectReply {
1924 public int mStatus = 1;
1925 };
1926
Eric Laurente78fced2013-03-15 16:03:47 -07001927 private void loadTouchSoundAssetDefaults() {
1928 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
1929 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
1930 SOUND_EFFECT_FILES_MAP[i][0] = 0;
1931 SOUND_EFFECT_FILES_MAP[i][1] = -1;
1932 }
1933 }
1934
1935 private void loadTouchSoundAssets() {
1936 XmlResourceParser parser = null;
1937
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001938 // only load assets once.
1939 if (!SOUND_EFFECT_FILES.isEmpty()) {
1940 return;
1941 }
1942
Eric Laurente78fced2013-03-15 16:03:47 -07001943 loadTouchSoundAssetDefaults();
1944
1945 try {
1946 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
1947
1948 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
1949 String version = parser.getAttributeValue(null, ATTR_VERSION);
1950 boolean inTouchSoundsGroup = false;
1951
1952 if (ASSET_FILE_VERSION.equals(version)) {
1953 while (true) {
1954 XmlUtils.nextElement(parser);
1955 String element = parser.getName();
1956 if (element == null) {
1957 break;
1958 }
1959 if (element.equals(TAG_GROUP)) {
1960 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
1961 if (GROUP_TOUCH_SOUNDS.equals(name)) {
1962 inTouchSoundsGroup = true;
1963 break;
1964 }
1965 }
1966 }
1967 while (inTouchSoundsGroup) {
1968 XmlUtils.nextElement(parser);
1969 String element = parser.getName();
1970 if (element == null) {
1971 break;
1972 }
1973 if (element.equals(TAG_ASSET)) {
1974 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
1975 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
1976 int fx;
1977
1978 try {
1979 Field field = AudioManager.class.getField(id);
1980 fx = field.getInt(null);
1981 } catch (Exception e) {
1982 Log.w(TAG, "Invalid touch sound ID: "+id);
1983 continue;
1984 }
1985
1986 int i = SOUND_EFFECT_FILES.indexOf(file);
1987 if (i == -1) {
1988 i = SOUND_EFFECT_FILES.size();
1989 SOUND_EFFECT_FILES.add(file);
1990 }
1991 SOUND_EFFECT_FILES_MAP[fx][0] = i;
1992 } else {
1993 break;
1994 }
1995 }
1996 }
1997 } catch (Resources.NotFoundException e) {
1998 Log.w(TAG, "audio assets file not found", e);
1999 } catch (XmlPullParserException e) {
2000 Log.w(TAG, "XML parser exception reading touch sound assets", e);
2001 } catch (IOException e) {
2002 Log.w(TAG, "I/O exception reading touch sound assets", e);
2003 } finally {
2004 if (parser != null) {
2005 parser.close();
2006 }
2007 }
2008 }
2009
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002010 /** @see AudioManager#playSoundEffect(int) */
2011 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002012 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002013 }
2014
2015 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002016 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07002017 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
2018 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
2019 return;
2020 }
2021
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002022 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002023 effectType, (int) (volume * 1000), null, 0);
2024 }
2025
2026 /**
2027 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08002028 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002029 */
2030 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002031 int attempts = 3;
2032 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08002033
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002034 synchronized (reply) {
2035 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
2036 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08002037 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07002038 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002039 } catch (InterruptedException e) {
2040 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08002041 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002042 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002043 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002044 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002045 }
2046
2047 /**
2048 * Unloads samples from the sound pool.
2049 * This method can be called to free some memory when
2050 * sound effects are disabled.
2051 */
2052 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002053 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 }
2055
Eric Laurenta60e2122010-12-28 16:49:07 -08002056 class SoundPoolListenerThread extends Thread {
2057 public SoundPoolListenerThread() {
2058 super("SoundPoolListenerThread");
2059 }
2060
2061 @Override
2062 public void run() {
2063
2064 Looper.prepare();
2065 mSoundPoolLooper = Looper.myLooper();
2066
2067 synchronized (mSoundEffectsLock) {
2068 if (mSoundPool != null) {
2069 mSoundPoolCallBack = new SoundPoolCallback();
2070 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2071 }
2072 mSoundEffectsLock.notify();
2073 }
2074 Looper.loop();
2075 }
2076 }
2077
2078 private final class SoundPoolCallback implements
2079 android.media.SoundPool.OnLoadCompleteListener {
2080
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002081 int mStatus = 1; // 1 means neither error nor last sample loaded yet
2082 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08002083
2084 public int status() {
2085 return mStatus;
2086 }
2087
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002088 public void setSamples(int[] samples) {
2089 for (int i = 0; i < samples.length; i++) {
2090 // do not wait ack for samples rejected upfront by SoundPool
2091 if (samples[i] > 0) {
2092 mSamples.add(samples[i]);
2093 }
2094 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002095 }
2096
2097 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2098 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002099 int i = mSamples.indexOf(sampleId);
2100 if (i >= 0) {
2101 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08002102 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002103 if ((status != 0) || mSamples. isEmpty()) {
2104 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08002105 mSoundEffectsLock.notify();
2106 }
2107 }
2108 }
2109 }
2110
Eric Laurent4050c932009-07-08 02:52:14 -07002111 /** @see AudioManager#reloadAudioSettings() */
2112 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002113 readAudioSettings(false /*userSwitch*/);
2114 }
2115
2116 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07002117 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2118 readPersistedSettings();
2119
2120 // restore volume settings
2121 int numStreamTypes = AudioSystem.getNumStreamTypes();
2122 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2123 VolumeStreamState streamState = mStreamStates[streamType];
2124
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002125 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2126 continue;
2127 }
2128
Eric Laurent3172d5e2012-05-09 11:38:16 -07002129 synchronized (streamState) {
2130 streamState.readSettings();
Eric Laurenta553c252009-07-17 12:17:14 -07002131
Eric Laurent3172d5e2012-05-09 11:38:16 -07002132 // unmute stream that was muted but is not affect by mute anymore
Eric Laurent42b041e2013-03-29 11:36:03 -07002133 if (streamState.isMuted() && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07002134 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002135 int size = streamState.mDeathHandlers.size();
2136 for (int i = 0; i < size; i++) {
2137 streamState.mDeathHandlers.get(i).mMuteCount = 1;
2138 streamState.mDeathHandlers.get(i).mute(false);
2139 }
Eric Laurent4050c932009-07-08 02:52:14 -07002140 }
Eric Laurent4050c932009-07-08 02:52:14 -07002141 }
2142 }
2143
Eric Laurent33902db2012-10-07 16:15:07 -07002144 // apply new ringer mode before checking volume for alias streams so that streams
2145 // muted by ringer mode have the correct volume
2146 setRingerModeInt(getRingerMode(), false);
2147
Eric Laurent212532b2014-07-21 15:43:18 -07002148 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07002149 checkAllAliasStreamVolumes();
2150
Eric Laurentd640bd32012-09-28 18:01:48 -07002151 synchronized (mSafeMediaVolumeState) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002152 mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2153 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2154 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
Eric Laurentd640bd32012-09-28 18:01:48 -07002155 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07002156 enforceSafeMediaVolume();
2157 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07002158 }
Eric Laurent4050c932009-07-08 02:52:14 -07002159 }
2160
Dianne Hackborn961cae92013-03-20 14:59:43 -07002161 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002162 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002163 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2164 return;
2165 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002166
2167 if (on) {
2168 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2169 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2170 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
2171 }
2172 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2173 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2174 mForcedUseForComm = AudioSystem.FORCE_NONE;
2175 }
Eric Laurentfa640152011-03-12 15:59:51 -08002176
Eric Laurentafbb0472011-12-15 09:04:23 -08002177 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002178 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002179 }
2180
2181 /** @see AudioManager#isSpeakerphoneOn() */
2182 public boolean isSpeakerphoneOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002183 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002184 }
2185
Dianne Hackborn961cae92013-03-20 14:59:43 -07002186 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002187 public void setBluetoothScoOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002188 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2189 return;
2190 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002191
2192 if (on) {
2193 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2194 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2195 mForcedUseForComm = AudioSystem.FORCE_NONE;
2196 }
Eric Laurentfa640152011-03-12 15:59:51 -08002197
Eric Laurentafbb0472011-12-15 09:04:23 -08002198 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002199 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08002200 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002201 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002202 }
2203
2204 /** @see AudioManager#isBluetoothScoOn() */
2205 public boolean isBluetoothScoOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002206 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002207 }
2208
Dianne Hackborn961cae92013-03-20 14:59:43 -07002209 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07002210 public void setBluetoothA2dpOn(boolean on) {
Eric Laurentc390bed2012-07-03 12:24:05 -07002211 synchronized (mBluetoothA2dpEnabledLock) {
2212 mBluetoothA2dpEnabled = on;
2213 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2214 AudioSystem.FOR_MEDIA,
2215 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2216 null, 0);
2217 }
Eric Laurent78472112012-05-21 08:57:21 -07002218 }
2219
2220 /** @see AudioManager#isBluetoothA2dpOn() */
2221 public boolean isBluetoothA2dpOn() {
2222 synchronized (mBluetoothA2dpEnabledLock) {
2223 return mBluetoothA2dpEnabled;
2224 }
2225 }
2226
Eric Laurent3def1ee2010-03-17 23:26:26 -07002227 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07002228 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
2229 int scoAudioMode =
2230 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
Liejun Taof4e51d82014-07-16 11:18:29 -07002231 SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
Eric Laurent83900752014-05-15 15:14:22 -07002232 startBluetoothScoInt(cb, scoAudioMode);
2233 }
2234
2235 /** @see AudioManager#startBluetoothScoVirtualCall() */
2236 public void startBluetoothScoVirtualCall(IBinder cb) {
2237 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
2238 }
2239
2240 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07002241 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002242 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002243 return;
2244 }
Eric Laurent854938a2011-02-22 12:05:20 -08002245 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002246 // The calling identity must be cleared before calling ScoClient.incCount().
2247 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2248 // and this must be done on behalf of system server to make sure permissions are granted.
2249 // The caller identity must be cleared after getScoClient() because it is needed if a new
2250 // client is created.
2251 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07002252 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08002253 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002254 }
2255
2256 /** @see AudioManager#stopBluetoothSco() */
2257 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07002258 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002259 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002260 return;
2261 }
Eric Laurent854938a2011-02-22 12:05:20 -08002262 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002263 // The calling identity must be cleared before calling ScoClient.decCount().
2264 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2265 // and this must be done on behalf of system server to make sure permissions are granted.
2266 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08002267 if (client != null) {
2268 client.decCount();
2269 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08002270 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002271 }
2272
Eric Laurent78472112012-05-21 08:57:21 -07002273
Eric Laurent3def1ee2010-03-17 23:26:26 -07002274 private class ScoClient implements IBinder.DeathRecipient {
2275 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002276 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002277 private int mStartcount; // number of SCO connections started by this client
2278
2279 ScoClient(IBinder cb) {
2280 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002281 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002282 mStartcount = 0;
2283 }
2284
2285 public void binderDied() {
2286 synchronized(mScoClients) {
2287 Log.w(TAG, "SCO client died");
2288 int index = mScoClients.indexOf(this);
2289 if (index < 0) {
2290 Log.w(TAG, "unregistered SCO client died");
2291 } else {
2292 clearCount(true);
2293 mScoClients.remove(this);
2294 }
2295 }
2296 }
2297
Eric Laurent83900752014-05-15 15:14:22 -07002298 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002299 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07002300 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002301 if (mStartcount == 0) {
2302 try {
2303 mCb.linkToDeath(this, 0);
2304 } catch (RemoteException e) {
2305 // client has already died!
2306 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
2307 }
2308 }
2309 mStartcount++;
2310 }
2311 }
2312
2313 public void decCount() {
2314 synchronized(mScoClients) {
2315 if (mStartcount == 0) {
2316 Log.w(TAG, "ScoClient.decCount() already 0");
2317 } else {
2318 mStartcount--;
2319 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002320 try {
2321 mCb.unlinkToDeath(this, 0);
2322 } catch (NoSuchElementException e) {
2323 Log.w(TAG, "decCount() going to 0 but not registered to binder");
2324 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002325 }
Eric Laurentc18c9132013-04-12 17:24:56 -07002326 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002327 }
2328 }
2329 }
2330
2331 public void clearCount(boolean stopSco) {
2332 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002333 if (mStartcount != 0) {
2334 try {
2335 mCb.unlinkToDeath(this, 0);
2336 } catch (NoSuchElementException e) {
2337 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2338 }
2339 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002340 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002341 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002342 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002343 }
2344 }
2345 }
2346
2347 public int getCount() {
2348 return mStartcount;
2349 }
2350
2351 public IBinder getBinder() {
2352 return mCb;
2353 }
2354
Eric Laurentd7454be2011-09-14 08:45:58 -07002355 public int getPid() {
2356 return mCreatorPid;
2357 }
2358
Eric Laurent3def1ee2010-03-17 23:26:26 -07002359 public int totalCount() {
2360 synchronized(mScoClients) {
2361 int count = 0;
2362 int size = mScoClients.size();
2363 for (int i = 0; i < size; i++) {
2364 count += mScoClients.get(i).getCount();
2365 }
2366 return count;
2367 }
2368 }
2369
Eric Laurent83900752014-05-15 15:14:22 -07002370 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08002371 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07002372 if (totalCount() == 0) {
2373 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2374 // Make sure that the state transitions to CONNECTING even if we cannot initiate
2375 // the connection.
2376 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2377 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002378 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07002379 synchronized(mSetModeDeathHandlers) {
2380 if ((mSetModeDeathHandlers.isEmpty() ||
2381 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2382 (mScoAudioState == SCO_STATE_INACTIVE ||
2383 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2384 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07002385 mScoAudioMode = scoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -07002386 if (scoAudioMode == SCO_MODE_UNDEFINED) {
2387 mScoAudioMode = new Integer(Settings.Global.getInt(
2388 mContentResolver,
2389 "bluetooth_sco_channel_"+
2390 mBluetoothHeadsetDevice.getAddress(),
2391 SCO_MODE_VIRTUAL_CALL));
2392 if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2393 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2394 }
2395 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002396 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002397 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002398 if (mScoAudioMode == SCO_MODE_RAW) {
2399 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002400 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002401 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2402 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002403 } else if (mScoAudioMode == SCO_MODE_VR) {
2404 status = mBluetoothHeadset.startVoiceRecognition(
2405 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002406 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002407
Eric Laurentc18c9132013-04-12 17:24:56 -07002408 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07002409 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2410 } else {
2411 broadcastScoConnectionState(
2412 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2413 }
2414 } else if (getBluetoothHeadset()) {
2415 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07002416 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002417 } else {
2418 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2419 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002420 }
2421 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07002422 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002423 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002424 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002425 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002426 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2427 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2428 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07002429 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002430 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002431 if (mScoAudioMode == SCO_MODE_RAW) {
2432 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002433 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002434 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2435 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002436 } else if (mScoAudioMode == SCO_MODE_VR) {
2437 status = mBluetoothHeadset.stopVoiceRecognition(
2438 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002439 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002440
Eric Laurentc18c9132013-04-12 17:24:56 -07002441 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002442 mScoAudioState = SCO_STATE_INACTIVE;
2443 broadcastScoConnectionState(
2444 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2445 }
2446 } else if (getBluetoothHeadset()) {
2447 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2448 }
2449 } else {
2450 mScoAudioState = SCO_STATE_INACTIVE;
2451 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2452 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002453 }
2454 }
2455 }
2456 }
2457
Eric Laurent62ef7672010-11-24 10:58:32 -08002458 private void checkScoAudioState() {
2459 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002460 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08002461 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2462 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2463 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2464 }
2465 }
2466
Eric Laurent854938a2011-02-22 12:05:20 -08002467 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002468 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002469 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002470 int size = mScoClients.size();
2471 for (int i = 0; i < size; i++) {
2472 client = mScoClients.get(i);
2473 if (client.getBinder() == cb)
2474 return client;
2475 }
Eric Laurent854938a2011-02-22 12:05:20 -08002476 if (create) {
2477 client = new ScoClient(cb);
2478 mScoClients.add(client);
2479 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002480 return client;
2481 }
2482 }
2483
Eric Laurentd7454be2011-09-14 08:45:58 -07002484 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002485 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002486 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002487 int size = mScoClients.size();
2488 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08002489 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07002490 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08002491 cl.clearCount(stopSco);
2492 } else {
2493 savedClient = cl;
2494 }
2495 }
2496 mScoClients.clear();
2497 if (savedClient != null) {
2498 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002499 }
2500 }
2501 }
2502
Eric Laurentdc03c612011-04-01 10:59:41 -07002503 private boolean getBluetoothHeadset() {
2504 boolean result = false;
2505 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2506 if (adapter != null) {
2507 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2508 BluetoothProfile.HEADSET);
2509 }
2510 // If we could not get a bluetooth headset proxy, send a failure message
2511 // without delay to reset the SCO audio state and clear SCO clients.
2512 // If we could get a proxy, send a delayed failure message that will reset our state
2513 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08002514 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002515 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2516 return result;
2517 }
2518
Eric Laurentd7454be2011-09-14 08:45:58 -07002519 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002520 synchronized(mScoClients) {
2521 checkScoAudioState();
2522 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2523 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2524 if (mBluetoothHeadsetDevice != null) {
2525 if (mBluetoothHeadset != null) {
2526 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07002527 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002528 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002529 SENDMSG_REPLACE, 0, 0, null, 0);
2530 }
2531 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2532 getBluetoothHeadset()) {
2533 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2534 }
2535 }
2536 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07002537 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07002538 }
2539 }
2540 }
2541
2542 private void resetBluetoothSco() {
2543 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002544 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07002545 mScoAudioState = SCO_STATE_INACTIVE;
2546 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2547 }
2548 }
2549
2550 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08002551 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
2552 SENDMSG_QUEUE, state, 0, null, 0);
2553 }
2554
2555 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002556 if (state != mScoConnectionState) {
2557 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2558 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2559 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2560 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002561 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07002562 mScoConnectionState = state;
2563 }
2564 }
2565
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002566 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
2567 new BluetoothProfile.ServiceListener() {
2568 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002569 BluetoothDevice btDevice;
2570 List<BluetoothDevice> deviceList;
2571 switch(profile) {
2572 case BluetoothProfile.A2DP:
John Du5a0cf7a2013-07-19 11:30:34 -07002573 synchronized (mA2dpAvrcpLock) {
2574 mA2dp = (BluetoothA2dp) proxy;
2575 deviceList = mA2dp.getConnectedDevices();
2576 if (deviceList.size() > 0) {
2577 btDevice = deviceList.get(0);
2578 synchronized (mConnectedDevices) {
2579 int state = mA2dp.getConnectionState(btDevice);
2580 int delay = checkSendBecomingNoisyIntent(
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002581 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2582 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
John Du5a0cf7a2013-07-19 11:30:34 -07002583 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002584 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07002585 state,
2586 0,
2587 btDevice,
2588 delay);
2589 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002590 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002591 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002592 break;
2593
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002594 case BluetoothProfile.A2DP_SINK:
2595 deviceList = proxy.getConnectedDevices();
2596 if (deviceList.size() > 0) {
2597 btDevice = deviceList.get(0);
2598 synchronized (mConnectedDevices) {
2599 int state = proxy.getConnectionState(btDevice);
2600 queueMsgUnderWakeLock(mAudioHandler,
2601 MSG_SET_A2DP_SRC_CONNECTION_STATE,
2602 state,
2603 0,
2604 btDevice,
2605 0 /* delay */);
2606 }
2607 }
2608 break;
2609
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002610 case BluetoothProfile.HEADSET:
2611 synchronized (mScoClients) {
2612 // Discard timeout message
2613 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
2614 mBluetoothHeadset = (BluetoothHeadset) proxy;
2615 deviceList = mBluetoothHeadset.getConnectedDevices();
2616 if (deviceList.size() > 0) {
2617 mBluetoothHeadsetDevice = deviceList.get(0);
2618 } else {
2619 mBluetoothHeadsetDevice = null;
2620 }
2621 // Refresh SCO audio state
2622 checkScoAudioState();
2623 // Continue pending action if any
2624 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
2625 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
2626 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2627 boolean status = false;
2628 if (mBluetoothHeadsetDevice != null) {
2629 switch (mScoAudioState) {
2630 case SCO_STATE_ACTIVATE_REQ:
2631 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07002632 if (mScoAudioMode == SCO_MODE_RAW) {
2633 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002634 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002635 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2636 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002637 } else if (mScoAudioMode == SCO_MODE_VR) {
2638 status = mBluetoothHeadset.startVoiceRecognition(
2639 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002640 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002641 break;
2642 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07002643 if (mScoAudioMode == SCO_MODE_RAW) {
2644 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002645 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002646 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2647 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002648 } else if (mScoAudioMode == SCO_MODE_VR) {
2649 status = mBluetoothHeadset.stopVoiceRecognition(
2650 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002651 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002652 break;
2653 case SCO_STATE_DEACTIVATE_EXT_REQ:
2654 status = mBluetoothHeadset.stopVoiceRecognition(
2655 mBluetoothHeadsetDevice);
2656 }
2657 }
2658 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002659 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002660 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07002661 }
2662 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002663 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002664 break;
2665
2666 default:
2667 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002668 }
2669 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002670 public void onServiceDisconnected(int profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002671 switch(profile) {
2672 case BluetoothProfile.A2DP:
John Du5a0cf7a2013-07-19 11:30:34 -07002673 synchronized (mA2dpAvrcpLock) {
2674 mA2dp = null;
2675 synchronized (mConnectedDevices) {
2676 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
2677 makeA2dpDeviceUnavailableNow(
2678 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
2679 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002680 }
2681 }
2682 break;
2683
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002684 case BluetoothProfile.A2DP_SINK:
2685 synchronized (mConnectedDevices) {
2686 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) {
2687 makeA2dpSrcUnavailable(
2688 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP));
2689 }
2690 }
2691 break;
2692
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002693 case BluetoothProfile.HEADSET:
2694 synchronized (mScoClients) {
2695 mBluetoothHeadset = null;
2696 }
2697 break;
2698
2699 default:
2700 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002701 }
2702 }
2703 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08002704
Eric Laurentc34dcc12012-09-10 13:51:52 -07002705 private void onCheckMusicActive() {
Eric Laurentd640bd32012-09-28 18:01:48 -07002706 synchronized (mSafeMediaVolumeState) {
2707 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002708 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
2709
2710 if ((device & mSafeMediaVolumeDevices) != 0) {
2711 sendMsg(mAudioHandler,
2712 MSG_CHECK_MUSIC_ACTIVE,
2713 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07002714 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07002715 0,
2716 null,
2717 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07002718 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07002719 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
2720 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002721 // Approximate cumulative active music time
2722 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
2723 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
2724 setSafeMediaVolumeEnabled(true);
2725 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07002726 }
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002727 saveMusicActiveMs();
Eric Laurentc34dcc12012-09-10 13:51:52 -07002728 }
2729 }
2730 }
2731 }
2732 }
2733
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002734 private void saveMusicActiveMs() {
2735 mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
2736 }
2737
Eric Laurentd640bd32012-09-28 18:01:48 -07002738 private void onConfigureSafeVolume(boolean force) {
2739 synchronized (mSafeMediaVolumeState) {
2740 int mcc = mContext.getResources().getConfiguration().mcc;
2741 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
2742 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
2743 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
John Spurlock35134602014-07-24 18:10:48 -04002744 boolean safeMediaVolumeEnabled =
2745 SystemProperties.getBoolean("audio.safemedia.force", false)
2746 || mContext.getResources().getBoolean(
2747 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08002748
2749 // The persisted state is either "disabled" or "active": this is the state applied
2750 // next time we boot and cannot be "inactive"
2751 int persistedState;
Eric Laurentd640bd32012-09-28 18:01:48 -07002752 if (safeMediaVolumeEnabled) {
Eric Laurent05274f32012-11-29 12:48:18 -08002753 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
2754 // The state can already be "inactive" here if the user has forced it before
2755 // the 30 seconds timeout for forced configuration. In this case we don't reset
2756 // it to "active".
2757 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002758 if (mMusicActiveMs == 0) {
2759 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
2760 enforceSafeMediaVolume();
2761 } else {
2762 // We have existing playback time recorded, already confirmed.
2763 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
2764 }
Eric Laurent05274f32012-11-29 12:48:18 -08002765 }
Eric Laurentd640bd32012-09-28 18:01:48 -07002766 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08002767 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07002768 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
2769 }
2770 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08002771 sendMsg(mAudioHandler,
2772 MSG_PERSIST_SAFE_VOLUME_STATE,
2773 SENDMSG_QUEUE,
2774 persistedState,
2775 0,
2776 null,
2777 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07002778 }
2779 }
2780 }
2781
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002782 ///////////////////////////////////////////////////////////////////////////
2783 // Internal methods
2784 ///////////////////////////////////////////////////////////////////////////
2785
2786 /**
2787 * Checks if the adjustment should change ringer mode instead of just
2788 * adjusting volume. If so, this will set the proper ringer mode and volume
2789 * indices on the stream states.
2790 */
John Spurlocka11b4af2014-06-01 11:52:23 -04002791 private int checkForRingerModeChange(int oldIndex, int direction, int step) {
2792 int result = FLAG_ADJUST_VOLUME;
Glenn Kastenba195eb2011-12-13 09:30:40 -08002793 int ringerMode = getRingerMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002794
Eric Laurentbffc3d12012-05-07 17:43:49 -07002795 switch (ringerMode) {
2796 case RINGER_MODE_NORMAL:
2797 if (direction == AudioManager.ADJUST_LOWER) {
2798 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07002799 // "step" is the delta in internal index units corresponding to a
2800 // change of 1 in UI index units.
2801 // Because of rounding when rescaling from one stream index range to its alias
2802 // index range, we cannot simply test oldIndex == step:
2803 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
2804 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002805 ringerMode = RINGER_MODE_VIBRATE;
2806 }
2807 } else {
Eric Laurent24482012012-05-10 09:41:17 -07002808 // (oldIndex < step) is equivalent to (old UI index == 0)
John Spurlock86005342014-05-23 11:58:00 -04002809 if ((oldIndex < step)
2810 && VOLUME_SETS_RINGER_MODE_SILENT
2811 && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002812 ringerMode = RINGER_MODE_SILENT;
2813 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07002814 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002815 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07002816 break;
2817 case RINGER_MODE_VIBRATE:
2818 if (!mHasVibrator) {
2819 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
2820 "but no vibrator is present");
2821 break;
2822 }
Amith Yamasanic696a532011-10-28 17:02:37 -07002823 if ((direction == AudioManager.ADJUST_LOWER)) {
John Spurlock86005342014-05-23 11:58:00 -04002824 if (VOLUME_SETS_RINGER_MODE_SILENT
2825 && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002826 ringerMode = RINGER_MODE_SILENT;
Amith Yamasanic696a532011-10-28 17:02:37 -07002827 }
2828 } else if (direction == AudioManager.ADJUST_RAISE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002829 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07002830 }
John Spurlocka11b4af2014-06-01 11:52:23 -04002831 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07002832 break;
2833 case RINGER_MODE_SILENT:
Daniel Sandler6329bf72010-02-26 15:17:44 -05002834 if (direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04002835 if (PREVENT_VOLUME_ADJUSTMENT_IF_SILENT) {
2836 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07002837 } else {
John Spurlocka11b4af2014-06-01 11:52:23 -04002838 if (mHasVibrator) {
2839 ringerMode = RINGER_MODE_VIBRATE;
2840 } else {
2841 ringerMode = RINGER_MODE_NORMAL;
2842 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07002843 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05002844 }
John Spurlocka11b4af2014-06-01 11:52:23 -04002845 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07002846 break;
2847 default:
2848 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
2849 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002850 }
2851
Eric Laurentbffc3d12012-05-07 17:43:49 -07002852 setRingerMode(ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002853
Eric Laurent25101b02011-02-02 09:33:30 -08002854 mPrevVolDirection = direction;
2855
John Spurlocka11b4af2014-06-01 11:52:23 -04002856 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002857 }
2858
John Spurlock3346a802014-05-20 16:25:37 -04002859 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002860 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07002861 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002862 }
2863
Eric Laurent5b4e6542010-03-19 20:02:21 -07002864 private boolean isStreamMutedByRingerMode(int streamType) {
2865 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
2866 }
2867
Eric Laurent24e0d9b2013-10-03 18:15:07 -07002868 boolean updateRingerModeAffectedStreams() {
2869 int ringerModeAffectedStreams;
2870 // make sure settings for ringer mode are consistent with device type: non voice capable
2871 // devices (tablets) include media stream in silent mode whereas phones don't.
2872 ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
2873 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
2874 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
2875 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
2876 UserHandle.USER_CURRENT);
2877
2878 // ringtone, notification and system streams are always affected by ringer mode
2879 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
2880 (1 << AudioSystem.STREAM_NOTIFICATION)|
2881 (1 << AudioSystem.STREAM_SYSTEM);
2882
Eric Laurent212532b2014-07-21 15:43:18 -07002883 switch (mPlatformType) {
2884 case PLATFORM_VOICE:
2885 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
2886 break;
2887 case PLATFORM_TELEVISION:
2888 ringerModeAffectedStreams = 0;
2889 break;
2890 default:
2891 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
2892 break;
Eric Laurent24e0d9b2013-10-03 18:15:07 -07002893 }
Eric Laurent212532b2014-07-21 15:43:18 -07002894
Eric Laurent24e0d9b2013-10-03 18:15:07 -07002895 synchronized (mCameraSoundForced) {
2896 if (mCameraSoundForced) {
2897 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
2898 } else {
2899 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
2900 }
2901 }
2902 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
2903 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
2904 } else {
2905 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
2906 }
2907
2908 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
2909 Settings.System.putIntForUser(mContentResolver,
2910 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
2911 ringerModeAffectedStreams,
2912 UserHandle.USER_CURRENT);
2913 mRingerModeAffectedStreams = ringerModeAffectedStreams;
2914 return true;
2915 }
2916 return false;
2917 }
2918
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002919 public boolean isStreamAffectedByMute(int streamType) {
2920 return (mMuteAffectedStreams & (1 << streamType)) != 0;
2921 }
2922
2923 private void ensureValidDirection(int direction) {
2924 if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
2925 throw new IllegalArgumentException("Bad direction " + direction);
2926 }
2927 }
2928
Lei Zhang6c798972012-03-02 11:40:12 -08002929 private void ensureValidSteps(int steps) {
2930 if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
2931 throw new IllegalArgumentException("Bad volume adjust steps " + steps);
2932 }
2933 }
2934
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002935 private void ensureValidStreamType(int streamType) {
2936 if (streamType < 0 || streamType >= mStreamStates.length) {
2937 throw new IllegalArgumentException("Bad stream type " + streamType);
2938 }
2939 }
2940
Eric Laurent6d517662012-04-23 18:42:39 -07002941 private boolean isInCommunication() {
Santos Cordon9eb45932014-06-27 12:28:43 -07002942 boolean isInAPhoneCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002943
Santos Cordon9eb45932014-06-27 12:28:43 -07002944 TelecommManager telecommManager =
2945 (TelecommManager) mContext.getSystemService(Context.TELECOMM_SERVICE);
2946 isInAPhoneCall = telecommManager.isInAPhoneCall();
2947
2948 return (isInAPhoneCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
Eric Laurent6d517662012-04-23 18:42:39 -07002949 }
Eric Laurent25101b02011-02-02 09:33:30 -08002950
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002951 /**
2952 * For code clarity for getActiveStreamType(int)
2953 * @param delay_ms max time since last STREAM_MUSIC activity to consider
2954 * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
2955 * in the last "delay_ms" ms.
2956 */
2957 private boolean isAfMusicActiveRecently(int delay_ms) {
2958 return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
2959 || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
2960 }
2961
Eric Laurent6d517662012-04-23 18:42:39 -07002962 private int getActiveStreamType(int suggestedStreamType) {
Eric Laurent212532b2014-07-21 15:43:18 -07002963 switch (mPlatformType) {
2964 case PLATFORM_VOICE:
Eric Laurent6d517662012-04-23 18:42:39 -07002965 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08002966 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
2967 == AudioSystem.FORCE_BT_SCO) {
2968 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
2969 return AudioSystem.STREAM_BLUETOOTH_SCO;
2970 } else {
2971 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
2972 return AudioSystem.STREAM_VOICE_CALL;
2973 }
Eric Laurent25101b02011-02-02 09:33:30 -08002974 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002975 if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002976 if (DEBUG_VOL)
2977 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
2978 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002979 } else
2980 if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC))
2981 {
2982 if (DEBUG_VOL)
2983 Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
2984 return STREAM_REMOTE_MUSIC;
2985 } else {
2986 if (DEBUG_VOL)
2987 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
2988 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002989 }
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002990 } else if (isAfMusicActiveRecently(0)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002991 if (DEBUG_VOL)
2992 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
2993 return AudioSystem.STREAM_MUSIC;
Eric Laurent25101b02011-02-02 09:33:30 -08002994 }
Eric Laurent212532b2014-07-21 15:43:18 -07002995 break;
2996 case PLATFORM_TELEVISION:
2997 if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
2998 if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
2999 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
3000 return AudioSystem.STREAM_MUSIC;
3001 } else if (mMediaFocusControl.checkUpdateRemoteStateIfActive(
3002 AudioSystem.STREAM_MUSIC)) {
3003 if (DEBUG_VOL)
3004 Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
3005 return STREAM_REMOTE_MUSIC;
3006 } else {
3007 if (DEBUG_VOL) Log.v(TAG,
3008 "getActiveStreamType: using STREAM_MUSIC as default");
3009 return AudioSystem.STREAM_MUSIC;
3010 }
3011 }
3012 break;
3013 default:
Eric Laurent6d517662012-04-23 18:42:39 -07003014 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003015 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3016 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003017 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08003018 return AudioSystem.STREAM_BLUETOOTH_SCO;
3019 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003020 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08003021 return AudioSystem.STREAM_VOICE_CALL;
3022 }
3023 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
Eric Laurent9903e262012-09-21 18:10:32 -07003024 DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS) ||
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003025 AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
Eric Laurent9903e262012-09-21 18:10:32 -07003026 DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003027 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08003028 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003029 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003030 if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
3031 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
3032 return AudioSystem.STREAM_MUSIC;
3033 } else
3034 if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC))
3035 {
3036 if (DEBUG_VOL)
3037 Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
3038 return STREAM_REMOTE_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003039 } else {
John Spurlockeb1d88d2014-07-19 14:49:19 -04003040 if (DEBUG_VOL) Log.v(TAG,
3041 "getActiveStreamType: using STREAM_NOTIFICATION as default");
3042 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003043 }
Joe Onoratoc7fcba42011-01-05 16:53:11 -08003044 }
Eric Laurent212532b2014-07-21 15:43:18 -07003045 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003046 }
Eric Laurent212532b2014-07-21 15:43:18 -07003047 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
3048 + suggestedStreamType);
3049 return suggestedStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003050 }
3051
Glenn Kastenba195eb2011-12-13 09:30:40 -08003052 private void broadcastRingerMode(int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003053 // Send sticky broadcast
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003054 Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION);
Glenn Kastenba195eb2011-12-13 09:30:40 -08003055 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003056 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
3057 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003058 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003059 }
3060
3061 private void broadcastVibrateSetting(int vibrateType) {
3062 // Send broadcast
3063 if (ActivityManagerNative.isSystemReady()) {
3064 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
3065 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
3066 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003067 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003068 }
3069 }
3070
3071 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003072 /**
3073 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
3074 * Note that the wake lock needs to be released after the message has been handled.
3075 */
3076 private void queueMsgUnderWakeLock(Handler handler, int msg,
3077 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003078 final long ident = Binder.clearCallingIdentity();
3079 // Always acquire the wake lock as AudioService because it is released by the
3080 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003081 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003082 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003083 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
3084 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003085
Eric Laurentafbb0472011-12-15 09:04:23 -08003086 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003087 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003088
3089 if (existingMsgPolicy == SENDMSG_REPLACE) {
3090 handler.removeMessages(msg);
3091 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
3092 return;
3093 }
3094
Eric Laurentafbb0472011-12-15 09:04:23 -08003095 handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003096 }
3097
3098 boolean checkAudioSettingsPermission(String method) {
3099 if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS")
3100 == PackageManager.PERMISSION_GRANTED) {
3101 return true;
3102 }
3103 String msg = "Audio Settings Permission Denial: " + method + " from pid="
3104 + Binder.getCallingPid()
3105 + ", uid=" + Binder.getCallingUid();
3106 Log.w(TAG, msg);
3107 return false;
3108 }
3109
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003110 private int getDeviceForStream(int stream) {
3111 int device = AudioSystem.getDevicesForStream(stream);
3112 if ((device & (device - 1)) != 0) {
3113 // Multiple device selection is either:
3114 // - speaker + one other device: give priority to speaker in this case.
3115 // - one A2DP device + another device: happens with duplicated output. In this case
3116 // retain the device on the A2DP output as the other must not correspond to an active
3117 // selection if not the speaker.
3118 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
3119 device = AudioSystem.DEVICE_OUT_SPEAKER;
3120 } else {
3121 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
3122 }
3123 }
3124 return device;
3125 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003126
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003127 public void setWiredDeviceConnectionState(int device, int state, String name) {
3128 synchronized (mConnectedDevices) {
3129 int delay = checkSendBecomingNoisyIntent(device, state);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003130 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003131 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003132 device,
3133 state,
3134 name,
3135 delay);
3136 }
3137 }
3138
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003139 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003140 {
3141 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003142 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
3143 throw new IllegalArgumentException("invalid profile " + profile);
3144 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003145 synchronized (mConnectedDevices) {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003146 if (profile == BluetoothProfile.A2DP) {
3147 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3148 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
3149 } else {
3150 delay = 0;
3151 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003152 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003153 (profile == BluetoothProfile.A2DP ?
3154 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003155 state,
3156 0,
3157 device,
3158 delay);
3159 }
3160 return delay;
3161 }
3162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003163 ///////////////////////////////////////////////////////////////////////////
3164 // Inner classes
3165 ///////////////////////////////////////////////////////////////////////////
3166
3167 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003168 private final int mStreamType;
3169
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003170 private String mVolumeIndexSettingName;
Eric Laurenta553c252009-07-17 12:17:14 -07003171 private int mIndexMax;
Eric Laurent3172d5e2012-05-09 11:38:16 -07003172 private final ConcurrentHashMap<Integer, Integer> mIndex =
3173 new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003174 private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003175
Eric Laurenta553c252009-07-17 12:17:14 -07003176 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003177
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003178 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003179
3180 mStreamType = streamType;
Jared Suttles59820132009-08-13 21:50:52 -05003181 mIndexMax = MAX_STREAM_VOLUME[streamType];
Eric Laurenta553c252009-07-17 12:17:14 -07003182 AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
3183 mIndexMax *= 10;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003184
Eric Laurent33902db2012-10-07 16:15:07 -07003185 // mDeathHandlers must be created before calling readSettings()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003186 mDeathHandlers = new ArrayList<VolumeDeathHandler>();
Eric Laurent33902db2012-10-07 16:15:07 -07003187
3188 readSettings();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003189 }
3190
Eric Laurent42b041e2013-03-29 11:36:03 -07003191 public String getSettingNameForDevice(int device) {
3192 String name = mVolumeIndexSettingName;
Eric Laurent948d3272014-05-16 15:18:45 -07003193 String suffix = AudioSystem.getOutputDeviceName(device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003194 if (suffix.isEmpty()) {
3195 return name;
3196 }
3197 return name + "_" + suffix;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003198 }
3199
Eric Laurentfdbee862014-05-12 15:26:12 -07003200 public void readSettings() {
3201 synchronized (VolumeStreamState.class) {
3202 // force maximum volume on all streams if fixed volume property is set
3203 if (mUseFixedVolume) {
3204 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
3205 return;
3206 }
3207 // do not read system stream volume from settings: this stream is always aliased
3208 // to another stream type and its volume is never persisted. Values in settings can
3209 // only be stale values
3210 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3211 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
3212 int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
3213 synchronized (mCameraSoundForced) {
3214 if (mCameraSoundForced) {
3215 index = mIndexMax;
3216 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003217 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003218 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
3219 return;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003220 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003221
Eric Laurentfdbee862014-05-12 15:26:12 -07003222 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
3223
3224 for (int i = 0; remainingDevices != 0; i++) {
3225 int device = (1 << i);
3226 if ((device & remainingDevices) == 0) {
3227 continue;
3228 }
3229 remainingDevices &= ~device;
3230
3231 // retrieve current volume for device
3232 String name = getSettingNameForDevice(device);
3233 // if no volume stored for current stream and device, use default volume if default
3234 // device, continue otherwise
3235 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
3236 AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
3237 int index = Settings.System.getIntForUser(
3238 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3239 if (index == -1) {
3240 continue;
3241 }
3242
Eric Laurent212532b2014-07-21 15:43:18 -07003243 mIndex.put(device, getValidIndex(10 * index));
Eric Laurentdd45d012012-10-08 09:04:34 -07003244 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003245 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003246 }
3247
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003248 public void applyDeviceVolume(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003249 int index;
3250 if (isMuted()) {
3251 index = 0;
Eric Laurentcd772d02013-10-30 18:31:07 -07003252 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003253 mAvrcpAbsVolSupported) {
3254 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07003255 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07003256 index = (getIndex(device) + 5)/10;
3257 }
3258 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003259 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003260
Eric Laurentfdbee862014-05-12 15:26:12 -07003261 public void applyAllVolumes() {
3262 synchronized (VolumeStreamState.class) {
3263 // apply default volume first: by convention this will reset all
3264 // devices volumes in audio policy manager to the supplied value
3265 int index;
3266 if (isMuted()) {
3267 index = 0;
3268 } else {
3269 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3270 }
3271 AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3272 // then apply device specific volumes
3273 Set set = mIndex.entrySet();
3274 Iterator i = set.iterator();
3275 while (i.hasNext()) {
3276 Map.Entry entry = (Map.Entry)i.next();
3277 int device = ((Integer)entry.getKey()).intValue();
3278 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
3279 if (isMuted()) {
3280 index = 0;
3281 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3282 mAvrcpAbsVolSupported) {
3283 index = (mIndexMax + 5)/10;
3284 } else {
3285 index = ((Integer)entry.getValue() + 5)/10;
3286 }
3287 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07003288 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003289 }
3290 }
3291 }
3292
3293 public boolean adjustIndex(int deltaIndex, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003294 return setIndex(getIndex(device) + deltaIndex,
3295 device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003296 }
3297
Eric Laurentfdbee862014-05-12 15:26:12 -07003298 public boolean setIndex(int index, int device) {
3299 synchronized (VolumeStreamState.class) {
3300 int oldIndex = getIndex(device);
3301 index = getValidIndex(index);
3302 synchronized (mCameraSoundForced) {
3303 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3304 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07003305 }
3306 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003307 mIndex.put(device, index);
3308
3309 if (oldIndex != index) {
3310 // Apply change to all streams using this one as alias
3311 // if changing volume of current device, also change volume of current
3312 // device on aliased stream
3313 boolean currentDevice = (device == getDeviceForStream(mStreamType));
3314 int numStreamTypes = AudioSystem.getNumStreamTypes();
3315 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3316 if (streamType != mStreamType &&
3317 mStreamVolumeAlias[streamType] == mStreamType) {
3318 int scaledIndex = rescaleIndex(index, mStreamType, streamType);
3319 mStreamStates[streamType].setIndex(scaledIndex,
3320 device);
3321 if (currentDevice) {
3322 mStreamStates[streamType].setIndex(scaledIndex,
3323 getDeviceForStream(streamType));
3324 }
3325 }
3326 }
3327 return true;
3328 } else {
3329 return false;
3330 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003331 }
3332 }
3333
Eric Laurentfdbee862014-05-12 15:26:12 -07003334 public int getIndex(int device) {
3335 synchronized (VolumeStreamState.class) {
3336 Integer index = mIndex.get(device);
3337 if (index == null) {
3338 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
3339 index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
3340 }
3341 return index.intValue();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003342 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07003343 }
3344
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003345 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07003346 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003347 }
3348
Eric Laurentfdbee862014-05-12 15:26:12 -07003349 public void setAllIndexes(VolumeStreamState srcStream) {
3350 synchronized (VolumeStreamState.class) {
3351 int srcStreamType = srcStream.getStreamType();
3352 // apply default device volume from source stream to all devices first in case
3353 // some devices are present in this stream state but not in source stream state
3354 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003355 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurentfdbee862014-05-12 15:26:12 -07003356 Set set = mIndex.entrySet();
3357 Iterator i = set.iterator();
3358 while (i.hasNext()) {
3359 Map.Entry entry = (Map.Entry)i.next();
3360 entry.setValue(index);
3361 }
3362 // Now apply actual volume for devices in source stream state
3363 set = srcStream.mIndex.entrySet();
3364 i = set.iterator();
3365 while (i.hasNext()) {
3366 Map.Entry entry = (Map.Entry)i.next();
3367 int device = ((Integer)entry.getKey()).intValue();
3368 index = ((Integer)entry.getValue()).intValue();
3369 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07003370
Eric Laurentfdbee862014-05-12 15:26:12 -07003371 setIndex(index, device);
3372 }
Eric Laurent6d517662012-04-23 18:42:39 -07003373 }
3374 }
3375
Eric Laurentfdbee862014-05-12 15:26:12 -07003376 public void setAllIndexesToMax() {
3377 synchronized (VolumeStreamState.class) {
3378 Set set = mIndex.entrySet();
3379 Iterator i = set.iterator();
3380 while (i.hasNext()) {
3381 Map.Entry entry = (Map.Entry)i.next();
3382 entry.setValue(mIndexMax);
3383 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003384 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003385 }
3386
Eric Laurentfdbee862014-05-12 15:26:12 -07003387 public void mute(IBinder cb, boolean state) {
3388 synchronized (VolumeStreamState.class) {
3389 VolumeDeathHandler handler = getDeathHandler(cb, state);
3390 if (handler == null) {
3391 Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
3392 return;
3393 }
3394 handler.mute(state);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003395 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003396 }
3397
Eric Laurent6d517662012-04-23 18:42:39 -07003398 public int getStreamType() {
3399 return mStreamType;
3400 }
3401
Eric Laurent212532b2014-07-21 15:43:18 -07003402 public void checkFixedVolumeDevices() {
3403 synchronized (VolumeStreamState.class) {
3404 // ignore settings for fixed volume devices: volume should always be at max or 0
3405 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
3406 Set set = mIndex.entrySet();
3407 Iterator i = set.iterator();
3408 while (i.hasNext()) {
3409 Map.Entry entry = (Map.Entry)i.next();
3410 int device = ((Integer)entry.getKey()).intValue();
3411 int index = ((Integer)entry.getValue()).intValue();
3412 if (((device & mFixedVolumeDevices) != 0) && index != 0) {
3413 entry.setValue(mIndexMax);
3414 }
3415 applyDeviceVolume(device);
3416 }
3417 }
3418 }
3419 }
3420
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003421 private int getValidIndex(int index) {
3422 if (index < 0) {
3423 return 0;
Eric Laurent83a017b2013-03-19 18:15:31 -07003424 } else if (mUseFixedVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07003425 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003426 }
3427
3428 return index;
3429 }
3430
3431 private class VolumeDeathHandler implements IBinder.DeathRecipient {
3432 private IBinder mICallback; // To be notified of client's death
3433 private int mMuteCount; // Number of active mutes for this client
3434
3435 VolumeDeathHandler(IBinder cb) {
3436 mICallback = cb;
3437 }
3438
Eric Laurent3172d5e2012-05-09 11:38:16 -07003439 // must be called while synchronized on parent VolumeStreamState
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003440 public void mute(boolean state) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003441 boolean updateVolume = false;
Eric Laurent3172d5e2012-05-09 11:38:16 -07003442 if (state) {
3443 if (mMuteCount == 0) {
3444 // Register for client death notification
3445 try {
3446 // mICallback can be 0 if muted by AudioService
3447 if (mICallback != null) {
3448 mICallback.linkToDeath(this, 0);
3449 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003450 VolumeStreamState.this.mDeathHandlers.add(this);
Eric Laurent3172d5e2012-05-09 11:38:16 -07003451 // If the stream is not yet muted by any client, set level to 0
Eric Laurent42b041e2013-03-29 11:36:03 -07003452 if (!VolumeStreamState.this.isMuted()) {
3453 updateVolume = true;
Eric Laurent3172d5e2012-05-09 11:38:16 -07003454 }
3455 } catch (RemoteException e) {
3456 // Client has died!
3457 binderDied();
3458 return;
3459 }
3460 } else {
3461 Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
3462 }
3463 mMuteCount++;
3464 } else {
3465 if (mMuteCount == 0) {
3466 Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
3467 } else {
3468 mMuteCount--;
3469 if (mMuteCount == 0) {
3470 // Unregister from client death notification
Eric Laurent42b041e2013-03-29 11:36:03 -07003471 VolumeStreamState.this.mDeathHandlers.remove(this);
Eric Laurent3172d5e2012-05-09 11:38:16 -07003472 // mICallback can be 0 if muted by AudioService
3473 if (mICallback != null) {
3474 mICallback.unlinkToDeath(this, 0);
3475 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003476 if (!VolumeStreamState.this.isMuted()) {
3477 updateVolume = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003478 }
3479 }
3480 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003481 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003482 if (updateVolume) {
3483 sendMsg(mAudioHandler,
3484 MSG_SET_ALL_VOLUMES,
3485 SENDMSG_QUEUE,
3486 0,
3487 0,
3488 VolumeStreamState.this, 0);
3489 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003490 }
3491
3492 public void binderDied() {
3493 Log.w(TAG, "Volume service client died for stream: "+mStreamType);
3494 if (mMuteCount != 0) {
3495 // Reset all active mute requests from this client.
3496 mMuteCount = 1;
3497 mute(false);
3498 }
3499 }
3500 }
3501
Eric Laurent3172d5e2012-05-09 11:38:16 -07003502 private synchronized int muteCount() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003503 int count = 0;
3504 int size = mDeathHandlers.size();
3505 for (int i = 0; i < size; i++) {
3506 count += mDeathHandlers.get(i).mMuteCount;
3507 }
3508 return count;
3509 }
3510
Eric Laurent42b041e2013-03-29 11:36:03 -07003511 private synchronized boolean isMuted() {
3512 return muteCount() != 0;
3513 }
3514
Eric Laurent3172d5e2012-05-09 11:38:16 -07003515 // only called by mute() which is already synchronized
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003516 private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07003517 VolumeDeathHandler handler;
3518 int size = mDeathHandlers.size();
3519 for (int i = 0; i < size; i++) {
3520 handler = mDeathHandlers.get(i);
3521 if (cb == handler.mICallback) {
3522 return handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003523 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003524 }
Eric Laurent3172d5e2012-05-09 11:38:16 -07003525 // If this is the first mute request for this client, create a new
3526 // client death handler. Otherwise, it is an out of sequence unmute request.
3527 if (state) {
3528 handler = new VolumeDeathHandler(cb);
3529 } else {
3530 Log.w(TAG, "stream was not muted by this client");
3531 handler = null;
3532 }
3533 return handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003534 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003535
3536 private void dump(PrintWriter pw) {
Eric Laurentdd45d012012-10-08 09:04:34 -07003537 pw.print(" Mute count: ");
3538 pw.println(muteCount());
Eric Laurentbffc3d12012-05-07 17:43:49 -07003539 pw.print(" Current: ");
3540 Set set = mIndex.entrySet();
3541 Iterator i = set.iterator();
3542 while (i.hasNext()) {
3543 Map.Entry entry = (Map.Entry)i.next();
3544 pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue())
3545 + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", ");
3546 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003547 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003548 }
3549
3550 /** Thread that handles native AudioSystem control. */
3551 private class AudioSystemThread extends Thread {
3552 AudioSystemThread() {
3553 super("AudioService");
3554 }
3555
3556 @Override
3557 public void run() {
3558 // Set this thread up so the handler will work on it
3559 Looper.prepare();
3560
3561 synchronized(AudioService.this) {
3562 mAudioHandler = new AudioHandler();
3563
3564 // Notify that the handler has been created
3565 AudioService.this.notify();
3566 }
3567
3568 // Listen for volume change requests that are set by VolumePanel
3569 Looper.loop();
3570 }
3571 }
3572
3573 /** Handles internal volume messages in separate volume thread. */
3574 private class AudioHandler extends Handler {
3575
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003576 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003577
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003578 // Apply volume
3579 streamState.applyDeviceVolume(device);
Eric Laurenta553c252009-07-17 12:17:14 -07003580
3581 // Apply change to all streams using this one as alias
3582 int numStreamTypes = AudioSystem.getNumStreamTypes();
3583 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3584 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07003585 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurentcd772d02013-10-30 18:31:07 -07003586 // Make sure volume is also maxed out on A2DP device for aliased stream
3587 // that may have a different device selected
3588 int streamDevice = getDeviceForStream(streamType);
3589 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
3590 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
3591 mStreamStates[streamType].applyDeviceVolume(device);
3592 }
3593 mStreamStates[streamType].applyDeviceVolume(streamDevice);
Eric Laurenta553c252009-07-17 12:17:14 -07003594 }
3595 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003596
3597 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08003598 sendMsg(mAudioHandler,
3599 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08003600 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003601 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07003602 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08003603 streamState,
3604 PERSIST_DELAY);
3605
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003606 }
3607
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003608 private void setAllVolumes(VolumeStreamState streamState) {
3609
3610 // Apply volume
3611 streamState.applyAllVolumes();
3612
3613 // Apply change to all streams using this one as alias
3614 int numStreamTypes = AudioSystem.getNumStreamTypes();
3615 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3616 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07003617 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003618 mStreamStates[streamType].applyAllVolumes();
3619 }
3620 }
3621 }
3622
Eric Laurent42b041e2013-03-29 11:36:03 -07003623 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003624 if (mUseFixedVolume) {
3625 return;
3626 }
Eric Laurent212532b2014-07-21 15:43:18 -07003627 if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
3628 return;
3629 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003630 System.putIntForUser(mContentResolver,
3631 streamState.getSettingNameForDevice(device),
3632 (streamState.getIndex(device) + 5)/ 10,
3633 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003634 }
3635
Glenn Kastenba195eb2011-12-13 09:30:40 -08003636 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003637 if (mUseFixedVolume) {
3638 return;
3639 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07003640 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003641 }
3642
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003643 private boolean onLoadSoundEffects() {
3644 int status;
3645
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003646 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07003647 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003648 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
3649 return false;
3650 }
3651
3652 if (mSoundPool != null) {
3653 return true;
3654 }
3655
3656 loadTouchSoundAssets();
3657
Jean-Michel Trivi55a30c42014-07-20 17:56:11 -07003658 mSoundPool = new SoundPool.Builder()
3659 .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
3660 .setAudioAttributes(new AudioAttributes.Builder()
3661 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
3662 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
3663 .build())
3664 .build();
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003665 mSoundPoolCallBack = null;
3666 mSoundPoolListenerThread = new SoundPoolListenerThread();
3667 mSoundPoolListenerThread.start();
3668 int attempts = 3;
3669 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
3670 try {
3671 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07003672 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003673 } catch (InterruptedException e) {
3674 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
3675 }
3676 }
3677
3678 if (mSoundPoolCallBack == null) {
3679 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
3680 if (mSoundPoolLooper != null) {
3681 mSoundPoolLooper.quit();
3682 mSoundPoolLooper = null;
3683 }
3684 mSoundPoolListenerThread = null;
3685 mSoundPool.release();
3686 mSoundPool = null;
3687 return false;
3688 }
3689 /*
3690 * poolId table: The value -1 in this table indicates that corresponding
3691 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
3692 * Once loaded, the value in poolId is the sample ID and the same
3693 * sample can be reused for another effect using the same file.
3694 */
3695 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3696 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3697 poolId[fileIdx] = -1;
3698 }
3699 /*
3700 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
3701 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
3702 * this indicates we have a valid sample loaded for this effect.
3703 */
3704
3705 int numSamples = 0;
3706 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3707 // Do not load sample if this effect uses the MediaPlayer
3708 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
3709 continue;
3710 }
3711 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
3712 String filePath = Environment.getRootDirectory()
3713 + SOUND_EFFECTS_PATH
3714 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
3715 int sampleId = mSoundPool.load(filePath, 0);
3716 if (sampleId <= 0) {
3717 Log.w(TAG, "Soundpool could not load file: "+filePath);
3718 } else {
3719 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
3720 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
3721 numSamples++;
3722 }
3723 } else {
3724 SOUND_EFFECT_FILES_MAP[effect][1] =
3725 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
3726 }
3727 }
3728 // wait for all samples to be loaded
3729 if (numSamples > 0) {
3730 mSoundPoolCallBack.setSamples(poolId);
3731
3732 attempts = 3;
3733 status = 1;
3734 while ((status == 1) && (attempts-- > 0)) {
3735 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07003736 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003737 status = mSoundPoolCallBack.status();
3738 } catch (InterruptedException e) {
3739 Log.w(TAG, "Interrupted while waiting sound pool callback.");
3740 }
3741 }
3742 } else {
3743 status = -1;
3744 }
3745
3746 if (mSoundPoolLooper != null) {
3747 mSoundPoolLooper.quit();
3748 mSoundPoolLooper = null;
3749 }
3750 mSoundPoolListenerThread = null;
3751 if (status != 0) {
3752 Log.w(TAG,
3753 "onLoadSoundEffects(), Error "+status+ " while loading samples");
3754 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3755 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
3756 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3757 }
3758 }
3759
3760 mSoundPool.release();
3761 mSoundPool = null;
3762 }
3763 }
3764 return (status == 0);
3765 }
3766
3767 /**
3768 * Unloads samples from the sound pool.
3769 * This method can be called to free some memory when
3770 * sound effects are disabled.
3771 */
3772 private void onUnloadSoundEffects() {
3773 synchronized (mSoundEffectsLock) {
3774 if (mSoundPool == null) {
3775 return;
3776 }
3777
3778 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3779 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3780 poolId[fileIdx] = 0;
3781 }
3782
3783 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3784 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
3785 continue;
3786 }
3787 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
3788 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
3789 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3790 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
3791 }
3792 }
3793 mSoundPool.release();
3794 mSoundPool = null;
3795 }
3796 }
3797
3798 private void onPlaySoundEffect(int effectType, int volume) {
3799 synchronized (mSoundEffectsLock) {
3800
3801 onLoadSoundEffects();
3802
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003803 if (mSoundPool == null) {
3804 return;
3805 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003806 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08003807 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003808 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07003809 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003810 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07003811 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003812 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003813
3814 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003815 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
3816 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003817 } else {
3818 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003819 try {
Eric Laurente78fced2013-03-15 16:03:47 -07003820 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
3821 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003822 mediaPlayer.setDataSource(filePath);
3823 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
3824 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08003825 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003826 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
3827 public void onCompletion(MediaPlayer mp) {
3828 cleanupPlayer(mp);
3829 }
3830 });
3831 mediaPlayer.setOnErrorListener(new OnErrorListener() {
3832 public boolean onError(MediaPlayer mp, int what, int extra) {
3833 cleanupPlayer(mp);
3834 return true;
3835 }
3836 });
3837 mediaPlayer.start();
3838 } catch (IOException ex) {
3839 Log.w(TAG, "MediaPlayer IOException: "+ex);
3840 } catch (IllegalArgumentException ex) {
3841 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
3842 } catch (IllegalStateException ex) {
3843 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003844 }
3845 }
3846 }
3847 }
3848
3849 private void cleanupPlayer(MediaPlayer mp) {
3850 if (mp != null) {
3851 try {
3852 mp.stop();
3853 mp.release();
3854 } catch (IllegalStateException ex) {
3855 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
3856 }
3857 }
3858 }
3859
Eric Laurentfa640152011-03-12 15:59:51 -08003860 private void setForceUse(int usage, int config) {
3861 AudioSystem.setForceUse(usage, config);
3862 }
3863
Eric Laurent05274f32012-11-29 12:48:18 -08003864 private void onPersistSafeVolumeState(int state) {
3865 Settings.Global.putInt(mContentResolver,
3866 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
3867 state);
3868 }
3869
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003870 @Override
3871 public void handleMessage(Message msg) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003872
Eric Laurentafbb0472011-12-15 09:04:23 -08003873 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003874
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003875 case MSG_SET_DEVICE_VOLUME:
3876 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
3877 break;
3878
3879 case MSG_SET_ALL_VOLUMES:
3880 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003881 break;
3882
3883 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07003884 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003885 break;
3886
Mike Lockwood5c55a052011-12-15 17:21:44 -05003887 case MSG_PERSIST_MASTER_VOLUME:
Eric Laurent83a017b2013-03-19 18:15:31 -07003888 if (mUseFixedVolume) {
3889 return;
3890 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07003891 Settings.System.putFloatForUser(mContentResolver,
3892 Settings.System.VOLUME_MASTER,
RoboErik8a2cfc32014-05-16 11:19:38 -07003893 msg.arg1 / (float)1000.0,
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07003894 UserHandle.USER_CURRENT);
Mike Lockwood5c55a052011-12-15 17:21:44 -05003895 break;
3896
Justin Koh57978ed2012-04-03 17:37:58 -07003897 case MSG_PERSIST_MASTER_VOLUME_MUTE:
Eric Laurent83a017b2013-03-19 18:15:31 -07003898 if (mUseFixedVolume) {
3899 return;
3900 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07003901 Settings.System.putIntForUser(mContentResolver,
3902 Settings.System.VOLUME_MASTER_MUTE,
3903 msg.arg1,
3904 UserHandle.USER_CURRENT);
Justin Koh57978ed2012-04-03 17:37:58 -07003905 break;
3906
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003907 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08003908 // note that the value persisted is the current ringer mode, not the
3909 // value of ringer mode as of the time the request was made to persist
3910 persistRingerMode(getRingerMode());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003911 break;
3912
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003913 case MSG_MEDIA_SERVER_DIED:
Eric Laurenteb4b8a22014-07-21 13:10:07 -07003914 if (!mSystemReady ||
3915 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Eric Laurent89e74ba2009-09-30 18:26:36 -07003916 Log.e(TAG, "Media server died.");
Eric Laurentafbb0472011-12-15 09:04:23 -08003917 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent89e74ba2009-09-30 18:26:36 -07003918 null, 500);
Eric Laurentdfb881f2013-07-18 14:41:39 -07003919 break;
Eric Laurent89e74ba2009-09-30 18:26:36 -07003920 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003921 Log.e(TAG, "Media server started.");
Eric Laurentdfb881f2013-07-18 14:41:39 -07003922
Eric Laurent3c652ca2010-06-21 20:46:26 -07003923 // indicate to audio HAL that we start the reconfiguration phase after a media
3924 // server crash
Eric Laurentdfb881f2013-07-18 14:41:39 -07003925 // Note that we only execute this when the media server
Eric Laurent3c652ca2010-06-21 20:46:26 -07003926 // process restarts after a crash, not the first time it is started.
3927 AudioSystem.setParameters("restarting=true");
3928
Glenn Kastenfd116ad2013-07-12 17:10:39 -07003929 readAndSetLowRamDevice();
3930
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003931 // Restore device connection states
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003932 synchronized (mConnectedDevices) {
3933 Set set = mConnectedDevices.entrySet();
3934 Iterator i = set.iterator();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003935 while (i.hasNext()) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003936 Map.Entry device = (Map.Entry)i.next();
3937 AudioSystem.setDeviceConnectionState(
3938 ((Integer)device.getKey()).intValue(),
3939 AudioSystem.DEVICE_STATE_AVAILABLE,
3940 (String)device.getValue());
3941 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003942 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003943 // Restore call state
3944 AudioSystem.setPhoneState(mMode);
3945
Eric Laurentd5603c12009-08-06 08:49:39 -07003946 // Restore forced usage for communcations and record
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003947 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
Eric Laurentd5603c12009-08-06 08:49:39 -07003948 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
Eric Laurentdd45d012012-10-08 09:04:34 -07003949 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
3950 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003951
Eric Laurenta553c252009-07-17 12:17:14 -07003952 // Restore stream volumes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003953 int numStreamTypes = AudioSystem.getNumStreamTypes();
3954 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003955 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003956 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003957
3958 streamState.applyAllVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003959 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003960
3961 // Restore ringer mode
3962 setRingerModeInt(getRingerMode(), false);
Eric Laurent3c652ca2010-06-21 20:46:26 -07003963
Mike Lockwood90631542012-01-06 11:20:37 -05003964 // Restore master volume
3965 restoreMasterVolume();
3966
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07003967 // Reset device orientation (if monitored for this device)
Eric Laurentd640bd32012-09-28 18:01:48 -07003968 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07003969 setOrientationForAudioSystem();
3970 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07003971 if (mMonitorRotation) {
3972 setRotationForAudioSystem();
3973 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07003974
Eric Laurent78472112012-05-21 08:57:21 -07003975 synchronized (mBluetoothA2dpEnabledLock) {
3976 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
3977 mBluetoothA2dpEnabled ?
3978 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
3979 }
Eric Laurentbff5ca52012-11-02 16:48:26 -07003980
3981 synchronized (mSettingsLock) {
3982 AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
3983 mDockAudioMediaEnabled ?
3984 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
3985 }
Eric Laurent212532b2014-07-21 15:43:18 -07003986 if (mHdmiManager != null) {
3987 synchronized (mHdmiManager) {
3988 if (mHdmiTvClient != null) {
3989 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
3990 }
3991 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09003992 }
Eric Laurent3c652ca2010-06-21 20:46:26 -07003993 // indicate the end of reconfiguration phase to audio HAL
3994 AudioSystem.setParameters("restarting=false");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003995 break;
3996
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003997 case MSG_UNLOAD_SOUND_EFFECTS:
3998 onUnloadSoundEffects();
3999 break;
4000
Eric Laurent117b7bb2011-01-16 17:07:27 -08004001 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004002 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
4003 // can take several dozens of milliseconds to complete
4004 boolean loaded = onLoadSoundEffects();
4005 if (msg.obj != null) {
4006 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
4007 synchronized (reply) {
4008 reply.mStatus = loaded ? 0 : -1;
4009 reply.notify();
4010 }
4011 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08004012 break;
4013
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004014 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004015 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004016 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004017
4018 case MSG_BTA2DP_DOCK_TIMEOUT:
4019 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004020 synchronized (mConnectedDevices) {
4021 makeA2dpDeviceUnavailableNow( (String) msg.obj );
4022 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004023 break;
Eric Laurentfa640152011-03-12 15:59:51 -08004024
4025 case MSG_SET_FORCE_USE:
Eric Laurentc390bed2012-07-03 12:24:05 -07004026 case MSG_SET_FORCE_BT_A2DP_USE:
Eric Laurentfa640152011-03-12 15:59:51 -08004027 setForceUse(msg.arg1, msg.arg2);
4028 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07004029
Eric Laurentdc03c612011-04-01 10:59:41 -07004030 case MSG_BT_HEADSET_CNCT_FAILED:
4031 resetBluetoothSco();
4032 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004033
4034 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
4035 onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004036 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004037 break;
4038
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004039 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
4040 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
4041 mAudioEventWakeLock.release();
4042 break;
4043
4044 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
4045 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004046 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004047 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004048
4049 case MSG_REPORT_NEW_ROUTES: {
4050 int N = mRoutesObservers.beginBroadcast();
4051 if (N > 0) {
4052 AudioRoutesInfo routes;
4053 synchronized (mCurAudioRoutes) {
4054 routes = new AudioRoutesInfo(mCurAudioRoutes);
4055 }
4056 while (N > 0) {
4057 N--;
4058 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
4059 try {
4060 obs.dispatchAudioRoutesChanged(routes);
4061 } catch (RemoteException e) {
4062 }
4063 }
4064 }
4065 mRoutesObservers.finishBroadcast();
4066 break;
4067 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004068
Eric Laurentc34dcc12012-09-10 13:51:52 -07004069 case MSG_CHECK_MUSIC_ACTIVE:
4070 onCheckMusicActive();
4071 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004072
4073 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
4074 onSendBecomingNoisyIntent();
4075 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07004076
4077 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
4078 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
4079 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
4080 break;
Eric Laurent05274f32012-11-29 12:48:18 -08004081 case MSG_PERSIST_SAFE_VOLUME_STATE:
4082 onPersistSafeVolumeState(msg.arg1);
4083 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08004084
Eric Laurent2a57ca92013-03-07 17:29:27 -08004085 case MSG_BROADCAST_BT_CONNECTION_STATE:
4086 onBroadcastScoConnectionState(msg.arg1);
4087 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004088
4089 case MSG_SYSTEM_READY:
4090 onSystemReady();
4091 break;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004092
4093 case MSG_PERSIST_MUSIC_ACTIVE_MS:
4094 final int musicActiveMs = msg.arg1;
4095 Settings.Secure.putIntForUser(mContentResolver,
4096 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
4097 UserHandle.USER_CURRENT);
4098 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004099 }
4100 }
4101 }
4102
Jason Parekhb1096152009-03-24 17:48:25 -07004103 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07004104
Jason Parekhb1096152009-03-24 17:48:25 -07004105 SettingsObserver() {
4106 super(new Handler());
4107 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4108 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004109 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4110 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07004111 }
4112
4113 @Override
4114 public void onChange(boolean selfChange) {
4115 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08004116 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
4117 // However there appear to be some missing locks around mRingerModeMutedStreams
4118 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
4119 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07004120 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004121 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07004122 /*
4123 * Ensure all stream types that should be affected by ringer mode
4124 * are in the proper state.
4125 */
Eric Laurenta553c252009-07-17 12:17:14 -07004126 setRingerModeInt(getRingerMode(), false);
4127 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004128 readDockAudioSettings(mContentResolver);
Eric Laurenta553c252009-07-17 12:17:14 -07004129 }
Jason Parekhb1096152009-03-24 17:48:25 -07004130 }
Jason Parekhb1096152009-03-24 17:48:25 -07004131 }
Eric Laurenta553c252009-07-17 12:17:14 -07004132
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004133 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004134 private void makeA2dpDeviceAvailable(String address) {
Eric Laurent78472112012-05-21 08:57:21 -07004135 // enable A2DP before notifying A2DP connection to avoid unecessary processing in
4136 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004137 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4138 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4139 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Eric Laurent78472112012-05-21 08:57:21 -07004140 setBluetoothA2dpOnInt(true);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004141 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4142 AudioSystem.DEVICE_STATE_AVAILABLE,
4143 address);
4144 // Reset A2DP suspend state each time a new sink is connected
4145 AudioSystem.setParameters("A2dpSuspended=false");
4146 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
4147 address);
4148 }
4149
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004150 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004151 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07004152 }
4153
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004154 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004155 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004156 synchronized (mA2dpAvrcpLock) {
4157 mAvrcpAbsVolSupported = false;
4158 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004159 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4160 AudioSystem.DEVICE_STATE_UNAVAILABLE,
4161 address);
4162 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
4163 }
4164
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004165 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004166 private void makeA2dpDeviceUnavailableLater(String address) {
Eric Laurent3b591262010-04-20 07:01:00 -07004167 // prevent any activity on the A2DP audio output to avoid unwanted
4168 // reconnection of the sink.
4169 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004170 // the device will be made unavailable later, so consider it disconnected right away
4171 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
4172 // send the delayed message to make the device unavailable later
4173 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
4174 mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
4175
4176 }
4177
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004178 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004179 private void makeA2dpSrcAvailable(String address) {
4180 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
4181 AudioSystem.DEVICE_STATE_AVAILABLE,
4182 address);
4183 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
4184 address);
4185 }
4186
4187 // must be called synchronized on mConnectedDevices
4188 private void makeA2dpSrcUnavailable(String address) {
4189 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
4190 AudioSystem.DEVICE_STATE_UNAVAILABLE,
4191 address);
4192 mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
4193 }
4194
4195 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004196 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004197 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4198 }
4199
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004200 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004201 private boolean hasScheduledA2dpDockTimeout() {
4202 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4203 }
4204
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004205 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004206 {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004207 if (DEBUG_VOL) {
4208 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
4209 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004210 if (btDevice == null) {
4211 return;
4212 }
4213 String address = btDevice.getAddress();
4214 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4215 address = "";
4216 }
John Du5a0cf7a2013-07-19 11:30:34 -07004217
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004218 synchronized (mConnectedDevices) {
4219 boolean isConnected =
4220 (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
4221 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
4222
4223 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4224 if (btDevice.isBluetoothDock()) {
4225 if (state == BluetoothProfile.STATE_DISCONNECTED) {
4226 // introduction of a delay for transient disconnections of docks when
4227 // power is rapidly turned off/on, this message will be canceled if
4228 // we reconnect the dock under a preset delay
4229 makeA2dpDeviceUnavailableLater(address);
4230 // the next time isConnected is evaluated, it will be false for the dock
4231 }
4232 } else {
4233 makeA2dpDeviceUnavailableNow(address);
4234 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07004235 synchronized (mCurAudioRoutes) {
4236 if (mCurAudioRoutes.mBluetoothName != null) {
4237 mCurAudioRoutes.mBluetoothName = null;
4238 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4239 SENDMSG_NOOP, 0, 0, null, 0);
4240 }
4241 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004242 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4243 if (btDevice.isBluetoothDock()) {
4244 // this could be a reconnection after a transient disconnection
4245 cancelA2dpDeviceTimeout();
4246 mDockAddress = address;
4247 } else {
4248 // this could be a connection of another A2DP device before the timeout of
4249 // a dock: cancel the dock timeout, and make the dock unavailable now
4250 if(hasScheduledA2dpDockTimeout()) {
4251 cancelA2dpDeviceTimeout();
4252 makeA2dpDeviceUnavailableNow(mDockAddress);
4253 }
4254 }
4255 makeA2dpDeviceAvailable(address);
Dianne Hackborn632ca412012-06-14 19:34:10 -07004256 synchronized (mCurAudioRoutes) {
4257 String name = btDevice.getAliasName();
4258 if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
4259 mCurAudioRoutes.mBluetoothName = name;
4260 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4261 SENDMSG_NOOP, 0, 0, null, 0);
4262 }
4263 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004264 }
4265 }
4266 }
4267
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004268 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
4269 {
4270 if (DEBUG_VOL) {
4271 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
4272 }
4273 if (btDevice == null) {
4274 return;
4275 }
4276 String address = btDevice.getAddress();
4277 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4278 address = "";
4279 }
4280
4281 synchronized (mConnectedDevices) {
4282 boolean isConnected =
4283 (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
4284 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));
4285
4286 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4287 makeA2dpSrcUnavailable(address);
4288 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4289 makeA2dpSrcAvailable(address);
4290 }
4291 }
4292 }
4293
John Du5a0cf7a2013-07-19 11:30:34 -07004294 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
4295 // address is not used for now, but may be used when multiple a2dp devices are supported
4296 synchronized (mA2dpAvrcpLock) {
4297 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004298 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07004299 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4300 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4301 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4302 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4303 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07004304 }
4305 }
4306
Eric Laurent59f48272012-04-05 19:42:21 -07004307 private boolean handleDeviceConnection(boolean connected, int device, String params) {
4308 synchronized (mConnectedDevices) {
4309 boolean isConnected = (mConnectedDevices.containsKey(device) &&
Mike Lockwood98418182012-05-10 17:13:20 -07004310 (params.isEmpty() || mConnectedDevices.get(device).equals(params)));
Eric Laurent59f48272012-04-05 19:42:21 -07004311
4312 if (isConnected && !connected) {
4313 AudioSystem.setDeviceConnectionState(device,
4314 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Mike Lockwood98418182012-05-10 17:13:20 -07004315 mConnectedDevices.get(device));
Eric Laurent59f48272012-04-05 19:42:21 -07004316 mConnectedDevices.remove(device);
4317 return true;
4318 } else if (!isConnected && connected) {
4319 AudioSystem.setDeviceConnectionState(device,
4320 AudioSystem.DEVICE_STATE_AVAILABLE,
4321 params);
4322 mConnectedDevices.put(new Integer(device), params);
4323 return true;
4324 }
4325 }
4326 return false;
4327 }
4328
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004329 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4330 // sent if none of these devices is connected.
4331 int mBecomingNoisyIntentDevices =
4332 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07004333 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07004334 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
4335 AudioSystem.DEVICE_OUT_ALL_USB;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004336
4337 // must be called before removing the device from mConnectedDevices
4338 private int checkSendBecomingNoisyIntent(int device, int state) {
4339 int delay = 0;
4340 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4341 int devices = 0;
4342 for (int dev : mConnectedDevices.keySet()) {
4343 if ((dev & mBecomingNoisyIntentDevices) != 0) {
4344 devices |= dev;
4345 }
4346 }
4347 if (devices == device) {
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004348 sendMsg(mAudioHandler,
4349 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4350 SENDMSG_REPLACE,
4351 0,
4352 0,
4353 null,
4354 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004355 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004356 }
4357 }
4358
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004359 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
4360 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004361 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
4362 delay = 1000;
4363 }
4364 return delay;
4365 }
4366
4367 private void sendDeviceConnectionIntent(int device, int state, String name)
4368 {
4369 Intent intent = new Intent();
4370
4371 intent.putExtra("state", state);
4372 intent.putExtra("name", name);
4373 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4374
Dianne Hackborn632ca412012-06-14 19:34:10 -07004375 int connType = 0;
4376
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004377 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004378 connType = AudioRoutesInfo.MAIN_HEADSET;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004379 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4380 intent.putExtra("microphone", 1);
4381 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004382 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004383 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4384 intent.putExtra("microphone", 0);
4385 } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004386 connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004387 intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
4388 } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004389 connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004390 intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
Eric Laurent948d3272014-05-16 15:18:45 -07004391 } else if (device == AudioSystem.DEVICE_OUT_HDMI) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004392 connType = AudioRoutesInfo.MAIN_HDMI;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004393 intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);
4394 }
4395
Dianne Hackborn632ca412012-06-14 19:34:10 -07004396 synchronized (mCurAudioRoutes) {
4397 if (connType != 0) {
4398 int newConn = mCurAudioRoutes.mMainType;
4399 if (state != 0) {
4400 newConn |= connType;
4401 } else {
4402 newConn &= ~connType;
4403 }
4404 if (newConn != mCurAudioRoutes.mMainType) {
4405 mCurAudioRoutes.mMainType = newConn;
4406 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4407 SENDMSG_NOOP, 0, 0, null, 0);
4408 }
4409 }
4410 }
4411
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004412 final long ident = Binder.clearCallingIdentity();
4413 try {
4414 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
4415 } finally {
4416 Binder.restoreCallingIdentity(ident);
4417 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004418 }
4419
4420 private void onSetWiredDeviceConnectionState(int device, int state, String name)
4421 {
4422 synchronized (mConnectedDevices) {
4423 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
4424 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) {
4425 setBluetoothA2dpOnInt(true);
4426 }
Eric Laurentae4506e2014-05-29 16:04:32 -07004427 boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
4428 (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
4429 ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
Mike Lockwooddb454842012-09-18 11:16:57 -07004430 handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
Eric Laurentf1a457d2012-09-20 16:27:23 -07004431 if (state != 0) {
4432 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
4433 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE)) {
4434 setBluetoothA2dpOnInt(false);
4435 }
4436 if ((device & mSafeMediaVolumeDevices) != 0) {
4437 sendMsg(mAudioHandler,
4438 MSG_CHECK_MUSIC_ACTIVE,
4439 SENDMSG_REPLACE,
4440 0,
4441 0,
4442 null,
4443 MUSIC_ACTIVE_POLL_PERIOD_MS);
4444 }
Eric Laurent212532b2014-07-21 15:43:18 -07004445 // Television devices without CEC service apply software volume on HDMI output
4446 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4447 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
4448 checkAllFixedVolumeDevices();
4449 if (mHdmiManager != null) {
4450 synchronized (mHdmiManager) {
4451 if (mHdmiPlaybackClient != null) {
4452 mHdmiCecSink = false;
4453 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
4454 }
4455 }
4456 }
4457 }
4458 } else {
4459 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4460 if (mHdmiManager != null) {
4461 synchronized (mHdmiManager) {
4462 mHdmiCecSink = false;
4463 }
4464 }
4465 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004466 }
Eric Laurentae4506e2014-05-29 16:04:32 -07004467 if (!isUsb && (device != AudioSystem.DEVICE_IN_WIRED_HEADSET)) {
Mike Lockwooddb454842012-09-18 11:16:57 -07004468 sendDeviceConnectionIntent(device, state, name);
4469 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004470 }
4471 }
4472
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004473 /* cache of the address of the last dock the device was connected to */
4474 private String mDockAddress;
4475
Eric Laurenta553c252009-07-17 12:17:14 -07004476 /**
4477 * Receiver for misc intent broadcasts the Phone app cares about.
4478 */
4479 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4480 @Override
4481 public void onReceive(Context context, Intent intent) {
4482 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07004483 int outDevice;
4484 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07004485 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07004486
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004487 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4488 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4489 Intent.EXTRA_DOCK_STATE_UNDOCKED);
4490 int config;
4491 switch (dockState) {
4492 case Intent.EXTRA_DOCK_STATE_DESK:
4493 config = AudioSystem.FORCE_BT_DESK_DOCK;
4494 break;
4495 case Intent.EXTRA_DOCK_STATE_CAR:
4496 config = AudioSystem.FORCE_BT_CAR_DOCK;
4497 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004498 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08004499 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004500 break;
4501 case Intent.EXTRA_DOCK_STATE_HE_DESK:
4502 config = AudioSystem.FORCE_DIGITAL_DOCK;
4503 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004504 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4505 default:
4506 config = AudioSystem.FORCE_NONE;
4507 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08004508 // Low end docks have a menu to enable or disable audio
4509 // (see mDockAudioMediaEnabled)
4510 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
4511 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
4512 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
4513 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
4514 }
4515 mDockState = dockState;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004516 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
Eric Laurent59f48272012-04-05 19:42:21 -07004517 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004518 BluetoothProfile.STATE_DISCONNECTED);
Eric Laurentae4506e2014-05-29 16:04:32 -07004519 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
4520 inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
Nick Pellya56d1c72009-08-19 14:49:29 -07004521 String address = null;
Eric Laurentdca56b92011-09-02 14:20:56 -07004522
4523 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
4524 if (btDevice == null) {
4525 return;
4526 }
4527
4528 address = btDevice.getAddress();
4529 BluetoothClass btClass = btDevice.getBluetoothClass();
4530 if (btClass != null) {
4531 switch (btClass.getDeviceClass()) {
4532 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
4533 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
Eric Laurentae4506e2014-05-29 16:04:32 -07004534 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurentdca56b92011-09-02 14:20:56 -07004535 break;
4536 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
Eric Laurentae4506e2014-05-29 16:04:32 -07004537 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurentdca56b92011-09-02 14:20:56 -07004538 break;
Eric Laurentd5603c12009-08-06 08:49:39 -07004539 }
4540 }
4541
Eric Laurentdca56b92011-09-02 14:20:56 -07004542 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4543 address = "";
4544 }
Eric Laurentd5603c12009-08-06 08:49:39 -07004545
Eric Laurent59f48272012-04-05 19:42:21 -07004546 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
Eric Laurentae4506e2014-05-29 16:04:32 -07004547 boolean success = handleDeviceConnection(connected, outDevice, address) &&
4548 handleDeviceConnection(connected, inDevice, address);
4549 if (success) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004550 synchronized (mScoClients) {
Eric Laurent59f48272012-04-05 19:42:21 -07004551 if (connected) {
4552 mBluetoothHeadsetDevice = btDevice;
4553 } else {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004554 mBluetoothHeadsetDevice = null;
4555 resetBluetoothSco();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004556 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004557 }
Eric Laurenta553c252009-07-17 12:17:14 -07004558 }
Paul McLeandf361462014-04-10 16:02:55 -07004559 } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG)) {
4560 state = intent.getIntExtra("state", 0);
4561
4562 int alsaCard = intent.getIntExtra("card", -1);
4563 int alsaDevice = intent.getIntExtra("device", -1);
4564
4565 String params = (alsaCard == -1 && alsaDevice == -1 ? ""
4566 : "card=" + alsaCard + ";device=" + alsaDevice);
4567
4568 // Playback Device
Eric Laurentae4506e2014-05-29 16:04:32 -07004569 outDevice = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
4570 setWiredDeviceConnectionState(outDevice, state, params);
Paul McLeandf361462014-04-10 16:02:55 -07004571 } else if (action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
Eric Laurent59f48272012-04-05 19:42:21 -07004572 state = intent.getIntExtra("state", 0);
Paul McLeanc837a452014-04-09 09:04:43 -07004573
Eric Laurent59f48272012-04-05 19:42:21 -07004574 int alsaCard = intent.getIntExtra("card", -1);
4575 int alsaDevice = intent.getIntExtra("device", -1);
Paul McLeanc837a452014-04-09 09:04:43 -07004576 boolean hasPlayback = intent.getBooleanExtra("hasPlayback", false);
4577 boolean hasCapture = intent.getBooleanExtra("hasCapture", false);
4578 boolean hasMIDI = intent.getBooleanExtra("hasMIDI", false);
4579
Mike Lockwood98418182012-05-10 17:13:20 -07004580 String params = (alsaCard == -1 && alsaDevice == -1 ? ""
4581 : "card=" + alsaCard + ";device=" + alsaDevice);
Paul McLeanc837a452014-04-09 09:04:43 -07004582
Paul McLeanc837a452014-04-09 09:04:43 -07004583 // Playback Device
Paul McLeandf361462014-04-10 16:02:55 -07004584 if (hasPlayback) {
Eric Laurentae4506e2014-05-29 16:04:32 -07004585 outDevice = AudioSystem.DEVICE_OUT_USB_DEVICE;
4586 setWiredDeviceConnectionState(outDevice, state, params);
Paul McLeandf361462014-04-10 16:02:55 -07004587 }
Paul McLeanc837a452014-04-09 09:04:43 -07004588
4589 // Capture Device
Paul McLeandf361462014-04-10 16:02:55 -07004590 if (hasCapture) {
Eric Laurentae4506e2014-05-29 16:04:32 -07004591 inDevice = AudioSystem.DEVICE_IN_USB_DEVICE;
4592 setWiredDeviceConnectionState(inDevice, state, params);
Paul McLeandf361462014-04-10 16:02:55 -07004593 }
4594 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004595 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07004596 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004597 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004598 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07004599 // broadcast intent if the connection was initated by AudioService
4600 if (!mScoClients.isEmpty() &&
4601 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
4602 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
4603 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004604 broadcast = true;
4605 }
4606 switch (btState) {
4607 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004608 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07004609 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4610 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4611 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004612 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004613 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004614 break;
4615 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004616 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08004617 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07004618 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08004619 break;
4620 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07004621 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4622 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4623 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004624 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004625 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004626 default:
4627 // do not broadcast CONNECTING or invalid state
4628 broadcast = false;
4629 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004630 }
4631 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004632 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07004633 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07004634 //FIXME: this is to maintain compatibility with deprecated intent
4635 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08004636 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07004637 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004638 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08004639 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004640 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
4641 AudioSystem.setParameters("screen_state=on");
4642 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
4643 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07004644 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004645 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004646 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004647 // attempt to stop music playback for background user
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004648 sendMsg(mAudioHandler,
4649 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4650 SENDMSG_REPLACE,
4651 0,
4652 0,
4653 null,
4654 0);
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004655 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004656 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004657
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004658 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004659 readAudioSettings(true /*userSwitch*/);
4660 // preserve STREAM_MUSIC volume from one user to the next.
4661 sendMsg(mAudioHandler,
4662 MSG_SET_ALL_VOLUMES,
4663 SENDMSG_QUEUE,
4664 0,
4665 0,
4666 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Eric Laurenta553c252009-07-17 12:17:14 -07004667 }
4668 }
Paul McLeanc837a452014-04-09 09:04:43 -07004669 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004670
4671 //==========================================================================================
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004672 // RemoteControlDisplay / RemoteControlClient / Remote info
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004673 //==========================================================================================
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004674 public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
4675 ComponentName listenerComp) {
4676 return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
4677 }
4678
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004679 public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004680 return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004681 }
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004682
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004683 public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004684 mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004685 }
4686
4687 public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004688 mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004689 }
4690
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07004691 public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
4692 boolean wantsSync) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004693 mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
4694 }
4695
John Spurlock3346a802014-05-20 16:25:37 -04004696 @Override
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004697 public void setRemoteStreamVolume(int index) {
John Spurlock3346a802014-05-20 16:25:37 -04004698 enforceSelfOrSystemUI("set the remote stream volume");
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004699 mMediaFocusControl.setRemoteStreamVolume(index);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004700 }
4701
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004702 //==========================================================================================
4703 // Audio Focus
4704 //==========================================================================================
4705 public int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb,
4706 IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
4707 return mMediaFocusControl.requestAudioFocus(mainStreamType, durationHint, cb, fd,
4708 clientId, callingPackageName);
4709 }
4710
4711 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId) {
4712 return mMediaFocusControl.abandonAudioFocus(fd, clientId);
4713 }
4714
4715 public void unregisterAudioFocusClient(String clientId) {
4716 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004717 }
4718
Jean-Michel Trivi23805662013-07-31 14:19:18 -07004719 public int getCurrentAudioFocus() {
4720 return mMediaFocusControl.getCurrentAudioFocus();
4721 }
4722
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004723 //==========================================================================================
4724 // Device orientation
4725 //==========================================================================================
4726 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004727 * Handles device configuration changes that may map to a change in the orientation
4728 * or orientation.
4729 * Monitoring orientation and rotation is optional, and is defined by the definition and value
4730 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004731 */
4732 private void handleConfigurationChanged(Context context) {
4733 try {
4734 // reading new orientation "safely" (i.e. under try catch) in case anything
4735 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07004736 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004737 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07004738 if (mMonitorOrientation) {
4739 int newOrientation = config.orientation;
4740 if (newOrientation != mDeviceOrientation) {
4741 mDeviceOrientation = newOrientation;
4742 setOrientationForAudioSystem();
4743 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004744 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004745 if (mMonitorRotation) {
4746 int newRotation = ((WindowManager) context.getSystemService(
4747 Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
4748 if (newRotation != mDeviceRotation) {
4749 mDeviceRotation = newRotation;
4750 setRotationForAudioSystem();
4751 }
4752 }
Eric Laurentd640bd32012-09-28 18:01:48 -07004753 sendMsg(mAudioHandler,
4754 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
4755 SENDMSG_REPLACE,
4756 0,
4757 0,
4758 null,
4759 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07004760
4761 boolean cameraSoundForced = mContext.getResources().getBoolean(
4762 com.android.internal.R.bool.config_camera_sound_forced);
4763 synchronized (mSettingsLock) {
4764 synchronized (mCameraSoundForced) {
4765 if (cameraSoundForced != mCameraSoundForced) {
4766 mCameraSoundForced = cameraSoundForced;
4767
Eric Laurent212532b2014-07-21 15:43:18 -07004768 if (!isPlatformTelevision()) {
4769 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
4770 if (cameraSoundForced) {
4771 s.setAllIndexesToMax();
4772 mRingerModeAffectedStreams &=
4773 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4774 } else {
4775 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
4776 mRingerModeAffectedStreams |=
4777 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4778 }
4779 // take new state into account for streams muted by ringer mode
4780 setRingerModeInt(getRingerMode(), false);
Eric Laurentdd45d012012-10-08 09:04:34 -07004781 }
Eric Laurentdd45d012012-10-08 09:04:34 -07004782
4783 sendMsg(mAudioHandler,
4784 MSG_SET_FORCE_USE,
4785 SENDMSG_QUEUE,
4786 AudioSystem.FOR_SYSTEM,
4787 cameraSoundForced ?
4788 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
4789 null,
4790 0);
4791
4792 sendMsg(mAudioHandler,
4793 MSG_SET_ALL_VOLUMES,
4794 SENDMSG_QUEUE,
4795 0,
4796 0,
4797 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
4798 }
4799 }
4800 }
John Spurlock3346a802014-05-20 16:25:37 -04004801 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004802 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004803 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004804 }
4805 }
4806
4807 private void setOrientationForAudioSystem() {
4808 switch (mDeviceOrientation) {
4809 case Configuration.ORIENTATION_LANDSCAPE:
4810 //Log.i(TAG, "orientation is landscape");
4811 AudioSystem.setParameters("orientation=landscape");
4812 break;
4813 case Configuration.ORIENTATION_PORTRAIT:
4814 //Log.i(TAG, "orientation is portrait");
4815 AudioSystem.setParameters("orientation=portrait");
4816 break;
4817 case Configuration.ORIENTATION_SQUARE:
4818 //Log.i(TAG, "orientation is square");
4819 AudioSystem.setParameters("orientation=square");
4820 break;
4821 case Configuration.ORIENTATION_UNDEFINED:
4822 //Log.i(TAG, "orientation is undefined");
4823 AudioSystem.setParameters("orientation=undefined");
4824 break;
4825 default:
4826 Log.e(TAG, "Unknown orientation");
4827 }
4828 }
4829
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004830 private void setRotationForAudioSystem() {
4831 switch (mDeviceRotation) {
4832 case Surface.ROTATION_0:
4833 AudioSystem.setParameters("rotation=0");
4834 break;
4835 case Surface.ROTATION_90:
4836 AudioSystem.setParameters("rotation=90");
4837 break;
4838 case Surface.ROTATION_180:
4839 AudioSystem.setParameters("rotation=180");
4840 break;
4841 case Surface.ROTATION_270:
4842 AudioSystem.setParameters("rotation=270");
4843 break;
4844 default:
4845 Log.e(TAG, "Unknown device rotation");
4846 }
4847 }
4848
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004849
Eric Laurent78472112012-05-21 08:57:21 -07004850 // Handles request to override default use of A2DP for media.
4851 public void setBluetoothA2dpOnInt(boolean on) {
4852 synchronized (mBluetoothA2dpEnabledLock) {
4853 mBluetoothA2dpEnabled = on;
Eric Laurentc390bed2012-07-03 12:24:05 -07004854 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
4855 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
4856 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
Eric Laurent78472112012-05-21 08:57:21 -07004857 }
4858 }
4859
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004860 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07004861 public void setRingtonePlayer(IRingtonePlayer player) {
4862 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
4863 mRingtonePlayer = player;
4864 }
4865
4866 @Override
4867 public IRingtonePlayer getRingtonePlayer() {
4868 return mRingtonePlayer;
4869 }
4870
4871 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07004872 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
4873 synchronized (mCurAudioRoutes) {
4874 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
4875 mRoutesObservers.register(observer);
4876 return routes;
4877 }
4878 }
4879
Eric Laurentc34dcc12012-09-10 13:51:52 -07004880
4881 //==========================================================================================
4882 // Safe media volume management.
4883 // MUSIC stream volume level is limited when headphones are connected according to safety
4884 // regulation. When the user attempts to raise the volume above the limit, a warning is
4885 // displayed and the user has to acknowlegde before the volume is actually changed.
4886 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
4887 // property. Platforms with a different limit must set this property accordingly in their
4888 // overlay.
4889 //==========================================================================================
4890
Eric Laurentd640bd32012-09-28 18:01:48 -07004891 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
4892 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
4893 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
4894 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
4895 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
4896 // (when user opts out).
John Spurlock35134602014-07-24 18:10:48 -04004897 private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
4898 private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
4899 private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed
4900 private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
Eric Laurentd640bd32012-09-28 18:01:48 -07004901 private Integer mSafeMediaVolumeState;
4902
4903 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07004904 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07004905 private int mSafeMediaVolumeIndex;
Eric Laurentc34dcc12012-09-10 13:51:52 -07004906 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
4907 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
4908 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
4909 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
4910 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
4911 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
4912 private int mMusicActiveMs;
4913 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
4914 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07004915 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07004916
4917 private void setSafeMediaVolumeEnabled(boolean on) {
Eric Laurentd640bd32012-09-28 18:01:48 -07004918 synchronized (mSafeMediaVolumeState) {
4919 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
4920 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
4921 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
4922 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
4923 enforceSafeMediaVolume();
4924 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
4925 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004926 mMusicActiveMs = 1; // nonzero = confirmed
4927 saveMusicActiveMs();
Eric Laurentd640bd32012-09-28 18:01:48 -07004928 sendMsg(mAudioHandler,
4929 MSG_CHECK_MUSIC_ACTIVE,
4930 SENDMSG_REPLACE,
4931 0,
4932 0,
4933 null,
4934 MUSIC_ACTIVE_POLL_PERIOD_MS);
4935 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07004936 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07004937 }
4938 }
4939
4940 private void enforceSafeMediaVolume() {
4941 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07004942 int devices = mSafeMediaVolumeDevices;
4943 int i = 0;
4944
4945 while (devices != 0) {
4946 int device = 1 << i++;
4947 if ((device & devices) == 0) {
4948 continue;
4949 }
Eric Laurent42b041e2013-03-29 11:36:03 -07004950 int index = streamState.getIndex(device);
Eric Laurentc34dcc12012-09-10 13:51:52 -07004951 if (index > mSafeMediaVolumeIndex) {
Eric Laurent42b041e2013-03-29 11:36:03 -07004952 streamState.setIndex(mSafeMediaVolumeIndex, device);
4953 sendMsg(mAudioHandler,
4954 MSG_SET_DEVICE_VOLUME,
4955 SENDMSG_QUEUE,
4956 device,
4957 0,
4958 streamState,
4959 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07004960 }
4961 devices &= ~device;
4962 }
4963 }
4964
4965 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07004966 synchronized (mSafeMediaVolumeState) {
4967 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07004968 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
4969 ((device & mSafeMediaVolumeDevices) != 0) &&
4970 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07004971 return false;
4972 }
4973 return true;
4974 }
4975 }
4976
John Spurlock3346a802014-05-20 16:25:37 -04004977 @Override
Eric Laurentc34dcc12012-09-10 13:51:52 -07004978 public void disableSafeMediaVolume() {
John Spurlock3346a802014-05-20 16:25:37 -04004979 enforceSelfOrSystemUI("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07004980 synchronized (mSafeMediaVolumeState) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07004981 setSafeMediaVolumeEnabled(false);
Eric Laurentfde16d52012-12-03 14:42:39 -08004982 if (mPendingVolumeCommand != null) {
4983 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
4984 mPendingVolumeCommand.mIndex,
4985 mPendingVolumeCommand.mFlags,
4986 mPendingVolumeCommand.mDevice);
4987 mPendingVolumeCommand = null;
4988 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07004989 }
4990 }
4991
Jungshik Jang41d97462014-06-30 22:26:29 +09004992 //==========================================================================================
4993 // Hdmi Cec system audio mode.
4994 // If Hdmi Cec's system audio mode is on, audio service should notify volume change
4995 // to HdmiControlService so that audio recevier can handle volume change.
4996 //==========================================================================================
4997
Eric Laurent212532b2014-07-21 15:43:18 -07004998 private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
4999 public void onComplete(int status) {
5000 if (mHdmiManager != null) {
5001 synchronized (mHdmiManager) {
5002 mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
5003 // Television devices without CEC service apply software volume on HDMI output
5004 if (isPlatformTelevision() && !mHdmiCecSink) {
5005 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5006 }
5007 checkAllFixedVolumeDevices();
5008 }
5009 }
5010 }
5011 };
5012
Jungshik Jang41d97462014-06-30 22:26:29 +09005013 // If HDMI-CEC system audio is supported
5014 private boolean mHdmiSystemAudioSupported = false;
5015 // Set only when device is tv.
5016 private HdmiTvClient mHdmiTvClient;
Eric Laurent212532b2014-07-21 15:43:18 -07005017 // true if the device has system feature PackageManager.FEATURE_TELEVISION.
5018 // cached HdmiControlManager interface
5019 private HdmiControlManager mHdmiManager;
5020 // Set only when device is a set-top box.
5021 private HdmiPlaybackClient mHdmiPlaybackClient;
5022 // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5023 private boolean mHdmiCecSink;
5024
5025 private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
Jungshik Jang41d97462014-06-30 22:26:29 +09005026
5027 @Override
Jungshik Jang12307ca2014-07-15 19:27:56 +09005028 public int setHdmiSystemAudioSupported(boolean on) {
Eric Laurent212532b2014-07-21 15:43:18 -07005029 int device = AudioSystem.DEVICE_NONE;
5030 if (mHdmiManager != null) {
5031 synchronized (mHdmiManager) {
5032 if (mHdmiTvClient == null) {
5033 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5034 return device;
5035 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005036
Eric Laurent212532b2014-07-21 15:43:18 -07005037 synchronized (mHdmiTvClient) {
5038 if (mHdmiSystemAudioSupported != on) {
5039 mHdmiSystemAudioSupported = on;
5040 AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5041 on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5042 AudioSystem.FORCE_NONE);
5043 }
5044 device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
5045 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005046 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005047 }
Eric Laurent212532b2014-07-21 15:43:18 -07005048 return device;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005049 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005050
Eric Laurentdd45d012012-10-08 09:04:34 -07005051 //==========================================================================================
5052 // Camera shutter sound policy.
5053 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5054 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5055 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5056 //==========================================================================================
5057
5058 // cached value of com.android.internal.R.bool.config_camera_sound_forced
5059 private Boolean mCameraSoundForced;
5060
5061 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5062 public boolean isCameraSoundForced() {
5063 synchronized (mCameraSoundForced) {
5064 return mCameraSoundForced;
5065 }
5066 }
5067
5068 private static final String[] RINGER_MODE_NAMES = new String[] {
5069 "SILENT",
5070 "VIBRATE",
5071 "NORMAL"
5072 };
5073
5074 private void dumpRingerMode(PrintWriter pw) {
5075 pw.println("\nRinger mode: ");
5076 pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]);
5077 pw.print("- ringer mode affected streams = 0x");
5078 pw.println(Integer.toHexString(mRingerModeAffectedStreams));
5079 pw.print("- ringer mode muted streams = 0x");
5080 pw.println(Integer.toHexString(mRingerModeMutedStreams));
5081 }
5082
Dianne Hackborn632ca412012-06-14 19:34:10 -07005083 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005084 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07005085 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5086
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005087 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07005088 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07005089 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005090 pw.println("\nAudio routes:");
5091 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
5092 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
John Spurlock35134602014-07-24 18:10:48 -04005093
5094 pw.println("\nOther state:");
John Spurlock3346a802014-05-20 16:25:37 -04005095 pw.print(" mVolumeController="); pw.println(mVolumeController);
John Spurlock35134602014-07-24 18:10:48 -04005096 pw.print(" mSafeMediaVolumeState=");
5097 pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
5098 pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
5099 pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
5100 pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005101 pw.print(" mMcc="); pw.println(mMcc);
John Spurlock35134602014-07-24 18:10:48 -04005102 }
5103
5104 private static String safeMediaVolumeStateToString(Integer state) {
5105 switch(state) {
5106 case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
5107 case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
5108 case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
5109 case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
5110 }
5111 return null;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005112 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07005113
5114 // Inform AudioFlinger of our device's low RAM attribute
5115 private static void readAndSetLowRamDevice()
5116 {
5117 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
5118 if (status != 0) {
5119 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
5120 }
5121 }
John Spurlock3346a802014-05-20 16:25:37 -04005122
5123 private void enforceSelfOrSystemUI(String action) {
5124 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
5125 "Only SystemUI can " + action);
5126 }
5127
5128 @Override
5129 public void setVolumeController(final IVolumeController controller) {
5130 enforceSelfOrSystemUI("set the volume controller");
5131
5132 // return early if things are not actually changing
5133 if (mVolumeController.isSameBinder(controller)) {
5134 return;
5135 }
5136
5137 // dismiss the old volume controller
5138 mVolumeController.postDismiss();
5139 if (controller != null) {
5140 // we are about to register a new controller, listen for its death
5141 try {
5142 controller.asBinder().linkToDeath(new DeathRecipient() {
5143 @Override
5144 public void binderDied() {
5145 if (mVolumeController.isSameBinder(controller)) {
5146 Log.w(TAG, "Current remote volume controller died, unregistering");
5147 setVolumeController(null);
5148 }
5149 }
5150 }, 0);
5151 } catch (RemoteException e) {
5152 // noop
5153 }
5154 }
5155 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04005156 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
5157 }
5158
5159 @Override
5160 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
5161 enforceSelfOrSystemUI("notify about volume controller visibility");
5162
5163 // return early if the controller is not current
5164 if (!mVolumeController.isSameBinder(controller)) {
5165 return;
5166 }
5167
5168 mVolumeController.setVisible(visible);
5169 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04005170 }
RoboErikd09bd0c2014-06-24 17:45:19 -07005171
5172 public static class VolumeController {
5173 private static final String TAG = "VolumeController";
5174
5175 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04005176 private boolean mVisible;
5177 private long mNextLongPress;
5178 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07005179
5180 public void setController(IVolumeController controller) {
5181 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04005182 mVisible = false;
5183 }
5184
5185 public void loadSettings(ContentResolver cr) {
5186 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
5187 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
5188 }
5189
5190 public boolean suppressAdjustment(int resolvedStream, int flags) {
5191 boolean suppress = false;
5192 if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
5193 final long now = SystemClock.uptimeMillis();
5194 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
5195 // ui will become visible
5196 if (mNextLongPress < now) {
5197 mNextLongPress = now + mLongPressTimeout;
5198 }
5199 suppress = true;
5200 } else if (mNextLongPress > 0) { // in a long-press
5201 if (now > mNextLongPress) {
5202 // long press triggered, no more suppression
5203 mNextLongPress = 0;
5204 } else {
5205 // keep suppressing until the long press triggers
5206 suppress = true;
5207 }
5208 }
5209 }
5210 return suppress;
5211 }
5212
5213 public void setVisible(boolean visible) {
5214 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07005215 }
5216
5217 public boolean isSameBinder(IVolumeController controller) {
5218 return Objects.equals(asBinder(), binder(controller));
5219 }
5220
5221 public IBinder asBinder() {
5222 return binder(mController);
5223 }
5224
5225 private static IBinder binder(IVolumeController controller) {
5226 return controller == null ? null : controller.asBinder();
5227 }
5228
5229 @Override
5230 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04005231 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07005232 }
5233
5234 public void postDisplaySafeVolumeWarning(int flags) {
5235 if (mController == null)
5236 return;
5237 try {
5238 mController.displaySafeVolumeWarning(flags);
5239 } catch (RemoteException e) {
5240 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
5241 }
5242 }
5243
5244 public void postVolumeChanged(int streamType, int flags) {
5245 if (mController == null)
5246 return;
5247 try {
5248 mController.volumeChanged(streamType, flags);
5249 } catch (RemoteException e) {
5250 Log.w(TAG, "Error calling volumeChanged", e);
5251 }
5252 }
5253
5254 public void postMasterVolumeChanged(int flags) {
5255 if (mController == null)
5256 return;
5257 try {
5258 mController.masterVolumeChanged(flags);
5259 } catch (RemoteException e) {
5260 Log.w(TAG, "Error calling masterVolumeChanged", e);
5261 }
5262 }
5263
5264 public void postMasterMuteChanged(int flags) {
5265 if (mController == null)
5266 return;
5267 try {
5268 mController.masterMuteChanged(flags);
5269 } catch (RemoteException e) {
5270 Log.w(TAG, "Error calling masterMuteChanged", e);
5271 }
5272 }
5273
5274 public void setLayoutDirection(int layoutDirection) {
5275 if (mController == null)
5276 return;
5277 try {
5278 mController.setLayoutDirection(layoutDirection);
5279 } catch (RemoteException e) {
5280 Log.w(TAG, "Error calling setLayoutDirection", e);
5281 }
5282 }
5283
5284 public void postDismiss() {
5285 if (mController == null)
5286 return;
5287 try {
5288 mController.dismiss();
5289 } catch (RemoteException e) {
5290 Log.w(TAG, "Error calling dismiss", e);
5291 }
5292 }
5293 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005294
5295 //==========================================================================================
5296 // Audio policy management
5297 //==========================================================================================
5298 public boolean registerAudioPolicy(AudioPolicyConfig policyConfig, IBinder cb) {
5299 //Log.v(TAG, "registerAudioPolicy for " + cb + " got policy:" + policyConfig);
5300 boolean hasPermissionForPolicy =
5301 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
5302 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5303 if (!hasPermissionForPolicy) {
5304 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
5305 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
5306 return false;
5307 }
5308 synchronized (mAudioPolicies) {
5309 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, cb);
5310 try {
5311 cb.linkToDeath(app, 0/*flags*/);
5312 mAudioPolicies.put(cb, app);
5313 } catch (RemoteException e) {
5314 // audio policy owner has already died!
5315 Slog.w(TAG, "Audio policy registration failed, could not link to " + cb +
5316 " binder death", e);
5317 return false;
5318 }
5319 }
5320 // TODO implement registration with native audio policy (including permission check)
5321 return true;
5322 }
5323 public void unregisterAudioPolicyAsync(IBinder cb) {
5324 synchronized (mAudioPolicies) {
5325 AudioPolicyProxy app = mAudioPolicies.remove(cb);
5326 if (app == null) {
5327 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
5328 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
5329 } else {
5330 cb.unlinkToDeath(app, 0/*flags*/);
5331 }
5332 }
5333 // TODO implement registration with native audio policy
5334 }
5335
5336 public class AudioPolicyProxy implements IBinder.DeathRecipient {
5337 private static final String TAG = "AudioPolicyProxy";
5338 AudioPolicyConfig mConfig;
5339 IBinder mToken;
5340 AudioPolicyProxy(AudioPolicyConfig config, IBinder token) {
5341 mConfig = config;
5342 mToken = token;
5343 }
5344
5345 public void binderDied() {
5346 synchronized (mAudioPolicies) {
5347 Log.v(TAG, "audio policy " + mToken + " died");
5348 mAudioPolicies.remove(mToken);
5349 }
5350 }
5351 };
5352
5353 private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
5354 new HashMap<IBinder, AudioPolicyProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005355}