blob: ab6314532ffc9884fcc6b21dd8573042943c9fcd [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;
47import android.hardware.hdmi.HdmiTvClient;
Paul McLeanc837a452014-04-09 09:04:43 -070048import android.hardware.usb.UsbManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.media.MediaPlayer.OnCompletionListener;
50import android.media.MediaPlayer.OnErrorListener;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070051import android.media.audiopolicy.AudioPolicyConfig;
RoboErik8a2cfc32014-05-16 11:19:38 -070052import android.media.session.MediaSessionLegacyHelper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.os.Binder;
Eric Laurentc18c9132013-04-12 17:24:56 -070054import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.os.Environment;
56import android.os.Handler;
57import android.os.IBinder;
58import android.os.Looper;
59import android.os.Message;
Jean-Michel Trivic6802222012-04-30 11:15:03 -070060import android.os.PowerManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070061import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.os.RemoteException;
63import android.os.ServiceManager;
John Spurlock33f4e042014-07-11 13:10:58 -040064import android.os.SystemClock;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070065import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070066import android.os.UserHandle;
Eric Laurentbffc3d12012-05-07 17:43:49 -070067import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068import android.provider.Settings;
69import android.provider.Settings.System;
Santos Cordon9eb45932014-06-27 12:28:43 -070070import android.telecomm.TelecommManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070071import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.util.Log;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070073import android.util.Slog;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070074import android.view.KeyEvent;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -070075import android.view.Surface;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -070076import android.view.WindowManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077
78import com.android.internal.telephony.ITelephony;
Eric Laurente78fced2013-03-15 16:03:47 -070079import com.android.internal.util.XmlUtils;
80
81import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -080083import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084import java.io.IOException;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -080085import java.io.PrintWriter;
Eric Laurente78fced2013-03-15 16:03:47 -070086import java.lang.reflect.Field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087import java.util.ArrayList;
Eric Laurent3172d5e2012-05-09 11:38:16 -070088import java.util.concurrent.ConcurrentHashMap;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +090089import java.util.Arrays;
Eric Laurentc42ac9d2009-07-29 08:53:03 -070090import java.util.HashMap;
91import java.util.Iterator;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -070092import java.util.List;
Eric Laurentc42ac9d2009-07-29 08:53:03 -070093import java.util.Map;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070094import java.util.NoSuchElementException;
RoboErikd09bd0c2014-06-24 17:45:19 -070095import java.util.Objects;
Eric Laurentc42ac9d2009-07-29 08:53:03 -070096import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097
98/**
99 * The implementation of the volume manager service.
100 * <p>
101 * This implementation focuses on delivering a responsive UI. Most methods are
102 * asynchronous to external calls. For example, the task of setting a volume
103 * will update our internal state, but in a separate thread will set the system
104 * volume and later persist to the database. Similarly, setting the ringer mode
105 * will update the state and broadcast a change and in a separate thread later
106 * persist the ringer mode.
107 *
108 * @hide
109 */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700110public class AudioService extends IAudioService.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111
112 private static final String TAG = "AudioService";
113
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700114 /** Debug remote control client/display feature */
John Spurlockae641c92014-06-30 18:11:40 -0400115 protected static final boolean DEBUG_RC = Log.isLoggable(TAG + ".RC", Log.DEBUG);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700116 /** Debug volumes */
John Spurlockae641c92014-06-30 18:11:40 -0400117 protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700118
RoboErik430fc482014-06-12 15:49:20 -0700119 /** debug calls to media session apis */
John Spurlockae641c92014-06-30 18:11:40 -0400120 private static final boolean DEBUG_SESSIONS = Log.isLoggable(TAG + ".SESSIONS", Log.DEBUG);
RoboErik8a2cfc32014-05-16 11:19:38 -0700121
John Spurlock86005342014-05-23 11:58:00 -0400122 /** Allow volume changes to set ringer mode to silent? */
123 private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
124
John Spurlocka11b4af2014-06-01 11:52:23 -0400125 /** In silent mode, are volume adjustments (raises) prevented? */
126 private static final boolean PREVENT_VOLUME_ADJUSTMENT_IF_SILENT = true;
127
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 /** How long to delay before persisting a change in volume/ringer mode. */
RoboErik45edba12012-03-27 17:54:36 -0700129 private static final int PERSIST_DELAY = 500;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130
John Spurlock3346a802014-05-20 16:25:37 -0400131 /**
132 * The delay before playing a sound. This small period exists so the user
133 * can press another key (non-volume keys, too) to have it NOT be audible.
134 * <p>
135 * PhoneWindow will implement this part.
136 */
137 public static final int PLAY_SOUND_DELAY = 300;
138
John Spurlocka11b4af2014-06-01 11:52:23 -0400139 /**
140 * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
141 */
142 private static final int FLAG_ADJUST_VOLUME = 1;
143
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700144 private final Context mContext;
145 private final ContentResolver mContentResolver;
146 private final AppOpsManager mAppOps;
147 private final boolean mVoiceCapable;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800148
John Spurlock3346a802014-05-20 16:25:37 -0400149 /** The controller for the volume UI. */
150 private final VolumeController mVolumeController = new VolumeController();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151
152 // sendMsg() flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 /** If the msg is already queued, replace it with this one. */
154 private static final int SENDMSG_REPLACE = 0;
155 /** If the msg is already queued, ignore this one and leave the old. */
156 private static final int SENDMSG_NOOP = 1;
157 /** If the msg is already queued, queue this one and leave the old. */
158 private static final int SENDMSG_QUEUE = 2;
159
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700160 // AudioHandler messages
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800161 private static final int MSG_SET_DEVICE_VOLUME = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 private static final int MSG_PERSIST_VOLUME = 1;
Mike Lockwood5c55a052011-12-15 17:21:44 -0500163 private static final int MSG_PERSIST_MASTER_VOLUME = 2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 private static final int MSG_PERSIST_RINGER_MODE = 3;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700165 private static final int MSG_MEDIA_SERVER_DIED = 4;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700166 private static final int MSG_PLAY_SOUND_EFFECT = 5;
167 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
168 private static final int MSG_LOAD_SOUND_EFFECTS = 7;
169 private static final int MSG_SET_FORCE_USE = 8;
170 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
171 private static final int MSG_SET_ALL_VOLUMES = 10;
172 private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
173 private static final int MSG_REPORT_NEW_ROUTES = 12;
174 private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
175 private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
176 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
177 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
178 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
179 private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
180 private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
181 private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700182 private static final int MSG_SYSTEM_READY = 21;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700183 // start of messages handled under wakelock
184 // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
Jean-Michel Trivie12c39b2012-06-06 10:51:58 -0700185 // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700186 private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
Mike Lockwood0a40ec22014-05-21 10:08:50 -0700187 private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
188 private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700189 // end of messages handled under wakelock
Eric Laurentafbb0472011-12-15 09:04:23 -0800190
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -0700191 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
Eric Laurentdc03c612011-04-01 10:59:41 -0700192 // Timeout for connection to bluetooth headset service
193 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 /** @see AudioSystemThread */
196 private AudioSystemThread mAudioSystemThread;
197 /** @see AudioHandler */
198 private AudioHandler mAudioHandler;
199 /** @see VolumeStreamState */
200 private VolumeStreamState[] mStreamStates;
Jason Parekhb1096152009-03-24 17:48:25 -0700201 private SettingsObserver mSettingsObserver;
Eric Laurenta553c252009-07-17 12:17:14 -0700202
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700203 private int mMode = AudioSystem.MODE_NORMAL;
Glenn Kastenba195eb2011-12-13 09:30:40 -0800204 // protects mRingerMode
205 private final Object mSettingsLock = new Object();
Eric Laurent45c90ce2012-04-24 18:44:22 -0700206
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 private SoundPool mSoundPool;
Glenn Kasten30c918c2011-11-10 17:56:41 -0800208 private final Object mSoundEffectsLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 private static final int NUM_SOUNDPOOL_CHANNELS = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210
Mike Lockwood47676902011-11-08 10:31:21 -0800211 // Internally master volume is a float in the 0.0 - 1.0 range,
212 // but to support integer based AudioManager API we translate it to 0 - 100
213 private static final int MAX_MASTER_VOLUME = 100;
214
Lei Zhang6c798972012-03-02 11:40:12 -0800215 // Maximum volume adjust steps allowed in a single batch call.
216 private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 /* Sound effect file names */
219 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
Eric Laurente78fced2013-03-15 16:03:47 -0700220 private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221
222 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
223 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
224 * uses soundpool (second column) */
Eric Laurente78fced2013-03-15 16:03:47 -0700225 private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226
Jared Suttles59820132009-08-13 21:50:52 -0500227 /** @hide Maximum volume index values for audio streams */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700228 private static final int[] MAX_STREAM_VOLUME = new int[] {
Eric Laurent6ee99522009-08-25 06:30:59 -0700229 5, // STREAM_VOICE_CALL
230 7, // STREAM_SYSTEM
231 7, // STREAM_RING
232 15, // STREAM_MUSIC
233 7, // STREAM_ALARM
234 7, // STREAM_NOTIFICATION
235 15, // STREAM_BLUETOOTH_SCO
236 7, // STREAM_SYSTEM_ENFORCED
237 15, // STREAM_DTMF
238 15 // STREAM_TTS
Jared Suttles59820132009-08-13 21:50:52 -0500239 };
Eric Laurent6d517662012-04-23 18:42:39 -0700240 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
Eric Laurenta553c252009-07-17 12:17:14 -0700241 * of another stream: This avoids multiplying the volume settings for hidden
242 * stream types that follow other stream behavior for volume settings
Eric Laurent6d517662012-04-23 18:42:39 -0700243 * NOTE: do not create loops in aliases!
244 * Some streams alias to different streams according to device category (phone or tablet) or
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700245 * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
Eric Laurent6d517662012-04-23 18:42:39 -0700246 * mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and
247 * STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/
Glenn Kasten30c918c2011-11-10 17:56:41 -0800248 private final int[] STREAM_VOLUME_ALIAS = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700249 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
250 AudioSystem.STREAM_RING, // STREAM_SYSTEM
251 AudioSystem.STREAM_RING, // STREAM_RING
252 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
253 AudioSystem.STREAM_ALARM, // STREAM_ALARM
254 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
255 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
256 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
257 AudioSystem.STREAM_RING, // STREAM_DTMF
258 AudioSystem.STREAM_MUSIC // STREAM_TTS
Eric Laurenta553c252009-07-17 12:17:14 -0700259 };
Eric Laurent6d517662012-04-23 18:42:39 -0700260 private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] {
261 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
262 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
263 AudioSystem.STREAM_RING, // STREAM_RING
264 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
265 AudioSystem.STREAM_ALARM, // STREAM_ALARM
266 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
267 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
268 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
269 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
270 AudioSystem.STREAM_MUSIC // STREAM_TTS
271 };
272 private int[] mStreamVolumeAlias;
Eric Laurenta553c252009-07-17 12:17:14 -0700273
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700274 /**
275 * Map AudioSystem.STREAM_* constants to app ops. This should be used
276 * after mapping through mStreamVolumeAlias.
277 */
278 private static final int[] STEAM_VOLUME_OPS = new int[] {
279 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL
280 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM
281 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING
282 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC
283 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM
284 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION
285 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO
286 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED
287 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF
288 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS
289 };
290
Eric Laurent83a017b2013-03-19 18:15:31 -0700291 private final boolean mUseFixedVolume;
292
Eric Laurentbffc3d12012-05-07 17:43:49 -0700293 // stream names used by dumpStreamStates()
John Spurlock1af30c72014-03-10 08:33:35 -0400294 private static final String[] STREAM_NAMES = new String[] {
Eric Laurentbffc3d12012-05-07 17:43:49 -0700295 "STREAM_VOICE_CALL",
296 "STREAM_SYSTEM",
297 "STREAM_RING",
298 "STREAM_MUSIC",
299 "STREAM_ALARM",
300 "STREAM_NOTIFICATION",
301 "STREAM_BLUETOOTH_SCO",
302 "STREAM_SYSTEM_ENFORCED",
303 "STREAM_DTMF",
304 "STREAM_TTS"
305 };
306
Glenn Kasten30c918c2011-11-10 17:56:41 -0800307 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 public void onError(int error) {
309 switch (error) {
310 case AudioSystem.AUDIO_STATUS_SERVER_DIED:
Eric Laurentdfb881f2013-07-18 14:41:39 -0700311 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
312 SENDMSG_NOOP, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313 break;
314 default:
315 break;
316 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700317 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 };
319
320 /**
321 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
322 * {@link AudioManager#RINGER_MODE_SILENT}, or
323 * {@link AudioManager#RINGER_MODE_VIBRATE}.
324 */
Glenn Kastenba195eb2011-12-13 09:30:40 -0800325 // protected by mSettingsLock
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 private int mRingerMode;
327
Eric Laurent9bcf4012009-06-12 06:09:28 -0700328 /** @see System#MODE_RINGER_STREAMS_AFFECTED */
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700329 private int mRingerModeAffectedStreams = 0;
Eric Laurent9bcf4012009-06-12 06:09:28 -0700330
Eric Laurent5b4e6542010-03-19 20:02:21 -0700331 // Streams currently muted by ringer mode
332 private int mRingerModeMutedStreams;
333
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 /** @see System#MUTE_STREAMS_AFFECTED */
335 private int mMuteAffectedStreams;
336
337 /**
Eric Laurentbffc3d12012-05-07 17:43:49 -0700338 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
339 * mVibrateSetting is just maintained during deprecation period but vibration policy is
340 * now only controlled by mHasVibrator and mRingerMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 */
342 private int mVibrateSetting;
343
Eric Laurentbffc3d12012-05-07 17:43:49 -0700344 // Is there a vibrator
345 private final boolean mHasVibrator;
346
Eric Laurenta553c252009-07-17 12:17:14 -0700347 // Broadcast receiver for device connections intent broadcasts
348 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
349
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700350 // Devices currently connected
Glenn Kasten30c918c2011-11-10 17:56:41 -0800351 private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700352
353 // Forced device usage for communications
354 private int mForcedUseForComm;
355
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500356 // True if we have master volume support
357 private final boolean mUseMasterVolume;
358
Mike Lockwood97606472012-02-09 11:24:10 -0800359 private final int[] mMasterVolumeRamp;
360
Eric Laurent9272b4b2010-01-23 17:12:59 -0800361 // List of binder death handlers for setMode() client processes.
362 // The last process to have called setMode() is at the top of the list.
Glenn Kasten30c918c2011-11-10 17:56:41 -0800363 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
Eric Laurenteb14a782009-12-17 03:12:59 -0800364
Eric Laurent3def1ee2010-03-17 23:26:26 -0700365 // List of clients having issued a SCO start request
Glenn Kasten30c918c2011-11-10 17:56:41 -0800366 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
Eric Laurent3def1ee2010-03-17 23:26:26 -0700367
368 // BluetoothHeadset API to control SCO connection
369 private BluetoothHeadset mBluetoothHeadset;
370
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700371 // Bluetooth headset device
372 private BluetoothDevice mBluetoothHeadsetDevice;
Eric Laurent3def1ee2010-03-17 23:26:26 -0700373
Eric Laurent62ef7672010-11-24 10:58:32 -0800374 // Indicate if SCO audio connection is currently active and if the initiator is
375 // audio service (internal) or bluetooth headset (external)
376 private int mScoAudioState;
377 // SCO audio state is not active
378 private static final int SCO_STATE_INACTIVE = 0;
Eric Laurentdc03c612011-04-01 10:59:41 -0700379 // SCO audio activation request waiting for headset service to connect
380 private static final int SCO_STATE_ACTIVATE_REQ = 1;
Eric Laurent25fc29b2013-04-05 12:13:54 -0700381 // SCO audio state is active or starting due to a request from AudioManager API
Eric Laurentdc03c612011-04-01 10:59:41 -0700382 private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
383 // SCO audio deactivation request waiting for headset service to connect
384 private static final int SCO_STATE_DEACTIVATE_REQ = 5;
385
Eric Laurent62ef7672010-11-24 10:58:32 -0800386 // SCO audio state is active due to an action in BT handsfree (either voice recognition or
387 // in call audio)
388 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
Eric Laurentdc03c612011-04-01 10:59:41 -0700389 // Deactivation request for all SCO connections (initiated by audio mode change)
390 // waiting for headset service to connect
391 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
392
Eric Laurentc18c9132013-04-12 17:24:56 -0700393 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
394 // originated from an app targeting an API version before JB MR2 and raw audio after that.
395 private int mScoAudioMode;
396 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
397 private static final int SCO_MODE_VIRTUAL_CALL = 0;
398 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
399 private static final int SCO_MODE_RAW = 1;
400
Eric Laurentdc03c612011-04-01 10:59:41 -0700401 // Current connection state indicated by bluetooth headset
402 private int mScoConnectionState;
Eric Laurent62ef7672010-11-24 10:58:32 -0800403
Eric Laurenta60e2122010-12-28 16:49:07 -0800404 // true if boot sequence has been completed
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700405 private boolean mSystemReady;
Eric Laurenta60e2122010-12-28 16:49:07 -0800406 // listener for SoundPool sample load completion indication
407 private SoundPoolCallback mSoundPoolCallBack;
408 // thread for SoundPool listener
409 private SoundPoolListenerThread mSoundPoolListenerThread;
410 // message looper for SoundPool listener
411 private Looper mSoundPoolLooper = null;
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700412 // volume applied to sound played with playSoundEffect()
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700413 private static int sSoundEffectVolumeDb;
Eric Laurent9903e262012-09-21 18:10:32 -0700414 // getActiveStreamType() will return:
415 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
416 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
Eric Laurent25101b02011-02-02 09:33:30 -0800417 // stopped
Eric Laurent9903e262012-09-21 18:10:32 -0700418 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
Eric Laurent25101b02011-02-02 09:33:30 -0800419 // previous volume adjustment direction received by checkForRingerModeChange()
420 private int mPrevVolDirection = AudioManager.ADJUST_SAME;
Amith Yamasani6243edd2011-12-05 19:58:48 -0800421 // Keyguard manager proxy
422 private KeyguardManager mKeyguardManager;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700423 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
424 // is controlled by Vol keys.
425 private int mVolumeControlStream = -1;
426 private final Object mForceControlStreamLock = new Object();
427 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
428 // server process so in theory it is not necessary to monitor the client death.
429 // However it is good to be ready for future evolutions.
430 private ForceControlStreamClient mForceControlStreamClient = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700431 // Used to play ringtones outside system_server
432 private volatile IRingtonePlayer mRingtonePlayer;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800433
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700434 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700435 private int mDeviceRotation = Surface.ROTATION_0;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700436
Eric Laurent78472112012-05-21 08:57:21 -0700437 // Request to override default use of A2DP for media.
438 private boolean mBluetoothA2dpEnabled;
439 private final Object mBluetoothA2dpEnabledLock = new Object();
440
Dianne Hackborn632ca412012-06-14 19:34:10 -0700441 // Monitoring of audio routes. Protected by mCurAudioRoutes.
442 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
443 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
444 = new RemoteCallbackList<IAudioRoutesObserver>();
445
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700446 /**
447 * A fake stream type to match the notion of remote media playback
448 */
449 public final static int STREAM_REMOTE_MUSIC = -200;
450
Eric Laurent4bbcc652012-09-24 14:26:30 -0700451 // Devices for which the volume is fixed and VolumePanel slider should be disabled
Eric Laurent948d3272014-05-16 15:18:45 -0700452 final int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700453 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Paul McLeanfb917e02014-06-26 15:28:40 -0700454 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
Eric Laurent4bbcc652012-09-24 14:26:30 -0700455
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700456 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700457 private final boolean mMonitorOrientation;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700458 private final boolean mMonitorRotation;
Eric Laurentd640bd32012-09-28 18:01:48 -0700459
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700460 private boolean mDockAudioMediaEnabled = true;
461
Eric Laurent08ed1b92012-11-05 14:54:12 -0800462 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
463
Eric Laurentfde16d52012-12-03 14:42:39 -0800464 // Used when safe volume warning message display is requested by setStreamVolume(). In this
465 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
466 // and used later when/if disableSafeMediaVolume() is called.
467 private StreamVolumeCommand mPendingVolumeCommand;
468
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700469 private PowerManager.WakeLock mAudioEventWakeLock;
470
471 private final MediaFocusControl mMediaFocusControl;
472
John Du5a0cf7a2013-07-19 11:30:34 -0700473 // Reference to BluetoothA2dp to query for AbsoluteVolume.
474 private BluetoothA2dp mA2dp;
475 private final Object mA2dpAvrcpLock = new Object();
476 // If absolute volume is supported in AVRCP device
477 private boolean mAvrcpAbsVolSupported = false;
478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 ///////////////////////////////////////////////////////////////////////////
480 // Construction
481 ///////////////////////////////////////////////////////////////////////////
482
483 /** @hide */
484 public AudioService(Context context) {
485 mContext = context;
486 mContentResolver = context.getContentResolver();
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700487 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Joe Onoratoc7fcba42011-01-05 16:53:11 -0800488 mVoiceCapable = mContext.getResources().getBoolean(
489 com.android.internal.R.bool.config_voice_capable);
Jared Suttles59820132009-08-13 21:50:52 -0500490
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700491 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700492 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700493
Eric Laurentbffc3d12012-05-07 17:43:49 -0700494 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
495 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
496
Jared Suttles59820132009-08-13 21:50:52 -0500497 // Intialized volume
498 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt(
499 "ro.config.vc_call_vol_steps",
500 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
501
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700502 sSoundEffectVolumeDb = context.getResources().getInteger(
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700503 com.android.internal.R.integer.config_soundEffectVolumeDb);
Eric Laurent25101b02011-02-02 09:33:30 -0800504
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700505 mForcedUseForComm = AudioSystem.FORCE_NONE;
Eric Laurentdd45d012012-10-08 09:04:34 -0700506
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 createAudioSystemThread();
Eric Laurentdd45d012012-10-08 09:04:34 -0700508
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700509 mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
John Spurlock3346a802014-05-20 16:25:37 -0400510 mContext, mVolumeController, this);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700511
Eric Laurentdfb881f2013-07-18 14:41:39 -0700512 AudioSystem.setErrorCallback(mAudioSystemCallback);
513
Eric Laurentdd45d012012-10-08 09:04:34 -0700514 boolean cameraSoundForced = mContext.getResources().getBoolean(
515 com.android.internal.R.bool.config_camera_sound_forced);
516 mCameraSoundForced = new Boolean(cameraSoundForced);
517 sendMsg(mAudioHandler,
518 MSG_SET_FORCE_USE,
519 SENDMSG_QUEUE,
520 AudioSystem.FOR_SYSTEM,
521 cameraSoundForced ?
522 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
523 null,
524 0);
525
Eric Laurent05274f32012-11-29 12:48:18 -0800526 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
527 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
528 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
529 // The default safe volume index read here will be replaced by the actual value when
530 // the mcc is read by onConfigureSafeVolume()
531 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
532 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
533
Eric Laurent83a017b2013-03-19 18:15:31 -0700534 mUseFixedVolume = mContext.getResources().getBoolean(
535 com.android.internal.R.bool.config_useFixedVolume);
536
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700537 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
538 // array initialized by updateStreamVolumeAlias()
539 updateStreamVolumeAlias(false /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800540 readPersistedSettings();
Eric Laurentc1d41662011-07-19 11:21:13 -0700541 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700542 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700543
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700544 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700545
546 // Call setRingerModeInt() to apply correct mute
547 // state on streams affected by ringer mode.
548 mRingerModeMutedStreams = 0;
549 setRingerModeInt(getRingerMode(), false);
550
Eric Laurenta553c252009-07-17 12:17:14 -0700551 // Register for device connection intent broadcasts.
552 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700553 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700554 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
555 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Eric Laurent59f48272012-04-05 19:42:21 -0700556 intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
557 intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700558 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
559 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700560 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Paul McLeanc837a452014-04-09 09:04:43 -0700561 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700562
Eric Laurentd640bd32012-09-28 18:01:48 -0700563 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700564 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700565 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
566 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700567 Log.v(TAG, "monitoring device orientation");
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700568 // initialize orientation in AudioSystem
569 setOrientationForAudioSystem();
570 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700571 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
572 if (mMonitorRotation) {
573 mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
574 .getDefaultDisplay().getRotation();
575 Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
576 // initialize rotation in AudioSystem
577 setRotationForAudioSystem();
578 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700579
Jungshik Jang41d97462014-06-30 22:26:29 +0900580 HdmiControlManager hdmiManager =
581 (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
582 // Null if device is not Tv.
583 mHdmiTvClient = hdmiManager.getTvClient();
584
Eric Laurenta553c252009-07-17 12:17:14 -0700585 context.registerReceiver(mReceiver, intentFilter);
Jared Suttles59820132009-08-13 21:50:52 -0500586
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500587 mUseMasterVolume = context.getResources().getBoolean(
588 com.android.internal.R.bool.config_useMasterVolume);
Mike Lockwood90631542012-01-06 11:20:37 -0500589 restoreMasterVolume();
Mike Lockwood97606472012-02-09 11:24:10 -0800590
591 mMasterVolumeRamp = context.getResources().getIntArray(
592 com.android.internal.R.array.config_masterVolumeRamp);
Eric Laurent78472112012-05-21 08:57:21 -0700593
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 }
595
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700596 public void systemReady() {
597 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
598 0, 0, null, 0);
599 }
600
601 public void onSystemReady() {
602 mSystemReady = true;
603 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
604 0, 0, null, 0);
605
606 mKeyguardManager =
607 (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
608 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
609 resetBluetoothSco();
610 getBluetoothHeadset();
611 //FIXME: this is to maintain compatibility with deprecated intent
612 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
613 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
614 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
615 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
616 sendStickyBroadcastToAll(newIntent);
617
618 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
619 if (adapter != null) {
620 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
621 BluetoothProfile.A2DP);
622 }
623
624 sendMsg(mAudioHandler,
625 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
626 SENDMSG_REPLACE,
627 0,
628 0,
629 null,
630 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
631 }
632
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 private void createAudioSystemThread() {
634 mAudioSystemThread = new AudioSystemThread();
635 mAudioSystemThread.start();
636 waitForAudioHandlerCreation();
637 }
638
639 /** Waits for the volume handler to be created by the other thread. */
640 private void waitForAudioHandlerCreation() {
641 synchronized(this) {
642 while (mAudioHandler == null) {
643 try {
644 // Wait for mAudioHandler to be set by the other thread
645 wait();
646 } catch (InterruptedException e) {
647 Log.e(TAG, "Interrupted while waiting on volume handler.");
648 }
649 }
650 }
651 }
652
Eric Laurent24482012012-05-10 09:41:17 -0700653 private void checkAllAliasStreamVolumes() {
654 int numStreamTypes = AudioSystem.getNumStreamTypes();
655 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
656 if (streamType != mStreamVolumeAlias[streamType]) {
657 mStreamStates[streamType].
Eric Laurent42b041e2013-03-29 11:36:03 -0700658 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
Eric Laurent24482012012-05-10 09:41:17 -0700659 }
660 // apply stream volume
Eric Laurent42b041e2013-03-29 11:36:03 -0700661 if (!mStreamStates[streamType].isMuted()) {
Eric Laurent24482012012-05-10 09:41:17 -0700662 mStreamStates[streamType].applyAllVolumes();
663 }
664 }
665 }
666
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 int numStreamTypes = AudioSystem.getNumStreamTypes();
669 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
670
671 for (int i = 0; i < numStreamTypes; i++) {
Eric Laurent6d517662012-04-23 18:42:39 -0700672 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -0700673 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674
Eric Laurent24482012012-05-10 09:41:17 -0700675 checkAllAliasStreamVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 }
677
Eric Laurentbffc3d12012-05-07 17:43:49 -0700678 private void dumpStreamStates(PrintWriter pw) {
679 pw.println("\nStream volumes (device: index)");
680 int numStreamTypes = AudioSystem.getNumStreamTypes();
681 for (int i = 0; i < numStreamTypes; i++) {
682 pw.println("- "+STREAM_NAMES[i]+":");
683 mStreamStates[i].dump(pw);
684 pw.println("");
685 }
Eric Laurentdd45d012012-10-08 09:04:34 -0700686 pw.print("\n- mute affected streams = 0x");
687 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -0700688 }
689
John Spurlock1af30c72014-03-10 08:33:35 -0400690 /** @hide */
691 public static String streamToString(int stream) {
692 if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream];
693 if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE";
694 return "UNKNOWN_STREAM_" + stream;
695 }
Eric Laurent6d517662012-04-23 18:42:39 -0700696
697 private void updateStreamVolumeAlias(boolean updateVolumes) {
698 int dtmfStreamAlias;
699 if (mVoiceCapable) {
700 mStreamVolumeAlias = STREAM_VOLUME_ALIAS;
701 dtmfStreamAlias = AudioSystem.STREAM_RING;
702 } else {
703 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE;
704 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
705 }
706 if (isInCommunication()) {
707 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700708 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
709 } else {
710 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
Eric Laurent6d517662012-04-23 18:42:39 -0700711 }
712 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
713 if (updateVolumes) {
Eric Laurent42b041e2013-03-29 11:36:03 -0700714 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700715 // apply stream mute states according to new value of mRingerModeAffectedStreams
716 setRingerModeInt(getRingerMode(), false);
Eric Laurent6d517662012-04-23 18:42:39 -0700717 sendMsg(mAudioHandler,
718 MSG_SET_ALL_VOLUMES,
719 SENDMSG_QUEUE,
720 0,
721 0,
722 mStreamStates[AudioSystem.STREAM_DTMF], 0);
723 }
724 }
725
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700726 private void readDockAudioSettings(ContentResolver cr)
727 {
728 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -0700729 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700730
731 if (mDockAudioMediaEnabled) {
732 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
733 } else {
734 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
735 }
736
737 sendMsg(mAudioHandler,
738 MSG_SET_FORCE_USE,
739 SENDMSG_QUEUE,
740 AudioSystem.FOR_DOCK,
741 mDockAudioMediaEnabled ?
742 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
743 null,
744 0);
745 }
746
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 private void readPersistedSettings() {
748 final ContentResolver cr = mContentResolver;
749
Eric Laurentbffc3d12012-05-07 17:43:49 -0700750 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700751 Settings.Global.getInt(
752 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -0700753 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -0700754 // sanity check in case the settings are restored from a device with incompatible
755 // ringer modes
Glenn Kastenba195eb2011-12-13 09:30:40 -0800756 if (!AudioManager.isValidRingerMode(ringerMode)) {
757 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700758 }
759 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
760 ringerMode = AudioManager.RINGER_MODE_SILENT;
761 }
762 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700763 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -0800764 }
Eric Laurent83a017b2013-03-19 18:15:31 -0700765 if (mUseFixedVolume) {
766 ringerMode = AudioManager.RINGER_MODE_NORMAL;
767 }
Glenn Kastenba195eb2011-12-13 09:30:40 -0800768 synchronized(mSettingsLock) {
769 mRingerMode = ringerMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770
Eric Laurentdd45d012012-10-08 09:04:34 -0700771 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
772 // are still needed while setVibrateSetting() and getVibrateSetting() are being
773 // deprecated.
774 mVibrateSetting = getValueForVibrateSetting(0,
775 AudioManager.VIBRATE_TYPE_NOTIFICATION,
776 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
777 : AudioManager.VIBRATE_SETTING_OFF);
778 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
779 AudioManager.VIBRATE_TYPE_RINGER,
780 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
781 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700783 updateRingerModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700784 readDockAudioSettings(cr);
Eric Laurent402f7f22011-02-04 12:30:32 -0800785 }
Eric Laurentc1d41662011-07-19 11:21:13 -0700786
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700787 mMuteAffectedStreams = System.getIntForUser(cr,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 System.MUTE_STREAMS_AFFECTED,
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700789 ((1 << AudioSystem.STREAM_MUSIC)|
790 (1 << AudioSystem.STREAM_RING)|
791 (1 << AudioSystem.STREAM_SYSTEM)),
792 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700794 boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
795 0, UserHandle.USER_CURRENT) == 1;
Eric Laurent83a017b2013-03-19 18:15:31 -0700796 if (mUseFixedVolume) {
797 masterMute = false;
798 AudioSystem.setMasterVolume(1.0f);
799 }
Justin Koh57978ed2012-04-03 17:37:58 -0700800 AudioSystem.setMasterMute(masterMute);
801 broadcastMasterMuteStatus(masterMute);
802
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 // Each stream will read its own persisted settings
804
805 // Broadcast the sticky intent
Glenn Kastenba195eb2011-12-13 09:30:40 -0800806 broadcastRingerMode(ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807
808 // Broadcast vibrate settings
809 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
810 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -0700811
812 // Restore the default media button receiver from the system settings
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700813 mMediaFocusControl.restoreMediaButtonReceiver();
John Spurlock33f4e042014-07-11 13:10:58 -0400814
815 // Load settings for the volume controller
816 mVolumeController.loadSettings(cr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800817 }
818
Eric Laurenta553c252009-07-17 12:17:14 -0700819 private int rescaleIndex(int index, int srcStream, int dstStream) {
820 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
821 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822
823 ///////////////////////////////////////////////////////////////////////////
824 // IPC methods
825 ///////////////////////////////////////////////////////////////////////////
Jean-Michel Trivifca1e602013-10-10 18:12:59 -0700826 /** @see AudioManager#isLocalOrRemoteMusicActive() */
827 public boolean isLocalOrRemoteMusicActive() {
828 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
829 // local / wired / BT playback active
830 if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): local");
831 return true;
832 }
833 if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
834 // remote "cast-like" playback active
835 if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): has PLAYBACK_TYPE_REMOTE");
836 return true;
837 }
838 if (AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, 0)) {
839 // remote submix playback active
840 if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): remote submix");
841 return true;
842 }
843 if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): no");
844 return false;
845 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846
847 /** @see AudioManager#adjustVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700848 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
849 String callingPackage) {
John Spurlockae641c92014-06-30 18:11:40 -0400850 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType
851 + ", flags=" + flags);
Eric Laurent402f7f22011-02-04 12:30:32 -0800852 int streamType;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700853 if (mVolumeControlStream != -1) {
854 streamType = mVolumeControlStream;
Eric Laurent402f7f22011-02-04 12:30:32 -0800855 } else {
856 streamType = getActiveStreamType(suggestedStreamType);
857 }
John Spurlock33f4e042014-07-11 13:10:58 -0400858 final int resolvedStream = mStreamVolumeAlias[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859
John Spurlock6bd096c2014-07-10 09:39:04 -0400860 // Play sounds on STREAM_RING and STREAM_REMOTE_MUSIC only.
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700861 if ((streamType != STREAM_REMOTE_MUSIC) &&
862 (flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
John Spurlock33f4e042014-07-11 13:10:58 -0400863 resolvedStream != AudioSystem.STREAM_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 flags &= ~AudioManager.FLAG_PLAY_SOUND;
865 }
866
John Spurlock33f4e042014-07-11 13:10:58 -0400867 // For notifications/ring, show the ui before making any adjustments
868 if (mVolumeController.suppressAdjustment(resolvedStream, flags)) {
869 direction = 0;
870 flags &= ~AudioManager.FLAG_PLAY_SOUND;
871 flags &= ~AudioManager.FLAG_VIBRATE;
872 if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
873 }
874
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700875 if (streamType == STREAM_REMOTE_MUSIC) {
RoboErik19c95182014-06-23 15:38:48 -0700876 // TODO bounce it to MediaSessionService to find an appropriate
877 // session
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700878 } else {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700879 adjustStreamVolume(streamType, direction, flags, callingPackage);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700880 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800881 }
882
883 /** @see AudioManager#adjustStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700884 public void adjustStreamVolume(int streamType, int direction, int flags,
885 String callingPackage) {
Eric Laurent83a017b2013-03-19 18:15:31 -0700886 if (mUseFixedVolume) {
887 return;
888 }
John Spurlockae641c92014-06-30 18:11:40 -0400889 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction
890 + ", flags="+flags);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700891
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800892 ensureValidDirection(direction);
893 ensureValidStreamType(streamType);
894
Eric Laurent96a33d12011-11-08 10:31:57 -0800895 // use stream type alias here so that streams with same alias have the same behavior,
896 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
897 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
Eric Laurent6d517662012-04-23 18:42:39 -0700898 int streamTypeAlias = mStreamVolumeAlias[streamType];
Eric Laurentb024c302011-10-14 17:19:27 -0700899 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800900
901 final int device = getDeviceForStream(streamTypeAlias);
Eric Laurent3ef75492012-11-28 12:12:23 -0800902
Eric Laurent42b041e2013-03-29 11:36:03 -0700903 int aliasIndex = streamState.getIndex(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 boolean adjustVolume = true;
Eric Laurent3ef75492012-11-28 12:12:23 -0800905 int step;
Eric Laurent24482012012-05-10 09:41:17 -0700906
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700907 // skip a2dp absolute volume control request when the device
908 // is not an a2dp device
909 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
910 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
911 return;
912 }
913
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700914 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
915 callingPackage) != AppOpsManager.MODE_ALLOWED) {
916 return;
917 }
918
Eric Laurentfde16d52012-12-03 14:42:39 -0800919 // reset any pending volume command
920 synchronized (mSafeMediaVolumeState) {
921 mPendingVolumeCommand = null;
922 }
923
Eric Laurent3ef75492012-11-28 12:12:23 -0800924 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
925 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
926 ((device & mFixedVolumeDevices) != 0)) {
927 flags |= AudioManager.FLAG_FIXED_VOLUME;
928
929 // Always toggle between max safe volume and 0 for fixed volume devices where safe
930 // volume is enforced, and max and 0 for the others.
931 // This is simulated by stepping by the full allowed volume range
932 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
933 (device & mSafeMediaVolumeDevices) != 0) {
934 step = mSafeMediaVolumeIndex;
935 } else {
936 step = streamState.getMaxIndex();
937 }
938 if (aliasIndex != 0) {
939 aliasIndex = step;
940 }
941 } else {
942 // convert one UI step (+/-1) into a number of internal units on the stream alias
943 step = rescaleIndex(10, streamType, streamTypeAlias);
944 }
945
Eric Laurent42b041e2013-03-29 11:36:03 -0700946 // If either the client forces allowing ringer modes for this adjustment,
947 // or the stream type is one that is affected by ringer modes
948 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
949 (streamTypeAlias == getMasterStreamType())) {
950 int ringerMode = getRingerMode();
951 // do not vibrate if already in vibrate mode
952 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
953 flags &= ~AudioManager.FLAG_VIBRATE;
Eric Laurent3ef75492012-11-28 12:12:23 -0800954 }
Eric Laurent42b041e2013-03-29 11:36:03 -0700955 // Check if the ringer mode changes with this volume adjustment. If
956 // it does, it will handle adjusting the volume, so we won't below
John Spurlocka11b4af2014-06-01 11:52:23 -0400957 final int result = checkForRingerModeChange(aliasIndex, direction, step);
958 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
959 // If suppressing a volume adjustment in silent mode, display the UI hint
960 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
961 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
962 }
Eric Laurent42b041e2013-03-29 11:36:03 -0700963 }
Eric Laurent3ef75492012-11-28 12:12:23 -0800964
Eric Laurent42b041e2013-03-29 11:36:03 -0700965 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -0800966
Eric Laurent42b041e2013-03-29 11:36:03 -0700967 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700968
John Du5a0cf7a2013-07-19 11:30:34 -0700969 // Check if volume update should be send to AVRCP
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700970 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
971 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
972 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
973 synchronized (mA2dpAvrcpLock) {
974 if (mA2dp != null && mAvrcpAbsVolSupported) {
975 mA2dp.adjustAvrcpAbsoluteVolume(direction);
976 }
John Du5a0cf7a2013-07-19 11:30:34 -0700977 }
978 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700979
Eric Laurent42b041e2013-03-29 11:36:03 -0700980 if ((direction == AudioManager.ADJUST_RAISE) &&
981 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
982 Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -0400983 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurent42b041e2013-03-29 11:36:03 -0700984 } else if (streamState.adjustIndex(direction * step, device)) {
985 // Post message to set system volume (it in turn will post a message
986 // to persist). Do not change volume if stream is muted.
987 sendMsg(mAudioHandler,
988 MSG_SET_DEVICE_VOLUME,
989 SENDMSG_QUEUE,
990 device,
991 0,
992 streamState,
993 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -0700994 }
Jungshik Jang41d97462014-06-30 22:26:29 +0900995
996 // Check if volume update should be send to Hdmi system audio.
997 int newIndex = mStreamStates[streamType].getIndex(device);
998 if (mHdmiTvClient != null &&
999 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1000 (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 &&
1001 oldIndex != newIndex) {
1002 int maxIndex = getStreamMaxVolume(streamType);
1003 synchronized (mHdmiTvClient) {
1004 if (mHdmiSystemAudioSupported) {
1005 mHdmiTvClient.setSystemAudioVolume(
1006 (oldIndex + 5) / 10, (newIndex + 5) / 10, maxIndex);
1007 }
1008 }
1009 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001010 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001011 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001012 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001013 }
1014
Dianne Hackborn961cae92013-03-20 14:59:43 -07001015 /** @see AudioManager#adjustMasterVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001016 public void adjustMasterVolume(int steps, int flags, String callingPackage) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001017 if (mUseFixedVolume) {
1018 return;
1019 }
Lei Zhang6c798972012-03-02 11:40:12 -08001020 ensureValidSteps(steps);
Mike Lockwood97606472012-02-09 11:24:10 -08001021 int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1022 int delta = 0;
Lei Zhang6c798972012-03-02 11:40:12 -08001023 int numSteps = Math.abs(steps);
1024 int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
1025 for (int i = 0; i < numSteps; ++i) {
1026 delta = findVolumeDelta(direction, volume);
1027 volume += delta;
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001028 }
RoboErik24b082f2012-02-24 14:21:16 -08001029
Lei Zhang6c798972012-03-02 11:40:12 -08001030 //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001031 setMasterVolume(volume, flags, callingPackage);
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001032 }
1033
Eric Laurentfde16d52012-12-03 14:42:39 -08001034 // StreamVolumeCommand contains the information needed to defer the process of
1035 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1036 class StreamVolumeCommand {
1037 public final int mStreamType;
1038 public final int mIndex;
1039 public final int mFlags;
1040 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001041
Eric Laurentfde16d52012-12-03 14:42:39 -08001042 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1043 mStreamType = streamType;
1044 mIndex = index;
1045 mFlags = flags;
1046 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001047 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001048 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001049
Eric Laurentfde16d52012-12-03 14:42:39 -08001050 private void onSetStreamVolume(int streamType, int index, int flags, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001051 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
Eric Laurent3ef75492012-11-28 12:12:23 -08001052 // setting volume on master stream type also controls silent mode
1053 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1054 (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
1055 int newRingerMode;
1056 if (index == 0) {
1057 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlock86005342014-05-23 11:58:00 -04001058 : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
1059 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001060 } else {
1061 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1062 }
1063 setRingerMode(newRingerMode);
1064 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001065 }
1066
1067 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001068 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001069 if (mUseFixedVolume) {
1070 return;
1071 }
1072
Eric Laurentfde16d52012-12-03 14:42:39 -08001073 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001074 int streamTypeAlias = mStreamVolumeAlias[streamType];
1075 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001076
1077 final int device = getDeviceForStream(streamType);
1078 int oldIndex;
1079
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001080 // skip a2dp absolute volume control request when the device
1081 // is not an a2dp device
1082 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1083 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1084 return;
1085 }
1086
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001087 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
1088 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1089 return;
1090 }
1091
Eric Laurentfde16d52012-12-03 14:42:39 -08001092 synchronized (mSafeMediaVolumeState) {
1093 // reset any pending volume command
1094 mPendingVolumeCommand = null;
1095
Eric Laurent42b041e2013-03-29 11:36:03 -07001096 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001097
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001098 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001099
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001100 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1101 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1102 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1103 synchronized (mA2dpAvrcpLock) {
1104 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001105 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001106 }
John Du5a0cf7a2013-07-19 11:30:34 -07001107 }
1108 }
1109
Jungshik Jang41d97462014-06-30 22:26:29 +09001110 if (mHdmiTvClient != null &&
1111 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1112 (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0 &&
1113 oldIndex != index) {
1114 int maxIndex = getStreamMaxVolume(streamType);
1115 synchronized (mHdmiTvClient) {
1116 if (mHdmiSystemAudioSupported) {
1117 mHdmiTvClient.setSystemAudioVolume(
1118 (oldIndex + 5) / 10, (index + 5) / 10, maxIndex);
1119 }
1120 }
1121 }
1122
Eric Laurentfde16d52012-12-03 14:42:39 -08001123 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001124 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001125 ((device & mFixedVolumeDevices) != 0)) {
1126 flags |= AudioManager.FLAG_FIXED_VOLUME;
1127
1128 // volume is either 0 or max allowed for fixed volume devices
1129 if (index != 0) {
1130 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1131 (device & mSafeMediaVolumeDevices) != 0) {
1132 index = mSafeMediaVolumeIndex;
1133 } else {
1134 index = streamState.getMaxIndex();
1135 }
1136 }
1137 }
1138
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001139 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001140 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001141 mPendingVolumeCommand = new StreamVolumeCommand(
1142 streamType, index, flags, device);
1143 } else {
1144 onSetStreamVolume(streamType, index, flags, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07001145 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001146 }
1147 }
Eric Laurent25101b02011-02-02 09:33:30 -08001148 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001149 }
1150
Eric Laurent45c90ce2012-04-24 18:44:22 -07001151 /** @see AudioManager#forceVolumeControlStream(int) */
1152 public void forceVolumeControlStream(int streamType, IBinder cb) {
1153 synchronized(mForceControlStreamLock) {
1154 mVolumeControlStream = streamType;
1155 if (mVolumeControlStream == -1) {
1156 if (mForceControlStreamClient != null) {
1157 mForceControlStreamClient.release();
1158 mForceControlStreamClient = null;
1159 }
1160 } else {
1161 mForceControlStreamClient = new ForceControlStreamClient(cb);
1162 }
1163 }
1164 }
1165
1166 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1167 private IBinder mCb; // To be notified of client's death
1168
1169 ForceControlStreamClient(IBinder cb) {
1170 if (cb != null) {
1171 try {
1172 cb.linkToDeath(this, 0);
1173 } catch (RemoteException e) {
1174 // Client has died!
1175 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1176 cb = null;
1177 }
1178 }
1179 mCb = cb;
1180 }
1181
1182 public void binderDied() {
1183 synchronized(mForceControlStreamLock) {
1184 Log.w(TAG, "SCO client died");
1185 if (mForceControlStreamClient != this) {
1186 Log.w(TAG, "unregistered control stream client died");
1187 } else {
1188 mForceControlStreamClient = null;
1189 mVolumeControlStream = -1;
1190 }
1191 }
1192 }
1193
1194 public void release() {
1195 if (mCb != null) {
1196 mCb.unlinkToDeath(this, 0);
1197 mCb = null;
1198 }
1199 }
1200 }
1201
Lei Zhang6c798972012-03-02 11:40:12 -08001202 private int findVolumeDelta(int direction, int volume) {
1203 int delta = 0;
1204 if (direction == AudioManager.ADJUST_RAISE) {
1205 if (volume == MAX_MASTER_VOLUME) {
1206 return 0;
1207 }
1208 // This is the default value if we make it to the end
1209 delta = mMasterVolumeRamp[1];
1210 // If we're raising the volume move down the ramp array until we
1211 // find the volume we're above and use that groups delta.
1212 for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
1213 if (volume >= mMasterVolumeRamp[i - 1]) {
1214 delta = mMasterVolumeRamp[i];
1215 break;
1216 }
1217 }
1218 } else if (direction == AudioManager.ADJUST_LOWER){
1219 if (volume == 0) {
1220 return 0;
1221 }
1222 int length = mMasterVolumeRamp.length;
1223 // This is the default value if we make it to the end
1224 delta = -mMasterVolumeRamp[length - 1];
1225 // If we're lowering the volume move up the ramp array until we
1226 // find the volume we're below and use the group below it's delta
1227 for (int i = 2; i < length; i += 2) {
1228 if (volume <= mMasterVolumeRamp[i]) {
1229 delta = -mMasterVolumeRamp[i - 1];
1230 break;
1231 }
1232 }
1233 }
1234 return delta;
1235 }
1236
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001237 private void sendBroadcastToAll(Intent intent) {
1238 final long ident = Binder.clearCallingIdentity();
1239 try {
1240 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1241 } finally {
1242 Binder.restoreCallingIdentity(ident);
1243 }
1244 }
1245
1246 private void sendStickyBroadcastToAll(Intent intent) {
1247 final long ident = Binder.clearCallingIdentity();
1248 try {
1249 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1250 } finally {
1251 Binder.restoreCallingIdentity(ident);
1252 }
1253 }
1254
Eric Laurent25101b02011-02-02 09:33:30 -08001255 // UI update and Broadcast Intent
1256 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
1257 if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) {
1258 streamType = AudioSystem.STREAM_NOTIFICATION;
1259 }
1260
John Spurlock3346a802014-05-20 16:25:37 -04001261 mVolumeController.postVolumeChanged(streamType, flags);
Eric Laurent25101b02011-02-02 09:33:30 -08001262
Eric Laurent4bbcc652012-09-24 14:26:30 -07001263 if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
1264 oldIndex = (oldIndex + 5) / 10;
1265 index = (index + 5) / 10;
1266 Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
1267 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
1268 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
1269 intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
1270 sendBroadcastToAll(intent);
1271 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001272 }
1273
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001274 // UI update and Broadcast Intent
1275 private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
John Spurlock3346a802014-05-20 16:25:37 -04001276 mVolumeController.postMasterVolumeChanged(flags);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001277
1278 Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
1279 intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
1280 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001281 sendBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001282 }
1283
1284 // UI update and Broadcast Intent
1285 private void sendMasterMuteUpdate(boolean muted, int flags) {
John Spurlock3346a802014-05-20 16:25:37 -04001286 mVolumeController.postMasterMuteChanged(flags);
Justin Koh57978ed2012-04-03 17:37:58 -07001287 broadcastMasterMuteStatus(muted);
1288 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001289
Justin Koh57978ed2012-04-03 17:37:58 -07001290 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001291 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1292 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001293 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1294 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001295 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001296 }
1297
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001298 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001299 * Sets the stream state's index, and posts a message to set system volume.
1300 * This will not call out to the UI. Assumes a valid stream type.
1301 *
1302 * @param streamType Type of the stream
1303 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001304 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001305 * @param force If true, set the volume even if the desired volume is same
1306 * as the current volume.
1307 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001308 private void setStreamVolumeInt(int streamType,
1309 int index,
1310 int device,
Eric Laurent42b041e2013-03-29 11:36:03 -07001311 boolean force) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07001313
Eric Laurent42b041e2013-03-29 11:36:03 -07001314 if (streamState.setIndex(index, device) || force) {
1315 // Post message to set system volume (it in turn will post a message
1316 // to persist).
1317 sendMsg(mAudioHandler,
1318 MSG_SET_DEVICE_VOLUME,
1319 SENDMSG_QUEUE,
1320 device,
1321 0,
1322 streamState,
1323 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001324 }
1325 }
1326
1327 /** @see AudioManager#setStreamSolo(int, boolean) */
1328 public void setStreamSolo(int streamType, boolean state, IBinder cb) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001329 if (mUseFixedVolume) {
1330 return;
1331 }
1332
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333 for (int stream = 0; stream < mStreamStates.length; stream++) {
1334 if (!isStreamAffectedByMute(stream) || stream == streamType) continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001335 mStreamStates[stream].mute(cb, state);
1336 }
1337 }
1338
1339 /** @see AudioManager#setStreamMute(int, boolean) */
1340 public void setStreamMute(int streamType, boolean state, IBinder cb) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001341 if (mUseFixedVolume) {
1342 return;
1343 }
1344
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001345 if (isStreamAffectedByMute(streamType)) {
Jungshik Jang41d97462014-06-30 22:26:29 +09001346 if (streamType == AudioSystem.STREAM_MUSIC && mHdmiTvClient != null) {
1347 synchronized (mHdmiTvClient) {
1348 if (mHdmiSystemAudioSupported) {
1349 mHdmiTvClient.setSystemAudioMute(state);
1350 }
1351 }
1352 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001353 mStreamStates[streamType].mute(cb, state);
1354 }
1355 }
1356
Eric Laurent25101b02011-02-02 09:33:30 -08001357 /** get stream mute state. */
1358 public boolean isStreamMute(int streamType) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001359 return mStreamStates[streamType].isMuted();
Eric Laurent25101b02011-02-02 09:33:30 -08001360 }
1361
Dianne Hackborn961cae92013-03-20 14:59:43 -07001362 /** @see AudioManager#setMasterMute(boolean, int) */
Julia Reynolds4a21b252014-06-04 11:11:43 -04001363 public void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001364 if (mUseFixedVolume) {
1365 return;
1366 }
1367
Julia Reynolds4a21b252014-06-04 11:11:43 -04001368 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
1369 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1370 return;
1371 }
1372
Jason Simmons1ce5b262012-02-02 13:00:17 -08001373 if (state != AudioSystem.getMasterMute()) {
1374 AudioSystem.setMasterMute(state);
Justin Koh57978ed2012-04-03 17:37:58 -07001375 // Post a persist master volume msg
Justin Koh75cf9e12012-04-04 15:27:37 -07001376 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
Justin Koh57978ed2012-04-03 17:37:58 -07001377 : 0, 0, null, PERSIST_DELAY);
Justin Koh0273af52012-04-04 18:29:50 -07001378 sendMasterMuteUpdate(state, flags);
Jason Simmons1ce5b262012-02-02 13:00:17 -08001379 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08001380 }
1381
1382 /** get master mute state. */
1383 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08001384 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001385 }
1386
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07001387 protected static int getMaxStreamVolume(int streamType) {
1388 return MAX_STREAM_VOLUME[streamType];
1389 }
1390
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001391 /** @see AudioManager#getStreamVolume(int) */
1392 public int getStreamVolume(int streamType) {
1393 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001394 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001395 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001396
Eric Laurent42b041e2013-03-29 11:36:03 -07001397 // by convention getStreamVolume() returns 0 when a stream is muted.
1398 if (mStreamStates[streamType].isMuted()) {
1399 index = 0;
1400 }
Eric Laurent3ef75492012-11-28 12:12:23 -08001401 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
Eric Laurent4bbcc652012-09-24 14:26:30 -07001402 (device & mFixedVolumeDevices) != 0) {
1403 index = mStreamStates[streamType].getMaxIndex();
Eric Laurent4bbcc652012-09-24 14:26:30 -07001404 }
1405 return (index + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001406 }
1407
Mike Lockwood47676902011-11-08 10:31:21 -08001408 public int getMasterVolume() {
Mike Lockwoodce952c82011-11-14 10:47:42 -08001409 if (isMasterMute()) return 0;
1410 return getLastAudibleMasterVolume();
Mike Lockwood8dc1dab2011-10-27 09:52:41 -04001411 }
1412
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001413 public void setMasterVolume(int volume, int flags, String callingPackage) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001414 if (mUseFixedVolume) {
1415 return;
1416 }
1417
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001418 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
1419 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1420 return;
1421 }
1422
Mike Lockwood97606472012-02-09 11:24:10 -08001423 if (volume < 0) {
1424 volume = 0;
1425 } else if (volume > MAX_MASTER_VOLUME) {
1426 volume = MAX_MASTER_VOLUME;
1427 }
Mike Lockwood5c55a052011-12-15 17:21:44 -05001428 doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
1429 }
1430
1431 private void doSetMasterVolume(float volume, int flags) {
1432 // don't allow changing master volume when muted
1433 if (!AudioSystem.getMasterMute()) {
1434 int oldVolume = getMasterVolume();
1435 AudioSystem.setMasterVolume(volume);
1436
1437 int newVolume = getMasterVolume();
1438 if (newVolume != oldVolume) {
1439 // Post a persist master volume msg
1440 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
1441 Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
Mike Lockwood5c55a052011-12-15 17:21:44 -05001442 }
Justin Koh3caba512012-04-02 15:32:18 -07001443 // Send the volume update regardless whether there was a change.
1444 sendMasterVolumeUpdate(flags, oldVolume, newVolume);
Mike Lockwood5c55a052011-12-15 17:21:44 -05001445 }
Mike Lockwood8dc1dab2011-10-27 09:52:41 -04001446 }
1447
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 /** @see AudioManager#getStreamMaxVolume(int) */
1449 public int getStreamMaxVolume(int streamType) {
1450 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07001451 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001452 }
1453
Mike Lockwood47676902011-11-08 10:31:21 -08001454 public int getMasterMaxVolume() {
1455 return MAX_MASTER_VOLUME;
1456 }
Eric Laurent25101b02011-02-02 09:33:30 -08001457
1458 /** Get last audible volume before stream was muted. */
1459 public int getLastAudibleStreamVolume(int streamType) {
1460 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001461 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001462 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08001463 }
1464
Mike Lockwoodce952c82011-11-14 10:47:42 -08001465 /** Get last audible master volume before it was muted. */
1466 public int getLastAudibleMasterVolume() {
1467 return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1468 }
1469
Dianne Hackborn961cae92013-03-20 14:59:43 -07001470 /** @see AudioManager#getMasterStreamType() */
Eric Laurent6d517662012-04-23 18:42:39 -07001471 public int getMasterStreamType() {
1472 if (mVoiceCapable) {
1473 return AudioSystem.STREAM_RING;
1474 } else {
1475 return AudioSystem.STREAM_MUSIC;
1476 }
1477 }
1478
Emily Bernier22c921a2014-05-28 11:01:32 -04001479 /** @see AudioManager#setMicrophoneMute(boolean) */
1480 public void setMicrophoneMute(boolean on, String callingPackage) {
1481 if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(),
1482 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1483 return;
1484 }
1485
1486 AudioSystem.muteMicrophone(on);
1487 }
1488
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001489 /** @see AudioManager#getRingerMode() */
1490 public int getRingerMode() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001491 synchronized(mSettingsLock) {
1492 return mRingerMode;
1493 }
1494 }
1495
1496 private void ensureValidRingerMode(int ringerMode) {
1497 if (!AudioManager.isValidRingerMode(ringerMode)) {
1498 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1499 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001500 }
1501
1502 /** @see AudioManager#setRingerMode(int) */
1503 public void setRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001504 if (mUseFixedVolume) {
1505 return;
1506 }
1507
Eric Laurent24482012012-05-10 09:41:17 -07001508 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1509 ringerMode = AudioManager.RINGER_MODE_SILENT;
1510 }
Glenn Kastenba195eb2011-12-13 09:30:40 -08001511 if (ringerMode != getRingerMode()) {
1512 setRingerModeInt(ringerMode, true);
1513 // Send sticky broadcast
1514 broadcastRingerMode(ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001515 }
1516 }
1517
Eric Laurent4050c932009-07-08 02:52:14 -07001518 private void setRingerModeInt(int ringerMode, boolean persist) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001519 synchronized(mSettingsLock) {
1520 mRingerMode = ringerMode;
1521 }
Jason Parekhb1096152009-03-24 17:48:25 -07001522
Eric Laurent5b4e6542010-03-19 20:02:21 -07001523 // Mute stream if not previously muted by ringer mode and ringer mode
1524 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
1525 // Unmute stream if previously muted by ringer mode and ringer mode
1526 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07001527 int numStreamTypes = AudioSystem.getNumStreamTypes();
Eric Laurent5b4e6542010-03-19 20:02:21 -07001528 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
1529 if (isStreamMutedByRingerMode(streamType)) {
1530 if (!isStreamAffectedByRingerMode(streamType) ||
Glenn Kastenba195eb2011-12-13 09:30:40 -08001531 ringerMode == AudioManager.RINGER_MODE_NORMAL) {
Eric Laurentb024c302011-10-14 17:19:27 -07001532 // ring and notifications volume should never be 0 when not silenced
1533 // on voice capable devices
1534 if (mVoiceCapable &&
Eric Laurent6d517662012-04-23 18:42:39 -07001535 mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07001536 synchronized (mStreamStates[streamType]) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001537 Set set = mStreamStates[streamType].mIndex.entrySet();
Eric Laurent3172d5e2012-05-09 11:38:16 -07001538 Iterator i = set.iterator();
1539 while (i.hasNext()) {
1540 Map.Entry entry = (Map.Entry)i.next();
1541 if ((Integer)entry.getValue() == 0) {
1542 entry.setValue(10);
1543 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001544 }
1545 }
Eric Laurentb024c302011-10-14 17:19:27 -07001546 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07001547 mStreamStates[streamType].mute(null, false);
1548 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent9bcf4012009-06-12 06:09:28 -07001549 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07001550 } else {
1551 if (isStreamAffectedByRingerMode(streamType) &&
Glenn Kastenba195eb2011-12-13 09:30:40 -08001552 ringerMode != AudioManager.RINGER_MODE_NORMAL) {
Eric Laurent5b4e6542010-03-19 20:02:21 -07001553 mStreamStates[streamType].mute(null, true);
1554 mRingerModeMutedStreams |= (1 << streamType);
1555 }
Jason Parekhb1096152009-03-24 17:48:25 -07001556 }
1557 }
Eric Laurenta553c252009-07-17 12:17:14 -07001558
Jason Parekhb1096152009-03-24 17:48:25 -07001559 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07001560 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08001561 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07001562 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
1563 }
Jason Parekhb1096152009-03-24 17:48:25 -07001564 }
1565
Mike Lockwood90631542012-01-06 11:20:37 -05001566 private void restoreMasterVolume() {
Eric Laurent83a017b2013-03-19 18:15:31 -07001567 if (mUseFixedVolume) {
1568 AudioSystem.setMasterVolume(1.0f);
1569 return;
1570 }
Mike Lockwood90631542012-01-06 11:20:37 -05001571 if (mUseMasterVolume) {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001572 float volume = Settings.System.getFloatForUser(mContentResolver,
1573 Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
Mike Lockwood90631542012-01-06 11:20:37 -05001574 if (volume >= 0.0f) {
1575 AudioSystem.setMasterVolume(volume);
1576 }
1577 }
1578 }
1579
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001580 /** @see AudioManager#shouldVibrate(int) */
1581 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001582 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583
1584 switch (getVibrateSetting(vibrateType)) {
1585
1586 case AudioManager.VIBRATE_SETTING_ON:
Glenn Kastenba195eb2011-12-13 09:30:40 -08001587 return getRingerMode() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001588
1589 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
Glenn Kastenba195eb2011-12-13 09:30:40 -08001590 return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001591
1592 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04001593 // return false, even for incoming calls
1594 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001595
1596 default:
1597 return false;
1598 }
1599 }
1600
1601 /** @see AudioManager#getVibrateSetting(int) */
1602 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001603 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604 return (mVibrateSetting >> (vibrateType * 2)) & 3;
1605 }
1606
1607 /** @see AudioManager#setVibrateSetting(int, int) */
1608 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
1609
Eric Laurentbffc3d12012-05-07 17:43:49 -07001610 if (!mHasVibrator) return;
1611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001612 mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
1613
1614 // Broadcast change
1615 broadcastVibrateSetting(vibrateType);
1616
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 }
1618
1619 /**
1620 * @see #setVibrateSetting(int, int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001621 */
1622 public static int getValueForVibrateSetting(int existingValue, int vibrateType,
1623 int vibrateSetting) {
1624
1625 // First clear the existing setting. Each vibrate type has two bits in
1626 // the value. Note '3' is '11' in binary.
1627 existingValue &= ~(3 << (vibrateType * 2));
1628
1629 // Set into the old value
1630 existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
1631
1632 return existingValue;
1633 }
1634
Eric Laurent9272b4b2010-01-23 17:12:59 -08001635 private class SetModeDeathHandler implements IBinder.DeathRecipient {
1636 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07001637 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001638 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
1639
Eric Laurent9f103de2011-09-08 15:04:23 -07001640 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08001641 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07001642 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001643 }
1644
1645 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07001646 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001647 synchronized(mSetModeDeathHandlers) {
1648 Log.w(TAG, "setMode() client died");
1649 int index = mSetModeDeathHandlers.indexOf(this);
1650 if (index < 0) {
1651 Log.w(TAG, "unregistered setMode() client died");
1652 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07001653 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
Eric Laurent9272b4b2010-01-23 17:12:59 -08001654 }
1655 }
Eric Laurent9f103de2011-09-08 15:04:23 -07001656 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1657 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07001658 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07001659 final long ident = Binder.clearCallingIdentity();
1660 disconnectBluetoothSco(newModeOwnerPid);
1661 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07001662 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08001663 }
1664
Marco Nelissenf1ddd512011-08-10 14:15:44 -07001665 public int getPid() {
1666 return mPid;
1667 }
1668
Eric Laurent9272b4b2010-01-23 17:12:59 -08001669 public void setMode(int mode) {
1670 mMode = mode;
1671 }
1672
1673 public int getMode() {
1674 return mMode;
1675 }
1676
1677 public IBinder getBinder() {
1678 return mCb;
1679 }
1680 }
1681
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682 /** @see AudioManager#setMode(int) */
Eric Laurent9272b4b2010-01-23 17:12:59 -08001683 public void setMode(int mode, IBinder cb) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001684 if (!checkAudioSettingsPermission("setMode()")) {
1685 return;
1686 }
Eric Laurenta553c252009-07-17 12:17:14 -07001687
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08001688 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07001689 return;
1690 }
1691
Eric Laurentd7454be2011-09-14 08:45:58 -07001692 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07001693 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07001694 if (mode == AudioSystem.MODE_CURRENT) {
1695 mode = mMode;
1696 }
Eric Laurentd7454be2011-09-14 08:45:58 -07001697 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
Eric Laurent9f103de2011-09-08 15:04:23 -07001698 }
1699 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1700 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07001701 if (newModeOwnerPid != 0) {
1702 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07001703 }
1704 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08001705
Eric Laurent9f103de2011-09-08 15:04:23 -07001706 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07001707 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07001708 // any mode other than NORMAL.
Eric Laurentd7454be2011-09-14 08:45:58 -07001709 int setModeInt(int mode, IBinder cb, int pid) {
1710 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07001711 if (cb == null) {
1712 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07001713 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07001714 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08001715
Eric Laurent9f103de2011-09-08 15:04:23 -07001716 SetModeDeathHandler hdlr = null;
1717 Iterator iter = mSetModeDeathHandlers.iterator();
1718 while (iter.hasNext()) {
1719 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
1720 if (h.getPid() == pid) {
1721 hdlr = h;
1722 // Remove from client list so that it is re-inserted at top of list
1723 iter.remove();
1724 hdlr.getBinder().unlinkToDeath(hdlr, 0);
1725 break;
1726 }
1727 }
1728 int status = AudioSystem.AUDIO_STATUS_OK;
1729 do {
1730 if (mode == AudioSystem.MODE_NORMAL) {
1731 // get new mode from client at top the list if any
1732 if (!mSetModeDeathHandlers.isEmpty()) {
1733 hdlr = mSetModeDeathHandlers.get(0);
1734 cb = hdlr.getBinder();
1735 mode = hdlr.getMode();
Eric Laurentb9c9d262009-05-06 08:13:20 -07001736 }
Eric Laurent9f103de2011-09-08 15:04:23 -07001737 } else {
1738 if (hdlr == null) {
1739 hdlr = new SetModeDeathHandler(cb, pid);
1740 }
1741 // Register for client death notification
1742 try {
1743 cb.linkToDeath(hdlr, 0);
1744 } catch (RemoteException e) {
1745 // Client has died!
1746 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
1747 }
1748
1749 // Last client to call setMode() is always at top of client list
1750 // as required by SetModeDeathHandler.binderDied()
1751 mSetModeDeathHandlers.add(0, hdlr);
1752 hdlr.setMode(mode);
1753 }
1754
1755 if (mode != mMode) {
1756 status = AudioSystem.setPhoneState(mode);
1757 if (status == AudioSystem.AUDIO_STATUS_OK) {
Eric Laurent9f103de2011-09-08 15:04:23 -07001758 mMode = mode;
1759 } else {
1760 if (hdlr != null) {
1761 mSetModeDeathHandlers.remove(hdlr);
1762 cb.unlinkToDeath(hdlr, 0);
1763 }
1764 // force reading new top of mSetModeDeathHandlers stack
1765 mode = AudioSystem.MODE_NORMAL;
1766 }
1767 } else {
1768 status = AudioSystem.AUDIO_STATUS_OK;
1769 }
1770 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
1771
1772 if (status == AudioSystem.AUDIO_STATUS_OK) {
1773 if (mode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07001774 if (mSetModeDeathHandlers.isEmpty()) {
1775 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
1776 } else {
1777 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
1778 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001779 }
1780 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07001781 if (streamType == STREAM_REMOTE_MUSIC) {
1782 // here handle remote media playback the same way as local playback
1783 streamType = AudioManager.STREAM_MUSIC;
1784 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001785 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001786 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
1787 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
Eric Laurent6d517662012-04-23 18:42:39 -07001788
1789 updateStreamVolumeAlias(true /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001790 }
Eric Laurentd7454be2011-09-14 08:45:58 -07001791 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001792 }
1793
1794 /** @see AudioManager#getMode() */
1795 public int getMode() {
1796 return mMode;
1797 }
1798
Eric Laurente78fced2013-03-15 16:03:47 -07001799 //==========================================================================================
1800 // Sound Effects
1801 //==========================================================================================
1802
1803 private static final String TAG_AUDIO_ASSETS = "audio_assets";
1804 private static final String ATTR_VERSION = "version";
1805 private static final String TAG_GROUP = "group";
1806 private static final String ATTR_GROUP_NAME = "name";
1807 private static final String TAG_ASSET = "asset";
1808 private static final String ATTR_ASSET_ID = "id";
1809 private static final String ATTR_ASSET_FILE = "file";
1810
1811 private static final String ASSET_FILE_VERSION = "1.0";
1812 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
1813
Glenn Kasten167d1a22013-07-23 16:24:41 -07001814 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001815
1816 class LoadSoundEffectReply {
1817 public int mStatus = 1;
1818 };
1819
Eric Laurente78fced2013-03-15 16:03:47 -07001820 private void loadTouchSoundAssetDefaults() {
1821 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
1822 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
1823 SOUND_EFFECT_FILES_MAP[i][0] = 0;
1824 SOUND_EFFECT_FILES_MAP[i][1] = -1;
1825 }
1826 }
1827
1828 private void loadTouchSoundAssets() {
1829 XmlResourceParser parser = null;
1830
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001831 // only load assets once.
1832 if (!SOUND_EFFECT_FILES.isEmpty()) {
1833 return;
1834 }
1835
Eric Laurente78fced2013-03-15 16:03:47 -07001836 loadTouchSoundAssetDefaults();
1837
1838 try {
1839 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
1840
1841 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
1842 String version = parser.getAttributeValue(null, ATTR_VERSION);
1843 boolean inTouchSoundsGroup = false;
1844
1845 if (ASSET_FILE_VERSION.equals(version)) {
1846 while (true) {
1847 XmlUtils.nextElement(parser);
1848 String element = parser.getName();
1849 if (element == null) {
1850 break;
1851 }
1852 if (element.equals(TAG_GROUP)) {
1853 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
1854 if (GROUP_TOUCH_SOUNDS.equals(name)) {
1855 inTouchSoundsGroup = true;
1856 break;
1857 }
1858 }
1859 }
1860 while (inTouchSoundsGroup) {
1861 XmlUtils.nextElement(parser);
1862 String element = parser.getName();
1863 if (element == null) {
1864 break;
1865 }
1866 if (element.equals(TAG_ASSET)) {
1867 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
1868 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
1869 int fx;
1870
1871 try {
1872 Field field = AudioManager.class.getField(id);
1873 fx = field.getInt(null);
1874 } catch (Exception e) {
1875 Log.w(TAG, "Invalid touch sound ID: "+id);
1876 continue;
1877 }
1878
1879 int i = SOUND_EFFECT_FILES.indexOf(file);
1880 if (i == -1) {
1881 i = SOUND_EFFECT_FILES.size();
1882 SOUND_EFFECT_FILES.add(file);
1883 }
1884 SOUND_EFFECT_FILES_MAP[fx][0] = i;
1885 } else {
1886 break;
1887 }
1888 }
1889 }
1890 } catch (Resources.NotFoundException e) {
1891 Log.w(TAG, "audio assets file not found", e);
1892 } catch (XmlPullParserException e) {
1893 Log.w(TAG, "XML parser exception reading touch sound assets", e);
1894 } catch (IOException e) {
1895 Log.w(TAG, "I/O exception reading touch sound assets", e);
1896 } finally {
1897 if (parser != null) {
1898 parser.close();
1899 }
1900 }
1901 }
1902
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001903 /** @see AudioManager#playSoundEffect(int) */
1904 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001905 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001906 }
1907
1908 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001909 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07001910 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
1911 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
1912 return;
1913 }
1914
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001915 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001916 effectType, (int) (volume * 1000), null, 0);
1917 }
1918
1919 /**
1920 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08001921 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001922 */
1923 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001924 int attempts = 3;
1925 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08001926
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001927 synchronized (reply) {
1928 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
1929 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08001930 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07001931 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001932 } catch (InterruptedException e) {
1933 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08001934 }
Eric Laurenta60e2122010-12-28 16:49:07 -08001935 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001936 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001937 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001938 }
1939
1940 /**
1941 * Unloads samples from the sound pool.
1942 * This method can be called to free some memory when
1943 * sound effects are disabled.
1944 */
1945 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001946 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001947 }
1948
Eric Laurenta60e2122010-12-28 16:49:07 -08001949 class SoundPoolListenerThread extends Thread {
1950 public SoundPoolListenerThread() {
1951 super("SoundPoolListenerThread");
1952 }
1953
1954 @Override
1955 public void run() {
1956
1957 Looper.prepare();
1958 mSoundPoolLooper = Looper.myLooper();
1959
1960 synchronized (mSoundEffectsLock) {
1961 if (mSoundPool != null) {
1962 mSoundPoolCallBack = new SoundPoolCallback();
1963 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
1964 }
1965 mSoundEffectsLock.notify();
1966 }
1967 Looper.loop();
1968 }
1969 }
1970
1971 private final class SoundPoolCallback implements
1972 android.media.SoundPool.OnLoadCompleteListener {
1973
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001974 int mStatus = 1; // 1 means neither error nor last sample loaded yet
1975 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08001976
1977 public int status() {
1978 return mStatus;
1979 }
1980
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001981 public void setSamples(int[] samples) {
1982 for (int i = 0; i < samples.length; i++) {
1983 // do not wait ack for samples rejected upfront by SoundPool
1984 if (samples[i] > 0) {
1985 mSamples.add(samples[i]);
1986 }
1987 }
Eric Laurenta60e2122010-12-28 16:49:07 -08001988 }
1989
1990 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
1991 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001992 int i = mSamples.indexOf(sampleId);
1993 if (i >= 0) {
1994 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08001995 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07001996 if ((status != 0) || mSamples. isEmpty()) {
1997 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08001998 mSoundEffectsLock.notify();
1999 }
2000 }
2001 }
2002 }
2003
Eric Laurent4050c932009-07-08 02:52:14 -07002004 /** @see AudioManager#reloadAudioSettings() */
2005 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002006 readAudioSettings(false /*userSwitch*/);
2007 }
2008
2009 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07002010 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2011 readPersistedSettings();
2012
2013 // restore volume settings
2014 int numStreamTypes = AudioSystem.getNumStreamTypes();
2015 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2016 VolumeStreamState streamState = mStreamStates[streamType];
2017
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002018 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2019 continue;
2020 }
2021
Eric Laurent3172d5e2012-05-09 11:38:16 -07002022 synchronized (streamState) {
2023 streamState.readSettings();
Eric Laurenta553c252009-07-17 12:17:14 -07002024
Eric Laurent3172d5e2012-05-09 11:38:16 -07002025 // unmute stream that was muted but is not affect by mute anymore
Eric Laurent42b041e2013-03-29 11:36:03 -07002026 if (streamState.isMuted() && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07002027 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002028 int size = streamState.mDeathHandlers.size();
2029 for (int i = 0; i < size; i++) {
2030 streamState.mDeathHandlers.get(i).mMuteCount = 1;
2031 streamState.mDeathHandlers.get(i).mute(false);
2032 }
Eric Laurent4050c932009-07-08 02:52:14 -07002033 }
Eric Laurent4050c932009-07-08 02:52:14 -07002034 }
2035 }
2036
Eric Laurent33902db2012-10-07 16:15:07 -07002037 // apply new ringer mode before checking volume for alias streams so that streams
2038 // muted by ringer mode have the correct volume
2039 setRingerModeInt(getRingerMode(), false);
2040
Eric Laurent24482012012-05-10 09:41:17 -07002041 checkAllAliasStreamVolumes();
2042
Eric Laurentd640bd32012-09-28 18:01:48 -07002043 synchronized (mSafeMediaVolumeState) {
2044 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07002045 enforceSafeMediaVolume();
2046 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07002047 }
Eric Laurent4050c932009-07-08 02:52:14 -07002048 }
2049
Dianne Hackborn961cae92013-03-20 14:59:43 -07002050 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002051 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002052 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2053 return;
2054 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002055
2056 if (on) {
2057 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2058 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2059 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
2060 }
2061 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2062 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2063 mForcedUseForComm = AudioSystem.FORCE_NONE;
2064 }
Eric Laurentfa640152011-03-12 15:59:51 -08002065
Eric Laurentafbb0472011-12-15 09:04:23 -08002066 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002067 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002068 }
2069
2070 /** @see AudioManager#isSpeakerphoneOn() */
2071 public boolean isSpeakerphoneOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002072 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002073 }
2074
Dianne Hackborn961cae92013-03-20 14:59:43 -07002075 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002076 public void setBluetoothScoOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002077 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2078 return;
2079 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002080
2081 if (on) {
2082 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2083 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2084 mForcedUseForComm = AudioSystem.FORCE_NONE;
2085 }
Eric Laurentfa640152011-03-12 15:59:51 -08002086
Eric Laurentafbb0472011-12-15 09:04:23 -08002087 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002088 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08002089 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002090 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002091 }
2092
2093 /** @see AudioManager#isBluetoothScoOn() */
2094 public boolean isBluetoothScoOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002095 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002096 }
2097
Dianne Hackborn961cae92013-03-20 14:59:43 -07002098 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07002099 public void setBluetoothA2dpOn(boolean on) {
Eric Laurentc390bed2012-07-03 12:24:05 -07002100 synchronized (mBluetoothA2dpEnabledLock) {
2101 mBluetoothA2dpEnabled = on;
2102 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2103 AudioSystem.FOR_MEDIA,
2104 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2105 null, 0);
2106 }
Eric Laurent78472112012-05-21 08:57:21 -07002107 }
2108
2109 /** @see AudioManager#isBluetoothA2dpOn() */
2110 public boolean isBluetoothA2dpOn() {
2111 synchronized (mBluetoothA2dpEnabledLock) {
2112 return mBluetoothA2dpEnabled;
2113 }
2114 }
2115
Eric Laurent3def1ee2010-03-17 23:26:26 -07002116 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07002117 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
2118 int scoAudioMode =
2119 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
2120 SCO_MODE_VIRTUAL_CALL : SCO_MODE_RAW;
2121 startBluetoothScoInt(cb, scoAudioMode);
2122 }
2123
2124 /** @see AudioManager#startBluetoothScoVirtualCall() */
2125 public void startBluetoothScoVirtualCall(IBinder cb) {
2126 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
2127 }
2128
2129 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07002130 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002131 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002132 return;
2133 }
Eric Laurent854938a2011-02-22 12:05:20 -08002134 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002135 // The calling identity must be cleared before calling ScoClient.incCount().
2136 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2137 // and this must be done on behalf of system server to make sure permissions are granted.
2138 // The caller identity must be cleared after getScoClient() because it is needed if a new
2139 // client is created.
2140 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07002141 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08002142 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002143 }
2144
2145 /** @see AudioManager#stopBluetoothSco() */
2146 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07002147 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002148 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002149 return;
2150 }
Eric Laurent854938a2011-02-22 12:05:20 -08002151 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002152 // The calling identity must be cleared before calling ScoClient.decCount().
2153 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2154 // and this must be done on behalf of system server to make sure permissions are granted.
2155 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08002156 if (client != null) {
2157 client.decCount();
2158 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08002159 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002160 }
2161
Eric Laurent78472112012-05-21 08:57:21 -07002162
Eric Laurent3def1ee2010-03-17 23:26:26 -07002163 private class ScoClient implements IBinder.DeathRecipient {
2164 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002165 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002166 private int mStartcount; // number of SCO connections started by this client
2167
2168 ScoClient(IBinder cb) {
2169 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002170 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002171 mStartcount = 0;
2172 }
2173
2174 public void binderDied() {
2175 synchronized(mScoClients) {
2176 Log.w(TAG, "SCO client died");
2177 int index = mScoClients.indexOf(this);
2178 if (index < 0) {
2179 Log.w(TAG, "unregistered SCO client died");
2180 } else {
2181 clearCount(true);
2182 mScoClients.remove(this);
2183 }
2184 }
2185 }
2186
Eric Laurent83900752014-05-15 15:14:22 -07002187 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002188 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07002189 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002190 if (mStartcount == 0) {
2191 try {
2192 mCb.linkToDeath(this, 0);
2193 } catch (RemoteException e) {
2194 // client has already died!
2195 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
2196 }
2197 }
2198 mStartcount++;
2199 }
2200 }
2201
2202 public void decCount() {
2203 synchronized(mScoClients) {
2204 if (mStartcount == 0) {
2205 Log.w(TAG, "ScoClient.decCount() already 0");
2206 } else {
2207 mStartcount--;
2208 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002209 try {
2210 mCb.unlinkToDeath(this, 0);
2211 } catch (NoSuchElementException e) {
2212 Log.w(TAG, "decCount() going to 0 but not registered to binder");
2213 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002214 }
Eric Laurentc18c9132013-04-12 17:24:56 -07002215 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002216 }
2217 }
2218 }
2219
2220 public void clearCount(boolean stopSco) {
2221 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002222 if (mStartcount != 0) {
2223 try {
2224 mCb.unlinkToDeath(this, 0);
2225 } catch (NoSuchElementException e) {
2226 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2227 }
2228 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002229 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002230 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002231 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002232 }
2233 }
2234 }
2235
2236 public int getCount() {
2237 return mStartcount;
2238 }
2239
2240 public IBinder getBinder() {
2241 return mCb;
2242 }
2243
Eric Laurentd7454be2011-09-14 08:45:58 -07002244 public int getPid() {
2245 return mCreatorPid;
2246 }
2247
Eric Laurent3def1ee2010-03-17 23:26:26 -07002248 public int totalCount() {
2249 synchronized(mScoClients) {
2250 int count = 0;
2251 int size = mScoClients.size();
2252 for (int i = 0; i < size; i++) {
2253 count += mScoClients.get(i).getCount();
2254 }
2255 return count;
2256 }
2257 }
2258
Eric Laurent83900752014-05-15 15:14:22 -07002259 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08002260 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07002261 if (totalCount() == 0) {
2262 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2263 // Make sure that the state transitions to CONNECTING even if we cannot initiate
2264 // the connection.
2265 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2266 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002267 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07002268 synchronized(mSetModeDeathHandlers) {
2269 if ((mSetModeDeathHandlers.isEmpty() ||
2270 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2271 (mScoAudioState == SCO_STATE_INACTIVE ||
2272 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2273 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07002274 mScoAudioMode = scoAudioMode;
Eric Laurent9f103de2011-09-08 15:04:23 -07002275 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002276 boolean status;
2277 if (mScoAudioMode == SCO_MODE_RAW) {
2278 status = mBluetoothHeadset.connectAudio();
2279 } else {
2280 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2281 mBluetoothHeadsetDevice);
2282 }
2283 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07002284 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2285 } else {
2286 broadcastScoConnectionState(
2287 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2288 }
2289 } else if (getBluetoothHeadset()) {
2290 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07002291 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002292 } else {
2293 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2294 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002295 }
2296 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07002297 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002298 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002299 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002300 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002301 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2302 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2303 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07002304 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002305 boolean status;
2306 if (mScoAudioMode == SCO_MODE_RAW) {
2307 status = mBluetoothHeadset.disconnectAudio();
2308 } else {
2309 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2310 mBluetoothHeadsetDevice);
2311 }
2312 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002313 mScoAudioState = SCO_STATE_INACTIVE;
2314 broadcastScoConnectionState(
2315 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2316 }
2317 } else if (getBluetoothHeadset()) {
2318 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2319 }
2320 } else {
2321 mScoAudioState = SCO_STATE_INACTIVE;
2322 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2323 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002324 }
2325 }
2326 }
2327 }
2328
Eric Laurent62ef7672010-11-24 10:58:32 -08002329 private void checkScoAudioState() {
2330 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002331 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08002332 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2333 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2334 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2335 }
2336 }
2337
Eric Laurent854938a2011-02-22 12:05:20 -08002338 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002339 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002340 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002341 int size = mScoClients.size();
2342 for (int i = 0; i < size; i++) {
2343 client = mScoClients.get(i);
2344 if (client.getBinder() == cb)
2345 return client;
2346 }
Eric Laurent854938a2011-02-22 12:05:20 -08002347 if (create) {
2348 client = new ScoClient(cb);
2349 mScoClients.add(client);
2350 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002351 return client;
2352 }
2353 }
2354
Eric Laurentd7454be2011-09-14 08:45:58 -07002355 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002356 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002357 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002358 int size = mScoClients.size();
2359 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08002360 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07002361 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08002362 cl.clearCount(stopSco);
2363 } else {
2364 savedClient = cl;
2365 }
2366 }
2367 mScoClients.clear();
2368 if (savedClient != null) {
2369 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002370 }
2371 }
2372 }
2373
Eric Laurentdc03c612011-04-01 10:59:41 -07002374 private boolean getBluetoothHeadset() {
2375 boolean result = false;
2376 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2377 if (adapter != null) {
2378 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2379 BluetoothProfile.HEADSET);
2380 }
2381 // If we could not get a bluetooth headset proxy, send a failure message
2382 // without delay to reset the SCO audio state and clear SCO clients.
2383 // If we could get a proxy, send a delayed failure message that will reset our state
2384 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08002385 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002386 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2387 return result;
2388 }
2389
Eric Laurentd7454be2011-09-14 08:45:58 -07002390 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002391 synchronized(mScoClients) {
2392 checkScoAudioState();
2393 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2394 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2395 if (mBluetoothHeadsetDevice != null) {
2396 if (mBluetoothHeadset != null) {
2397 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07002398 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002399 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002400 SENDMSG_REPLACE, 0, 0, null, 0);
2401 }
2402 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2403 getBluetoothHeadset()) {
2404 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2405 }
2406 }
2407 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07002408 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07002409 }
2410 }
2411 }
2412
2413 private void resetBluetoothSco() {
2414 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002415 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07002416 mScoAudioState = SCO_STATE_INACTIVE;
2417 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2418 }
2419 }
2420
2421 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08002422 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
2423 SENDMSG_QUEUE, state, 0, null, 0);
2424 }
2425
2426 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002427 if (state != mScoConnectionState) {
2428 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2429 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2430 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2431 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002432 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07002433 mScoConnectionState = state;
2434 }
2435 }
2436
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002437 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
2438 new BluetoothProfile.ServiceListener() {
2439 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002440 BluetoothDevice btDevice;
2441 List<BluetoothDevice> deviceList;
2442 switch(profile) {
2443 case BluetoothProfile.A2DP:
John Du5a0cf7a2013-07-19 11:30:34 -07002444 synchronized (mA2dpAvrcpLock) {
2445 mA2dp = (BluetoothA2dp) proxy;
2446 deviceList = mA2dp.getConnectedDevices();
2447 if (deviceList.size() > 0) {
2448 btDevice = deviceList.get(0);
2449 synchronized (mConnectedDevices) {
2450 int state = mA2dp.getConnectionState(btDevice);
2451 int delay = checkSendBecomingNoisyIntent(
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002452 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2453 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
John Du5a0cf7a2013-07-19 11:30:34 -07002454 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002455 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07002456 state,
2457 0,
2458 btDevice,
2459 delay);
2460 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002461 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002462 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002463 break;
2464
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002465 case BluetoothProfile.A2DP_SINK:
2466 deviceList = proxy.getConnectedDevices();
2467 if (deviceList.size() > 0) {
2468 btDevice = deviceList.get(0);
2469 synchronized (mConnectedDevices) {
2470 int state = proxy.getConnectionState(btDevice);
2471 queueMsgUnderWakeLock(mAudioHandler,
2472 MSG_SET_A2DP_SRC_CONNECTION_STATE,
2473 state,
2474 0,
2475 btDevice,
2476 0 /* delay */);
2477 }
2478 }
2479 break;
2480
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002481 case BluetoothProfile.HEADSET:
2482 synchronized (mScoClients) {
2483 // Discard timeout message
2484 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
2485 mBluetoothHeadset = (BluetoothHeadset) proxy;
2486 deviceList = mBluetoothHeadset.getConnectedDevices();
2487 if (deviceList.size() > 0) {
2488 mBluetoothHeadsetDevice = deviceList.get(0);
2489 } else {
2490 mBluetoothHeadsetDevice = null;
2491 }
2492 // Refresh SCO audio state
2493 checkScoAudioState();
2494 // Continue pending action if any
2495 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
2496 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
2497 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2498 boolean status = false;
2499 if (mBluetoothHeadsetDevice != null) {
2500 switch (mScoAudioState) {
2501 case SCO_STATE_ACTIVATE_REQ:
2502 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07002503 if (mScoAudioMode == SCO_MODE_RAW) {
2504 status = mBluetoothHeadset.connectAudio();
2505 } else {
2506 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2507 mBluetoothHeadsetDevice);
2508 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002509 break;
2510 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07002511 if (mScoAudioMode == SCO_MODE_RAW) {
2512 status = mBluetoothHeadset.disconnectAudio();
2513 } else {
2514 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2515 mBluetoothHeadsetDevice);
2516 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002517 break;
2518 case SCO_STATE_DEACTIVATE_EXT_REQ:
2519 status = mBluetoothHeadset.stopVoiceRecognition(
2520 mBluetoothHeadsetDevice);
2521 }
2522 }
2523 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002524 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002525 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07002526 }
2527 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002528 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002529 break;
2530
2531 default:
2532 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002533 }
2534 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002535 public void onServiceDisconnected(int profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002536 switch(profile) {
2537 case BluetoothProfile.A2DP:
John Du5a0cf7a2013-07-19 11:30:34 -07002538 synchronized (mA2dpAvrcpLock) {
2539 mA2dp = null;
2540 synchronized (mConnectedDevices) {
2541 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
2542 makeA2dpDeviceUnavailableNow(
2543 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
2544 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002545 }
2546 }
2547 break;
2548
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002549 case BluetoothProfile.A2DP_SINK:
2550 synchronized (mConnectedDevices) {
2551 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) {
2552 makeA2dpSrcUnavailable(
2553 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP));
2554 }
2555 }
2556 break;
2557
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002558 case BluetoothProfile.HEADSET:
2559 synchronized (mScoClients) {
2560 mBluetoothHeadset = null;
2561 }
2562 break;
2563
2564 default:
2565 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002566 }
2567 }
2568 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08002569
Eric Laurentc34dcc12012-09-10 13:51:52 -07002570 private void onCheckMusicActive() {
Eric Laurentd640bd32012-09-28 18:01:48 -07002571 synchronized (mSafeMediaVolumeState) {
2572 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002573 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
2574
2575 if ((device & mSafeMediaVolumeDevices) != 0) {
2576 sendMsg(mAudioHandler,
2577 MSG_CHECK_MUSIC_ACTIVE,
2578 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07002579 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07002580 0,
2581 null,
2582 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07002583 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07002584 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
2585 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002586 // Approximate cumulative active music time
2587 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
2588 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
2589 setSafeMediaVolumeEnabled(true);
2590 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07002591 }
2592 }
2593 }
2594 }
2595 }
2596 }
2597
Eric Laurentd640bd32012-09-28 18:01:48 -07002598 private void onConfigureSafeVolume(boolean force) {
2599 synchronized (mSafeMediaVolumeState) {
2600 int mcc = mContext.getResources().getConfiguration().mcc;
2601 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
2602 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
2603 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
2604 boolean safeMediaVolumeEnabled = mContext.getResources().getBoolean(
2605 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08002606
2607 // The persisted state is either "disabled" or "active": this is the state applied
2608 // next time we boot and cannot be "inactive"
2609 int persistedState;
Eric Laurentd640bd32012-09-28 18:01:48 -07002610 if (safeMediaVolumeEnabled) {
Eric Laurent05274f32012-11-29 12:48:18 -08002611 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
2612 // The state can already be "inactive" here if the user has forced it before
2613 // the 30 seconds timeout for forced configuration. In this case we don't reset
2614 // it to "active".
2615 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
2616 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
2617 enforceSafeMediaVolume();
2618 }
Eric Laurentd640bd32012-09-28 18:01:48 -07002619 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08002620 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07002621 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
2622 }
2623 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08002624 sendMsg(mAudioHandler,
2625 MSG_PERSIST_SAFE_VOLUME_STATE,
2626 SENDMSG_QUEUE,
2627 persistedState,
2628 0,
2629 null,
2630 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07002631 }
2632 }
2633 }
2634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002635 ///////////////////////////////////////////////////////////////////////////
2636 // Internal methods
2637 ///////////////////////////////////////////////////////////////////////////
2638
2639 /**
2640 * Checks if the adjustment should change ringer mode instead of just
2641 * adjusting volume. If so, this will set the proper ringer mode and volume
2642 * indices on the stream states.
2643 */
John Spurlocka11b4af2014-06-01 11:52:23 -04002644 private int checkForRingerModeChange(int oldIndex, int direction, int step) {
2645 int result = FLAG_ADJUST_VOLUME;
Glenn Kastenba195eb2011-12-13 09:30:40 -08002646 int ringerMode = getRingerMode();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002647
Eric Laurentbffc3d12012-05-07 17:43:49 -07002648 switch (ringerMode) {
2649 case RINGER_MODE_NORMAL:
2650 if (direction == AudioManager.ADJUST_LOWER) {
2651 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07002652 // "step" is the delta in internal index units corresponding to a
2653 // change of 1 in UI index units.
2654 // Because of rounding when rescaling from one stream index range to its alias
2655 // index range, we cannot simply test oldIndex == step:
2656 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
2657 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002658 ringerMode = RINGER_MODE_VIBRATE;
2659 }
2660 } else {
Eric Laurent24482012012-05-10 09:41:17 -07002661 // (oldIndex < step) is equivalent to (old UI index == 0)
John Spurlock86005342014-05-23 11:58:00 -04002662 if ((oldIndex < step)
2663 && VOLUME_SETS_RINGER_MODE_SILENT
2664 && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002665 ringerMode = RINGER_MODE_SILENT;
2666 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07002667 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002668 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07002669 break;
2670 case RINGER_MODE_VIBRATE:
2671 if (!mHasVibrator) {
2672 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
2673 "but no vibrator is present");
2674 break;
2675 }
Amith Yamasanic696a532011-10-28 17:02:37 -07002676 if ((direction == AudioManager.ADJUST_LOWER)) {
John Spurlock86005342014-05-23 11:58:00 -04002677 if (VOLUME_SETS_RINGER_MODE_SILENT
2678 && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002679 ringerMode = RINGER_MODE_SILENT;
Amith Yamasanic696a532011-10-28 17:02:37 -07002680 }
2681 } else if (direction == AudioManager.ADJUST_RAISE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002682 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07002683 }
John Spurlocka11b4af2014-06-01 11:52:23 -04002684 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07002685 break;
2686 case RINGER_MODE_SILENT:
Daniel Sandler6329bf72010-02-26 15:17:44 -05002687 if (direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04002688 if (PREVENT_VOLUME_ADJUSTMENT_IF_SILENT) {
2689 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07002690 } else {
John Spurlocka11b4af2014-06-01 11:52:23 -04002691 if (mHasVibrator) {
2692 ringerMode = RINGER_MODE_VIBRATE;
2693 } else {
2694 ringerMode = RINGER_MODE_NORMAL;
2695 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07002696 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05002697 }
John Spurlocka11b4af2014-06-01 11:52:23 -04002698 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07002699 break;
2700 default:
2701 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
2702 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002703 }
2704
Eric Laurentbffc3d12012-05-07 17:43:49 -07002705 setRingerMode(ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002706
Eric Laurent25101b02011-02-02 09:33:30 -08002707 mPrevVolDirection = direction;
2708
John Spurlocka11b4af2014-06-01 11:52:23 -04002709 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002710 }
2711
John Spurlock3346a802014-05-20 16:25:37 -04002712 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002713 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07002714 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002715 }
2716
Eric Laurent5b4e6542010-03-19 20:02:21 -07002717 private boolean isStreamMutedByRingerMode(int streamType) {
2718 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
2719 }
2720
Eric Laurent24e0d9b2013-10-03 18:15:07 -07002721 boolean updateRingerModeAffectedStreams() {
2722 int ringerModeAffectedStreams;
2723 // make sure settings for ringer mode are consistent with device type: non voice capable
2724 // devices (tablets) include media stream in silent mode whereas phones don't.
2725 ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
2726 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
2727 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
2728 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
2729 UserHandle.USER_CURRENT);
2730
2731 // ringtone, notification and system streams are always affected by ringer mode
2732 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
2733 (1 << AudioSystem.STREAM_NOTIFICATION)|
2734 (1 << AudioSystem.STREAM_SYSTEM);
2735
2736 if (mVoiceCapable) {
2737 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
2738 } else {
2739 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
2740 }
2741 synchronized (mCameraSoundForced) {
2742 if (mCameraSoundForced) {
2743 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
2744 } else {
2745 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
2746 }
2747 }
2748 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
2749 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
2750 } else {
2751 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
2752 }
2753
2754 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
2755 Settings.System.putIntForUser(mContentResolver,
2756 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
2757 ringerModeAffectedStreams,
2758 UserHandle.USER_CURRENT);
2759 mRingerModeAffectedStreams = ringerModeAffectedStreams;
2760 return true;
2761 }
2762 return false;
2763 }
2764
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002765 public boolean isStreamAffectedByMute(int streamType) {
2766 return (mMuteAffectedStreams & (1 << streamType)) != 0;
2767 }
2768
2769 private void ensureValidDirection(int direction) {
2770 if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
2771 throw new IllegalArgumentException("Bad direction " + direction);
2772 }
2773 }
2774
Lei Zhang6c798972012-03-02 11:40:12 -08002775 private void ensureValidSteps(int steps) {
2776 if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
2777 throw new IllegalArgumentException("Bad volume adjust steps " + steps);
2778 }
2779 }
2780
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002781 private void ensureValidStreamType(int streamType) {
2782 if (streamType < 0 || streamType >= mStreamStates.length) {
2783 throw new IllegalArgumentException("Bad stream type " + streamType);
2784 }
2785 }
2786
Eric Laurent6d517662012-04-23 18:42:39 -07002787 private boolean isInCommunication() {
Santos Cordon9eb45932014-06-27 12:28:43 -07002788 boolean isInAPhoneCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002789
Santos Cordon9eb45932014-06-27 12:28:43 -07002790 TelecommManager telecommManager =
2791 (TelecommManager) mContext.getSystemService(Context.TELECOMM_SERVICE);
2792 isInAPhoneCall = telecommManager.isInAPhoneCall();
2793
2794 return (isInAPhoneCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
Eric Laurent6d517662012-04-23 18:42:39 -07002795 }
Eric Laurent25101b02011-02-02 09:33:30 -08002796
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002797 /**
2798 * For code clarity for getActiveStreamType(int)
2799 * @param delay_ms max time since last STREAM_MUSIC activity to consider
2800 * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
2801 * in the last "delay_ms" ms.
2802 */
2803 private boolean isAfMusicActiveRecently(int delay_ms) {
2804 return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
2805 || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
2806 }
2807
Eric Laurent6d517662012-04-23 18:42:39 -07002808 private int getActiveStreamType(int suggestedStreamType) {
2809 if (mVoiceCapable) {
2810 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08002811 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
2812 == AudioSystem.FORCE_BT_SCO) {
2813 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
2814 return AudioSystem.STREAM_BLUETOOTH_SCO;
2815 } else {
2816 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
2817 return AudioSystem.STREAM_VOICE_CALL;
2818 }
Eric Laurent25101b02011-02-02 09:33:30 -08002819 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002820 if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002821 if (DEBUG_VOL)
2822 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
2823 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002824 } else
2825 if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC))
2826 {
2827 if (DEBUG_VOL)
2828 Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
2829 return STREAM_REMOTE_MUSIC;
2830 } else {
2831 if (DEBUG_VOL)
2832 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
2833 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002834 }
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002835 } else if (isAfMusicActiveRecently(0)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002836 if (DEBUG_VOL)
2837 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
2838 return AudioSystem.STREAM_MUSIC;
Joe Onoratoc7fcba42011-01-05 16:53:11 -08002839 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002840 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
2841 + suggestedStreamType);
Eric Laurent25101b02011-02-02 09:33:30 -08002842 return suggestedStreamType;
2843 }
2844 } else {
Eric Laurent6d517662012-04-23 18:42:39 -07002845 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08002846 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
2847 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002848 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08002849 return AudioSystem.STREAM_BLUETOOTH_SCO;
2850 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002851 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08002852 return AudioSystem.STREAM_VOICE_CALL;
2853 }
2854 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
Eric Laurent9903e262012-09-21 18:10:32 -07002855 DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS) ||
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002856 AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
Eric Laurent9903e262012-09-21 18:10:32 -07002857 DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002858 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08002859 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002860 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002861 if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
2862 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
2863 return AudioSystem.STREAM_MUSIC;
2864 } else
2865 if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC))
2866 {
2867 if (DEBUG_VOL)
2868 Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
2869 return STREAM_REMOTE_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002870 } else {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07002871 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default");
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002872 return AudioSystem.STREAM_MUSIC;
2873 }
Eric Laurent25101b02011-02-02 09:33:30 -08002874 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07002875 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
2876 + suggestedStreamType);
Eric Laurent25101b02011-02-02 09:33:30 -08002877 return suggestedStreamType;
Joe Onoratoc7fcba42011-01-05 16:53:11 -08002878 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002879 }
2880 }
2881
Glenn Kastenba195eb2011-12-13 09:30:40 -08002882 private void broadcastRingerMode(int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002883 // Send sticky broadcast
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08002884 Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION);
Glenn Kastenba195eb2011-12-13 09:30:40 -08002885 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08002886 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
2887 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002888 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002889 }
2890
2891 private void broadcastVibrateSetting(int vibrateType) {
2892 // Send broadcast
2893 if (ActivityManagerNative.isSystemReady()) {
2894 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
2895 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
2896 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002897 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002898 }
2899 }
2900
2901 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07002902 /**
2903 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
2904 * Note that the wake lock needs to be released after the message has been handled.
2905 */
2906 private void queueMsgUnderWakeLock(Handler handler, int msg,
2907 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07002908 final long ident = Binder.clearCallingIdentity();
2909 // Always acquire the wake lock as AudioService because it is released by the
2910 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07002911 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07002912 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07002913 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
2914 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002915
Eric Laurentafbb0472011-12-15 09:04:23 -08002916 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002917 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002918
2919 if (existingMsgPolicy == SENDMSG_REPLACE) {
2920 handler.removeMessages(msg);
2921 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
2922 return;
2923 }
2924
Eric Laurentafbb0472011-12-15 09:04:23 -08002925 handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002926 }
2927
2928 boolean checkAudioSettingsPermission(String method) {
2929 if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS")
2930 == PackageManager.PERMISSION_GRANTED) {
2931 return true;
2932 }
2933 String msg = "Audio Settings Permission Denial: " + method + " from pid="
2934 + Binder.getCallingPid()
2935 + ", uid=" + Binder.getCallingUid();
2936 Log.w(TAG, msg);
2937 return false;
2938 }
2939
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002940 private int getDeviceForStream(int stream) {
2941 int device = AudioSystem.getDevicesForStream(stream);
2942 if ((device & (device - 1)) != 0) {
2943 // Multiple device selection is either:
2944 // - speaker + one other device: give priority to speaker in this case.
2945 // - one A2DP device + another device: happens with duplicated output. In this case
2946 // retain the device on the A2DP output as the other must not correspond to an active
2947 // selection if not the speaker.
2948 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
2949 device = AudioSystem.DEVICE_OUT_SPEAKER;
2950 } else {
2951 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
2952 }
2953 }
2954 return device;
2955 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002956
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002957 public void setWiredDeviceConnectionState(int device, int state, String name) {
2958 synchronized (mConnectedDevices) {
2959 int delay = checkSendBecomingNoisyIntent(device, state);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07002960 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002961 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002962 device,
2963 state,
2964 name,
2965 delay);
2966 }
2967 }
2968
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002969 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002970 {
2971 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002972 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
2973 throw new IllegalArgumentException("invalid profile " + profile);
2974 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002975 synchronized (mConnectedDevices) {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002976 if (profile == BluetoothProfile.A2DP) {
2977 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2978 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
2979 } else {
2980 delay = 0;
2981 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07002982 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002983 (profile == BluetoothProfile.A2DP ?
2984 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002985 state,
2986 0,
2987 device,
2988 delay);
2989 }
2990 return delay;
2991 }
2992
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002993 ///////////////////////////////////////////////////////////////////////////
2994 // Inner classes
2995 ///////////////////////////////////////////////////////////////////////////
2996
2997 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002998 private final int mStreamType;
2999
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003000 private String mVolumeIndexSettingName;
Eric Laurenta553c252009-07-17 12:17:14 -07003001 private int mIndexMax;
Eric Laurent3172d5e2012-05-09 11:38:16 -07003002 private final ConcurrentHashMap<Integer, Integer> mIndex =
3003 new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003004 private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003005
Eric Laurenta553c252009-07-17 12:17:14 -07003006 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003007
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003008 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003009
3010 mStreamType = streamType;
Jared Suttles59820132009-08-13 21:50:52 -05003011 mIndexMax = MAX_STREAM_VOLUME[streamType];
Eric Laurenta553c252009-07-17 12:17:14 -07003012 AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
3013 mIndexMax *= 10;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003014
Eric Laurent33902db2012-10-07 16:15:07 -07003015 // mDeathHandlers must be created before calling readSettings()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003016 mDeathHandlers = new ArrayList<VolumeDeathHandler>();
Eric Laurent33902db2012-10-07 16:15:07 -07003017
3018 readSettings();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003019 }
3020
Eric Laurent42b041e2013-03-29 11:36:03 -07003021 public String getSettingNameForDevice(int device) {
3022 String name = mVolumeIndexSettingName;
Eric Laurent948d3272014-05-16 15:18:45 -07003023 String suffix = AudioSystem.getOutputDeviceName(device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003024 if (suffix.isEmpty()) {
3025 return name;
3026 }
3027 return name + "_" + suffix;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003028 }
3029
Eric Laurentfdbee862014-05-12 15:26:12 -07003030 public void readSettings() {
3031 synchronized (VolumeStreamState.class) {
3032 // force maximum volume on all streams if fixed volume property is set
3033 if (mUseFixedVolume) {
3034 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
3035 return;
3036 }
3037 // do not read system stream volume from settings: this stream is always aliased
3038 // to another stream type and its volume is never persisted. Values in settings can
3039 // only be stale values
3040 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3041 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
3042 int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
3043 synchronized (mCameraSoundForced) {
3044 if (mCameraSoundForced) {
3045 index = mIndexMax;
3046 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003047 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003048 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
3049 return;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003050 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003051
Eric Laurentfdbee862014-05-12 15:26:12 -07003052 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
3053
3054 for (int i = 0; remainingDevices != 0; i++) {
3055 int device = (1 << i);
3056 if ((device & remainingDevices) == 0) {
3057 continue;
3058 }
3059 remainingDevices &= ~device;
3060
3061 // retrieve current volume for device
3062 String name = getSettingNameForDevice(device);
3063 // if no volume stored for current stream and device, use default volume if default
3064 // device, continue otherwise
3065 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
3066 AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
3067 int index = Settings.System.getIntForUser(
3068 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3069 if (index == -1) {
3070 continue;
3071 }
3072
3073 // ignore settings for fixed volume devices: volume should always be at max or 0
3074 if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) &&
3075 ((device & mFixedVolumeDevices) != 0)) {
3076 mIndex.put(device, (index != 0) ? mIndexMax : 0);
3077 } else {
3078 mIndex.put(device, getValidIndex(10 * index));
3079 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003080 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003081 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003082 }
3083
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003084 public void applyDeviceVolume(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003085 int index;
3086 if (isMuted()) {
3087 index = 0;
Eric Laurentcd772d02013-10-30 18:31:07 -07003088 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003089 mAvrcpAbsVolSupported) {
3090 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07003091 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07003092 index = (getIndex(device) + 5)/10;
3093 }
3094 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003095 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003096
Eric Laurentfdbee862014-05-12 15:26:12 -07003097 public void applyAllVolumes() {
3098 synchronized (VolumeStreamState.class) {
3099 // apply default volume first: by convention this will reset all
3100 // devices volumes in audio policy manager to the supplied value
3101 int index;
3102 if (isMuted()) {
3103 index = 0;
3104 } else {
3105 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3106 }
3107 AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3108 // then apply device specific volumes
3109 Set set = mIndex.entrySet();
3110 Iterator i = set.iterator();
3111 while (i.hasNext()) {
3112 Map.Entry entry = (Map.Entry)i.next();
3113 int device = ((Integer)entry.getKey()).intValue();
3114 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
3115 if (isMuted()) {
3116 index = 0;
3117 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3118 mAvrcpAbsVolSupported) {
3119 index = (mIndexMax + 5)/10;
3120 } else {
3121 index = ((Integer)entry.getValue() + 5)/10;
3122 }
3123 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07003124 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003125 }
3126 }
3127 }
3128
3129 public boolean adjustIndex(int deltaIndex, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003130 return setIndex(getIndex(device) + deltaIndex,
3131 device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003132 }
3133
Eric Laurentfdbee862014-05-12 15:26:12 -07003134 public boolean setIndex(int index, int device) {
3135 synchronized (VolumeStreamState.class) {
3136 int oldIndex = getIndex(device);
3137 index = getValidIndex(index);
3138 synchronized (mCameraSoundForced) {
3139 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3140 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07003141 }
3142 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003143 mIndex.put(device, index);
3144
3145 if (oldIndex != index) {
3146 // Apply change to all streams using this one as alias
3147 // if changing volume of current device, also change volume of current
3148 // device on aliased stream
3149 boolean currentDevice = (device == getDeviceForStream(mStreamType));
3150 int numStreamTypes = AudioSystem.getNumStreamTypes();
3151 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3152 if (streamType != mStreamType &&
3153 mStreamVolumeAlias[streamType] == mStreamType) {
3154 int scaledIndex = rescaleIndex(index, mStreamType, streamType);
3155 mStreamStates[streamType].setIndex(scaledIndex,
3156 device);
3157 if (currentDevice) {
3158 mStreamStates[streamType].setIndex(scaledIndex,
3159 getDeviceForStream(streamType));
3160 }
3161 }
3162 }
3163 return true;
3164 } else {
3165 return false;
3166 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003167 }
3168 }
3169
Eric Laurentfdbee862014-05-12 15:26:12 -07003170 public int getIndex(int device) {
3171 synchronized (VolumeStreamState.class) {
3172 Integer index = mIndex.get(device);
3173 if (index == null) {
3174 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
3175 index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
3176 }
3177 return index.intValue();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003178 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07003179 }
3180
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003181 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07003182 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003183 }
3184
Eric Laurentfdbee862014-05-12 15:26:12 -07003185 public void setAllIndexes(VolumeStreamState srcStream) {
3186 synchronized (VolumeStreamState.class) {
3187 int srcStreamType = srcStream.getStreamType();
3188 // apply default device volume from source stream to all devices first in case
3189 // some devices are present in this stream state but not in source stream state
3190 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003191 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurentfdbee862014-05-12 15:26:12 -07003192 Set set = mIndex.entrySet();
3193 Iterator i = set.iterator();
3194 while (i.hasNext()) {
3195 Map.Entry entry = (Map.Entry)i.next();
3196 entry.setValue(index);
3197 }
3198 // Now apply actual volume for devices in source stream state
3199 set = srcStream.mIndex.entrySet();
3200 i = set.iterator();
3201 while (i.hasNext()) {
3202 Map.Entry entry = (Map.Entry)i.next();
3203 int device = ((Integer)entry.getKey()).intValue();
3204 index = ((Integer)entry.getValue()).intValue();
3205 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07003206
Eric Laurentfdbee862014-05-12 15:26:12 -07003207 setIndex(index, device);
3208 }
Eric Laurent6d517662012-04-23 18:42:39 -07003209 }
3210 }
3211
Eric Laurentfdbee862014-05-12 15:26:12 -07003212 public void setAllIndexesToMax() {
3213 synchronized (VolumeStreamState.class) {
3214 Set set = mIndex.entrySet();
3215 Iterator i = set.iterator();
3216 while (i.hasNext()) {
3217 Map.Entry entry = (Map.Entry)i.next();
3218 entry.setValue(mIndexMax);
3219 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003220 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003221 }
3222
Eric Laurentfdbee862014-05-12 15:26:12 -07003223 public void mute(IBinder cb, boolean state) {
3224 synchronized (VolumeStreamState.class) {
3225 VolumeDeathHandler handler = getDeathHandler(cb, state);
3226 if (handler == null) {
3227 Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
3228 return;
3229 }
3230 handler.mute(state);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003231 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003232 }
3233
Eric Laurent6d517662012-04-23 18:42:39 -07003234 public int getStreamType() {
3235 return mStreamType;
3236 }
3237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003238 private int getValidIndex(int index) {
3239 if (index < 0) {
3240 return 0;
Eric Laurent83a017b2013-03-19 18:15:31 -07003241 } else if (mUseFixedVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07003242 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003243 }
3244
3245 return index;
3246 }
3247
3248 private class VolumeDeathHandler implements IBinder.DeathRecipient {
3249 private IBinder mICallback; // To be notified of client's death
3250 private int mMuteCount; // Number of active mutes for this client
3251
3252 VolumeDeathHandler(IBinder cb) {
3253 mICallback = cb;
3254 }
3255
Eric Laurent3172d5e2012-05-09 11:38:16 -07003256 // must be called while synchronized on parent VolumeStreamState
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003257 public void mute(boolean state) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003258 boolean updateVolume = false;
Eric Laurent3172d5e2012-05-09 11:38:16 -07003259 if (state) {
3260 if (mMuteCount == 0) {
3261 // Register for client death notification
3262 try {
3263 // mICallback can be 0 if muted by AudioService
3264 if (mICallback != null) {
3265 mICallback.linkToDeath(this, 0);
3266 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003267 VolumeStreamState.this.mDeathHandlers.add(this);
Eric Laurent3172d5e2012-05-09 11:38:16 -07003268 // If the stream is not yet muted by any client, set level to 0
Eric Laurent42b041e2013-03-29 11:36:03 -07003269 if (!VolumeStreamState.this.isMuted()) {
3270 updateVolume = true;
Eric Laurent3172d5e2012-05-09 11:38:16 -07003271 }
3272 } catch (RemoteException e) {
3273 // Client has died!
3274 binderDied();
3275 return;
3276 }
3277 } else {
3278 Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
3279 }
3280 mMuteCount++;
3281 } else {
3282 if (mMuteCount == 0) {
3283 Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
3284 } else {
3285 mMuteCount--;
3286 if (mMuteCount == 0) {
3287 // Unregister from client death notification
Eric Laurent42b041e2013-03-29 11:36:03 -07003288 VolumeStreamState.this.mDeathHandlers.remove(this);
Eric Laurent3172d5e2012-05-09 11:38:16 -07003289 // mICallback can be 0 if muted by AudioService
3290 if (mICallback != null) {
3291 mICallback.unlinkToDeath(this, 0);
3292 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003293 if (!VolumeStreamState.this.isMuted()) {
3294 updateVolume = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003295 }
3296 }
3297 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003298 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003299 if (updateVolume) {
3300 sendMsg(mAudioHandler,
3301 MSG_SET_ALL_VOLUMES,
3302 SENDMSG_QUEUE,
3303 0,
3304 0,
3305 VolumeStreamState.this, 0);
3306 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003307 }
3308
3309 public void binderDied() {
3310 Log.w(TAG, "Volume service client died for stream: "+mStreamType);
3311 if (mMuteCount != 0) {
3312 // Reset all active mute requests from this client.
3313 mMuteCount = 1;
3314 mute(false);
3315 }
3316 }
3317 }
3318
Eric Laurent3172d5e2012-05-09 11:38:16 -07003319 private synchronized int muteCount() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003320 int count = 0;
3321 int size = mDeathHandlers.size();
3322 for (int i = 0; i < size; i++) {
3323 count += mDeathHandlers.get(i).mMuteCount;
3324 }
3325 return count;
3326 }
3327
Eric Laurent42b041e2013-03-29 11:36:03 -07003328 private synchronized boolean isMuted() {
3329 return muteCount() != 0;
3330 }
3331
Eric Laurent3172d5e2012-05-09 11:38:16 -07003332 // only called by mute() which is already synchronized
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003333 private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07003334 VolumeDeathHandler handler;
3335 int size = mDeathHandlers.size();
3336 for (int i = 0; i < size; i++) {
3337 handler = mDeathHandlers.get(i);
3338 if (cb == handler.mICallback) {
3339 return handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003340 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003341 }
Eric Laurent3172d5e2012-05-09 11:38:16 -07003342 // If this is the first mute request for this client, create a new
3343 // client death handler. Otherwise, it is an out of sequence unmute request.
3344 if (state) {
3345 handler = new VolumeDeathHandler(cb);
3346 } else {
3347 Log.w(TAG, "stream was not muted by this client");
3348 handler = null;
3349 }
3350 return handler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003351 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003352
3353 private void dump(PrintWriter pw) {
Eric Laurentdd45d012012-10-08 09:04:34 -07003354 pw.print(" Mute count: ");
3355 pw.println(muteCount());
Eric Laurentbffc3d12012-05-07 17:43:49 -07003356 pw.print(" Current: ");
3357 Set set = mIndex.entrySet();
3358 Iterator i = set.iterator();
3359 while (i.hasNext()) {
3360 Map.Entry entry = (Map.Entry)i.next();
3361 pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue())
3362 + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", ");
3363 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003364 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003365 }
3366
3367 /** Thread that handles native AudioSystem control. */
3368 private class AudioSystemThread extends Thread {
3369 AudioSystemThread() {
3370 super("AudioService");
3371 }
3372
3373 @Override
3374 public void run() {
3375 // Set this thread up so the handler will work on it
3376 Looper.prepare();
3377
3378 synchronized(AudioService.this) {
3379 mAudioHandler = new AudioHandler();
3380
3381 // Notify that the handler has been created
3382 AudioService.this.notify();
3383 }
3384
3385 // Listen for volume change requests that are set by VolumePanel
3386 Looper.loop();
3387 }
3388 }
3389
3390 /** Handles internal volume messages in separate volume thread. */
3391 private class AudioHandler extends Handler {
3392
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003393 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003394
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003395 // Apply volume
3396 streamState.applyDeviceVolume(device);
Eric Laurenta553c252009-07-17 12:17:14 -07003397
3398 // Apply change to all streams using this one as alias
3399 int numStreamTypes = AudioSystem.getNumStreamTypes();
3400 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3401 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07003402 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurentcd772d02013-10-30 18:31:07 -07003403 // Make sure volume is also maxed out on A2DP device for aliased stream
3404 // that may have a different device selected
3405 int streamDevice = getDeviceForStream(streamType);
3406 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
3407 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
3408 mStreamStates[streamType].applyDeviceVolume(device);
3409 }
3410 mStreamStates[streamType].applyDeviceVolume(streamDevice);
Eric Laurenta553c252009-07-17 12:17:14 -07003411 }
3412 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003413
3414 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08003415 sendMsg(mAudioHandler,
3416 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08003417 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003418 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07003419 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08003420 streamState,
3421 PERSIST_DELAY);
3422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003423 }
3424
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003425 private void setAllVolumes(VolumeStreamState streamState) {
3426
3427 // Apply volume
3428 streamState.applyAllVolumes();
3429
3430 // Apply change to all streams using this one as alias
3431 int numStreamTypes = AudioSystem.getNumStreamTypes();
3432 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3433 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07003434 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003435 mStreamStates[streamType].applyAllVolumes();
3436 }
3437 }
3438 }
3439
Eric Laurent42b041e2013-03-29 11:36:03 -07003440 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003441 if (mUseFixedVolume) {
3442 return;
3443 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003444 System.putIntForUser(mContentResolver,
3445 streamState.getSettingNameForDevice(device),
3446 (streamState.getIndex(device) + 5)/ 10,
3447 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003448 }
3449
Glenn Kastenba195eb2011-12-13 09:30:40 -08003450 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003451 if (mUseFixedVolume) {
3452 return;
3453 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07003454 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003455 }
3456
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003457 private boolean onLoadSoundEffects() {
3458 int status;
3459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003460 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07003461 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003462 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
3463 return false;
3464 }
3465
3466 if (mSoundPool != null) {
3467 return true;
3468 }
3469
3470 loadTouchSoundAssets();
3471
3472 mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0);
3473 mSoundPoolCallBack = null;
3474 mSoundPoolListenerThread = new SoundPoolListenerThread();
3475 mSoundPoolListenerThread.start();
3476 int attempts = 3;
3477 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
3478 try {
3479 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07003480 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003481 } catch (InterruptedException e) {
3482 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
3483 }
3484 }
3485
3486 if (mSoundPoolCallBack == null) {
3487 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
3488 if (mSoundPoolLooper != null) {
3489 mSoundPoolLooper.quit();
3490 mSoundPoolLooper = null;
3491 }
3492 mSoundPoolListenerThread = null;
3493 mSoundPool.release();
3494 mSoundPool = null;
3495 return false;
3496 }
3497 /*
3498 * poolId table: The value -1 in this table indicates that corresponding
3499 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
3500 * Once loaded, the value in poolId is the sample ID and the same
3501 * sample can be reused for another effect using the same file.
3502 */
3503 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3504 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3505 poolId[fileIdx] = -1;
3506 }
3507 /*
3508 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
3509 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
3510 * this indicates we have a valid sample loaded for this effect.
3511 */
3512
3513 int numSamples = 0;
3514 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3515 // Do not load sample if this effect uses the MediaPlayer
3516 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
3517 continue;
3518 }
3519 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
3520 String filePath = Environment.getRootDirectory()
3521 + SOUND_EFFECTS_PATH
3522 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
3523 int sampleId = mSoundPool.load(filePath, 0);
3524 if (sampleId <= 0) {
3525 Log.w(TAG, "Soundpool could not load file: "+filePath);
3526 } else {
3527 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
3528 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
3529 numSamples++;
3530 }
3531 } else {
3532 SOUND_EFFECT_FILES_MAP[effect][1] =
3533 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
3534 }
3535 }
3536 // wait for all samples to be loaded
3537 if (numSamples > 0) {
3538 mSoundPoolCallBack.setSamples(poolId);
3539
3540 attempts = 3;
3541 status = 1;
3542 while ((status == 1) && (attempts-- > 0)) {
3543 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07003544 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003545 status = mSoundPoolCallBack.status();
3546 } catch (InterruptedException e) {
3547 Log.w(TAG, "Interrupted while waiting sound pool callback.");
3548 }
3549 }
3550 } else {
3551 status = -1;
3552 }
3553
3554 if (mSoundPoolLooper != null) {
3555 mSoundPoolLooper.quit();
3556 mSoundPoolLooper = null;
3557 }
3558 mSoundPoolListenerThread = null;
3559 if (status != 0) {
3560 Log.w(TAG,
3561 "onLoadSoundEffects(), Error "+status+ " while loading samples");
3562 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3563 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
3564 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3565 }
3566 }
3567
3568 mSoundPool.release();
3569 mSoundPool = null;
3570 }
3571 }
3572 return (status == 0);
3573 }
3574
3575 /**
3576 * Unloads samples from the sound pool.
3577 * This method can be called to free some memory when
3578 * sound effects are disabled.
3579 */
3580 private void onUnloadSoundEffects() {
3581 synchronized (mSoundEffectsLock) {
3582 if (mSoundPool == null) {
3583 return;
3584 }
3585
3586 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3587 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3588 poolId[fileIdx] = 0;
3589 }
3590
3591 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3592 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
3593 continue;
3594 }
3595 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
3596 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
3597 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3598 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
3599 }
3600 }
3601 mSoundPool.release();
3602 mSoundPool = null;
3603 }
3604 }
3605
3606 private void onPlaySoundEffect(int effectType, int volume) {
3607 synchronized (mSoundEffectsLock) {
3608
3609 onLoadSoundEffects();
3610
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003611 if (mSoundPool == null) {
3612 return;
3613 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003614 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08003615 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003616 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07003617 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003618 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07003619 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003620 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003621
3622 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003623 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
3624 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003625 } else {
3626 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003627 try {
Eric Laurente78fced2013-03-15 16:03:47 -07003628 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
3629 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003630 mediaPlayer.setDataSource(filePath);
3631 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
3632 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08003633 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003634 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
3635 public void onCompletion(MediaPlayer mp) {
3636 cleanupPlayer(mp);
3637 }
3638 });
3639 mediaPlayer.setOnErrorListener(new OnErrorListener() {
3640 public boolean onError(MediaPlayer mp, int what, int extra) {
3641 cleanupPlayer(mp);
3642 return true;
3643 }
3644 });
3645 mediaPlayer.start();
3646 } catch (IOException ex) {
3647 Log.w(TAG, "MediaPlayer IOException: "+ex);
3648 } catch (IllegalArgumentException ex) {
3649 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
3650 } catch (IllegalStateException ex) {
3651 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003652 }
3653 }
3654 }
3655 }
3656
3657 private void cleanupPlayer(MediaPlayer mp) {
3658 if (mp != null) {
3659 try {
3660 mp.stop();
3661 mp.release();
3662 } catch (IllegalStateException ex) {
3663 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
3664 }
3665 }
3666 }
3667
Eric Laurentfa640152011-03-12 15:59:51 -08003668 private void setForceUse(int usage, int config) {
3669 AudioSystem.setForceUse(usage, config);
3670 }
3671
Eric Laurent05274f32012-11-29 12:48:18 -08003672 private void onPersistSafeVolumeState(int state) {
3673 Settings.Global.putInt(mContentResolver,
3674 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
3675 state);
3676 }
3677
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003678 @Override
3679 public void handleMessage(Message msg) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003680
Eric Laurentafbb0472011-12-15 09:04:23 -08003681 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003682
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003683 case MSG_SET_DEVICE_VOLUME:
3684 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
3685 break;
3686
3687 case MSG_SET_ALL_VOLUMES:
3688 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003689 break;
3690
3691 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07003692 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003693 break;
3694
Mike Lockwood5c55a052011-12-15 17:21:44 -05003695 case MSG_PERSIST_MASTER_VOLUME:
Eric Laurent83a017b2013-03-19 18:15:31 -07003696 if (mUseFixedVolume) {
3697 return;
3698 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07003699 Settings.System.putFloatForUser(mContentResolver,
3700 Settings.System.VOLUME_MASTER,
RoboErik8a2cfc32014-05-16 11:19:38 -07003701 msg.arg1 / (float)1000.0,
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07003702 UserHandle.USER_CURRENT);
Mike Lockwood5c55a052011-12-15 17:21:44 -05003703 break;
3704
Justin Koh57978ed2012-04-03 17:37:58 -07003705 case MSG_PERSIST_MASTER_VOLUME_MUTE:
Eric Laurent83a017b2013-03-19 18:15:31 -07003706 if (mUseFixedVolume) {
3707 return;
3708 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07003709 Settings.System.putIntForUser(mContentResolver,
3710 Settings.System.VOLUME_MASTER_MUTE,
3711 msg.arg1,
3712 UserHandle.USER_CURRENT);
Justin Koh57978ed2012-04-03 17:37:58 -07003713 break;
3714
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003715 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08003716 // note that the value persisted is the current ringer mode, not the
3717 // value of ringer mode as of the time the request was made to persist
3718 persistRingerMode(getRingerMode());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003719 break;
3720
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003721 case MSG_MEDIA_SERVER_DIED:
Eric Laurentdfb881f2013-07-18 14:41:39 -07003722 if (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK) {
Eric Laurent89e74ba2009-09-30 18:26:36 -07003723 Log.e(TAG, "Media server died.");
Eric Laurentafbb0472011-12-15 09:04:23 -08003724 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent89e74ba2009-09-30 18:26:36 -07003725 null, 500);
Eric Laurentdfb881f2013-07-18 14:41:39 -07003726 break;
Eric Laurent89e74ba2009-09-30 18:26:36 -07003727 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003728 Log.e(TAG, "Media server started.");
Eric Laurentdfb881f2013-07-18 14:41:39 -07003729
Eric Laurent3c652ca2010-06-21 20:46:26 -07003730 // indicate to audio HAL that we start the reconfiguration phase after a media
3731 // server crash
Eric Laurentdfb881f2013-07-18 14:41:39 -07003732 // Note that we only execute this when the media server
Eric Laurent3c652ca2010-06-21 20:46:26 -07003733 // process restarts after a crash, not the first time it is started.
3734 AudioSystem.setParameters("restarting=true");
3735
Glenn Kastenfd116ad2013-07-12 17:10:39 -07003736 readAndSetLowRamDevice();
3737
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003738 // Restore device connection states
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003739 synchronized (mConnectedDevices) {
3740 Set set = mConnectedDevices.entrySet();
3741 Iterator i = set.iterator();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003742 while (i.hasNext()) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003743 Map.Entry device = (Map.Entry)i.next();
3744 AudioSystem.setDeviceConnectionState(
3745 ((Integer)device.getKey()).intValue(),
3746 AudioSystem.DEVICE_STATE_AVAILABLE,
3747 (String)device.getValue());
3748 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003749 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003750 // Restore call state
3751 AudioSystem.setPhoneState(mMode);
3752
Eric Laurentd5603c12009-08-06 08:49:39 -07003753 // Restore forced usage for communcations and record
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003754 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
Eric Laurentd5603c12009-08-06 08:49:39 -07003755 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
Eric Laurentdd45d012012-10-08 09:04:34 -07003756 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
3757 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003758
Eric Laurenta553c252009-07-17 12:17:14 -07003759 // Restore stream volumes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003760 int numStreamTypes = AudioSystem.getNumStreamTypes();
3761 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003762 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003763 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003764
3765 streamState.applyAllVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003766 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003767
3768 // Restore ringer mode
3769 setRingerModeInt(getRingerMode(), false);
Eric Laurent3c652ca2010-06-21 20:46:26 -07003770
Mike Lockwood90631542012-01-06 11:20:37 -05003771 // Restore master volume
3772 restoreMasterVolume();
3773
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07003774 // Reset device orientation (if monitored for this device)
Eric Laurentd640bd32012-09-28 18:01:48 -07003775 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07003776 setOrientationForAudioSystem();
3777 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07003778 if (mMonitorRotation) {
3779 setRotationForAudioSystem();
3780 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07003781
Eric Laurent78472112012-05-21 08:57:21 -07003782 synchronized (mBluetoothA2dpEnabledLock) {
3783 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
3784 mBluetoothA2dpEnabled ?
3785 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
3786 }
Eric Laurentbff5ca52012-11-02 16:48:26 -07003787
3788 synchronized (mSettingsLock) {
3789 AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
3790 mDockAudioMediaEnabled ?
3791 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
3792 }
3793
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09003794 if (mHdmiTvClient != null) {
3795 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported,
3796 mHdmiSystemAudioOutputDevice, "");
3797 }
3798
Eric Laurent3c652ca2010-06-21 20:46:26 -07003799 // indicate the end of reconfiguration phase to audio HAL
3800 AudioSystem.setParameters("restarting=false");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003801 break;
3802
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003803 case MSG_UNLOAD_SOUND_EFFECTS:
3804 onUnloadSoundEffects();
3805 break;
3806
Eric Laurent117b7bb2011-01-16 17:07:27 -08003807 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003808 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
3809 // can take several dozens of milliseconds to complete
3810 boolean loaded = onLoadSoundEffects();
3811 if (msg.obj != null) {
3812 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
3813 synchronized (reply) {
3814 reply.mStatus = loaded ? 0 : -1;
3815 reply.notify();
3816 }
3817 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08003818 break;
3819
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003820 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003821 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003822 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003823
3824 case MSG_BTA2DP_DOCK_TIMEOUT:
3825 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003826 synchronized (mConnectedDevices) {
3827 makeA2dpDeviceUnavailableNow( (String) msg.obj );
3828 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003829 break;
Eric Laurentfa640152011-03-12 15:59:51 -08003830
3831 case MSG_SET_FORCE_USE:
Eric Laurentc390bed2012-07-03 12:24:05 -07003832 case MSG_SET_FORCE_BT_A2DP_USE:
Eric Laurentfa640152011-03-12 15:59:51 -08003833 setForceUse(msg.arg1, msg.arg2);
3834 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07003835
Eric Laurentdc03c612011-04-01 10:59:41 -07003836 case MSG_BT_HEADSET_CNCT_FAILED:
3837 resetBluetoothSco();
3838 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003839
3840 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
3841 onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003842 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003843 break;
3844
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003845 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
3846 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
3847 mAudioEventWakeLock.release();
3848 break;
3849
3850 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
3851 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003852 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003853 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07003854
3855 case MSG_REPORT_NEW_ROUTES: {
3856 int N = mRoutesObservers.beginBroadcast();
3857 if (N > 0) {
3858 AudioRoutesInfo routes;
3859 synchronized (mCurAudioRoutes) {
3860 routes = new AudioRoutesInfo(mCurAudioRoutes);
3861 }
3862 while (N > 0) {
3863 N--;
3864 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
3865 try {
3866 obs.dispatchAudioRoutesChanged(routes);
3867 } catch (RemoteException e) {
3868 }
3869 }
3870 }
3871 mRoutesObservers.finishBroadcast();
3872 break;
3873 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003874
Eric Laurentc34dcc12012-09-10 13:51:52 -07003875 case MSG_CHECK_MUSIC_ACTIVE:
3876 onCheckMusicActive();
3877 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07003878
3879 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
3880 onSendBecomingNoisyIntent();
3881 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07003882
3883 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
3884 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
3885 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
3886 break;
Eric Laurent05274f32012-11-29 12:48:18 -08003887 case MSG_PERSIST_SAFE_VOLUME_STATE:
3888 onPersistSafeVolumeState(msg.arg1);
3889 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08003890
Eric Laurent2a57ca92013-03-07 17:29:27 -08003891 case MSG_BROADCAST_BT_CONNECTION_STATE:
3892 onBroadcastScoConnectionState(msg.arg1);
3893 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07003894
3895 case MSG_SYSTEM_READY:
3896 onSystemReady();
3897 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003898 }
3899 }
3900 }
3901
Jason Parekhb1096152009-03-24 17:48:25 -07003902 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07003903
Jason Parekhb1096152009-03-24 17:48:25 -07003904 SettingsObserver() {
3905 super(new Handler());
3906 mContentResolver.registerContentObserver(Settings.System.getUriFor(
3907 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07003908 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
3909 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07003910 }
3911
3912 @Override
3913 public void onChange(boolean selfChange) {
3914 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08003915 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
3916 // However there appear to be some missing locks around mRingerModeMutedStreams
3917 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
3918 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07003919 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003920 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07003921 /*
3922 * Ensure all stream types that should be affected by ringer mode
3923 * are in the proper state.
3924 */
Eric Laurenta553c252009-07-17 12:17:14 -07003925 setRingerModeInt(getRingerMode(), false);
3926 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07003927 readDockAudioSettings(mContentResolver);
Eric Laurenta553c252009-07-17 12:17:14 -07003928 }
Jason Parekhb1096152009-03-24 17:48:25 -07003929 }
Jason Parekhb1096152009-03-24 17:48:25 -07003930 }
Eric Laurenta553c252009-07-17 12:17:14 -07003931
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003932 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003933 private void makeA2dpDeviceAvailable(String address) {
Eric Laurent78472112012-05-21 08:57:21 -07003934 // enable A2DP before notifying A2DP connection to avoid unecessary processing in
3935 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003936 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
3937 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
3938 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Eric Laurent78472112012-05-21 08:57:21 -07003939 setBluetoothA2dpOnInt(true);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003940 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3941 AudioSystem.DEVICE_STATE_AVAILABLE,
3942 address);
3943 // Reset A2DP suspend state each time a new sink is connected
3944 AudioSystem.setParameters("A2dpSuspended=false");
3945 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
3946 address);
3947 }
3948
Eric Laurent5bfaeae2012-09-21 18:44:48 -07003949 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003950 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07003951 }
3952
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003953 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003954 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003955 synchronized (mA2dpAvrcpLock) {
3956 mAvrcpAbsVolSupported = false;
3957 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003958 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3959 AudioSystem.DEVICE_STATE_UNAVAILABLE,
3960 address);
3961 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
3962 }
3963
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003964 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003965 private void makeA2dpDeviceUnavailableLater(String address) {
Eric Laurent3b591262010-04-20 07:01:00 -07003966 // prevent any activity on the A2DP audio output to avoid unwanted
3967 // reconnection of the sink.
3968 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003969 // the device will be made unavailable later, so consider it disconnected right away
3970 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
3971 // send the delayed message to make the device unavailable later
3972 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
3973 mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
3974
3975 }
3976
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003977 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003978 private void makeA2dpSrcAvailable(String address) {
3979 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
3980 AudioSystem.DEVICE_STATE_AVAILABLE,
3981 address);
3982 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
3983 address);
3984 }
3985
3986 // must be called synchronized on mConnectedDevices
3987 private void makeA2dpSrcUnavailable(String address) {
3988 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
3989 AudioSystem.DEVICE_STATE_UNAVAILABLE,
3990 address);
3991 mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
3992 }
3993
3994 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07003995 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07003996 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
3997 }
3998
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003999 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004000 private boolean hasScheduledA2dpDockTimeout() {
4001 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4002 }
4003
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004004 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004005 {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004006 if (DEBUG_VOL) {
4007 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
4008 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004009 if (btDevice == null) {
4010 return;
4011 }
4012 String address = btDevice.getAddress();
4013 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4014 address = "";
4015 }
John Du5a0cf7a2013-07-19 11:30:34 -07004016
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004017 synchronized (mConnectedDevices) {
4018 boolean isConnected =
4019 (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
4020 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
4021
4022 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4023 if (btDevice.isBluetoothDock()) {
4024 if (state == BluetoothProfile.STATE_DISCONNECTED) {
4025 // introduction of a delay for transient disconnections of docks when
4026 // power is rapidly turned off/on, this message will be canceled if
4027 // we reconnect the dock under a preset delay
4028 makeA2dpDeviceUnavailableLater(address);
4029 // the next time isConnected is evaluated, it will be false for the dock
4030 }
4031 } else {
4032 makeA2dpDeviceUnavailableNow(address);
4033 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07004034 synchronized (mCurAudioRoutes) {
4035 if (mCurAudioRoutes.mBluetoothName != null) {
4036 mCurAudioRoutes.mBluetoothName = null;
4037 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4038 SENDMSG_NOOP, 0, 0, null, 0);
4039 }
4040 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004041 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4042 if (btDevice.isBluetoothDock()) {
4043 // this could be a reconnection after a transient disconnection
4044 cancelA2dpDeviceTimeout();
4045 mDockAddress = address;
4046 } else {
4047 // this could be a connection of another A2DP device before the timeout of
4048 // a dock: cancel the dock timeout, and make the dock unavailable now
4049 if(hasScheduledA2dpDockTimeout()) {
4050 cancelA2dpDeviceTimeout();
4051 makeA2dpDeviceUnavailableNow(mDockAddress);
4052 }
4053 }
4054 makeA2dpDeviceAvailable(address);
Dianne Hackborn632ca412012-06-14 19:34:10 -07004055 synchronized (mCurAudioRoutes) {
4056 String name = btDevice.getAliasName();
4057 if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
4058 mCurAudioRoutes.mBluetoothName = name;
4059 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4060 SENDMSG_NOOP, 0, 0, null, 0);
4061 }
4062 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004063 }
4064 }
4065 }
4066
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004067 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
4068 {
4069 if (DEBUG_VOL) {
4070 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
4071 }
4072 if (btDevice == null) {
4073 return;
4074 }
4075 String address = btDevice.getAddress();
4076 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4077 address = "";
4078 }
4079
4080 synchronized (mConnectedDevices) {
4081 boolean isConnected =
4082 (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
4083 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));
4084
4085 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4086 makeA2dpSrcUnavailable(address);
4087 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4088 makeA2dpSrcAvailable(address);
4089 }
4090 }
4091 }
4092
John Du5a0cf7a2013-07-19 11:30:34 -07004093 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
4094 // address is not used for now, but may be used when multiple a2dp devices are supported
4095 synchronized (mA2dpAvrcpLock) {
4096 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004097 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07004098 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4099 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4100 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4101 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4102 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07004103 }
4104 }
4105
Eric Laurent59f48272012-04-05 19:42:21 -07004106 private boolean handleDeviceConnection(boolean connected, int device, String params) {
4107 synchronized (mConnectedDevices) {
4108 boolean isConnected = (mConnectedDevices.containsKey(device) &&
Mike Lockwood98418182012-05-10 17:13:20 -07004109 (params.isEmpty() || mConnectedDevices.get(device).equals(params)));
Eric Laurent59f48272012-04-05 19:42:21 -07004110
4111 if (isConnected && !connected) {
4112 AudioSystem.setDeviceConnectionState(device,
4113 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Mike Lockwood98418182012-05-10 17:13:20 -07004114 mConnectedDevices.get(device));
Eric Laurent59f48272012-04-05 19:42:21 -07004115 mConnectedDevices.remove(device);
4116 return true;
4117 } else if (!isConnected && connected) {
4118 AudioSystem.setDeviceConnectionState(device,
4119 AudioSystem.DEVICE_STATE_AVAILABLE,
4120 params);
4121 mConnectedDevices.put(new Integer(device), params);
4122 return true;
4123 }
4124 }
4125 return false;
4126 }
4127
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004128 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4129 // sent if none of these devices is connected.
4130 int mBecomingNoisyIntentDevices =
4131 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07004132 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07004133 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
4134 AudioSystem.DEVICE_OUT_ALL_USB;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004135
4136 // must be called before removing the device from mConnectedDevices
4137 private int checkSendBecomingNoisyIntent(int device, int state) {
4138 int delay = 0;
4139 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4140 int devices = 0;
4141 for (int dev : mConnectedDevices.keySet()) {
4142 if ((dev & mBecomingNoisyIntentDevices) != 0) {
4143 devices |= dev;
4144 }
4145 }
4146 if (devices == device) {
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004147 sendMsg(mAudioHandler,
4148 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4149 SENDMSG_REPLACE,
4150 0,
4151 0,
4152 null,
4153 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004154 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004155 }
4156 }
4157
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004158 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
4159 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004160 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
4161 delay = 1000;
4162 }
4163 return delay;
4164 }
4165
4166 private void sendDeviceConnectionIntent(int device, int state, String name)
4167 {
4168 Intent intent = new Intent();
4169
4170 intent.putExtra("state", state);
4171 intent.putExtra("name", name);
4172 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4173
Dianne Hackborn632ca412012-06-14 19:34:10 -07004174 int connType = 0;
4175
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004176 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004177 connType = AudioRoutesInfo.MAIN_HEADSET;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004178 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4179 intent.putExtra("microphone", 1);
4180 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004181 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004182 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4183 intent.putExtra("microphone", 0);
4184 } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004185 connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004186 intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
4187 } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004188 connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004189 intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
Eric Laurent948d3272014-05-16 15:18:45 -07004190 } else if (device == AudioSystem.DEVICE_OUT_HDMI) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004191 connType = AudioRoutesInfo.MAIN_HDMI;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004192 intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);
4193 }
4194
Dianne Hackborn632ca412012-06-14 19:34:10 -07004195 synchronized (mCurAudioRoutes) {
4196 if (connType != 0) {
4197 int newConn = mCurAudioRoutes.mMainType;
4198 if (state != 0) {
4199 newConn |= connType;
4200 } else {
4201 newConn &= ~connType;
4202 }
4203 if (newConn != mCurAudioRoutes.mMainType) {
4204 mCurAudioRoutes.mMainType = newConn;
4205 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4206 SENDMSG_NOOP, 0, 0, null, 0);
4207 }
4208 }
4209 }
4210
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004211 final long ident = Binder.clearCallingIdentity();
4212 try {
4213 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
4214 } finally {
4215 Binder.restoreCallingIdentity(ident);
4216 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004217 }
4218
4219 private void onSetWiredDeviceConnectionState(int device, int state, String name)
4220 {
4221 synchronized (mConnectedDevices) {
4222 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
4223 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) {
4224 setBluetoothA2dpOnInt(true);
4225 }
Eric Laurentae4506e2014-05-29 16:04:32 -07004226 boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
4227 (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
4228 ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
Mike Lockwooddb454842012-09-18 11:16:57 -07004229 handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
Eric Laurentf1a457d2012-09-20 16:27:23 -07004230 if (state != 0) {
4231 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
4232 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE)) {
4233 setBluetoothA2dpOnInt(false);
4234 }
4235 if ((device & mSafeMediaVolumeDevices) != 0) {
4236 sendMsg(mAudioHandler,
4237 MSG_CHECK_MUSIC_ACTIVE,
4238 SENDMSG_REPLACE,
4239 0,
4240 0,
4241 null,
4242 MUSIC_ACTIVE_POLL_PERIOD_MS);
4243 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004244 }
Eric Laurentae4506e2014-05-29 16:04:32 -07004245 if (!isUsb && (device != AudioSystem.DEVICE_IN_WIRED_HEADSET)) {
Mike Lockwooddb454842012-09-18 11:16:57 -07004246 sendDeviceConnectionIntent(device, state, name);
4247 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004248 }
4249 }
4250
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004251 /* cache of the address of the last dock the device was connected to */
4252 private String mDockAddress;
4253
Eric Laurenta553c252009-07-17 12:17:14 -07004254 /**
4255 * Receiver for misc intent broadcasts the Phone app cares about.
4256 */
4257 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4258 @Override
4259 public void onReceive(Context context, Intent intent) {
4260 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07004261 int outDevice;
4262 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07004263 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07004264
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004265 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4266 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4267 Intent.EXTRA_DOCK_STATE_UNDOCKED);
4268 int config;
4269 switch (dockState) {
4270 case Intent.EXTRA_DOCK_STATE_DESK:
4271 config = AudioSystem.FORCE_BT_DESK_DOCK;
4272 break;
4273 case Intent.EXTRA_DOCK_STATE_CAR:
4274 config = AudioSystem.FORCE_BT_CAR_DOCK;
4275 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004276 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08004277 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004278 break;
4279 case Intent.EXTRA_DOCK_STATE_HE_DESK:
4280 config = AudioSystem.FORCE_DIGITAL_DOCK;
4281 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004282 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4283 default:
4284 config = AudioSystem.FORCE_NONE;
4285 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08004286 // Low end docks have a menu to enable or disable audio
4287 // (see mDockAudioMediaEnabled)
4288 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
4289 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
4290 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
4291 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
4292 }
4293 mDockState = dockState;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004294 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
Eric Laurent59f48272012-04-05 19:42:21 -07004295 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004296 BluetoothProfile.STATE_DISCONNECTED);
Eric Laurentae4506e2014-05-29 16:04:32 -07004297 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
4298 inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
Nick Pellya56d1c72009-08-19 14:49:29 -07004299 String address = null;
Eric Laurentdca56b92011-09-02 14:20:56 -07004300
4301 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
4302 if (btDevice == null) {
4303 return;
4304 }
4305
4306 address = btDevice.getAddress();
4307 BluetoothClass btClass = btDevice.getBluetoothClass();
4308 if (btClass != null) {
4309 switch (btClass.getDeviceClass()) {
4310 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
4311 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
Eric Laurentae4506e2014-05-29 16:04:32 -07004312 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurentdca56b92011-09-02 14:20:56 -07004313 break;
4314 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
Eric Laurentae4506e2014-05-29 16:04:32 -07004315 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurentdca56b92011-09-02 14:20:56 -07004316 break;
Eric Laurentd5603c12009-08-06 08:49:39 -07004317 }
4318 }
4319
Eric Laurentdca56b92011-09-02 14:20:56 -07004320 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4321 address = "";
4322 }
Eric Laurentd5603c12009-08-06 08:49:39 -07004323
Eric Laurent59f48272012-04-05 19:42:21 -07004324 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
Eric Laurentae4506e2014-05-29 16:04:32 -07004325 boolean success = handleDeviceConnection(connected, outDevice, address) &&
4326 handleDeviceConnection(connected, inDevice, address);
4327 if (success) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004328 synchronized (mScoClients) {
Eric Laurent59f48272012-04-05 19:42:21 -07004329 if (connected) {
4330 mBluetoothHeadsetDevice = btDevice;
4331 } else {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004332 mBluetoothHeadsetDevice = null;
4333 resetBluetoothSco();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004334 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004335 }
Eric Laurenta553c252009-07-17 12:17:14 -07004336 }
Paul McLeandf361462014-04-10 16:02:55 -07004337 } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG)) {
4338 state = intent.getIntExtra("state", 0);
4339
4340 int alsaCard = intent.getIntExtra("card", -1);
4341 int alsaDevice = intent.getIntExtra("device", -1);
4342
4343 String params = (alsaCard == -1 && alsaDevice == -1 ? ""
4344 : "card=" + alsaCard + ";device=" + alsaDevice);
4345
4346 // Playback Device
Eric Laurentae4506e2014-05-29 16:04:32 -07004347 outDevice = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
4348 setWiredDeviceConnectionState(outDevice, state, params);
Paul McLeandf361462014-04-10 16:02:55 -07004349 } else if (action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
Eric Laurent59f48272012-04-05 19:42:21 -07004350 state = intent.getIntExtra("state", 0);
Paul McLeanc837a452014-04-09 09:04:43 -07004351
Eric Laurent59f48272012-04-05 19:42:21 -07004352 int alsaCard = intent.getIntExtra("card", -1);
4353 int alsaDevice = intent.getIntExtra("device", -1);
Paul McLeanc837a452014-04-09 09:04:43 -07004354 boolean hasPlayback = intent.getBooleanExtra("hasPlayback", false);
4355 boolean hasCapture = intent.getBooleanExtra("hasCapture", false);
4356 boolean hasMIDI = intent.getBooleanExtra("hasMIDI", false);
4357
Mike Lockwood98418182012-05-10 17:13:20 -07004358 String params = (alsaCard == -1 && alsaDevice == -1 ? ""
4359 : "card=" + alsaCard + ";device=" + alsaDevice);
Paul McLeanc837a452014-04-09 09:04:43 -07004360
Paul McLeanc837a452014-04-09 09:04:43 -07004361 // Playback Device
Paul McLeandf361462014-04-10 16:02:55 -07004362 if (hasPlayback) {
Eric Laurentae4506e2014-05-29 16:04:32 -07004363 outDevice = AudioSystem.DEVICE_OUT_USB_DEVICE;
4364 setWiredDeviceConnectionState(outDevice, state, params);
Paul McLeandf361462014-04-10 16:02:55 -07004365 }
Paul McLeanc837a452014-04-09 09:04:43 -07004366
4367 // Capture Device
Paul McLeandf361462014-04-10 16:02:55 -07004368 if (hasCapture) {
Eric Laurentae4506e2014-05-29 16:04:32 -07004369 inDevice = AudioSystem.DEVICE_IN_USB_DEVICE;
4370 setWiredDeviceConnectionState(inDevice, state, params);
Paul McLeandf361462014-04-10 16:02:55 -07004371 }
4372 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004373 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07004374 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004375 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004376 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07004377 // broadcast intent if the connection was initated by AudioService
4378 if (!mScoClients.isEmpty() &&
4379 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
4380 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
4381 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004382 broadcast = true;
4383 }
4384 switch (btState) {
4385 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004386 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07004387 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4388 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4389 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004390 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004391 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004392 break;
4393 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004394 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08004395 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07004396 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08004397 break;
4398 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07004399 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4400 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4401 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004402 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004403 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004404 default:
4405 // do not broadcast CONNECTING or invalid state
4406 broadcast = false;
4407 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004408 }
4409 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004410 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07004411 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07004412 //FIXME: this is to maintain compatibility with deprecated intent
4413 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08004414 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07004415 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004416 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08004417 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004418 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
4419 AudioSystem.setParameters("screen_state=on");
4420 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
4421 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07004422 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004423 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004424 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004425 // attempt to stop music playback for background user
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004426 sendMsg(mAudioHandler,
4427 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4428 SENDMSG_REPLACE,
4429 0,
4430 0,
4431 null,
4432 0);
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004433 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004434 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004435
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004436 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004437 readAudioSettings(true /*userSwitch*/);
4438 // preserve STREAM_MUSIC volume from one user to the next.
4439 sendMsg(mAudioHandler,
4440 MSG_SET_ALL_VOLUMES,
4441 SENDMSG_QUEUE,
4442 0,
4443 0,
4444 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Eric Laurenta553c252009-07-17 12:17:14 -07004445 }
4446 }
Paul McLeanc837a452014-04-09 09:04:43 -07004447 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004448
4449 //==========================================================================================
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004450 // RemoteControlDisplay / RemoteControlClient / Remote info
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004451 //==========================================================================================
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004452 public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
4453 ComponentName listenerComp) {
4454 return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
4455 }
4456
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004457 public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004458 return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004459 }
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004460
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004461 public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004462 mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004463 }
4464
4465 public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004466 mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004467 }
4468
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07004469 public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
4470 boolean wantsSync) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004471 mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
4472 }
4473
John Spurlock3346a802014-05-20 16:25:37 -04004474 @Override
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004475 public void setRemoteStreamVolume(int index) {
John Spurlock3346a802014-05-20 16:25:37 -04004476 enforceSelfOrSystemUI("set the remote stream volume");
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004477 mMediaFocusControl.setRemoteStreamVolume(index);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004478 }
4479
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004480 //==========================================================================================
4481 // Audio Focus
4482 //==========================================================================================
4483 public int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb,
4484 IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
4485 return mMediaFocusControl.requestAudioFocus(mainStreamType, durationHint, cb, fd,
4486 clientId, callingPackageName);
4487 }
4488
4489 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId) {
4490 return mMediaFocusControl.abandonAudioFocus(fd, clientId);
4491 }
4492
4493 public void unregisterAudioFocusClient(String clientId) {
4494 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004495 }
4496
Jean-Michel Trivi23805662013-07-31 14:19:18 -07004497 public int getCurrentAudioFocus() {
4498 return mMediaFocusControl.getCurrentAudioFocus();
4499 }
4500
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004501 //==========================================================================================
4502 // Device orientation
4503 //==========================================================================================
4504 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004505 * Handles device configuration changes that may map to a change in the orientation
4506 * or orientation.
4507 * Monitoring orientation and rotation is optional, and is defined by the definition and value
4508 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004509 */
4510 private void handleConfigurationChanged(Context context) {
4511 try {
4512 // reading new orientation "safely" (i.e. under try catch) in case anything
4513 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07004514 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004515 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07004516 if (mMonitorOrientation) {
4517 int newOrientation = config.orientation;
4518 if (newOrientation != mDeviceOrientation) {
4519 mDeviceOrientation = newOrientation;
4520 setOrientationForAudioSystem();
4521 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004522 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004523 if (mMonitorRotation) {
4524 int newRotation = ((WindowManager) context.getSystemService(
4525 Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
4526 if (newRotation != mDeviceRotation) {
4527 mDeviceRotation = newRotation;
4528 setRotationForAudioSystem();
4529 }
4530 }
Eric Laurentd640bd32012-09-28 18:01:48 -07004531 sendMsg(mAudioHandler,
4532 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
4533 SENDMSG_REPLACE,
4534 0,
4535 0,
4536 null,
4537 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07004538
4539 boolean cameraSoundForced = mContext.getResources().getBoolean(
4540 com.android.internal.R.bool.config_camera_sound_forced);
4541 synchronized (mSettingsLock) {
4542 synchronized (mCameraSoundForced) {
4543 if (cameraSoundForced != mCameraSoundForced) {
4544 mCameraSoundForced = cameraSoundForced;
4545
4546 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
4547 if (cameraSoundForced) {
4548 s.setAllIndexesToMax();
4549 mRingerModeAffectedStreams &=
4550 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4551 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07004552 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
Eric Laurentdd45d012012-10-08 09:04:34 -07004553 mRingerModeAffectedStreams |=
4554 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4555 }
4556 // take new state into account for streams muted by ringer mode
4557 setRingerModeInt(getRingerMode(), false);
4558
4559 sendMsg(mAudioHandler,
4560 MSG_SET_FORCE_USE,
4561 SENDMSG_QUEUE,
4562 AudioSystem.FOR_SYSTEM,
4563 cameraSoundForced ?
4564 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
4565 null,
4566 0);
4567
4568 sendMsg(mAudioHandler,
4569 MSG_SET_ALL_VOLUMES,
4570 SENDMSG_QUEUE,
4571 0,
4572 0,
4573 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
4574 }
4575 }
4576 }
John Spurlock3346a802014-05-20 16:25:37 -04004577 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004578 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004579 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004580 }
4581 }
4582
4583 private void setOrientationForAudioSystem() {
4584 switch (mDeviceOrientation) {
4585 case Configuration.ORIENTATION_LANDSCAPE:
4586 //Log.i(TAG, "orientation is landscape");
4587 AudioSystem.setParameters("orientation=landscape");
4588 break;
4589 case Configuration.ORIENTATION_PORTRAIT:
4590 //Log.i(TAG, "orientation is portrait");
4591 AudioSystem.setParameters("orientation=portrait");
4592 break;
4593 case Configuration.ORIENTATION_SQUARE:
4594 //Log.i(TAG, "orientation is square");
4595 AudioSystem.setParameters("orientation=square");
4596 break;
4597 case Configuration.ORIENTATION_UNDEFINED:
4598 //Log.i(TAG, "orientation is undefined");
4599 AudioSystem.setParameters("orientation=undefined");
4600 break;
4601 default:
4602 Log.e(TAG, "Unknown orientation");
4603 }
4604 }
4605
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004606 private void setRotationForAudioSystem() {
4607 switch (mDeviceRotation) {
4608 case Surface.ROTATION_0:
4609 AudioSystem.setParameters("rotation=0");
4610 break;
4611 case Surface.ROTATION_90:
4612 AudioSystem.setParameters("rotation=90");
4613 break;
4614 case Surface.ROTATION_180:
4615 AudioSystem.setParameters("rotation=180");
4616 break;
4617 case Surface.ROTATION_270:
4618 AudioSystem.setParameters("rotation=270");
4619 break;
4620 default:
4621 Log.e(TAG, "Unknown device rotation");
4622 }
4623 }
4624
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004625
Eric Laurent78472112012-05-21 08:57:21 -07004626 // Handles request to override default use of A2DP for media.
4627 public void setBluetoothA2dpOnInt(boolean on) {
4628 synchronized (mBluetoothA2dpEnabledLock) {
4629 mBluetoothA2dpEnabled = on;
Eric Laurentc390bed2012-07-03 12:24:05 -07004630 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
4631 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
4632 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
Eric Laurent78472112012-05-21 08:57:21 -07004633 }
4634 }
4635
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004636 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07004637 public void setRingtonePlayer(IRingtonePlayer player) {
4638 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
4639 mRingtonePlayer = player;
4640 }
4641
4642 @Override
4643 public IRingtonePlayer getRingtonePlayer() {
4644 return mRingtonePlayer;
4645 }
4646
4647 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07004648 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
4649 synchronized (mCurAudioRoutes) {
4650 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
4651 mRoutesObservers.register(observer);
4652 return routes;
4653 }
4654 }
4655
Eric Laurentc34dcc12012-09-10 13:51:52 -07004656
4657 //==========================================================================================
4658 // Safe media volume management.
4659 // MUSIC stream volume level is limited when headphones are connected according to safety
4660 // regulation. When the user attempts to raise the volume above the limit, a warning is
4661 // displayed and the user has to acknowlegde before the volume is actually changed.
4662 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
4663 // property. Platforms with a different limit must set this property accordingly in their
4664 // overlay.
4665 //==========================================================================================
4666
Eric Laurentd640bd32012-09-28 18:01:48 -07004667 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
4668 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
4669 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
4670 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
4671 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
4672 // (when user opts out).
4673 private final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
4674 private final int SAFE_MEDIA_VOLUME_DISABLED = 1;
4675 private final int SAFE_MEDIA_VOLUME_INACTIVE = 2;
4676 private final int SAFE_MEDIA_VOLUME_ACTIVE = 3;
4677 private Integer mSafeMediaVolumeState;
4678
4679 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07004680 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07004681 private int mSafeMediaVolumeIndex;
Eric Laurentc34dcc12012-09-10 13:51:52 -07004682 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
4683 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
4684 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
4685 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
4686 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
4687 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
4688 private int mMusicActiveMs;
4689 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
4690 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07004691 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07004692
4693 private void setSafeMediaVolumeEnabled(boolean on) {
Eric Laurentd640bd32012-09-28 18:01:48 -07004694 synchronized (mSafeMediaVolumeState) {
4695 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
4696 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
4697 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
4698 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
4699 enforceSafeMediaVolume();
4700 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
4701 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
4702 mMusicActiveMs = 0;
4703 sendMsg(mAudioHandler,
4704 MSG_CHECK_MUSIC_ACTIVE,
4705 SENDMSG_REPLACE,
4706 0,
4707 0,
4708 null,
4709 MUSIC_ACTIVE_POLL_PERIOD_MS);
4710 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07004711 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07004712 }
4713 }
4714
4715 private void enforceSafeMediaVolume() {
4716 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07004717 int devices = mSafeMediaVolumeDevices;
4718 int i = 0;
4719
4720 while (devices != 0) {
4721 int device = 1 << i++;
4722 if ((device & devices) == 0) {
4723 continue;
4724 }
Eric Laurent42b041e2013-03-29 11:36:03 -07004725 int index = streamState.getIndex(device);
Eric Laurentc34dcc12012-09-10 13:51:52 -07004726 if (index > mSafeMediaVolumeIndex) {
Eric Laurent42b041e2013-03-29 11:36:03 -07004727 streamState.setIndex(mSafeMediaVolumeIndex, device);
4728 sendMsg(mAudioHandler,
4729 MSG_SET_DEVICE_VOLUME,
4730 SENDMSG_QUEUE,
4731 device,
4732 0,
4733 streamState,
4734 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07004735 }
4736 devices &= ~device;
4737 }
4738 }
4739
4740 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07004741 synchronized (mSafeMediaVolumeState) {
4742 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07004743 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
4744 ((device & mSafeMediaVolumeDevices) != 0) &&
4745 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07004746 return false;
4747 }
4748 return true;
4749 }
4750 }
4751
John Spurlock3346a802014-05-20 16:25:37 -04004752 @Override
Eric Laurentc34dcc12012-09-10 13:51:52 -07004753 public void disableSafeMediaVolume() {
John Spurlock3346a802014-05-20 16:25:37 -04004754 enforceSelfOrSystemUI("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07004755 synchronized (mSafeMediaVolumeState) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07004756 setSafeMediaVolumeEnabled(false);
Eric Laurentfde16d52012-12-03 14:42:39 -08004757 if (mPendingVolumeCommand != null) {
4758 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
4759 mPendingVolumeCommand.mIndex,
4760 mPendingVolumeCommand.mFlags,
4761 mPendingVolumeCommand.mDevice);
4762 mPendingVolumeCommand = null;
4763 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07004764 }
4765 }
4766
Jungshik Jang41d97462014-06-30 22:26:29 +09004767 //==========================================================================================
4768 // Hdmi Cec system audio mode.
4769 // If Hdmi Cec's system audio mode is on, audio service should notify volume change
4770 // to HdmiControlService so that audio recevier can handle volume change.
4771 //==========================================================================================
4772
4773 // If HDMI-CEC system audio is supported
4774 private boolean mHdmiSystemAudioSupported = false;
4775 // Set only when device is tv.
4776 private HdmiTvClient mHdmiTvClient;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004777 private int mHdmiSystemAudioOutputDevice = AudioSystem.DEVICE_NONE;
4778 private int[] mSpeakerGains;
Jungshik Jang41d97462014-06-30 22:26:29 +09004779
4780 @Override
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004781 public int setHdmiSystemAudioSupported(boolean on, int device, String name) {
Jungshik Jang41d97462014-06-30 22:26:29 +09004782 if (mHdmiTvClient == null) {
4783 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004784 return AudioSystem.DEVICE_NONE;
Jungshik Jang41d97462014-06-30 22:26:29 +09004785 }
4786
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004787 if (on && !checkHdmiSystemAudioOutput(device)) {
4788 return AudioSystem.DEVICE_NONE;
Jungshik Jang41d97462014-06-30 22:26:29 +09004789 }
4790
Jungshik Jang41d97462014-06-30 22:26:29 +09004791 synchronized (mHdmiTvClient) {
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004792 if (on) {
4793 mHdmiSystemAudioOutputDevice = device;
4794 }
4795 if (mHdmiSystemAudioSupported == on) {
4796 return AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
4797 }
Jungshik Jang41d97462014-06-30 22:26:29 +09004798 mHdmiSystemAudioSupported = on;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004799 updateHdmiSystemAudioVolumeLocked(on);
4800 }
4801 return AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
4802 }
Jungshik Jang41d97462014-06-30 22:26:29 +09004803
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004804 private boolean checkHdmiSystemAudioOutput(int device) {
4805 if ((device & AudioSystem.DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO) == 0) {
4806 Log.w(TAG, "Unsupported Hdmi-Cec system audio output:" + device);
4807 return false;
Jungshik Jang41d97462014-06-30 22:26:29 +09004808 }
4809
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004810 int streamDevice = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
4811 // If other devices except for system audio and speaker are available,
4812 // fails to start system audio mode.
4813 if ((streamDevice & ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER) != 0) {
4814 Log.w(TAG, "Should turn off other devices before starting system audio:"
4815 + streamDevice);
4816 return false;
4817 }
4818 if (AudioSystem.getDeviceConnectionState(device, "") !=
4819 AudioSystem.DEVICE_STATE_AVAILABLE) {
4820 Log.w(TAG, "Output device is not connected:" + device);
4821 return false;
4822 }
4823 return true;
4824 }
4825
4826 private void updateHdmiSystemAudioVolumeLocked(boolean on) {
4827 AudioDevicePort speaker = findAudioDevicePort(AudioSystem.DEVICE_OUT_SPEAKER);
4828 if (speaker == null) {
4829 Log.w(TAG, "Has no speaker output.");
4830 return;
4831 }
4832
4833 AudioPortConfig portConfig = speaker.activeConfig();
4834 AudioGainConfig gainConfig = portConfig.gain();
4835 int[] newGains;
4836 // When system audio is on, backup original gains and mute all channels of speaker by
4837 // setting gains to 0; otherwise, restore gains of speaker.
Jungshik Jang41d97462014-06-30 22:26:29 +09004838 if (on) {
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004839 if (gainConfig == null) {
4840 Log.w(TAG, "Speaker has no gain control.");
4841 return;
Jungshik Jang41d97462014-06-30 22:26:29 +09004842 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004843 // Back up original gains.
4844 mSpeakerGains = Arrays.copyOf(gainConfig.values(), gainConfig.values().length);
4845 // Set all gains to 0.
4846 newGains = new int[gainConfig.values().length];
Jungshik Jang41d97462014-06-30 22:26:29 +09004847 } else {
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004848 if (mSpeakerGains == null) {
4849 Log.w(TAG, "mSpeakerGains should not be null.");
4850 return;
Jungshik Jang41d97462014-06-30 22:26:29 +09004851 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004852 newGains = Arrays.copyOf(mSpeakerGains, mSpeakerGains.length);
Jungshik Jang41d97462014-06-30 22:26:29 +09004853 }
4854
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004855 gainConfig = gainConfig.mGain.buildConfig(gainConfig.mode(),
4856 gainConfig.channelMask(),
4857 newGains,
4858 gainConfig.rampDurationMs());
4859
4860 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
4861 if (AudioSystem.SUCCESS != audioManager.setAudioPortGain(speaker, gainConfig)) {
4862 Log.w(TAG, "Failed to update audio port config.");
Jungshik Jang41d97462014-06-30 22:26:29 +09004863 }
4864 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07004865
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004866 private AudioDevicePort findAudioDevicePort(int type) {
4867 ArrayList<AudioPort> devicePorts = new ArrayList<>();
4868 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
4869 int status = audioManager.listAudioDevicePorts(devicePorts);
4870 if (status != AudioSystem.SUCCESS) {
4871 Log.w(TAG, "Failed to list up all audio ports");
4872 return null;
4873 }
4874
4875 for (AudioPort port : devicePorts) {
4876 AudioDevicePort devicePort = (AudioDevicePort) port;
4877 if (devicePort.type() == type) {
4878 return devicePort;
4879 }
4880 }
4881 return null;
4882 }
4883
Eric Laurentdd45d012012-10-08 09:04:34 -07004884 //==========================================================================================
4885 // Camera shutter sound policy.
4886 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
4887 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
4888 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
4889 //==========================================================================================
4890
4891 // cached value of com.android.internal.R.bool.config_camera_sound_forced
4892 private Boolean mCameraSoundForced;
4893
4894 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
4895 public boolean isCameraSoundForced() {
4896 synchronized (mCameraSoundForced) {
4897 return mCameraSoundForced;
4898 }
4899 }
4900
4901 private static final String[] RINGER_MODE_NAMES = new String[] {
4902 "SILENT",
4903 "VIBRATE",
4904 "NORMAL"
4905 };
4906
4907 private void dumpRingerMode(PrintWriter pw) {
4908 pw.println("\nRinger mode: ");
4909 pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]);
4910 pw.print("- ringer mode affected streams = 0x");
4911 pw.println(Integer.toHexString(mRingerModeAffectedStreams));
4912 pw.print("- ringer mode muted streams = 0x");
4913 pw.println(Integer.toHexString(mRingerModeMutedStreams));
4914 }
4915
Dianne Hackborn632ca412012-06-14 19:34:10 -07004916 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004917 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07004918 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
4919
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004920 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07004921 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07004922 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07004923 pw.println("\nAudio routes:");
4924 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
4925 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
John Spurlock3346a802014-05-20 16:25:37 -04004926 pw.print(" mVolumeController="); pw.println(mVolumeController);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004927 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07004928
4929 // Inform AudioFlinger of our device's low RAM attribute
4930 private static void readAndSetLowRamDevice()
4931 {
4932 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
4933 if (status != 0) {
4934 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
4935 }
4936 }
John Spurlock3346a802014-05-20 16:25:37 -04004937
4938 private void enforceSelfOrSystemUI(String action) {
4939 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
4940 "Only SystemUI can " + action);
4941 }
4942
4943 @Override
4944 public void setVolumeController(final IVolumeController controller) {
4945 enforceSelfOrSystemUI("set the volume controller");
4946
4947 // return early if things are not actually changing
4948 if (mVolumeController.isSameBinder(controller)) {
4949 return;
4950 }
4951
4952 // dismiss the old volume controller
4953 mVolumeController.postDismiss();
4954 if (controller != null) {
4955 // we are about to register a new controller, listen for its death
4956 try {
4957 controller.asBinder().linkToDeath(new DeathRecipient() {
4958 @Override
4959 public void binderDied() {
4960 if (mVolumeController.isSameBinder(controller)) {
4961 Log.w(TAG, "Current remote volume controller died, unregistering");
4962 setVolumeController(null);
4963 }
4964 }
4965 }, 0);
4966 } catch (RemoteException e) {
4967 // noop
4968 }
4969 }
4970 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04004971 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
4972 }
4973
4974 @Override
4975 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
4976 enforceSelfOrSystemUI("notify about volume controller visibility");
4977
4978 // return early if the controller is not current
4979 if (!mVolumeController.isSameBinder(controller)) {
4980 return;
4981 }
4982
4983 mVolumeController.setVisible(visible);
4984 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04004985 }
RoboErikd09bd0c2014-06-24 17:45:19 -07004986
4987 public static class VolumeController {
4988 private static final String TAG = "VolumeController";
4989
4990 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04004991 private boolean mVisible;
4992 private long mNextLongPress;
4993 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07004994
4995 public void setController(IVolumeController controller) {
4996 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04004997 mVisible = false;
4998 }
4999
5000 public void loadSettings(ContentResolver cr) {
5001 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
5002 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
5003 }
5004
5005 public boolean suppressAdjustment(int resolvedStream, int flags) {
5006 boolean suppress = false;
5007 if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
5008 final long now = SystemClock.uptimeMillis();
5009 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
5010 // ui will become visible
5011 if (mNextLongPress < now) {
5012 mNextLongPress = now + mLongPressTimeout;
5013 }
5014 suppress = true;
5015 } else if (mNextLongPress > 0) { // in a long-press
5016 if (now > mNextLongPress) {
5017 // long press triggered, no more suppression
5018 mNextLongPress = 0;
5019 } else {
5020 // keep suppressing until the long press triggers
5021 suppress = true;
5022 }
5023 }
5024 }
5025 return suppress;
5026 }
5027
5028 public void setVisible(boolean visible) {
5029 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07005030 }
5031
5032 public boolean isSameBinder(IVolumeController controller) {
5033 return Objects.equals(asBinder(), binder(controller));
5034 }
5035
5036 public IBinder asBinder() {
5037 return binder(mController);
5038 }
5039
5040 private static IBinder binder(IVolumeController controller) {
5041 return controller == null ? null : controller.asBinder();
5042 }
5043
5044 @Override
5045 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04005046 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07005047 }
5048
5049 public void postDisplaySafeVolumeWarning(int flags) {
5050 if (mController == null)
5051 return;
5052 try {
5053 mController.displaySafeVolumeWarning(flags);
5054 } catch (RemoteException e) {
5055 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
5056 }
5057 }
5058
5059 public void postVolumeChanged(int streamType, int flags) {
5060 if (mController == null)
5061 return;
5062 try {
5063 mController.volumeChanged(streamType, flags);
5064 } catch (RemoteException e) {
5065 Log.w(TAG, "Error calling volumeChanged", e);
5066 }
5067 }
5068
5069 public void postMasterVolumeChanged(int flags) {
5070 if (mController == null)
5071 return;
5072 try {
5073 mController.masterVolumeChanged(flags);
5074 } catch (RemoteException e) {
5075 Log.w(TAG, "Error calling masterVolumeChanged", e);
5076 }
5077 }
5078
5079 public void postMasterMuteChanged(int flags) {
5080 if (mController == null)
5081 return;
5082 try {
5083 mController.masterMuteChanged(flags);
5084 } catch (RemoteException e) {
5085 Log.w(TAG, "Error calling masterMuteChanged", e);
5086 }
5087 }
5088
5089 public void setLayoutDirection(int layoutDirection) {
5090 if (mController == null)
5091 return;
5092 try {
5093 mController.setLayoutDirection(layoutDirection);
5094 } catch (RemoteException e) {
5095 Log.w(TAG, "Error calling setLayoutDirection", e);
5096 }
5097 }
5098
5099 public void postDismiss() {
5100 if (mController == null)
5101 return;
5102 try {
5103 mController.dismiss();
5104 } catch (RemoteException e) {
5105 Log.w(TAG, "Error calling dismiss", e);
5106 }
5107 }
5108 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005109
5110 //==========================================================================================
5111 // Audio policy management
5112 //==========================================================================================
5113 public boolean registerAudioPolicy(AudioPolicyConfig policyConfig, IBinder cb) {
5114 //Log.v(TAG, "registerAudioPolicy for " + cb + " got policy:" + policyConfig);
5115 boolean hasPermissionForPolicy =
5116 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
5117 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5118 if (!hasPermissionForPolicy) {
5119 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
5120 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
5121 return false;
5122 }
5123 synchronized (mAudioPolicies) {
5124 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, cb);
5125 try {
5126 cb.linkToDeath(app, 0/*flags*/);
5127 mAudioPolicies.put(cb, app);
5128 } catch (RemoteException e) {
5129 // audio policy owner has already died!
5130 Slog.w(TAG, "Audio policy registration failed, could not link to " + cb +
5131 " binder death", e);
5132 return false;
5133 }
5134 }
5135 // TODO implement registration with native audio policy (including permission check)
5136 return true;
5137 }
5138 public void unregisterAudioPolicyAsync(IBinder cb) {
5139 synchronized (mAudioPolicies) {
5140 AudioPolicyProxy app = mAudioPolicies.remove(cb);
5141 if (app == null) {
5142 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
5143 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
5144 } else {
5145 cb.unlinkToDeath(app, 0/*flags*/);
5146 }
5147 }
5148 // TODO implement registration with native audio policy
5149 }
5150
5151 public class AudioPolicyProxy implements IBinder.DeathRecipient {
5152 private static final String TAG = "AudioPolicyProxy";
5153 AudioPolicyConfig mConfig;
5154 IBinder mToken;
5155 AudioPolicyProxy(AudioPolicyConfig config, IBinder token) {
5156 mConfig = config;
5157 mToken = token;
5158 }
5159
5160 public void binderDied() {
5161 synchronized (mAudioPolicies) {
5162 Log.v(TAG, "audio policy " + mToken + " died");
5163 mAudioPolicies.remove(mToken);
5164 }
5165 }
5166 };
5167
5168 private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
5169 new HashMap<IBinder, AudioPolicyProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005170}