blob: eaece09c5ac785232afbe38802e7726283dd02a0 [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
John Spurlock61560172015-02-06 19:46:04 -050017package com.android.server.audio;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Jeff Sharkey098d5802012-04-26 17:30:34 -070019import static android.Manifest.permission.REMOTE_AUDIO_PLAYBACK;
Amith Yamasanic696a532011-10-28 17:02:37 -070020import static android.media.AudioManager.RINGER_MODE_NORMAL;
21import static android.media.AudioManager.RINGER_MODE_SILENT;
22import static android.media.AudioManager.RINGER_MODE_VIBRATE;
23
Glenn Kastenfd116ad2013-07-12 17:10:39 -070024import android.app.ActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.app.ActivityManagerNative;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -070026import android.app.AppOpsManager;
Amith Yamasani6243edd2011-12-05 19:58:48 -080027import android.app.KeyguardManager;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070028import android.bluetooth.BluetoothA2dp;
29import android.bluetooth.BluetoothAdapter;
30import android.bluetooth.BluetoothClass;
31import android.bluetooth.BluetoothDevice;
32import android.bluetooth.BluetoothHeadset;
33import android.bluetooth.BluetoothProfile;
Nick Pellybd022f42009-08-14 18:33:38 -070034import android.content.BroadcastReceiver;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070035import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.content.ContentResolver;
37import android.content.Context;
38import android.content.Intent;
Eric Laurenta553c252009-07-17 12:17:14 -070039import android.content.IntentFilter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.content.pm.PackageManager;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -070041import android.content.res.Configuration;
Eric Laurente78fced2013-03-15 16:03:47 -070042import android.content.res.Resources;
43import android.content.res.XmlResourceParser;
Jason Parekhb1096152009-03-24 17:48:25 -070044import android.database.ContentObserver;
Jungshik Jang41d97462014-06-30 22:26:29 +090045import android.hardware.hdmi.HdmiControlManager;
Eric Laurent212532b2014-07-21 15:43:18 -070046import android.hardware.hdmi.HdmiPlaybackClient;
Jungshik Jang41d97462014-06-30 22:26:29 +090047import android.hardware.hdmi.HdmiTvClient;
Paul McLeanc837a452014-04-09 09:04:43 -070048import android.hardware.usb.UsbManager;
John Spurlock61560172015-02-06 19:46:04 -050049import android.media.AudioAttributes;
50import android.media.AudioDevicePort;
51import android.media.AudioSystem;
52import android.media.AudioFormat;
53import android.media.AudioManager;
54import android.media.AudioManagerInternal;
55import android.media.AudioPort;
56import android.media.AudioRoutesInfo;
57import android.media.AudioSystem;
58import android.media.IAudioFocusDispatcher;
59import android.media.IAudioRoutesObserver;
60import android.media.IAudioService;
61import android.media.IRemoteControlDisplay;
62import android.media.IRingtonePlayer;
63import android.media.IVolumeController;
64import android.media.MediaPlayer;
65import android.media.SoundPool;
66import android.media.AudioAttributes.Builder;
67import android.media.AudioManagerInternal.RingerModeDelegate;
68import android.media.AudioSystem.ErrorCallback;
69import android.media.IAudioService.Stub;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070import android.media.MediaPlayer.OnCompletionListener;
71import android.media.MediaPlayer.OnErrorListener;
John Spurlock61560172015-02-06 19:46:04 -050072import android.media.SoundPool.OnLoadCompleteListener;
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -070073import android.media.audiopolicy.AudioMix;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -080074import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070075import android.media.audiopolicy.AudioPolicyConfig;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -080076import android.media.audiopolicy.IAudioPolicyCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077import android.os.Binder;
Eric Laurentc18c9132013-04-12 17:24:56 -070078import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079import android.os.Environment;
80import android.os.Handler;
81import android.os.IBinder;
82import android.os.Looper;
83import android.os.Message;
Jean-Michel Trivic6802222012-04-30 11:15:03 -070084import android.os.PowerManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070085import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086import android.os.RemoteException;
John Spurlock33f4e042014-07-11 13:10:58 -040087import android.os.SystemClock;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070088import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070089import android.os.UserHandle;
Eric Laurentbffc3d12012-05-07 17:43:49 -070090import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091import android.provider.Settings;
92import android.provider.Settings.System;
Tyler Gunnef9f6f92014-09-12 22:16:17 -070093import android.telecom.TelecomManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070094import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095import android.util.Log;
John Spurlockaa5ee4d2014-07-25 13:05:12 -040096import android.util.MathUtils;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070097import android.util.Slog;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070098import android.view.KeyEvent;
RoboErik519c7742014-11-18 10:59:09 -080099import android.view.OrientationEventListener;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700100import android.view.Surface;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700101import android.view.WindowManager;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700102import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103
Eric Laurente78fced2013-03-15 16:03:47 -0700104import com.android.internal.util.XmlUtils;
RoboErik0dac35a2014-08-12 15:48:49 -0700105import com.android.server.LocalServices;
Eric Laurente78fced2013-03-15 16:03:47 -0700106
107import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800109import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110import java.io.IOException;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800111import java.io.PrintWriter;
Eric Laurente78fced2013-03-15 16:03:47 -0700112import java.lang.reflect.Field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113import java.util.ArrayList;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700114import java.util.HashMap;
115import java.util.Iterator;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -0700116import java.util.List;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700117import java.util.Map;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700118import java.util.NoSuchElementException;
RoboErikd09bd0c2014-06-24 17:45:19 -0700119import java.util.Objects;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700120import java.util.Set;
RoboErik519c7742014-11-18 10:59:09 -0800121import java.util.concurrent.ConcurrentHashMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122
123/**
124 * The implementation of the volume manager service.
125 * <p>
126 * This implementation focuses on delivering a responsive UI. Most methods are
127 * asynchronous to external calls. For example, the task of setting a volume
128 * will update our internal state, but in a separate thread will set the system
129 * volume and later persist to the database. Similarly, setting the ringer mode
130 * will update the state and broadcast a change and in a separate thread later
131 * persist the ringer mode.
132 *
133 * @hide
134 */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700135public class AudioService extends IAudioService.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136
137 private static final String TAG = "AudioService";
138
Jean-Michel Trivi339567d2014-07-29 09:53:34 -0700139 /** Debug audio mode */
140 protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -0700141
142 /** Debug audio policy feature */
143 protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);
144
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700145 /** Debug volumes */
John Spurlockae641c92014-06-30 18:11:40 -0400146 protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700147
RoboErik430fc482014-06-12 15:49:20 -0700148 /** debug calls to media session apis */
John Spurlockae641c92014-06-30 18:11:40 -0400149 private static final boolean DEBUG_SESSIONS = Log.isLoggable(TAG + ".SESSIONS", Log.DEBUG);
RoboErik8a2cfc32014-05-16 11:19:38 -0700150
John Spurlock86005342014-05-23 11:58:00 -0400151 /** Allow volume changes to set ringer mode to silent? */
152 private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
153
John Spurlocka11b4af2014-06-01 11:52:23 -0400154 /** In silent mode, are volume adjustments (raises) prevented? */
155 private static final boolean PREVENT_VOLUME_ADJUSTMENT_IF_SILENT = true;
156
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 /** How long to delay before persisting a change in volume/ringer mode. */
RoboErik45edba12012-03-27 17:54:36 -0700158 private static final int PERSIST_DELAY = 500;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159
RoboErik5452e252015-02-06 15:33:53 -0800160 /** How long to delay after a volume down event before unmuting a stream */
161 private static final int UNMUTE_STREAM_DELAY = 350;
162
John Spurlock3346a802014-05-20 16:25:37 -0400163 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400164 * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
165 */
166 private static final int FLAG_ADJUST_VOLUME = 1;
167
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700168 private final Context mContext;
169 private final ContentResolver mContentResolver;
170 private final AppOpsManager mAppOps;
Eric Laurent212532b2014-07-21 15:43:18 -0700171
Eric Laurent212532b2014-07-21 15:43:18 -0700172 // the platform type affects volume and silent mode behavior
173 private final int mPlatformType;
174
175 private boolean isPlatformVoice() {
John Spurlock61560172015-02-06 19:46:04 -0500176 return mPlatformType == AudioSystem.PLATFORM_VOICE;
Eric Laurent212532b2014-07-21 15:43:18 -0700177 }
178
179 private boolean isPlatformTelevision() {
John Spurlock61560172015-02-06 19:46:04 -0500180 return mPlatformType == AudioSystem.PLATFORM_TELEVISION;
Eric Laurent212532b2014-07-21 15:43:18 -0700181 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800182
John Spurlock3346a802014-05-20 16:25:37 -0400183 /** The controller for the volume UI. */
184 private final VolumeController mVolumeController = new VolumeController();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185
186 // sendMsg() flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 /** If the msg is already queued, replace it with this one. */
188 private static final int SENDMSG_REPLACE = 0;
189 /** If the msg is already queued, ignore this one and leave the old. */
190 private static final int SENDMSG_NOOP = 1;
191 /** If the msg is already queued, queue this one and leave the old. */
192 private static final int SENDMSG_QUEUE = 2;
193
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700194 // AudioHandler messages
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800195 private static final int MSG_SET_DEVICE_VOLUME = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 private static final int MSG_PERSIST_VOLUME = 1;
Mike Lockwood5c55a052011-12-15 17:21:44 -0500197 private static final int MSG_PERSIST_MASTER_VOLUME = 2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 private static final int MSG_PERSIST_RINGER_MODE = 3;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700199 private static final int MSG_MEDIA_SERVER_DIED = 4;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700200 private static final int MSG_PLAY_SOUND_EFFECT = 5;
201 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
202 private static final int MSG_LOAD_SOUND_EFFECTS = 7;
203 private static final int MSG_SET_FORCE_USE = 8;
204 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
205 private static final int MSG_SET_ALL_VOLUMES = 10;
206 private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
207 private static final int MSG_REPORT_NEW_ROUTES = 12;
208 private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
209 private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
210 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
211 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
212 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
213 private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
214 private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
215 private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700216 private static final int MSG_SYSTEM_READY = 21;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400217 private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
Julia Reynoldsb53453f2014-08-22 11:42:43 -0400218 private static final int MSG_PERSIST_MICROPHONE_MUTE = 23;
RoboErik5452e252015-02-06 15:33:53 -0800219 private static final int MSG_UNMUTE_STREAM = 24;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700220 // start of messages handled under wakelock
221 // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
Jean-Michel Trivie12c39b2012-06-06 10:51:58 -0700222 // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700223 private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
Mike Lockwood0a40ec22014-05-21 10:08:50 -0700224 private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
225 private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700226 // end of messages handled under wakelock
Eric Laurentafbb0472011-12-15 09:04:23 -0800227
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -0700228 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
Eric Laurentdc03c612011-04-01 10:59:41 -0700229 // Timeout for connection to bluetooth headset service
230 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
231
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232 /** @see AudioSystemThread */
233 private AudioSystemThread mAudioSystemThread;
234 /** @see AudioHandler */
235 private AudioHandler mAudioHandler;
236 /** @see VolumeStreamState */
237 private VolumeStreamState[] mStreamStates;
Jason Parekhb1096152009-03-24 17:48:25 -0700238 private SettingsObserver mSettingsObserver;
Eric Laurenta553c252009-07-17 12:17:14 -0700239
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700240 private int mMode = AudioSystem.MODE_NORMAL;
Glenn Kastenba195eb2011-12-13 09:30:40 -0800241 // protects mRingerMode
242 private final Object mSettingsLock = new Object();
Eric Laurent45c90ce2012-04-24 18:44:22 -0700243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 private SoundPool mSoundPool;
Glenn Kasten30c918c2011-11-10 17:56:41 -0800245 private final Object mSoundEffectsLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800246 private static final int NUM_SOUNDPOOL_CHANNELS = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247
Mike Lockwood47676902011-11-08 10:31:21 -0800248 // Internally master volume is a float in the 0.0 - 1.0 range,
249 // but to support integer based AudioManager API we translate it to 0 - 100
250 private static final int MAX_MASTER_VOLUME = 100;
251
Lei Zhang6c798972012-03-02 11:40:12 -0800252 // Maximum volume adjust steps allowed in a single batch call.
253 private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 /* Sound effect file names */
256 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
Eric Laurente78fced2013-03-15 16:03:47 -0700257 private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258
259 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
260 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
261 * uses soundpool (second column) */
Eric Laurente78fced2013-03-15 16:03:47 -0700262 private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263
Jared Suttles59820132009-08-13 21:50:52 -0500264 /** @hide Maximum volume index values for audio streams */
Eric Laurent91377de2014-10-10 15:24:04 -0700265 private static int[] MAX_STREAM_VOLUME = new int[] {
Eric Laurent6ee99522009-08-25 06:30:59 -0700266 5, // STREAM_VOICE_CALL
267 7, // STREAM_SYSTEM
268 7, // STREAM_RING
269 15, // STREAM_MUSIC
270 7, // STREAM_ALARM
271 7, // STREAM_NOTIFICATION
272 15, // STREAM_BLUETOOTH_SCO
273 7, // STREAM_SYSTEM_ENFORCED
274 15, // STREAM_DTMF
275 15 // STREAM_TTS
Jared Suttles59820132009-08-13 21:50:52 -0500276 };
Eric Laurent91377de2014-10-10 15:24:04 -0700277
Eric Laurent6d517662012-04-23 18:42:39 -0700278 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
Eric Laurenta553c252009-07-17 12:17:14 -0700279 * of another stream: This avoids multiplying the volume settings for hidden
280 * stream types that follow other stream behavior for volume settings
Eric Laurent6d517662012-04-23 18:42:39 -0700281 * NOTE: do not create loops in aliases!
282 * Some streams alias to different streams according to device category (phone or tablet) or
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700283 * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
Eric Laurent212532b2014-07-21 15:43:18 -0700284 * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
285 * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
286 * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
287 private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700288 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
289 AudioSystem.STREAM_RING, // STREAM_SYSTEM
290 AudioSystem.STREAM_RING, // STREAM_RING
291 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
292 AudioSystem.STREAM_ALARM, // STREAM_ALARM
293 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
294 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
295 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
296 AudioSystem.STREAM_RING, // STREAM_DTMF
297 AudioSystem.STREAM_MUSIC // STREAM_TTS
Eric Laurenta553c252009-07-17 12:17:14 -0700298 };
Eric Laurent212532b2014-07-21 15:43:18 -0700299 private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
300 AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL
301 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
302 AudioSystem.STREAM_MUSIC, // STREAM_RING
303 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
304 AudioSystem.STREAM_MUSIC, // STREAM_ALARM
305 AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
306 AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO
307 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
308 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
309 AudioSystem.STREAM_MUSIC // STREAM_TTS
310 };
311 private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700312 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
John Spurlock4f0f1202014-08-05 13:28:33 -0400313 AudioSystem.STREAM_RING, // STREAM_SYSTEM
Eric Laurent6d517662012-04-23 18:42:39 -0700314 AudioSystem.STREAM_RING, // STREAM_RING
315 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
316 AudioSystem.STREAM_ALARM, // STREAM_ALARM
317 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
318 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
John Spurlock4f0f1202014-08-05 13:28:33 -0400319 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
320 AudioSystem.STREAM_RING, // STREAM_DTMF
Eric Laurent6d517662012-04-23 18:42:39 -0700321 AudioSystem.STREAM_MUSIC // STREAM_TTS
322 };
323 private int[] mStreamVolumeAlias;
Eric Laurenta553c252009-07-17 12:17:14 -0700324
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700325 /**
326 * Map AudioSystem.STREAM_* constants to app ops. This should be used
327 * after mapping through mStreamVolumeAlias.
328 */
329 private static final int[] STEAM_VOLUME_OPS = new int[] {
330 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL
331 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM
332 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING
333 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC
334 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM
335 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION
336 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO
337 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED
338 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF
339 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS
340 };
341
Eric Laurent83a017b2013-03-19 18:15:31 -0700342 private final boolean mUseFixedVolume;
343
Glenn Kasten30c918c2011-11-10 17:56:41 -0800344 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 public void onError(int error) {
346 switch (error) {
347 case AudioSystem.AUDIO_STATUS_SERVER_DIED:
Eric Laurentdfb881f2013-07-18 14:41:39 -0700348 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
349 SENDMSG_NOOP, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 break;
351 default:
352 break;
353 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700354 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 };
356
357 /**
358 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
359 * {@link AudioManager#RINGER_MODE_SILENT}, or
360 * {@link AudioManager#RINGER_MODE_VIBRATE}.
361 */
Glenn Kastenba195eb2011-12-13 09:30:40 -0800362 // protected by mSettingsLock
John Spurlock661f2cf2014-11-17 10:29:10 -0500363 private int mRingerMode; // internal ringer mode, affects muting of underlying streams
364 private int mRingerModeExternal = -1; // reported ringer mode to outside clients (AudioManager)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365
Eric Laurent9bcf4012009-06-12 06:09:28 -0700366 /** @see System#MODE_RINGER_STREAMS_AFFECTED */
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700367 private int mRingerModeAffectedStreams = 0;
Eric Laurent9bcf4012009-06-12 06:09:28 -0700368
Eric Laurent5b4e6542010-03-19 20:02:21 -0700369 // Streams currently muted by ringer mode
370 private int mRingerModeMutedStreams;
371
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 /** @see System#MUTE_STREAMS_AFFECTED */
373 private int mMuteAffectedStreams;
374
375 /**
Eric Laurentbffc3d12012-05-07 17:43:49 -0700376 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
377 * mVibrateSetting is just maintained during deprecation period but vibration policy is
378 * now only controlled by mHasVibrator and mRingerMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 */
380 private int mVibrateSetting;
381
Eric Laurentbffc3d12012-05-07 17:43:49 -0700382 // Is there a vibrator
383 private final boolean mHasVibrator;
384
Eric Laurenta553c252009-07-17 12:17:14 -0700385 // Broadcast receiver for device connections intent broadcasts
386 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
387
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700388 // Devices currently connected
Glenn Kasten30c918c2011-11-10 17:56:41 -0800389 private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700390
391 // Forced device usage for communications
392 private int mForcedUseForComm;
393
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500394 // True if we have master volume support
395 private final boolean mUseMasterVolume;
396
Mike Lockwood97606472012-02-09 11:24:10 -0800397 private final int[] mMasterVolumeRamp;
398
Eric Laurent9272b4b2010-01-23 17:12:59 -0800399 // List of binder death handlers for setMode() client processes.
400 // The last process to have called setMode() is at the top of the list.
Glenn Kasten30c918c2011-11-10 17:56:41 -0800401 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
Eric Laurenteb14a782009-12-17 03:12:59 -0800402
Eric Laurent3def1ee2010-03-17 23:26:26 -0700403 // List of clients having issued a SCO start request
Glenn Kasten30c918c2011-11-10 17:56:41 -0800404 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
Eric Laurent3def1ee2010-03-17 23:26:26 -0700405
406 // BluetoothHeadset API to control SCO connection
407 private BluetoothHeadset mBluetoothHeadset;
408
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700409 // Bluetooth headset device
410 private BluetoothDevice mBluetoothHeadsetDevice;
Eric Laurent3def1ee2010-03-17 23:26:26 -0700411
Eric Laurent62ef7672010-11-24 10:58:32 -0800412 // Indicate if SCO audio connection is currently active and if the initiator is
413 // audio service (internal) or bluetooth headset (external)
414 private int mScoAudioState;
415 // SCO audio state is not active
416 private static final int SCO_STATE_INACTIVE = 0;
Eric Laurentdc03c612011-04-01 10:59:41 -0700417 // SCO audio activation request waiting for headset service to connect
418 private static final int SCO_STATE_ACTIVATE_REQ = 1;
Eric Laurent25fc29b2013-04-05 12:13:54 -0700419 // SCO audio state is active or starting due to a request from AudioManager API
Eric Laurentdc03c612011-04-01 10:59:41 -0700420 private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
421 // SCO audio deactivation request waiting for headset service to connect
422 private static final int SCO_STATE_DEACTIVATE_REQ = 5;
423
Eric Laurent62ef7672010-11-24 10:58:32 -0800424 // SCO audio state is active due to an action in BT handsfree (either voice recognition or
425 // in call audio)
426 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
Eric Laurentdc03c612011-04-01 10:59:41 -0700427 // Deactivation request for all SCO connections (initiated by audio mode change)
428 // waiting for headset service to connect
429 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
430
Eric Laurentc18c9132013-04-12 17:24:56 -0700431 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
432 // originated from an app targeting an API version before JB MR2 and raw audio after that.
433 private int mScoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -0700434 // SCO audio mode is undefined
435 private static final int SCO_MODE_UNDEFINED = -1;
Eric Laurentc18c9132013-04-12 17:24:56 -0700436 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
437 private static final int SCO_MODE_VIRTUAL_CALL = 0;
438 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
439 private static final int SCO_MODE_RAW = 1;
Liejun Taof4e51d82014-07-16 11:18:29 -0700440 // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
441 private static final int SCO_MODE_VR = 2;
442
443 private static final int SCO_MODE_MAX = 2;
Eric Laurentc18c9132013-04-12 17:24:56 -0700444
Eric Laurentdc03c612011-04-01 10:59:41 -0700445 // Current connection state indicated by bluetooth headset
446 private int mScoConnectionState;
Eric Laurent62ef7672010-11-24 10:58:32 -0800447
Eric Laurenta60e2122010-12-28 16:49:07 -0800448 // true if boot sequence has been completed
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700449 private boolean mSystemReady;
Eric Laurenta60e2122010-12-28 16:49:07 -0800450 // listener for SoundPool sample load completion indication
451 private SoundPoolCallback mSoundPoolCallBack;
452 // thread for SoundPool listener
453 private SoundPoolListenerThread mSoundPoolListenerThread;
454 // message looper for SoundPool listener
455 private Looper mSoundPoolLooper = null;
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700456 // volume applied to sound played with playSoundEffect()
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700457 private static int sSoundEffectVolumeDb;
Eric Laurent25101b02011-02-02 09:33:30 -0800458 // previous volume adjustment direction received by checkForRingerModeChange()
459 private int mPrevVolDirection = AudioManager.ADJUST_SAME;
Amith Yamasani6243edd2011-12-05 19:58:48 -0800460 // Keyguard manager proxy
461 private KeyguardManager mKeyguardManager;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700462 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
463 // is controlled by Vol keys.
464 private int mVolumeControlStream = -1;
465 private final Object mForceControlStreamLock = new Object();
466 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
467 // server process so in theory it is not necessary to monitor the client death.
468 // However it is good to be ready for future evolutions.
469 private ForceControlStreamClient mForceControlStreamClient = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700470 // Used to play ringtones outside system_server
471 private volatile IRingtonePlayer mRingtonePlayer;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800472
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700473 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700474 private int mDeviceRotation = Surface.ROTATION_0;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700475
Eric Laurent78472112012-05-21 08:57:21 -0700476 // Request to override default use of A2DP for media.
477 private boolean mBluetoothA2dpEnabled;
478 private final Object mBluetoothA2dpEnabledLock = new Object();
479
Dianne Hackborn632ca412012-06-14 19:34:10 -0700480 // Monitoring of audio routes. Protected by mCurAudioRoutes.
481 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
482 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
483 = new RemoteCallbackList<IAudioRoutesObserver>();
484
Eric Laurent4bbcc652012-09-24 14:26:30 -0700485 // Devices for which the volume is fixed and VolumePanel slider should be disabled
Eric Laurent212532b2014-07-21 15:43:18 -0700486 int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700487 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Eric Laurent212532b2014-07-21 15:43:18 -0700488 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
489 AudioSystem.DEVICE_OUT_HDMI_ARC |
490 AudioSystem.DEVICE_OUT_SPDIF |
491 AudioSystem.DEVICE_OUT_AUX_LINE;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700492 int mFullVolumeDevices = 0;
Eric Laurent4bbcc652012-09-24 14:26:30 -0700493
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700494 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700495 private final boolean mMonitorOrientation;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700496 private final boolean mMonitorRotation;
Eric Laurentd640bd32012-09-28 18:01:48 -0700497
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700498 private boolean mDockAudioMediaEnabled = true;
499
Eric Laurent08ed1b92012-11-05 14:54:12 -0800500 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
501
Eric Laurentfde16d52012-12-03 14:42:39 -0800502 // Used when safe volume warning message display is requested by setStreamVolume(). In this
503 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
504 // and used later when/if disableSafeMediaVolume() is called.
505 private StreamVolumeCommand mPendingVolumeCommand;
506
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700507 private PowerManager.WakeLock mAudioEventWakeLock;
508
509 private final MediaFocusControl mMediaFocusControl;
510
John Du5a0cf7a2013-07-19 11:30:34 -0700511 // Reference to BluetoothA2dp to query for AbsoluteVolume.
512 private BluetoothA2dp mA2dp;
seunghwan.hong4fe77952014-10-29 17:43:20 +0900513 // lock always taken synchronized on mConnectedDevices
John Du5a0cf7a2013-07-19 11:30:34 -0700514 private final Object mA2dpAvrcpLock = new Object();
515 // If absolute volume is supported in AVRCP device
516 private boolean mAvrcpAbsVolSupported = false;
517
Jon Eklund318f0fe2014-01-23 17:53:48 -0600518 private AudioOrientationEventListener mOrientationListener;
519
Eric Laurentadbe8bf2014-11-03 18:26:32 -0800520 private static Long mLastDeviceConnectMsgTime = new Long(0);
521
John Spurlock661f2cf2014-11-17 10:29:10 -0500522 private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
523
Paul McLean10804eb2015-01-28 11:16:35 -0800524 // Intent "extra" data keys.
525 public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName";
526 public static final String CONNECT_INTENT_KEY_STATE = "state";
527 public static final String CONNECT_INTENT_KEY_ADDRESS = "address";
528 public static final String CONNECT_INTENT_KEY_HAS_PLAYBACK = "hasPlayback";
529 public static final String CONNECT_INTENT_KEY_HAS_CAPTURE = "hasCapture";
530 public static final String CONNECT_INTENT_KEY_HAS_MIDI = "hasMIDI";
531 public static final String CONNECT_INTENT_KEY_DEVICE_CLASS = "class";
532
533 // Defines the format for the connection "address" for ALSA devices
534 public static String makeAlsaAddressString(int card, int device) {
535 return "card=" + card + ";device=" + device + ";";
536 }
537
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800538 ///////////////////////////////////////////////////////////////////////////
539 // Construction
540 ///////////////////////////////////////////////////////////////////////////
541
542 /** @hide */
543 public AudioService(Context context) {
544 mContext = context;
545 mContentResolver = context.getContentResolver();
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700546 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700547
John Spurlock61560172015-02-06 19:46:04 -0500548 mPlatformType = AudioSystem.getPlatformType(context);
Jared Suttles59820132009-08-13 21:50:52 -0500549
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700550 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700551 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700552
Eric Laurentbffc3d12012-05-07 17:43:49 -0700553 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
554 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
555
Jared Suttles59820132009-08-13 21:50:52 -0500556 // Intialized volume
Eric Laurent91377de2014-10-10 15:24:04 -0700557 int maxVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps",
558 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
559 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
560 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500561 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700562 }
563 maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
564 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
565 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
566 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500567 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700568 }
Jared Suttles59820132009-08-13 21:50:52 -0500569
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700570 sSoundEffectVolumeDb = context.getResources().getInteger(
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700571 com.android.internal.R.integer.config_soundEffectVolumeDb);
Eric Laurent25101b02011-02-02 09:33:30 -0800572
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700573 mForcedUseForComm = AudioSystem.FORCE_NONE;
Eric Laurentdd45d012012-10-08 09:04:34 -0700574
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 createAudioSystemThread();
Eric Laurentdd45d012012-10-08 09:04:34 -0700576
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700577 mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
John Spurlock3346a802014-05-20 16:25:37 -0400578 mContext, mVolumeController, this);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700579
Eric Laurentdfb881f2013-07-18 14:41:39 -0700580 AudioSystem.setErrorCallback(mAudioSystemCallback);
581
Eric Laurentdd45d012012-10-08 09:04:34 -0700582 boolean cameraSoundForced = mContext.getResources().getBoolean(
583 com.android.internal.R.bool.config_camera_sound_forced);
584 mCameraSoundForced = new Boolean(cameraSoundForced);
585 sendMsg(mAudioHandler,
586 MSG_SET_FORCE_USE,
587 SENDMSG_QUEUE,
588 AudioSystem.FOR_SYSTEM,
589 cameraSoundForced ?
590 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
591 null,
592 0);
593
Eric Laurent05274f32012-11-29 12:48:18 -0800594 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
595 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
596 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
597 // The default safe volume index read here will be replaced by the actual value when
598 // the mcc is read by onConfigureSafeVolume()
599 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
600 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
601
Eric Laurent83a017b2013-03-19 18:15:31 -0700602 mUseFixedVolume = mContext.getResources().getBoolean(
603 com.android.internal.R.bool.config_useFixedVolume);
Wally Yauda392902014-11-28 12:40:30 -0800604 mUseMasterVolume = context.getResources().getBoolean(
605 com.android.internal.R.bool.config_useMasterVolume);
606 mMasterVolumeRamp = context.getResources().getIntArray(
607 com.android.internal.R.array.config_masterVolumeRamp);
Eric Laurent83a017b2013-03-19 18:15:31 -0700608
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700609 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
610 // array initialized by updateStreamVolumeAlias()
611 updateStreamVolumeAlias(false /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 readPersistedSettings();
Eric Laurentc1d41662011-07-19 11:21:13 -0700613 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700614 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700615
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700616 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700617
618 // Call setRingerModeInt() to apply correct mute
619 // state on streams affected by ringer mode.
620 mRingerModeMutedStreams = 0;
John Spurlock661f2cf2014-11-17 10:29:10 -0500621 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3891c4c2010-04-20 09:40:57 -0700622
Eric Laurenta553c252009-07-17 12:17:14 -0700623 // Register for device connection intent broadcasts.
624 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700625 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700626 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
627 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700628 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
629 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700630 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Paul McLeanc837a452014-04-09 09:04:43 -0700631 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700632
Eric Laurentd640bd32012-09-28 18:01:48 -0700633 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700634 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700635 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
636 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700637 Log.v(TAG, "monitoring device orientation");
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700638 // initialize orientation in AudioSystem
639 setOrientationForAudioSystem();
640 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700641 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
642 if (mMonitorRotation) {
643 mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
644 .getDefaultDisplay().getRotation();
645 Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
Jon Eklund318f0fe2014-01-23 17:53:48 -0600646
647 mOrientationListener = new AudioOrientationEventListener(mContext);
648 mOrientationListener.enable();
649
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700650 // initialize rotation in AudioSystem
651 setRotationForAudioSystem();
652 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700653
Eric Laurenta553c252009-07-17 12:17:14 -0700654 context.registerReceiver(mReceiver, intentFilter);
Jared Suttles59820132009-08-13 21:50:52 -0500655
Mike Lockwood90631542012-01-06 11:20:37 -0500656 restoreMasterVolume();
Mike Lockwood97606472012-02-09 11:24:10 -0800657
RoboErik0dac35a2014-08-12 15:48:49 -0700658 LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 }
660
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700661 public void systemReady() {
662 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
663 0, 0, null, 0);
664 }
665
666 public void onSystemReady() {
667 mSystemReady = true;
668 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
669 0, 0, null, 0);
670
671 mKeyguardManager =
672 (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
673 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
674 resetBluetoothSco();
675 getBluetoothHeadset();
676 //FIXME: this is to maintain compatibility with deprecated intent
677 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
678 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
679 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
680 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
681 sendStickyBroadcastToAll(newIntent);
682
683 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
684 if (adapter != null) {
685 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
686 BluetoothProfile.A2DP);
687 }
688
Eric Laurent212532b2014-07-21 15:43:18 -0700689 mHdmiManager =
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900690 (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700691 if (mHdmiManager != null) {
692 synchronized (mHdmiManager) {
693 mHdmiTvClient = mHdmiManager.getTvClient();
Jungshik Jangc9ff9682014-09-15 17:41:06 +0900694 if (mHdmiTvClient != null) {
695 mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
696 }
Eric Laurent212532b2014-07-21 15:43:18 -0700697 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
698 mHdmiCecSink = false;
699 }
700 }
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900701
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700702 sendMsg(mAudioHandler,
703 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
704 SENDMSG_REPLACE,
705 0,
706 0,
707 null,
708 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700709
710 StreamOverride.init(mContext);
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700711 }
712
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 private void createAudioSystemThread() {
714 mAudioSystemThread = new AudioSystemThread();
715 mAudioSystemThread.start();
716 waitForAudioHandlerCreation();
717 }
718
719 /** Waits for the volume handler to be created by the other thread. */
720 private void waitForAudioHandlerCreation() {
721 synchronized(this) {
722 while (mAudioHandler == null) {
723 try {
724 // Wait for mAudioHandler to be set by the other thread
725 wait();
726 } catch (InterruptedException e) {
727 Log.e(TAG, "Interrupted while waiting on volume handler.");
728 }
729 }
730 }
731 }
732
Eric Laurent24482012012-05-10 09:41:17 -0700733 private void checkAllAliasStreamVolumes() {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700734 synchronized (VolumeStreamState.class) {
735 int numStreamTypes = AudioSystem.getNumStreamTypes();
736 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
737 if (streamType != mStreamVolumeAlias[streamType]) {
738 mStreamStates[streamType].
Eric Laurent42b041e2013-03-29 11:36:03 -0700739 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700740 }
741 // apply stream volume
RoboErik4197cb62015-01-21 15:45:32 -0800742 if (!mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700743 mStreamStates[streamType].applyAllVolumes();
744 }
Eric Laurent24482012012-05-10 09:41:17 -0700745 }
746 }
747 }
748
Eric Laurent212532b2014-07-21 15:43:18 -0700749 private void checkAllFixedVolumeDevices()
750 {
751 int numStreamTypes = AudioSystem.getNumStreamTypes();
752 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
753 mStreamStates[streamType].checkFixedVolumeDevices();
754 }
755 }
756
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700757 private void checkAllFixedVolumeDevices(int streamType) {
758 mStreamStates[streamType].checkFixedVolumeDevices();
759 }
760
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800762 int numStreamTypes = AudioSystem.getNumStreamTypes();
763 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
764
765 for (int i = 0; i < numStreamTypes; i++) {
Eric Laurent6d517662012-04-23 18:42:39 -0700766 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -0700767 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768
Eric Laurent212532b2014-07-21 15:43:18 -0700769 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -0700770 checkAllAliasStreamVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 }
772
Eric Laurentbffc3d12012-05-07 17:43:49 -0700773 private void dumpStreamStates(PrintWriter pw) {
774 pw.println("\nStream volumes (device: index)");
775 int numStreamTypes = AudioSystem.getNumStreamTypes();
776 for (int i = 0; i < numStreamTypes; i++) {
John Spurlock61560172015-02-06 19:46:04 -0500777 pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":");
Eric Laurentbffc3d12012-05-07 17:43:49 -0700778 mStreamStates[i].dump(pw);
779 pw.println("");
780 }
Eric Laurentdd45d012012-10-08 09:04:34 -0700781 pw.print("\n- mute affected streams = 0x");
782 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -0700783 }
784
Eric Laurent6d517662012-04-23 18:42:39 -0700785 private void updateStreamVolumeAlias(boolean updateVolumes) {
786 int dtmfStreamAlias;
Eric Laurent212532b2014-07-21 15:43:18 -0700787
788 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -0500789 case AudioSystem.PLATFORM_VOICE:
Eric Laurent212532b2014-07-21 15:43:18 -0700790 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
Eric Laurent6d517662012-04-23 18:42:39 -0700791 dtmfStreamAlias = AudioSystem.STREAM_RING;
Eric Laurent212532b2014-07-21 15:43:18 -0700792 break;
John Spurlock61560172015-02-06 19:46:04 -0500793 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -0700794 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
795 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
796 break;
797 default:
798 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
Eric Laurent6d517662012-04-23 18:42:39 -0700799 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
800 }
Eric Laurent212532b2014-07-21 15:43:18 -0700801
802 if (isPlatformTelevision()) {
803 mRingerModeAffectedStreams = 0;
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700804 } else {
Eric Laurent212532b2014-07-21 15:43:18 -0700805 if (isInCommunication()) {
806 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
807 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
808 } else {
809 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
810 }
Eric Laurent6d517662012-04-23 18:42:39 -0700811 }
Eric Laurent212532b2014-07-21 15:43:18 -0700812
Eric Laurent6d517662012-04-23 18:42:39 -0700813 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
814 if (updateVolumes) {
Eric Laurent42b041e2013-03-29 11:36:03 -0700815 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700816 // apply stream mute states according to new value of mRingerModeAffectedStreams
John Spurlock661f2cf2014-11-17 10:29:10 -0500817 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent6d517662012-04-23 18:42:39 -0700818 sendMsg(mAudioHandler,
819 MSG_SET_ALL_VOLUMES,
820 SENDMSG_QUEUE,
821 0,
822 0,
823 mStreamStates[AudioSystem.STREAM_DTMF], 0);
824 }
825 }
826
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700827 private void readDockAudioSettings(ContentResolver cr)
828 {
829 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -0700830 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700831
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700832 sendMsg(mAudioHandler,
833 MSG_SET_FORCE_USE,
834 SENDMSG_QUEUE,
835 AudioSystem.FOR_DOCK,
836 mDockAudioMediaEnabled ?
837 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
838 null,
839 0);
840 }
841
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800842 private void readPersistedSettings() {
843 final ContentResolver cr = mContentResolver;
844
Eric Laurentbffc3d12012-05-07 17:43:49 -0700845 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700846 Settings.Global.getInt(
847 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -0700848 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -0700849 // sanity check in case the settings are restored from a device with incompatible
850 // ringer modes
John Spurlock97559372014-10-24 16:27:36 -0400851 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -0800852 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700853 }
854 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
855 ringerMode = AudioManager.RINGER_MODE_SILENT;
856 }
857 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700858 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -0800859 }
Eric Laurent212532b2014-07-21 15:43:18 -0700860 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -0700861 ringerMode = AudioManager.RINGER_MODE_NORMAL;
862 }
Glenn Kastenba195eb2011-12-13 09:30:40 -0800863 synchronized(mSettingsLock) {
864 mRingerMode = ringerMode;
John Spurlock661f2cf2014-11-17 10:29:10 -0500865 if (mRingerModeExternal == -1) {
866 mRingerModeExternal = mRingerMode;
867 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868
Eric Laurentdd45d012012-10-08 09:04:34 -0700869 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
870 // are still needed while setVibrateSetting() and getVibrateSetting() are being
871 // deprecated.
John Spurlock61560172015-02-06 19:46:04 -0500872 mVibrateSetting = AudioSystem.getValueForVibrateSetting(0,
Eric Laurentdd45d012012-10-08 09:04:34 -0700873 AudioManager.VIBRATE_TYPE_NOTIFICATION,
874 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
875 : AudioManager.VIBRATE_SETTING_OFF);
John Spurlock61560172015-02-06 19:46:04 -0500876 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting,
Eric Laurentdd45d012012-10-08 09:04:34 -0700877 AudioManager.VIBRATE_TYPE_RINGER,
878 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
879 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800880
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700881 updateRingerModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700882 readDockAudioSettings(cr);
Eric Laurent402f7f22011-02-04 12:30:32 -0800883 }
Eric Laurentc1d41662011-07-19 11:21:13 -0700884
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700885 mMuteAffectedStreams = System.getIntForUser(cr,
John Spurlock61560172015-02-06 19:46:04 -0500886 System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
John Spurlock24c05182015-02-05 12:30:36 -0500887 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800888
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700889 boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
890 0, UserHandle.USER_CURRENT) == 1;
Eric Laurent83a017b2013-03-19 18:15:31 -0700891 if (mUseFixedVolume) {
892 masterMute = false;
893 AudioSystem.setMasterVolume(1.0f);
894 }
Justin Koh57978ed2012-04-03 17:37:58 -0700895 AudioSystem.setMasterMute(masterMute);
896 broadcastMasterMuteStatus(masterMute);
897
Julia Reynoldsb53453f2014-08-22 11:42:43 -0400898 boolean microphoneMute =
899 System.getIntForUser(cr, System.MICROPHONE_MUTE, 0, UserHandle.USER_CURRENT) == 1;
900 AudioSystem.muteMicrophone(microphoneMute);
901
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 // Each stream will read its own persisted settings
903
John Spurlockbcc10872014-11-28 15:29:21 -0500904 // Broadcast the sticky intents
905 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
906 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800907
908 // Broadcast vibrate settings
909 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
910 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -0700911
John Spurlock33f4e042014-07-11 13:10:58 -0400912 // Load settings for the volume controller
913 mVolumeController.loadSettings(cr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800914 }
915
Eric Laurenta553c252009-07-17 12:17:14 -0700916 private int rescaleIndex(int index, int srcStream, int dstStream) {
917 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
918 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800919
Jon Eklund318f0fe2014-01-23 17:53:48 -0600920 private class AudioOrientationEventListener
921 extends OrientationEventListener {
922 public AudioOrientationEventListener(Context context) {
923 super(context);
924 }
925
926 @Override
927 public void onOrientationChanged(int orientation) {
928 //Even though we're responding to phone orientation events,
929 //use display rotation so audio stays in sync with video/dialogs
930 int newRotation = ((WindowManager) mContext.getSystemService(
931 Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
932 if (newRotation != mDeviceRotation) {
933 mDeviceRotation = newRotation;
934 setRotationForAudioSystem();
935 }
936 }
937 }
938
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800939 ///////////////////////////////////////////////////////////////////////////
940 // IPC methods
941 ///////////////////////////////////////////////////////////////////////////
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 /** @see AudioManager#adjustVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700943 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
944 String callingPackage) {
RoboErik272e1612014-09-05 11:39:29 -0700945 adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
946 Binder.getCallingUid());
947 }
948
949 private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
950 String callingPackage, int uid) {
John Spurlockae641c92014-06-30 18:11:40 -0400951 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType
952 + ", flags=" + flags);
Eric Laurent402f7f22011-02-04 12:30:32 -0800953 int streamType;
RoboErik4197cb62015-01-21 15:45:32 -0800954 boolean isMute = isMuteAdjust(direction);
Eric Laurent45c90ce2012-04-24 18:44:22 -0700955 if (mVolumeControlStream != -1) {
956 streamType = mVolumeControlStream;
Eric Laurent402f7f22011-02-04 12:30:32 -0800957 } else {
958 streamType = getActiveStreamType(suggestedStreamType);
959 }
John Spurlock33f4e042014-07-11 13:10:58 -0400960 final int resolvedStream = mStreamVolumeAlias[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961
RoboErik2811dd32014-08-12 09:48:13 -0700962 // Play sounds on STREAM_RING only.
963 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
John Spurlock33f4e042014-07-11 13:10:58 -0400964 resolvedStream != AudioSystem.STREAM_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 flags &= ~AudioManager.FLAG_PLAY_SOUND;
966 }
967
John Spurlock33f4e042014-07-11 13:10:58 -0400968 // For notifications/ring, show the ui before making any adjustments
RoboErik4197cb62015-01-21 15:45:32 -0800969 // Don't suppress mute/unmute requests
970 if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
John Spurlock33f4e042014-07-11 13:10:58 -0400971 direction = 0;
972 flags &= ~AudioManager.FLAG_PLAY_SOUND;
973 flags &= ~AudioManager.FLAG_VIBRATE;
974 if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
975 }
976
RoboErik272e1612014-09-05 11:39:29 -0700977 adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978 }
979
980 /** @see AudioManager#adjustStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700981 public void adjustStreamVolume(int streamType, int direction, int flags,
982 String callingPackage) {
RoboErik0dac35a2014-08-12 15:48:49 -0700983 adjustStreamVolume(streamType, direction, flags, callingPackage, Binder.getCallingUid());
984 }
985
986 private void adjustStreamVolume(int streamType, int direction, int flags,
987 String callingPackage, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -0700988 if (mUseFixedVolume) {
989 return;
990 }
John Spurlockae641c92014-06-30 18:11:40 -0400991 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction
992 + ", flags="+flags);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700993
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 ensureValidDirection(direction);
995 ensureValidStreamType(streamType);
996
RoboErik4197cb62015-01-21 15:45:32 -0800997 boolean isMuteAdjust = isMuteAdjust(direction);
998
Eric Laurent96a33d12011-11-08 10:31:57 -0800999 // use stream type alias here so that streams with same alias have the same behavior,
1000 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
1001 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
Eric Laurent6d517662012-04-23 18:42:39 -07001002 int streamTypeAlias = mStreamVolumeAlias[streamType];
RoboErik4197cb62015-01-21 15:45:32 -08001003
1004 if (isMuteAdjust && !isStreamAffectedByMute(streamTypeAlias)) {
1005 return;
1006 }
1007
Eric Laurentb024c302011-10-14 17:19:27 -07001008 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001009
1010 final int device = getDeviceForStream(streamTypeAlias);
Eric Laurent3ef75492012-11-28 12:12:23 -08001011
Eric Laurent42b041e2013-03-29 11:36:03 -07001012 int aliasIndex = streamState.getIndex(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001013 boolean adjustVolume = true;
Eric Laurent3ef75492012-11-28 12:12:23 -08001014 int step;
Eric Laurent24482012012-05-10 09:41:17 -07001015
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001016 // skip a2dp absolute volume control request when the device
1017 // is not an a2dp device
1018 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1019 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1020 return;
1021 }
1022
RoboErik0dac35a2014-08-12 15:48:49 -07001023 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
1024 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001025 return;
1026 }
1027
Eric Laurentfde16d52012-12-03 14:42:39 -08001028 // reset any pending volume command
1029 synchronized (mSafeMediaVolumeState) {
1030 mPendingVolumeCommand = null;
1031 }
1032
Eric Laurent3ef75492012-11-28 12:12:23 -08001033 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1034 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1035 ((device & mFixedVolumeDevices) != 0)) {
1036 flags |= AudioManager.FLAG_FIXED_VOLUME;
1037
1038 // Always toggle between max safe volume and 0 for fixed volume devices where safe
1039 // volume is enforced, and max and 0 for the others.
1040 // This is simulated by stepping by the full allowed volume range
1041 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1042 (device & mSafeMediaVolumeDevices) != 0) {
1043 step = mSafeMediaVolumeIndex;
1044 } else {
1045 step = streamState.getMaxIndex();
1046 }
1047 if (aliasIndex != 0) {
1048 aliasIndex = step;
1049 }
1050 } else {
1051 // convert one UI step (+/-1) into a number of internal units on the stream alias
1052 step = rescaleIndex(10, streamType, streamTypeAlias);
1053 }
1054
Eric Laurent42b041e2013-03-29 11:36:03 -07001055 // If either the client forces allowing ringer modes for this adjustment,
1056 // or the stream type is one that is affected by ringer modes
1057 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1058 (streamTypeAlias == getMasterStreamType())) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001059 int ringerMode = getRingerModeInternal();
Eric Laurent42b041e2013-03-29 11:36:03 -07001060 // do not vibrate if already in vibrate mode
1061 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
1062 flags &= ~AudioManager.FLAG_VIBRATE;
Eric Laurent3ef75492012-11-28 12:12:23 -08001063 }
RoboErik5452e252015-02-06 15:33:53 -08001064 // Check if the ringer mode handles this adjustment. If it does we don't
1065 // need to adjust the volume further.
1066 final int result = checkForRingerModeChange(aliasIndex, direction, step, streamState.mIsMuted);
John Spurlocka11b4af2014-06-01 11:52:23 -04001067 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
1068 // If suppressing a volume adjustment in silent mode, display the UI hint
1069 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
1070 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
1071 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001072 // If suppressing a volume down adjustment in vibrate mode, display the UI hint
1073 if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
1074 flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
1075 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001076 }
Eric Laurent3ef75492012-11-28 12:12:23 -08001077
Eric Laurent42b041e2013-03-29 11:36:03 -07001078 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001079
Eric Laurent42b041e2013-03-29 11:36:03 -07001080 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
RoboErik5452e252015-02-06 15:33:53 -08001081 mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001082
John Du5a0cf7a2013-07-19 11:30:34 -07001083 // Check if volume update should be send to AVRCP
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001084 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1085 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1086 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1087 synchronized (mA2dpAvrcpLock) {
1088 if (mA2dp != null && mAvrcpAbsVolSupported) {
1089 mA2dp.adjustAvrcpAbsoluteVolume(direction);
1090 }
John Du5a0cf7a2013-07-19 11:30:34 -07001091 }
1092 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001093
RoboErik4197cb62015-01-21 15:45:32 -08001094 if (isMuteAdjust) {
1095 boolean state;
1096 if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
1097 state = !streamState.mIsMuted;
1098 } else {
1099 state = direction == AudioManager.ADJUST_MUTE;
1100 }
1101 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1102 setSystemAudioMute(state);
1103 }
1104 for (int stream = 0; stream < mStreamStates.length; stream++) {
1105 if (streamTypeAlias == mStreamVolumeAlias[stream]) {
1106 mStreamStates[stream].mute(state);
1107
1108 Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
1109 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, stream);
1110 intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
1111 sendBroadcastToAll(intent);
1112 }
1113 }
1114 } else if ((direction == AudioManager.ADJUST_RAISE) &&
Eric Laurent42b041e2013-03-29 11:36:03 -07001115 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
RoboErik4197cb62015-01-21 15:45:32 -08001116 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -04001117 mVolumeController.postDisplaySafeVolumeWarning(flags);
RoboErik4197cb62015-01-21 15:45:32 -08001118 } else if (streamState.adjustIndex(direction * step, device) || streamState.mIsMuted) {
1119 // Post message to set system volume (it in turn will post a
1120 // message to persist).
1121 if (streamState.mIsMuted) {
1122 // Unmute the stream if it was previously muted
RoboErik5452e252015-02-06 15:33:53 -08001123 if (direction == AudioManager.ADJUST_RAISE) {
1124 // unmute immediately for volume up
1125 streamState.mute(false);
1126 } else if (direction == AudioManager.ADJUST_LOWER) {
1127 sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
1128 streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
1129 }
RoboErik4197cb62015-01-21 15:45:32 -08001130 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001131 sendMsg(mAudioHandler,
1132 MSG_SET_DEVICE_VOLUME,
1133 SENDMSG_QUEUE,
1134 device,
1135 0,
1136 streamState,
1137 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001138 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001139
RoboErik4197cb62015-01-21 15:45:32 -08001140 // Check if volume update should be sent to Hdmi system audio.
Jungshik Jang41d97462014-06-30 22:26:29 +09001141 int newIndex = mStreamStates[streamType].getIndex(device);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001142 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1143 setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
1144 }
Eric Laurent212532b2014-07-21 15:43:18 -07001145 if (mHdmiManager != null) {
1146 synchronized (mHdmiManager) {
Eric Laurent212532b2014-07-21 15:43:18 -07001147 // mHdmiCecSink true => mHdmiPlaybackClient != null
1148 if (mHdmiCecSink &&
1149 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1150 oldIndex != newIndex) {
1151 synchronized (mHdmiPlaybackClient) {
1152 int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
RoboErik4197cb62015-01-21 15:45:32 -08001153 KeyEvent.KEYCODE_VOLUME_UP;
Eric Laurent212532b2014-07-21 15:43:18 -07001154 mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1155 mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1156 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001157 }
1158 }
1159 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001160 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001161 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001162 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001163 }
1164
RoboErik5452e252015-02-06 15:33:53 -08001165 // Called after a delay when volume down is pressed while muted
1166 private void onUnmuteStream(int stream, int flags) {
1167 VolumeStreamState streamState = mStreamStates[stream];
1168 streamState.mute(false);
1169
1170 final int device = getDeviceForStream(stream);
1171 final int index = mStreamStates[stream].getIndex(device);
1172 sendVolumeUpdate(stream, index, index, flags);
1173 }
1174
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001175 private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
1176 if (mHdmiManager == null
1177 || mHdmiTvClient == null
1178 || oldVolume == newVolume
1179 || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
1180
1181 // Sets the audio volume of AVR when we are in system audio mode. The new volume info
1182 // is tranformed to HDMI-CEC commands and passed through CEC bus.
1183 synchronized (mHdmiManager) {
1184 if (!mHdmiSystemAudioSupported) return;
1185 synchronized (mHdmiTvClient) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001186 final long token = Binder.clearCallingIdentity();
1187 try {
1188 mHdmiTvClient.setSystemAudioVolume(
1189 (oldVolume + 5) / 10, (newVolume + 5) / 10, maxVolume);
1190 } finally {
1191 Binder.restoreCallingIdentity(token);
1192 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001193 }
1194 }
1195 }
1196
Dianne Hackborn961cae92013-03-20 14:59:43 -07001197 /** @see AudioManager#adjustMasterVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001198 public void adjustMasterVolume(int steps, int flags, String callingPackage) {
RoboErik519c7742014-11-18 10:59:09 -08001199 adjustMasterVolume(steps, flags, callingPackage, Binder.getCallingUid());
1200 }
1201
1202 public void adjustMasterVolume(int steps, int flags, String callingPackage, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001203 if (mUseFixedVolume) {
1204 return;
1205 }
RoboErik4197cb62015-01-21 15:45:32 -08001206 if (isMuteAdjust(steps)) {
1207 setMasterMuteInternal(steps, flags, callingPackage, uid);
1208 return;
1209 }
Lei Zhang6c798972012-03-02 11:40:12 -08001210 ensureValidSteps(steps);
Mike Lockwood97606472012-02-09 11:24:10 -08001211 int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1212 int delta = 0;
Lei Zhang6c798972012-03-02 11:40:12 -08001213 int numSteps = Math.abs(steps);
1214 int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
1215 for (int i = 0; i < numSteps; ++i) {
1216 delta = findVolumeDelta(direction, volume);
1217 volume += delta;
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001218 }
RoboErik24b082f2012-02-24 14:21:16 -08001219
Lei Zhang6c798972012-03-02 11:40:12 -08001220 //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
RoboErik519c7742014-11-18 10:59:09 -08001221 setMasterVolume(volume, flags, callingPackage, uid);
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001222 }
1223
Eric Laurentfde16d52012-12-03 14:42:39 -08001224 // StreamVolumeCommand contains the information needed to defer the process of
1225 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1226 class StreamVolumeCommand {
1227 public final int mStreamType;
1228 public final int mIndex;
1229 public final int mFlags;
1230 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001231
Eric Laurentfde16d52012-12-03 14:42:39 -08001232 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1233 mStreamType = streamType;
1234 mIndex = index;
1235 mFlags = flags;
1236 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001237 }
John Spurlock35134602014-07-24 18:10:48 -04001238
1239 @Override
1240 public String toString() {
1241 return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1242 .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1243 .append(mDevice).append('}').toString();
1244 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001245 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001246
Eric Laurentfde16d52012-12-03 14:42:39 -08001247 private void onSetStreamVolume(int streamType, int index, int flags, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001248 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
Eric Laurent3ef75492012-11-28 12:12:23 -08001249 // setting volume on master stream type also controls silent mode
1250 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1251 (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
1252 int newRingerMode;
1253 if (index == 0) {
1254 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlock86005342014-05-23 11:58:00 -04001255 : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
1256 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001257 } else {
1258 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1259 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001260 setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/);
Eric Laurent3ef75492012-11-28 12:12:23 -08001261 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001262 }
1263
1264 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001265 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
RoboErik0dac35a2014-08-12 15:48:49 -07001266 setStreamVolume(streamType, index, flags, callingPackage, Binder.getCallingUid());
1267 }
1268
1269 private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
1270 int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001271 if (mUseFixedVolume) {
1272 return;
1273 }
1274
Eric Laurentfde16d52012-12-03 14:42:39 -08001275 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001276 int streamTypeAlias = mStreamVolumeAlias[streamType];
1277 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001278
1279 final int device = getDeviceForStream(streamType);
1280 int oldIndex;
1281
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001282 // skip a2dp absolute volume control request when the device
1283 // is not an a2dp device
1284 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1285 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1286 return;
1287 }
1288
RoboErik0dac35a2014-08-12 15:48:49 -07001289 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
1290 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001291 return;
1292 }
1293
Eric Laurentfde16d52012-12-03 14:42:39 -08001294 synchronized (mSafeMediaVolumeState) {
1295 // reset any pending volume command
1296 mPendingVolumeCommand = null;
1297
Eric Laurent42b041e2013-03-29 11:36:03 -07001298 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001299
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001300 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001301
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001302 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1303 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1304 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1305 synchronized (mA2dpAvrcpLock) {
1306 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001307 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001308 }
John Du5a0cf7a2013-07-19 11:30:34 -07001309 }
1310 }
1311
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001312 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1313 setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
Jungshik Jang41d97462014-06-30 22:26:29 +09001314 }
1315
Eric Laurentfde16d52012-12-03 14:42:39 -08001316 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001317 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001318 ((device & mFixedVolumeDevices) != 0)) {
1319 flags |= AudioManager.FLAG_FIXED_VOLUME;
1320
1321 // volume is either 0 or max allowed for fixed volume devices
1322 if (index != 0) {
1323 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1324 (device & mSafeMediaVolumeDevices) != 0) {
1325 index = mSafeMediaVolumeIndex;
1326 } else {
1327 index = streamState.getMaxIndex();
1328 }
1329 }
1330 }
1331
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001332 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001333 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001334 mPendingVolumeCommand = new StreamVolumeCommand(
1335 streamType, index, flags, device);
1336 } else {
1337 onSetStreamVolume(streamType, index, flags, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07001338 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001339 }
1340 }
Eric Laurent25101b02011-02-02 09:33:30 -08001341 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342 }
1343
Eric Laurent45c90ce2012-04-24 18:44:22 -07001344 /** @see AudioManager#forceVolumeControlStream(int) */
1345 public void forceVolumeControlStream(int streamType, IBinder cb) {
1346 synchronized(mForceControlStreamLock) {
1347 mVolumeControlStream = streamType;
1348 if (mVolumeControlStream == -1) {
1349 if (mForceControlStreamClient != null) {
1350 mForceControlStreamClient.release();
1351 mForceControlStreamClient = null;
1352 }
1353 } else {
1354 mForceControlStreamClient = new ForceControlStreamClient(cb);
1355 }
1356 }
1357 }
1358
1359 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1360 private IBinder mCb; // To be notified of client's death
1361
1362 ForceControlStreamClient(IBinder cb) {
1363 if (cb != null) {
1364 try {
1365 cb.linkToDeath(this, 0);
1366 } catch (RemoteException e) {
1367 // Client has died!
1368 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1369 cb = null;
1370 }
1371 }
1372 mCb = cb;
1373 }
1374
1375 public void binderDied() {
1376 synchronized(mForceControlStreamLock) {
1377 Log.w(TAG, "SCO client died");
1378 if (mForceControlStreamClient != this) {
1379 Log.w(TAG, "unregistered control stream client died");
1380 } else {
1381 mForceControlStreamClient = null;
1382 mVolumeControlStream = -1;
1383 }
1384 }
1385 }
1386
1387 public void release() {
1388 if (mCb != null) {
1389 mCb.unlinkToDeath(this, 0);
1390 mCb = null;
1391 }
1392 }
1393 }
1394
Lei Zhang6c798972012-03-02 11:40:12 -08001395 private int findVolumeDelta(int direction, int volume) {
1396 int delta = 0;
1397 if (direction == AudioManager.ADJUST_RAISE) {
1398 if (volume == MAX_MASTER_VOLUME) {
1399 return 0;
1400 }
1401 // This is the default value if we make it to the end
1402 delta = mMasterVolumeRamp[1];
1403 // If we're raising the volume move down the ramp array until we
1404 // find the volume we're above and use that groups delta.
1405 for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
1406 if (volume >= mMasterVolumeRamp[i - 1]) {
1407 delta = mMasterVolumeRamp[i];
1408 break;
1409 }
1410 }
1411 } else if (direction == AudioManager.ADJUST_LOWER){
1412 if (volume == 0) {
1413 return 0;
1414 }
1415 int length = mMasterVolumeRamp.length;
1416 // This is the default value if we make it to the end
1417 delta = -mMasterVolumeRamp[length - 1];
1418 // If we're lowering the volume move up the ramp array until we
1419 // find the volume we're below and use the group below it's delta
1420 for (int i = 2; i < length; i += 2) {
1421 if (volume <= mMasterVolumeRamp[i]) {
1422 delta = -mMasterVolumeRamp[i - 1];
1423 break;
1424 }
1425 }
1426 }
1427 return delta;
1428 }
1429
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001430 private void sendBroadcastToAll(Intent intent) {
Christopher Tate267603f2015-01-20 14:21:21 -08001431 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001432 final long ident = Binder.clearCallingIdentity();
1433 try {
1434 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1435 } finally {
1436 Binder.restoreCallingIdentity(ident);
1437 }
1438 }
1439
1440 private void sendStickyBroadcastToAll(Intent intent) {
1441 final long ident = Binder.clearCallingIdentity();
1442 try {
1443 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1444 } finally {
1445 Binder.restoreCallingIdentity(ident);
1446 }
1447 }
1448
Eric Laurent25101b02011-02-02 09:33:30 -08001449 // UI update and Broadcast Intent
1450 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
Eric Laurent212532b2014-07-21 15:43:18 -07001451 if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) {
Eric Laurent25101b02011-02-02 09:33:30 -08001452 streamType = AudioSystem.STREAM_NOTIFICATION;
1453 }
1454
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001455 if (streamType == AudioSystem.STREAM_MUSIC) {
1456 flags = updateFlagsForSystemAudio(flags);
Jungshik Jang1a6be6e2014-09-16 11:04:54 +09001457 }
John Spurlock3346a802014-05-20 16:25:37 -04001458 mVolumeController.postVolumeChanged(streamType, flags);
Eric Laurent25101b02011-02-02 09:33:30 -08001459
Eric Laurent4bbcc652012-09-24 14:26:30 -07001460 if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
1461 oldIndex = (oldIndex + 5) / 10;
1462 index = (index + 5) / 10;
1463 Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
1464 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
1465 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
1466 intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
1467 sendBroadcastToAll(intent);
1468 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001469 }
1470
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001471 // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
1472 // receives volume notification from Audio Receiver.
1473 private int updateFlagsForSystemAudio(int flags) {
1474 if (mHdmiTvClient != null) {
1475 synchronized (mHdmiTvClient) {
1476 if (mHdmiSystemAudioSupported &&
1477 ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
1478 flags &= ~AudioManager.FLAG_SHOW_UI;
1479 }
1480 }
1481 }
1482 return flags;
1483 }
1484
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001485 // UI update and Broadcast Intent
1486 private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001487 mVolumeController.postMasterVolumeChanged(updateFlagsForSystemAudio(flags));
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001488
1489 Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
1490 intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
1491 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001492 sendBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001493 }
1494
1495 // UI update and Broadcast Intent
1496 private void sendMasterMuteUpdate(boolean muted, int flags) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001497 mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
Justin Koh57978ed2012-04-03 17:37:58 -07001498 broadcastMasterMuteStatus(muted);
1499 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001500
Justin Koh57978ed2012-04-03 17:37:58 -07001501 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001502 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1503 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001504 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1505 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001506 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001507 }
1508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001509 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001510 * Sets the stream state's index, and posts a message to set system volume.
1511 * This will not call out to the UI. Assumes a valid stream type.
1512 *
1513 * @param streamType Type of the stream
1514 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001515 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001516 * @param force If true, set the volume even if the desired volume is same
1517 * as the current volume.
1518 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001519 private void setStreamVolumeInt(int streamType,
1520 int index,
1521 int device,
Eric Laurent42b041e2013-03-29 11:36:03 -07001522 boolean force) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001523 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07001524
Eric Laurent42b041e2013-03-29 11:36:03 -07001525 if (streamState.setIndex(index, device) || force) {
1526 // Post message to set system volume (it in turn will post a message
1527 // to persist).
1528 sendMsg(mAudioHandler,
1529 MSG_SET_DEVICE_VOLUME,
1530 SENDMSG_QUEUE,
1531 device,
1532 0,
1533 streamState,
1534 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001535 }
1536 }
1537
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001538 private void setSystemAudioMute(boolean state) {
1539 if (mHdmiManager == null || mHdmiTvClient == null) return;
1540 synchronized (mHdmiManager) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001541 if (!mHdmiSystemAudioSupported) return;
1542 synchronized (mHdmiTvClient) {
1543 final long token = Binder.clearCallingIdentity();
1544 try {
1545 mHdmiTvClient.setSystemAudioMute(state);
1546 } finally {
1547 Binder.restoreCallingIdentity(token);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001548 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001549 }
1550 }
1551 }
1552
Eric Laurent25101b02011-02-02 09:33:30 -08001553 /** get stream mute state. */
1554 public boolean isStreamMute(int streamType) {
RoboErik7c82ced2014-12-04 17:39:08 -08001555 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1556 streamType = getActiveStreamType(streamType);
1557 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001558 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08001559 return mStreamStates[streamType].mIsMuted;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001560 }
Eric Laurent25101b02011-02-02 09:33:30 -08001561 }
1562
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07001563 private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
1564 private IBinder mICallback; // To be notified of client's death
1565
1566 RmtSbmxFullVolDeathHandler(IBinder cb) {
1567 mICallback = cb;
1568 try {
1569 cb.linkToDeath(this, 0/*flags*/);
1570 } catch (RemoteException e) {
1571 Log.e(TAG, "can't link to death", e);
1572 }
1573 }
1574
1575 boolean isHandlerFor(IBinder cb) {
1576 return mICallback.equals(cb);
1577 }
1578
1579 void forget() {
1580 try {
1581 mICallback.unlinkToDeath(this, 0/*flags*/);
1582 } catch (NoSuchElementException e) {
1583 Log.e(TAG, "error unlinking to death", e);
1584 }
1585 }
1586
1587 public void binderDied() {
1588 Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
1589 forceRemoteSubmixFullVolume(false, mICallback);
1590 }
1591 }
1592
1593 /**
1594 * call must be synchronized on mRmtSbmxFullVolDeathHandlers
1595 * @return true if there is a registered death handler, false otherwise */
1596 private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1597 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1598 while (it.hasNext()) {
1599 final RmtSbmxFullVolDeathHandler handler = it.next();
1600 if (handler.isHandlerFor(cb)) {
1601 handler.forget();
1602 mRmtSbmxFullVolDeathHandlers.remove(handler);
1603 return true;
1604 }
1605 }
1606 return false;
1607 }
1608
1609 /** call synchronized on mRmtSbmxFullVolDeathHandlers */
1610 private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1611 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1612 while (it.hasNext()) {
1613 if (it.next().isHandlerFor(cb)) {
1614 return true;
1615 }
1616 }
1617 return false;
1618 }
1619
1620 private int mRmtSbmxFullVolRefCount = 0;
1621 private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
1622 new ArrayList<RmtSbmxFullVolDeathHandler>();
1623
1624 public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
1625 if (cb == null) {
1626 return;
1627 }
1628 if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
1629 android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
1630 Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
1631 return;
1632 }
1633 synchronized(mRmtSbmxFullVolDeathHandlers) {
1634 boolean applyRequired = false;
1635 if (startForcing) {
1636 if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
1637 mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
1638 if (mRmtSbmxFullVolRefCount == 0) {
1639 mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1640 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1641 applyRequired = true;
1642 }
1643 mRmtSbmxFullVolRefCount++;
1644 }
1645 } else {
1646 if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
1647 mRmtSbmxFullVolRefCount--;
1648 if (mRmtSbmxFullVolRefCount == 0) {
1649 mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1650 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1651 applyRequired = true;
1652 }
1653 }
1654 }
1655 if (applyRequired) {
1656 // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
1657 checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
1658 mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
1659 }
1660 }
1661 }
1662
RoboErik4197cb62015-01-21 15:45:32 -08001663 private void setMasterMuteInternal(int adjust, int flags, String callingPackage, int uid) {
RoboErik7c82ced2014-12-04 17:39:08 -08001664 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
1665 != AppOpsManager.MODE_ALLOWED) {
Julia Reynolds4a21b252014-06-04 11:11:43 -04001666 return;
1667 }
RoboErik4197cb62015-01-21 15:45:32 -08001668 boolean state;
1669 if (adjust == AudioManager.ADJUST_TOGGLE_MUTE) {
1670 state = !AudioSystem.getMasterMute();
1671 } else {
1672 state = adjust == AudioManager.ADJUST_MUTE;
1673 }
Jason Simmons1ce5b262012-02-02 13:00:17 -08001674 if (state != AudioSystem.getMasterMute()) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001675 setSystemAudioMute(state);
Jason Simmons1ce5b262012-02-02 13:00:17 -08001676 AudioSystem.setMasterMute(state);
Justin Koh57978ed2012-04-03 17:37:58 -07001677 // Post a persist master volume msg
Justin Koh75cf9e12012-04-04 15:27:37 -07001678 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001679 : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
Justin Koh0273af52012-04-04 18:29:50 -07001680 sendMasterMuteUpdate(state, flags);
RoboErik7c82ced2014-12-04 17:39:08 -08001681
1682 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1683 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, state);
1684 sendBroadcastToAll(intent);
Jason Simmons1ce5b262012-02-02 13:00:17 -08001685 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08001686 }
1687
1688 /** get master mute state. */
1689 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08001690 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001691 }
1692
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07001693 protected static int getMaxStreamVolume(int streamType) {
1694 return MAX_STREAM_VOLUME[streamType];
1695 }
1696
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001697 /** @see AudioManager#getStreamVolume(int) */
1698 public int getStreamVolume(int streamType) {
1699 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001700 int device = getDeviceForStream(streamType);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001701 synchronized (VolumeStreamState.class) {
1702 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001703
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001704 // by convention getStreamVolume() returns 0 when a stream is muted.
RoboErik4197cb62015-01-21 15:45:32 -08001705 if (mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001706 index = 0;
1707 }
1708 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
1709 (device & mFixedVolumeDevices) != 0) {
1710 index = mStreamStates[streamType].getMaxIndex();
1711 }
1712 return (index + 5) / 10;
Eric Laurent42b041e2013-03-29 11:36:03 -07001713 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001714 }
1715
RoboErik519c7742014-11-18 10:59:09 -08001716 @Override
Mike Lockwood47676902011-11-08 10:31:21 -08001717 public int getMasterVolume() {
Mike Lockwoodce952c82011-11-14 10:47:42 -08001718 if (isMasterMute()) return 0;
1719 return getLastAudibleMasterVolume();
Mike Lockwood8dc1dab2011-10-27 09:52:41 -04001720 }
1721
RoboErik519c7742014-11-18 10:59:09 -08001722 @Override
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001723 public void setMasterVolume(int volume, int flags, String callingPackage) {
RoboErik519c7742014-11-18 10:59:09 -08001724 setMasterVolume(volume, flags, callingPackage, Binder.getCallingUid());
1725 }
1726
1727 public void setMasterVolume(int volume, int flags, String callingPackage, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001728 if (mUseFixedVolume) {
1729 return;
1730 }
1731
RoboErik519c7742014-11-18 10:59:09 -08001732 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
1733 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001734 return;
1735 }
1736
Mike Lockwood97606472012-02-09 11:24:10 -08001737 if (volume < 0) {
1738 volume = 0;
1739 } else if (volume > MAX_MASTER_VOLUME) {
1740 volume = MAX_MASTER_VOLUME;
1741 }
Mike Lockwood5c55a052011-12-15 17:21:44 -05001742 doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
1743 }
1744
1745 private void doSetMasterVolume(float volume, int flags) {
1746 // don't allow changing master volume when muted
1747 if (!AudioSystem.getMasterMute()) {
1748 int oldVolume = getMasterVolume();
1749 AudioSystem.setMasterVolume(volume);
1750
1751 int newVolume = getMasterVolume();
1752 if (newVolume != oldVolume) {
1753 // Post a persist master volume msg
1754 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
1755 Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001756 setSystemAudioVolume(oldVolume, newVolume, getMasterMaxVolume(), flags);
Mike Lockwood5c55a052011-12-15 17:21:44 -05001757 }
Justin Koh3caba512012-04-02 15:32:18 -07001758 // Send the volume update regardless whether there was a change.
1759 sendMasterVolumeUpdate(flags, oldVolume, newVolume);
Mike Lockwood5c55a052011-12-15 17:21:44 -05001760 }
Mike Lockwood8dc1dab2011-10-27 09:52:41 -04001761 }
1762
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001763 /** @see AudioManager#getStreamMaxVolume(int) */
1764 public int getStreamMaxVolume(int streamType) {
1765 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07001766 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001767 }
1768
Mike Lockwood47676902011-11-08 10:31:21 -08001769 public int getMasterMaxVolume() {
1770 return MAX_MASTER_VOLUME;
1771 }
Eric Laurent25101b02011-02-02 09:33:30 -08001772
1773 /** Get last audible volume before stream was muted. */
1774 public int getLastAudibleStreamVolume(int streamType) {
1775 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001776 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001777 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08001778 }
1779
Mike Lockwoodce952c82011-11-14 10:47:42 -08001780 /** Get last audible master volume before it was muted. */
1781 public int getLastAudibleMasterVolume() {
1782 return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1783 }
1784
Dianne Hackborn961cae92013-03-20 14:59:43 -07001785 /** @see AudioManager#getMasterStreamType() */
Eric Laurent6d517662012-04-23 18:42:39 -07001786 public int getMasterStreamType() {
John Spurlock4f0f1202014-08-05 13:28:33 -04001787 return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
Eric Laurent6d517662012-04-23 18:42:39 -07001788 }
1789
Emily Bernier22c921a2014-05-28 11:01:32 -04001790 /** @see AudioManager#setMicrophoneMute(boolean) */
1791 public void setMicrophoneMute(boolean on, String callingPackage) {
1792 if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(),
1793 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1794 return;
1795 }
Jean-Michel Trivi4a4fea02014-08-29 18:14:09 -07001796 if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
1797 return;
1798 }
Emily Bernier22c921a2014-05-28 11:01:32 -04001799
1800 AudioSystem.muteMicrophone(on);
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001801 // Post a persist microphone msg.
1802 sendMsg(mAudioHandler, MSG_PERSIST_MICROPHONE_MUTE, SENDMSG_REPLACE, on ? 1
1803 : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
Emily Bernier22c921a2014-05-28 11:01:32 -04001804 }
1805
John Spurlock661f2cf2014-11-17 10:29:10 -05001806 @Override
1807 public int getRingerModeExternal() {
1808 synchronized(mSettingsLock) {
1809 return mRingerModeExternal;
1810 }
1811 }
1812
1813 @Override
1814 public int getRingerModeInternal() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001815 synchronized(mSettingsLock) {
1816 return mRingerMode;
1817 }
1818 }
1819
1820 private void ensureValidRingerMode(int ringerMode) {
John Spurlock97559372014-10-24 16:27:36 -04001821 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001822 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1823 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001824 }
1825
John Spurlock97559372014-10-24 16:27:36 -04001826 /** @see AudioManager#isValidRingerMode(int) */
1827 public boolean isValidRingerMode(int ringerMode) {
1828 return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
1829 }
1830
John Spurlock661f2cf2014-11-17 10:29:10 -05001831 public void setRingerModeExternal(int ringerMode, String caller) {
John Spurlockaf88a192014-12-23 16:14:44 -05001832 setRingerMode(ringerMode, caller, true /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05001833 }
1834
1835 public void setRingerModeInternal(int ringerMode, String caller) {
1836 enforceSelfOrSystemUI("setRingerModeInternal");
John Spurlockaf88a192014-12-23 16:14:44 -05001837 setRingerMode(ringerMode, caller, false /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05001838 }
1839
1840 private void setRingerMode(int ringerMode, String caller, boolean external) {
Eric Laurent212532b2014-07-21 15:43:18 -07001841 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001842 return;
1843 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001844 if (caller == null || caller.length() == 0) {
1845 throw new IllegalArgumentException("Bad caller: " + caller);
1846 }
John Spurlock97559372014-10-24 16:27:36 -04001847 ensureValidRingerMode(ringerMode);
Eric Laurent24482012012-05-10 09:41:17 -07001848 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1849 ringerMode = AudioManager.RINGER_MODE_SILENT;
1850 }
John Spurlockaf88a192014-12-23 16:14:44 -05001851 final long identity = Binder.clearCallingIdentity();
1852 try {
1853 synchronized (mSettingsLock) {
1854 final int ringerModeInternal = getRingerModeInternal();
1855 final int ringerModeExternal = getRingerModeExternal();
1856 if (external) {
1857 setRingerModeExt(ringerMode);
1858 if (mRingerModeDelegate != null) {
1859 ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
1860 ringerMode, caller, ringerModeInternal);
1861 }
1862 if (ringerMode != ringerModeInternal) {
1863 setRingerModeInt(ringerMode, true /*persist*/);
1864 }
1865 } else /*internal*/ {
1866 if (ringerMode != ringerModeInternal) {
1867 setRingerModeInt(ringerMode, true /*persist*/);
1868 }
1869 if (mRingerModeDelegate != null) {
1870 ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
1871 ringerMode, caller, ringerModeExternal);
1872 }
1873 setRingerModeExt(ringerMode);
John Spurlock57627792014-12-11 11:29:54 -05001874 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001875 }
John Spurlockaf88a192014-12-23 16:14:44 -05001876 } finally {
1877 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001878 }
1879 }
1880
John Spurlock661f2cf2014-11-17 10:29:10 -05001881 private void setRingerModeExt(int ringerMode) {
1882 synchronized(mSettingsLock) {
1883 if (ringerMode == mRingerModeExternal) return;
1884 mRingerModeExternal = ringerMode;
John Spurlocke5b42d92014-10-15 12:03:48 -04001885 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001886 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05001887 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
John Spurlocke5b42d92014-10-15 12:03:48 -04001888 }
1889
Eric Laurent4050c932009-07-08 02:52:14 -07001890 private void setRingerModeInt(int ringerMode, boolean persist) {
John Spurlockbcc10872014-11-28 15:29:21 -05001891 final boolean change;
Glenn Kastenba195eb2011-12-13 09:30:40 -08001892 synchronized(mSettingsLock) {
John Spurlockbcc10872014-11-28 15:29:21 -05001893 change = mRingerMode != ringerMode;
Glenn Kastenba195eb2011-12-13 09:30:40 -08001894 mRingerMode = ringerMode;
1895 }
Jason Parekhb1096152009-03-24 17:48:25 -07001896
Eric Laurent5b4e6542010-03-19 20:02:21 -07001897 // Mute stream if not previously muted by ringer mode and ringer mode
1898 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
1899 // Unmute stream if previously muted by ringer mode and ringer mode
1900 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07001901 int numStreamTypes = AudioSystem.getNumStreamTypes();
John Spurlock661f2cf2014-11-17 10:29:10 -05001902 final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE
1903 || ringerMode == AudioManager.RINGER_MODE_SILENT;
Eric Laurent5b4e6542010-03-19 20:02:21 -07001904 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001905 final boolean isMuted = isStreamMutedByRingerMode(streamType);
1906 final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
1907 if (isMuted == shouldMute) continue;
1908 if (!shouldMute) {
1909 // unmute
1910 // ring and notifications volume should never be 0 when not silenced
1911 // on voice capable devices or devices that support vibration
1912 if ((isPlatformVoice() || mHasVibrator) &&
1913 mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
1914 synchronized (VolumeStreamState.class) {
1915 Set set = mStreamStates[streamType].mIndex.entrySet();
1916 Iterator i = set.iterator();
1917 while (i.hasNext()) {
1918 Map.Entry entry = (Map.Entry)i.next();
1919 if ((Integer)entry.getValue() == 0) {
1920 entry.setValue(10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001921 }
1922 }
Eric Laurentb024c302011-10-14 17:19:27 -07001923 }
Eric Laurent9bcf4012009-06-12 06:09:28 -07001924 }
RoboErik4197cb62015-01-21 15:45:32 -08001925 mStreamStates[streamType].mute(false);
John Spurlock661f2cf2014-11-17 10:29:10 -05001926 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent5b4e6542010-03-19 20:02:21 -07001927 } else {
John Spurlock661f2cf2014-11-17 10:29:10 -05001928 // mute
RoboErik4197cb62015-01-21 15:45:32 -08001929 mStreamStates[streamType].mute(true);
John Spurlock661f2cf2014-11-17 10:29:10 -05001930 mRingerModeMutedStreams |= (1 << streamType);
Jason Parekhb1096152009-03-24 17:48:25 -07001931 }
1932 }
Eric Laurenta553c252009-07-17 12:17:14 -07001933
Jason Parekhb1096152009-03-24 17:48:25 -07001934 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07001935 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08001936 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07001937 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
1938 }
John Spurlockbcc10872014-11-28 15:29:21 -05001939 if (change) {
1940 // Send sticky broadcast
1941 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
1942 }
Jason Parekhb1096152009-03-24 17:48:25 -07001943 }
1944
Mike Lockwood90631542012-01-06 11:20:37 -05001945 private void restoreMasterVolume() {
Eric Laurent83a017b2013-03-19 18:15:31 -07001946 if (mUseFixedVolume) {
1947 AudioSystem.setMasterVolume(1.0f);
1948 return;
1949 }
Mike Lockwood90631542012-01-06 11:20:37 -05001950 if (mUseMasterVolume) {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001951 float volume = Settings.System.getFloatForUser(mContentResolver,
1952 Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
Mike Lockwood90631542012-01-06 11:20:37 -05001953 if (volume >= 0.0f) {
1954 AudioSystem.setMasterVolume(volume);
1955 }
1956 }
1957 }
1958
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001959 /** @see AudioManager#shouldVibrate(int) */
1960 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001961 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001962
1963 switch (getVibrateSetting(vibrateType)) {
1964
1965 case AudioManager.VIBRATE_SETTING_ON:
John Spurlock57627792014-12-11 11:29:54 -05001966 return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001967
1968 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
John Spurlock57627792014-12-11 11:29:54 -05001969 return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001970
1971 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04001972 // return false, even for incoming calls
1973 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001974
1975 default:
1976 return false;
1977 }
1978 }
1979
1980 /** @see AudioManager#getVibrateSetting(int) */
1981 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001982 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001983 return (mVibrateSetting >> (vibrateType * 2)) & 3;
1984 }
1985
1986 /** @see AudioManager#setVibrateSetting(int, int) */
1987 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
1988
Eric Laurentbffc3d12012-05-07 17:43:49 -07001989 if (!mHasVibrator) return;
1990
John Spurlock61560172015-02-06 19:46:04 -05001991 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
1992 vibrateSetting);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001993
1994 // Broadcast change
1995 broadcastVibrateSetting(vibrateType);
1996
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001997 }
1998
Eric Laurent9272b4b2010-01-23 17:12:59 -08001999 private class SetModeDeathHandler implements IBinder.DeathRecipient {
2000 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002001 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002002 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
2003
Eric Laurent9f103de2011-09-08 15:04:23 -07002004 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08002005 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07002006 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002007 }
2008
2009 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07002010 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002011 synchronized(mSetModeDeathHandlers) {
2012 Log.w(TAG, "setMode() client died");
2013 int index = mSetModeDeathHandlers.indexOf(this);
2014 if (index < 0) {
2015 Log.w(TAG, "unregistered setMode() client died");
2016 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07002017 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
Eric Laurent9272b4b2010-01-23 17:12:59 -08002018 }
2019 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002020 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2021 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002022 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07002023 final long ident = Binder.clearCallingIdentity();
2024 disconnectBluetoothSco(newModeOwnerPid);
2025 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07002026 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08002027 }
2028
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002029 public int getPid() {
2030 return mPid;
2031 }
2032
Eric Laurent9272b4b2010-01-23 17:12:59 -08002033 public void setMode(int mode) {
2034 mMode = mode;
2035 }
2036
2037 public int getMode() {
2038 return mMode;
2039 }
2040
2041 public IBinder getBinder() {
2042 return mCb;
2043 }
2044 }
2045
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002046 /** @see AudioManager#setMode(int) */
Eric Laurent9272b4b2010-01-23 17:12:59 -08002047 public void setMode(int mode, IBinder cb) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002048 if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ")"); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002049 if (!checkAudioSettingsPermission("setMode()")) {
2050 return;
2051 }
Eric Laurenta553c252009-07-17 12:17:14 -07002052
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07002053 if ( (mode == AudioSystem.MODE_IN_CALL) &&
2054 (mContext.checkCallingOrSelfPermission(
2055 android.Manifest.permission.MODIFY_PHONE_STATE)
2056 != PackageManager.PERMISSION_GRANTED)) {
2057 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
2058 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
2059 return;
2060 }
2061
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08002062 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07002063 return;
2064 }
2065
Eric Laurentd7454be2011-09-14 08:45:58 -07002066 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002067 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07002068 if (mode == AudioSystem.MODE_CURRENT) {
2069 mode = mMode;
2070 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002071 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
Eric Laurent9f103de2011-09-08 15:04:23 -07002072 }
2073 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2074 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002075 if (newModeOwnerPid != 0) {
2076 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07002077 }
2078 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002079
Eric Laurent9f103de2011-09-08 15:04:23 -07002080 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07002081 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07002082 // any mode other than NORMAL.
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07002083 private int setModeInt(int mode, IBinder cb, int pid) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002084 if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ")"); }
Eric Laurentd7454be2011-09-14 08:45:58 -07002085 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002086 if (cb == null) {
2087 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07002088 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07002089 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002090
Eric Laurent9f103de2011-09-08 15:04:23 -07002091 SetModeDeathHandler hdlr = null;
2092 Iterator iter = mSetModeDeathHandlers.iterator();
2093 while (iter.hasNext()) {
2094 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
2095 if (h.getPid() == pid) {
2096 hdlr = h;
2097 // Remove from client list so that it is re-inserted at top of list
2098 iter.remove();
2099 hdlr.getBinder().unlinkToDeath(hdlr, 0);
2100 break;
2101 }
2102 }
2103 int status = AudioSystem.AUDIO_STATUS_OK;
2104 do {
2105 if (mode == AudioSystem.MODE_NORMAL) {
2106 // get new mode from client at top the list if any
2107 if (!mSetModeDeathHandlers.isEmpty()) {
2108 hdlr = mSetModeDeathHandlers.get(0);
2109 cb = hdlr.getBinder();
2110 mode = hdlr.getMode();
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002111 if (DEBUG_MODE) {
2112 Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
2113 + hdlr.mPid);
2114 }
Eric Laurentb9c9d262009-05-06 08:13:20 -07002115 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002116 } else {
2117 if (hdlr == null) {
2118 hdlr = new SetModeDeathHandler(cb, pid);
2119 }
2120 // Register for client death notification
2121 try {
2122 cb.linkToDeath(hdlr, 0);
2123 } catch (RemoteException e) {
2124 // Client has died!
2125 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
2126 }
2127
2128 // Last client to call setMode() is always at top of client list
2129 // as required by SetModeDeathHandler.binderDied()
2130 mSetModeDeathHandlers.add(0, hdlr);
2131 hdlr.setMode(mode);
2132 }
2133
2134 if (mode != mMode) {
2135 status = AudioSystem.setPhoneState(mode);
2136 if (status == AudioSystem.AUDIO_STATUS_OK) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002137 if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002138 mMode = mode;
2139 } else {
2140 if (hdlr != null) {
2141 mSetModeDeathHandlers.remove(hdlr);
2142 cb.unlinkToDeath(hdlr, 0);
2143 }
2144 // force reading new top of mSetModeDeathHandlers stack
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002145 if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002146 mode = AudioSystem.MODE_NORMAL;
2147 }
2148 } else {
2149 status = AudioSystem.AUDIO_STATUS_OK;
2150 }
2151 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
2152
2153 if (status == AudioSystem.AUDIO_STATUS_OK) {
2154 if (mode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002155 if (mSetModeDeathHandlers.isEmpty()) {
2156 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
2157 } else {
2158 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2159 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002160 }
2161 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002162 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07002163 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
2164 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
Eric Laurent6d517662012-04-23 18:42:39 -07002165
2166 updateStreamVolumeAlias(true /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002167 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002168 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002169 }
2170
2171 /** @see AudioManager#getMode() */
2172 public int getMode() {
2173 return mMode;
2174 }
2175
Eric Laurente78fced2013-03-15 16:03:47 -07002176 //==========================================================================================
2177 // Sound Effects
2178 //==========================================================================================
2179
2180 private static final String TAG_AUDIO_ASSETS = "audio_assets";
2181 private static final String ATTR_VERSION = "version";
2182 private static final String TAG_GROUP = "group";
2183 private static final String ATTR_GROUP_NAME = "name";
2184 private static final String TAG_ASSET = "asset";
2185 private static final String ATTR_ASSET_ID = "id";
2186 private static final String ATTR_ASSET_FILE = "file";
2187
2188 private static final String ASSET_FILE_VERSION = "1.0";
2189 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
2190
Glenn Kasten167d1a22013-07-23 16:24:41 -07002191 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002192
2193 class LoadSoundEffectReply {
2194 public int mStatus = 1;
2195 };
2196
Eric Laurente78fced2013-03-15 16:03:47 -07002197 private void loadTouchSoundAssetDefaults() {
2198 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
2199 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
2200 SOUND_EFFECT_FILES_MAP[i][0] = 0;
2201 SOUND_EFFECT_FILES_MAP[i][1] = -1;
2202 }
2203 }
2204
2205 private void loadTouchSoundAssets() {
2206 XmlResourceParser parser = null;
2207
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002208 // only load assets once.
2209 if (!SOUND_EFFECT_FILES.isEmpty()) {
2210 return;
2211 }
2212
Eric Laurente78fced2013-03-15 16:03:47 -07002213 loadTouchSoundAssetDefaults();
2214
2215 try {
2216 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
2217
2218 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
2219 String version = parser.getAttributeValue(null, ATTR_VERSION);
2220 boolean inTouchSoundsGroup = false;
2221
2222 if (ASSET_FILE_VERSION.equals(version)) {
2223 while (true) {
2224 XmlUtils.nextElement(parser);
2225 String element = parser.getName();
2226 if (element == null) {
2227 break;
2228 }
2229 if (element.equals(TAG_GROUP)) {
2230 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
2231 if (GROUP_TOUCH_SOUNDS.equals(name)) {
2232 inTouchSoundsGroup = true;
2233 break;
2234 }
2235 }
2236 }
2237 while (inTouchSoundsGroup) {
2238 XmlUtils.nextElement(parser);
2239 String element = parser.getName();
2240 if (element == null) {
2241 break;
2242 }
2243 if (element.equals(TAG_ASSET)) {
2244 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
2245 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
2246 int fx;
2247
2248 try {
2249 Field field = AudioManager.class.getField(id);
2250 fx = field.getInt(null);
2251 } catch (Exception e) {
2252 Log.w(TAG, "Invalid touch sound ID: "+id);
2253 continue;
2254 }
2255
2256 int i = SOUND_EFFECT_FILES.indexOf(file);
2257 if (i == -1) {
2258 i = SOUND_EFFECT_FILES.size();
2259 SOUND_EFFECT_FILES.add(file);
2260 }
2261 SOUND_EFFECT_FILES_MAP[fx][0] = i;
2262 } else {
2263 break;
2264 }
2265 }
2266 }
2267 } catch (Resources.NotFoundException e) {
2268 Log.w(TAG, "audio assets file not found", e);
2269 } catch (XmlPullParserException e) {
2270 Log.w(TAG, "XML parser exception reading touch sound assets", e);
2271 } catch (IOException e) {
2272 Log.w(TAG, "I/O exception reading touch sound assets", e);
2273 } finally {
2274 if (parser != null) {
2275 parser.close();
2276 }
2277 }
2278 }
2279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002280 /** @see AudioManager#playSoundEffect(int) */
2281 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002282 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002283 }
2284
2285 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002286 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07002287 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
2288 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
2289 return;
2290 }
2291
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002292 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002293 effectType, (int) (volume * 1000), null, 0);
2294 }
2295
2296 /**
2297 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08002298 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002299 */
2300 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002301 int attempts = 3;
2302 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08002303
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002304 synchronized (reply) {
2305 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
2306 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08002307 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07002308 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002309 } catch (InterruptedException e) {
2310 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08002311 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002312 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002313 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002314 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002315 }
2316
2317 /**
2318 * Unloads samples from the sound pool.
2319 * This method can be called to free some memory when
2320 * sound effects are disabled.
2321 */
2322 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002323 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002324 }
2325
Eric Laurenta60e2122010-12-28 16:49:07 -08002326 class SoundPoolListenerThread extends Thread {
2327 public SoundPoolListenerThread() {
2328 super("SoundPoolListenerThread");
2329 }
2330
2331 @Override
2332 public void run() {
2333
2334 Looper.prepare();
2335 mSoundPoolLooper = Looper.myLooper();
2336
2337 synchronized (mSoundEffectsLock) {
2338 if (mSoundPool != null) {
2339 mSoundPoolCallBack = new SoundPoolCallback();
2340 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2341 }
2342 mSoundEffectsLock.notify();
2343 }
2344 Looper.loop();
2345 }
2346 }
2347
2348 private final class SoundPoolCallback implements
2349 android.media.SoundPool.OnLoadCompleteListener {
2350
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002351 int mStatus = 1; // 1 means neither error nor last sample loaded yet
2352 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08002353
2354 public int status() {
2355 return mStatus;
2356 }
2357
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002358 public void setSamples(int[] samples) {
2359 for (int i = 0; i < samples.length; i++) {
2360 // do not wait ack for samples rejected upfront by SoundPool
2361 if (samples[i] > 0) {
2362 mSamples.add(samples[i]);
2363 }
2364 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002365 }
2366
2367 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2368 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002369 int i = mSamples.indexOf(sampleId);
2370 if (i >= 0) {
2371 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08002372 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002373 if ((status != 0) || mSamples. isEmpty()) {
2374 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08002375 mSoundEffectsLock.notify();
2376 }
2377 }
2378 }
2379 }
2380
Eric Laurent4050c932009-07-08 02:52:14 -07002381 /** @see AudioManager#reloadAudioSettings() */
2382 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002383 readAudioSettings(false /*userSwitch*/);
2384 }
2385
2386 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07002387 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2388 readPersistedSettings();
2389
2390 // restore volume settings
2391 int numStreamTypes = AudioSystem.getNumStreamTypes();
2392 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2393 VolumeStreamState streamState = mStreamStates[streamType];
2394
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002395 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2396 continue;
2397 }
2398
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002399 streamState.readSettings();
2400 synchronized (VolumeStreamState.class) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002401 // unmute stream that was muted but is not affect by mute anymore
RoboErik4197cb62015-01-21 15:45:32 -08002402 if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07002403 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
RoboErik4197cb62015-01-21 15:45:32 -08002404 streamState.mIsMuted = false;
Eric Laurent4050c932009-07-08 02:52:14 -07002405 }
Eric Laurent4050c932009-07-08 02:52:14 -07002406 }
2407 }
2408
Eric Laurent33902db2012-10-07 16:15:07 -07002409 // apply new ringer mode before checking volume for alias streams so that streams
2410 // muted by ringer mode have the correct volume
John Spurlock661f2cf2014-11-17 10:29:10 -05002411 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent33902db2012-10-07 16:15:07 -07002412
Eric Laurent212532b2014-07-21 15:43:18 -07002413 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07002414 checkAllAliasStreamVolumes();
2415
Eric Laurentd640bd32012-09-28 18:01:48 -07002416 synchronized (mSafeMediaVolumeState) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002417 mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2418 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2419 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
Eric Laurentd640bd32012-09-28 18:01:48 -07002420 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07002421 enforceSafeMediaVolume();
2422 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07002423 }
Eric Laurent4050c932009-07-08 02:52:14 -07002424 }
2425
Dianne Hackborn961cae92013-03-20 14:59:43 -07002426 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002427 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002428 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2429 return;
2430 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002431
2432 if (on) {
2433 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2434 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2435 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
2436 }
2437 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2438 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2439 mForcedUseForComm = AudioSystem.FORCE_NONE;
2440 }
Eric Laurentfa640152011-03-12 15:59:51 -08002441
Eric Laurentafbb0472011-12-15 09:04:23 -08002442 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002443 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002444 }
2445
2446 /** @see AudioManager#isSpeakerphoneOn() */
2447 public boolean isSpeakerphoneOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002448 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002449 }
2450
Dianne Hackborn961cae92013-03-20 14:59:43 -07002451 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002452 public void setBluetoothScoOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002453 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2454 return;
2455 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002456
2457 if (on) {
2458 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2459 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2460 mForcedUseForComm = AudioSystem.FORCE_NONE;
2461 }
Eric Laurentfa640152011-03-12 15:59:51 -08002462
Eric Laurentafbb0472011-12-15 09:04:23 -08002463 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002464 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08002465 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002466 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002467 }
2468
2469 /** @see AudioManager#isBluetoothScoOn() */
2470 public boolean isBluetoothScoOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002471 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002472 }
2473
Dianne Hackborn961cae92013-03-20 14:59:43 -07002474 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07002475 public void setBluetoothA2dpOn(boolean on) {
Eric Laurentc390bed2012-07-03 12:24:05 -07002476 synchronized (mBluetoothA2dpEnabledLock) {
2477 mBluetoothA2dpEnabled = on;
2478 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2479 AudioSystem.FOR_MEDIA,
2480 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2481 null, 0);
2482 }
Eric Laurent78472112012-05-21 08:57:21 -07002483 }
2484
2485 /** @see AudioManager#isBluetoothA2dpOn() */
2486 public boolean isBluetoothA2dpOn() {
2487 synchronized (mBluetoothA2dpEnabledLock) {
2488 return mBluetoothA2dpEnabled;
2489 }
2490 }
2491
Eric Laurent3def1ee2010-03-17 23:26:26 -07002492 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07002493 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
2494 int scoAudioMode =
2495 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
Liejun Taof4e51d82014-07-16 11:18:29 -07002496 SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
Eric Laurent83900752014-05-15 15:14:22 -07002497 startBluetoothScoInt(cb, scoAudioMode);
2498 }
2499
2500 /** @see AudioManager#startBluetoothScoVirtualCall() */
2501 public void startBluetoothScoVirtualCall(IBinder cb) {
2502 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
2503 }
2504
2505 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07002506 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002507 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002508 return;
2509 }
Eric Laurent854938a2011-02-22 12:05:20 -08002510 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002511 // The calling identity must be cleared before calling ScoClient.incCount().
2512 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2513 // and this must be done on behalf of system server to make sure permissions are granted.
2514 // The caller identity must be cleared after getScoClient() because it is needed if a new
2515 // client is created.
2516 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07002517 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08002518 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002519 }
2520
2521 /** @see AudioManager#stopBluetoothSco() */
2522 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07002523 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002524 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002525 return;
2526 }
Eric Laurent854938a2011-02-22 12:05:20 -08002527 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002528 // The calling identity must be cleared before calling ScoClient.decCount().
2529 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2530 // and this must be done on behalf of system server to make sure permissions are granted.
2531 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08002532 if (client != null) {
2533 client.decCount();
2534 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08002535 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002536 }
2537
Eric Laurent78472112012-05-21 08:57:21 -07002538
Eric Laurent3def1ee2010-03-17 23:26:26 -07002539 private class ScoClient implements IBinder.DeathRecipient {
2540 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002541 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002542 private int mStartcount; // number of SCO connections started by this client
2543
2544 ScoClient(IBinder cb) {
2545 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002546 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002547 mStartcount = 0;
2548 }
2549
2550 public void binderDied() {
2551 synchronized(mScoClients) {
2552 Log.w(TAG, "SCO client died");
2553 int index = mScoClients.indexOf(this);
2554 if (index < 0) {
2555 Log.w(TAG, "unregistered SCO client died");
2556 } else {
2557 clearCount(true);
2558 mScoClients.remove(this);
2559 }
2560 }
2561 }
2562
Eric Laurent83900752014-05-15 15:14:22 -07002563 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002564 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07002565 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002566 if (mStartcount == 0) {
2567 try {
2568 mCb.linkToDeath(this, 0);
2569 } catch (RemoteException e) {
2570 // client has already died!
2571 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
2572 }
2573 }
2574 mStartcount++;
2575 }
2576 }
2577
2578 public void decCount() {
2579 synchronized(mScoClients) {
2580 if (mStartcount == 0) {
2581 Log.w(TAG, "ScoClient.decCount() already 0");
2582 } else {
2583 mStartcount--;
2584 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002585 try {
2586 mCb.unlinkToDeath(this, 0);
2587 } catch (NoSuchElementException e) {
2588 Log.w(TAG, "decCount() going to 0 but not registered to binder");
2589 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002590 }
Eric Laurentc18c9132013-04-12 17:24:56 -07002591 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002592 }
2593 }
2594 }
2595
2596 public void clearCount(boolean stopSco) {
2597 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002598 if (mStartcount != 0) {
2599 try {
2600 mCb.unlinkToDeath(this, 0);
2601 } catch (NoSuchElementException e) {
2602 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2603 }
2604 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002605 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002606 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002607 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002608 }
2609 }
2610 }
2611
2612 public int getCount() {
2613 return mStartcount;
2614 }
2615
2616 public IBinder getBinder() {
2617 return mCb;
2618 }
2619
Eric Laurentd7454be2011-09-14 08:45:58 -07002620 public int getPid() {
2621 return mCreatorPid;
2622 }
2623
Eric Laurent3def1ee2010-03-17 23:26:26 -07002624 public int totalCount() {
2625 synchronized(mScoClients) {
2626 int count = 0;
2627 int size = mScoClients.size();
2628 for (int i = 0; i < size; i++) {
2629 count += mScoClients.get(i).getCount();
2630 }
2631 return count;
2632 }
2633 }
2634
Eric Laurent83900752014-05-15 15:14:22 -07002635 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08002636 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07002637 if (totalCount() == 0) {
2638 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2639 // Make sure that the state transitions to CONNECTING even if we cannot initiate
2640 // the connection.
2641 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2642 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002643 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07002644 synchronized(mSetModeDeathHandlers) {
2645 if ((mSetModeDeathHandlers.isEmpty() ||
2646 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2647 (mScoAudioState == SCO_STATE_INACTIVE ||
2648 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2649 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07002650 mScoAudioMode = scoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -07002651 if (scoAudioMode == SCO_MODE_UNDEFINED) {
Andre Eisenbach570cc532014-10-28 17:03:18 -07002652 if (mBluetoothHeadsetDevice != null) {
2653 mScoAudioMode = new Integer(Settings.Global.getInt(
2654 mContentResolver,
2655 "bluetooth_sco_channel_"+
2656 mBluetoothHeadsetDevice.getAddress(),
2657 SCO_MODE_VIRTUAL_CALL));
2658 if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2659 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2660 }
2661 } else {
2662 mScoAudioMode = SCO_MODE_RAW;
Liejun Taof4e51d82014-07-16 11:18:29 -07002663 }
2664 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002665 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002666 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002667 if (mScoAudioMode == SCO_MODE_RAW) {
2668 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002669 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002670 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2671 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002672 } else if (mScoAudioMode == SCO_MODE_VR) {
2673 status = mBluetoothHeadset.startVoiceRecognition(
2674 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002675 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002676
Eric Laurentc18c9132013-04-12 17:24:56 -07002677 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07002678 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2679 } else {
2680 broadcastScoConnectionState(
2681 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2682 }
2683 } else if (getBluetoothHeadset()) {
2684 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07002685 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002686 } else {
2687 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2688 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002689 }
2690 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07002691 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002692 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002693 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002694 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002695 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2696 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2697 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07002698 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002699 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002700 if (mScoAudioMode == SCO_MODE_RAW) {
2701 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002702 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002703 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2704 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002705 } else if (mScoAudioMode == SCO_MODE_VR) {
2706 status = mBluetoothHeadset.stopVoiceRecognition(
2707 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002708 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002709
Eric Laurentc18c9132013-04-12 17:24:56 -07002710 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002711 mScoAudioState = SCO_STATE_INACTIVE;
2712 broadcastScoConnectionState(
2713 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2714 }
2715 } else if (getBluetoothHeadset()) {
2716 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2717 }
2718 } else {
2719 mScoAudioState = SCO_STATE_INACTIVE;
2720 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2721 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002722 }
2723 }
2724 }
2725 }
2726
Eric Laurent62ef7672010-11-24 10:58:32 -08002727 private void checkScoAudioState() {
2728 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002729 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08002730 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2731 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2732 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2733 }
2734 }
2735
Eric Laurent854938a2011-02-22 12:05:20 -08002736 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002737 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002738 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002739 int size = mScoClients.size();
2740 for (int i = 0; i < size; i++) {
2741 client = mScoClients.get(i);
2742 if (client.getBinder() == cb)
2743 return client;
2744 }
Eric Laurent854938a2011-02-22 12:05:20 -08002745 if (create) {
2746 client = new ScoClient(cb);
2747 mScoClients.add(client);
2748 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002749 return client;
2750 }
2751 }
2752
Eric Laurentd7454be2011-09-14 08:45:58 -07002753 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002754 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002755 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002756 int size = mScoClients.size();
2757 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08002758 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07002759 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08002760 cl.clearCount(stopSco);
2761 } else {
2762 savedClient = cl;
2763 }
2764 }
2765 mScoClients.clear();
2766 if (savedClient != null) {
2767 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002768 }
2769 }
2770 }
2771
Eric Laurentdc03c612011-04-01 10:59:41 -07002772 private boolean getBluetoothHeadset() {
2773 boolean result = false;
2774 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2775 if (adapter != null) {
2776 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2777 BluetoothProfile.HEADSET);
2778 }
2779 // If we could not get a bluetooth headset proxy, send a failure message
2780 // without delay to reset the SCO audio state and clear SCO clients.
2781 // If we could get a proxy, send a delayed failure message that will reset our state
2782 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08002783 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002784 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2785 return result;
2786 }
2787
Eric Laurentd7454be2011-09-14 08:45:58 -07002788 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002789 synchronized(mScoClients) {
2790 checkScoAudioState();
2791 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2792 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2793 if (mBluetoothHeadsetDevice != null) {
2794 if (mBluetoothHeadset != null) {
2795 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07002796 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002797 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002798 SENDMSG_REPLACE, 0, 0, null, 0);
2799 }
2800 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2801 getBluetoothHeadset()) {
2802 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2803 }
2804 }
2805 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07002806 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07002807 }
2808 }
2809 }
2810
2811 private void resetBluetoothSco() {
2812 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002813 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07002814 mScoAudioState = SCO_STATE_INACTIVE;
2815 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2816 }
2817 }
2818
2819 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08002820 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
2821 SENDMSG_QUEUE, state, 0, null, 0);
2822 }
2823
2824 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002825 if (state != mScoConnectionState) {
2826 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2827 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2828 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2829 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002830 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07002831 mScoConnectionState = state;
2832 }
2833 }
2834
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002835 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
2836 new BluetoothProfile.ServiceListener() {
2837 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002838 BluetoothDevice btDevice;
2839 List<BluetoothDevice> deviceList;
2840 switch(profile) {
2841 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09002842 synchronized (mConnectedDevices) {
2843 synchronized (mA2dpAvrcpLock) {
2844 mA2dp = (BluetoothA2dp) proxy;
2845 deviceList = mA2dp.getConnectedDevices();
2846 if (deviceList.size() > 0) {
2847 btDevice = deviceList.get(0);
John Du5a0cf7a2013-07-19 11:30:34 -07002848 int state = mA2dp.getConnectionState(btDevice);
2849 int delay = checkSendBecomingNoisyIntent(
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002850 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2851 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
John Du5a0cf7a2013-07-19 11:30:34 -07002852 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002853 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07002854 state,
2855 0,
2856 btDevice,
2857 delay);
2858 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002859 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002860 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002861 break;
2862
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002863 case BluetoothProfile.A2DP_SINK:
2864 deviceList = proxy.getConnectedDevices();
2865 if (deviceList.size() > 0) {
2866 btDevice = deviceList.get(0);
2867 synchronized (mConnectedDevices) {
2868 int state = proxy.getConnectionState(btDevice);
2869 queueMsgUnderWakeLock(mAudioHandler,
2870 MSG_SET_A2DP_SRC_CONNECTION_STATE,
2871 state,
2872 0,
2873 btDevice,
2874 0 /* delay */);
2875 }
2876 }
2877 break;
2878
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002879 case BluetoothProfile.HEADSET:
2880 synchronized (mScoClients) {
2881 // Discard timeout message
2882 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
2883 mBluetoothHeadset = (BluetoothHeadset) proxy;
2884 deviceList = mBluetoothHeadset.getConnectedDevices();
2885 if (deviceList.size() > 0) {
2886 mBluetoothHeadsetDevice = deviceList.get(0);
2887 } else {
2888 mBluetoothHeadsetDevice = null;
2889 }
2890 // Refresh SCO audio state
2891 checkScoAudioState();
2892 // Continue pending action if any
2893 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
2894 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
2895 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2896 boolean status = false;
2897 if (mBluetoothHeadsetDevice != null) {
2898 switch (mScoAudioState) {
2899 case SCO_STATE_ACTIVATE_REQ:
2900 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07002901 if (mScoAudioMode == SCO_MODE_RAW) {
2902 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002903 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002904 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2905 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002906 } else if (mScoAudioMode == SCO_MODE_VR) {
2907 status = mBluetoothHeadset.startVoiceRecognition(
2908 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002909 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002910 break;
2911 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07002912 if (mScoAudioMode == SCO_MODE_RAW) {
2913 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002914 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002915 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2916 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002917 } else if (mScoAudioMode == SCO_MODE_VR) {
2918 status = mBluetoothHeadset.stopVoiceRecognition(
2919 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002920 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002921 break;
2922 case SCO_STATE_DEACTIVATE_EXT_REQ:
2923 status = mBluetoothHeadset.stopVoiceRecognition(
2924 mBluetoothHeadsetDevice);
2925 }
2926 }
2927 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002928 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002929 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07002930 }
2931 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002932 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002933 break;
2934
2935 default:
2936 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002937 }
2938 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002939 public void onServiceDisconnected(int profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002940 switch(profile) {
2941 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09002942 synchronized (mConnectedDevices) {
2943 synchronized (mA2dpAvrcpLock) {
2944 mA2dp = null;
John Du5a0cf7a2013-07-19 11:30:34 -07002945 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
2946 makeA2dpDeviceUnavailableNow(
2947 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
2948 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002949 }
2950 }
2951 break;
2952
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002953 case BluetoothProfile.A2DP_SINK:
2954 synchronized (mConnectedDevices) {
2955 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) {
2956 makeA2dpSrcUnavailable(
2957 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP));
2958 }
2959 }
2960 break;
2961
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002962 case BluetoothProfile.HEADSET:
2963 synchronized (mScoClients) {
2964 mBluetoothHeadset = null;
2965 }
2966 break;
2967
2968 default:
2969 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002970 }
2971 }
2972 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08002973
Eric Laurentc34dcc12012-09-10 13:51:52 -07002974 private void onCheckMusicActive() {
Eric Laurentd640bd32012-09-28 18:01:48 -07002975 synchronized (mSafeMediaVolumeState) {
2976 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002977 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
2978
2979 if ((device & mSafeMediaVolumeDevices) != 0) {
2980 sendMsg(mAudioHandler,
2981 MSG_CHECK_MUSIC_ACTIVE,
2982 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07002983 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07002984 0,
2985 null,
2986 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07002987 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07002988 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
2989 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002990 // Approximate cumulative active music time
2991 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
2992 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
2993 setSafeMediaVolumeEnabled(true);
2994 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07002995 }
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002996 saveMusicActiveMs();
Eric Laurentc34dcc12012-09-10 13:51:52 -07002997 }
2998 }
2999 }
3000 }
3001 }
3002
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003003 private void saveMusicActiveMs() {
3004 mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
3005 }
3006
Eric Laurentd640bd32012-09-28 18:01:48 -07003007 private void onConfigureSafeVolume(boolean force) {
3008 synchronized (mSafeMediaVolumeState) {
3009 int mcc = mContext.getResources().getConfiguration().mcc;
3010 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
3011 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
3012 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
John Spurlock35134602014-07-24 18:10:48 -04003013 boolean safeMediaVolumeEnabled =
3014 SystemProperties.getBoolean("audio.safemedia.force", false)
3015 || mContext.getResources().getBoolean(
3016 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08003017
3018 // The persisted state is either "disabled" or "active": this is the state applied
3019 // next time we boot and cannot be "inactive"
3020 int persistedState;
Eric Laurentd640bd32012-09-28 18:01:48 -07003021 if (safeMediaVolumeEnabled) {
Eric Laurent05274f32012-11-29 12:48:18 -08003022 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
3023 // The state can already be "inactive" here if the user has forced it before
3024 // the 30 seconds timeout for forced configuration. In this case we don't reset
3025 // it to "active".
3026 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003027 if (mMusicActiveMs == 0) {
3028 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
3029 enforceSafeMediaVolume();
3030 } else {
3031 // We have existing playback time recorded, already confirmed.
3032 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
3033 }
Eric Laurent05274f32012-11-29 12:48:18 -08003034 }
Eric Laurentd640bd32012-09-28 18:01:48 -07003035 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08003036 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07003037 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
3038 }
3039 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08003040 sendMsg(mAudioHandler,
3041 MSG_PERSIST_SAFE_VOLUME_STATE,
3042 SENDMSG_QUEUE,
3043 persistedState,
3044 0,
3045 null,
3046 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07003047 }
3048 }
3049 }
3050
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003051 ///////////////////////////////////////////////////////////////////////////
3052 // Internal methods
3053 ///////////////////////////////////////////////////////////////////////////
3054
3055 /**
3056 * Checks if the adjustment should change ringer mode instead of just
3057 * adjusting volume. If so, this will set the proper ringer mode and volume
3058 * indices on the stream states.
3059 */
RoboErik5452e252015-02-06 15:33:53 -08003060 private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003061 int result = FLAG_ADJUST_VOLUME;
John Spurlock661f2cf2014-11-17 10:29:10 -05003062 int ringerMode = getRingerModeInternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003063
Eric Laurentbffc3d12012-05-07 17:43:49 -07003064 switch (ringerMode) {
3065 case RINGER_MODE_NORMAL:
3066 if (direction == AudioManager.ADJUST_LOWER) {
3067 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07003068 // "step" is the delta in internal index units corresponding to a
3069 // change of 1 in UI index units.
3070 // Because of rounding when rescaling from one stream index range to its alias
3071 // index range, we cannot simply test oldIndex == step:
3072 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
3073 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003074 ringerMode = RINGER_MODE_VIBRATE;
3075 }
3076 } else {
Eric Laurent24482012012-05-10 09:41:17 -07003077 // (oldIndex < step) is equivalent to (old UI index == 0)
John Spurlock86005342014-05-23 11:58:00 -04003078 if ((oldIndex < step)
3079 && VOLUME_SETS_RINGER_MODE_SILENT
3080 && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003081 ringerMode = RINGER_MODE_SILENT;
3082 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07003083 }
RoboErik5452e252015-02-06 15:33:53 -08003084 } else if (direction == AudioManager.ADJUST_TOGGLE_MUTE
3085 || direction == AudioManager.ADJUST_MUTE) {
3086 if (mHasVibrator) {
3087 ringerMode = RINGER_MODE_VIBRATE;
3088 } else {
3089 ringerMode = RINGER_MODE_SILENT;
3090 }
3091 // Setting the ringer mode will toggle mute
3092 result &= ~FLAG_ADJUST_VOLUME;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003093 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003094 break;
3095 case RINGER_MODE_VIBRATE:
3096 if (!mHasVibrator) {
3097 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
3098 "but no vibrator is present");
3099 break;
3100 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003101 if ((direction == AudioManager.ADJUST_LOWER)) {
RoboErik5452e252015-02-06 15:33:53 -08003102 // This is the case we were muted with the volume turned up
3103 if (oldIndex >= 2 * step && isMuted) {
3104 ringerMode = RINGER_MODE_NORMAL;
3105 } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
John Spurlock795a5142014-12-08 14:09:35 -05003106 if (VOLUME_SETS_RINGER_MODE_SILENT) {
3107 ringerMode = RINGER_MODE_SILENT;
3108 } else {
3109 result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
3110 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003111 }
RoboErik5452e252015-02-06 15:33:53 -08003112 } else if (direction == AudioManager.ADJUST_RAISE
3113 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3114 || direction == AudioManager.ADJUST_UNMUTE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003115 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07003116 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003117 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003118 break;
3119 case RINGER_MODE_SILENT:
RoboErik5452e252015-02-06 15:33:53 -08003120 if (direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
3121 // This is the case we were muted with the volume turned up
3122 ringerMode = RINGER_MODE_NORMAL;
3123 } else if (direction == AudioManager.ADJUST_RAISE
3124 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3125 || direction == AudioManager.ADJUST_UNMUTE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003126 if (PREVENT_VOLUME_ADJUSTMENT_IF_SILENT) {
3127 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003128 } else {
RoboErik5452e252015-02-06 15:33:53 -08003129 if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003130 ringerMode = RINGER_MODE_VIBRATE;
3131 } else {
RoboErik5452e252015-02-06 15:33:53 -08003132 // If we don't have a vibrator or they were toggling mute
3133 // go straight back to normal.
John Spurlocka11b4af2014-06-01 11:52:23 -04003134 ringerMode = RINGER_MODE_NORMAL;
3135 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003136 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05003137 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003138 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003139 break;
3140 default:
3141 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
3142 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003143 }
3144
John Spurlock661f2cf2014-11-17 10:29:10 -05003145 setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003146
Eric Laurent25101b02011-02-02 09:33:30 -08003147 mPrevVolDirection = direction;
3148
John Spurlocka11b4af2014-06-01 11:52:23 -04003149 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003150 }
3151
John Spurlock3346a802014-05-20 16:25:37 -04003152 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003153 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07003154 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003155 }
3156
Eric Laurent5b4e6542010-03-19 20:02:21 -07003157 private boolean isStreamMutedByRingerMode(int streamType) {
3158 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
3159 }
3160
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003161 boolean updateRingerModeAffectedStreams() {
3162 int ringerModeAffectedStreams;
3163 // make sure settings for ringer mode are consistent with device type: non voice capable
3164 // devices (tablets) include media stream in silent mode whereas phones don't.
3165 ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
3166 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3167 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
3168 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
3169 UserHandle.USER_CURRENT);
3170
3171 // ringtone, notification and system streams are always affected by ringer mode
3172 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
3173 (1 << AudioSystem.STREAM_NOTIFICATION)|
3174 (1 << AudioSystem.STREAM_SYSTEM);
3175
Eric Laurent212532b2014-07-21 15:43:18 -07003176 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003177 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -07003178 ringerModeAffectedStreams = 0;
3179 break;
3180 default:
John Spurlock77e54d92014-08-11 12:16:24 -04003181 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
Eric Laurent212532b2014-07-21 15:43:18 -07003182 break;
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003183 }
Eric Laurent212532b2014-07-21 15:43:18 -07003184
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003185 synchronized (mCameraSoundForced) {
3186 if (mCameraSoundForced) {
3187 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3188 } else {
3189 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3190 }
3191 }
3192 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
3193 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
3194 } else {
3195 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
3196 }
3197
3198 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3199 Settings.System.putIntForUser(mContentResolver,
3200 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3201 ringerModeAffectedStreams,
3202 UserHandle.USER_CURRENT);
3203 mRingerModeAffectedStreams = ringerModeAffectedStreams;
3204 return true;
3205 }
3206 return false;
3207 }
3208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003209 public boolean isStreamAffectedByMute(int streamType) {
3210 return (mMuteAffectedStreams & (1 << streamType)) != 0;
3211 }
3212
3213 private void ensureValidDirection(int direction) {
RoboErik4197cb62015-01-21 15:45:32 -08003214 switch (direction) {
3215 case AudioManager.ADJUST_LOWER:
3216 case AudioManager.ADJUST_RAISE:
3217 case AudioManager.ADJUST_SAME:
3218 case AudioManager.ADJUST_MUTE:
3219 case AudioManager.ADJUST_UNMUTE:
3220 case AudioManager.ADJUST_TOGGLE_MUTE:
3221 break;
3222 default:
3223 throw new IllegalArgumentException("Bad direction " + direction);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003224 }
3225 }
3226
Lei Zhang6c798972012-03-02 11:40:12 -08003227 private void ensureValidSteps(int steps) {
3228 if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
3229 throw new IllegalArgumentException("Bad volume adjust steps " + steps);
3230 }
3231 }
3232
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003233 private void ensureValidStreamType(int streamType) {
3234 if (streamType < 0 || streamType >= mStreamStates.length) {
3235 throw new IllegalArgumentException("Bad stream type " + streamType);
3236 }
3237 }
3238
RoboErik4197cb62015-01-21 15:45:32 -08003239 private boolean isMuteAdjust(int adjust) {
3240 return adjust == AudioManager.ADJUST_MUTE || adjust == AudioManager.ADJUST_UNMUTE
3241 || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
3242 }
3243
Eric Laurent6d517662012-04-23 18:42:39 -07003244 private boolean isInCommunication() {
Nancy Chen0eb1e402014-08-21 22:52:29 -07003245 boolean IsInCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003246
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003247 TelecomManager telecomManager =
3248 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
Eric Laurent38edfda2014-12-18 17:38:04 -08003249
3250 final long ident = Binder.clearCallingIdentity();
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003251 IsInCall = telecomManager.isInCall();
Eric Laurent38edfda2014-12-18 17:38:04 -08003252 Binder.restoreCallingIdentity(ident);
Santos Cordon9eb45932014-06-27 12:28:43 -07003253
Nancy Chen0eb1e402014-08-21 22:52:29 -07003254 return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
Eric Laurent6d517662012-04-23 18:42:39 -07003255 }
Eric Laurent25101b02011-02-02 09:33:30 -08003256
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003257 /**
3258 * For code clarity for getActiveStreamType(int)
3259 * @param delay_ms max time since last STREAM_MUSIC activity to consider
3260 * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
3261 * in the last "delay_ms" ms.
3262 */
3263 private boolean isAfMusicActiveRecently(int delay_ms) {
3264 return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
3265 || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
3266 }
3267
Eric Laurent6d517662012-04-23 18:42:39 -07003268 private int getActiveStreamType(int suggestedStreamType) {
Eric Laurent212532b2014-07-21 15:43:18 -07003269 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003270 case AudioSystem.PLATFORM_VOICE:
Eric Laurent6d517662012-04-23 18:42:39 -07003271 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003272 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3273 == AudioSystem.FORCE_BT_SCO) {
3274 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
3275 return AudioSystem.STREAM_BLUETOOTH_SCO;
3276 } else {
3277 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
3278 return AudioSystem.STREAM_VOICE_CALL;
3279 }
Eric Laurent25101b02011-02-02 09:33:30 -08003280 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003281 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003282 if (DEBUG_VOL)
3283 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3284 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003285 } else {
3286 if (DEBUG_VOL)
3287 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
3288 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003289 }
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003290 } else if (isAfMusicActiveRecently(0)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003291 if (DEBUG_VOL)
3292 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3293 return AudioSystem.STREAM_MUSIC;
Eric Laurent25101b02011-02-02 09:33:30 -08003294 }
Eric Laurent212532b2014-07-21 15:43:18 -07003295 break;
John Spurlock61560172015-02-06 19:46:04 -05003296 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -07003297 if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
RoboErik2811dd32014-08-12 09:48:13 -07003298 // TV always defaults to STREAM_MUSIC
Eric Laurent212532b2014-07-21 15:43:18 -07003299 return AudioSystem.STREAM_MUSIC;
Eric Laurent212532b2014-07-21 15:43:18 -07003300 }
3301 break;
3302 default:
Eric Laurent6d517662012-04-23 18:42:39 -07003303 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003304 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3305 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003306 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08003307 return AudioSystem.STREAM_BLUETOOTH_SCO;
3308 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003309 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08003310 return AudioSystem.STREAM_VOICE_CALL;
3311 }
3312 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003313 StreamOverride.sDelayMs) ||
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003314 AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003315 StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003316 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08003317 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003318 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003319 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003320 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
3321 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003322 } else {
John Spurlockeb1d88d2014-07-19 14:49:19 -04003323 if (DEBUG_VOL) Log.v(TAG,
3324 "getActiveStreamType: using STREAM_NOTIFICATION as default");
3325 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003326 }
Joe Onoratoc7fcba42011-01-05 16:53:11 -08003327 }
Eric Laurent212532b2014-07-21 15:43:18 -07003328 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003329 }
Eric Laurent212532b2014-07-21 15:43:18 -07003330 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
3331 + suggestedStreamType);
3332 return suggestedStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003333 }
3334
John Spurlockbcc10872014-11-28 15:29:21 -05003335 private void broadcastRingerMode(String action, int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003336 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05003337 Intent broadcast = new Intent(action);
Glenn Kastenba195eb2011-12-13 09:30:40 -08003338 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003339 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
3340 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003341 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003342 }
3343
3344 private void broadcastVibrateSetting(int vibrateType) {
3345 // Send broadcast
3346 if (ActivityManagerNative.isSystemReady()) {
3347 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
3348 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
3349 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003350 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003351 }
3352 }
3353
3354 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003355 /**
3356 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
3357 * Note that the wake lock needs to be released after the message has been handled.
3358 */
3359 private void queueMsgUnderWakeLock(Handler handler, int msg,
3360 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003361 final long ident = Binder.clearCallingIdentity();
3362 // Always acquire the wake lock as AudioService because it is released by the
3363 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003364 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003365 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003366 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
3367 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003368
Eric Laurentafbb0472011-12-15 09:04:23 -08003369 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003370 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003371
3372 if (existingMsgPolicy == SENDMSG_REPLACE) {
3373 handler.removeMessages(msg);
3374 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
3375 return;
3376 }
Eric Laurentadbe8bf2014-11-03 18:26:32 -08003377 synchronized (mLastDeviceConnectMsgTime) {
3378 long time = SystemClock.uptimeMillis() + delay;
3379 handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
3380 if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
3381 msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
3382 msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
3383 mLastDeviceConnectMsgTime = time;
3384 }
3385 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003386 }
3387
3388 boolean checkAudioSettingsPermission(String method) {
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07003389 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003390 == PackageManager.PERMISSION_GRANTED) {
3391 return true;
3392 }
3393 String msg = "Audio Settings Permission Denial: " + method + " from pid="
3394 + Binder.getCallingPid()
3395 + ", uid=" + Binder.getCallingUid();
3396 Log.w(TAG, msg);
3397 return false;
3398 }
3399
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003400 private int getDeviceForStream(int stream) {
3401 int device = AudioSystem.getDevicesForStream(stream);
3402 if ((device & (device - 1)) != 0) {
3403 // Multiple device selection is either:
3404 // - speaker + one other device: give priority to speaker in this case.
3405 // - one A2DP device + another device: happens with duplicated output. In this case
3406 // retain the device on the A2DP output as the other must not correspond to an active
3407 // selection if not the speaker.
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003408 // - HDMI-CEC system audio mode only output: give priority to available item in order.
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003409 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
3410 device = AudioSystem.DEVICE_OUT_SPEAKER;
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003411 } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
3412 device = AudioSystem.DEVICE_OUT_HDMI_ARC;
3413 } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
3414 device = AudioSystem.DEVICE_OUT_SPDIF;
3415 } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
3416 device = AudioSystem.DEVICE_OUT_AUX_LINE;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003417 } else {
3418 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
3419 }
3420 }
3421 return device;
3422 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003423
Paul McLean10804eb2015-01-28 11:16:35 -08003424 /*
3425 * A class just for packaging up a set of connection parameters.
3426 */
3427 private class WiredDeviceConnectionState {
3428 public int mType;
3429 public int mState;
3430 public String mAddress;
3431 public String mName;
3432
3433 public WiredDeviceConnectionState(int type, int state, String address, String name) {
3434 mType = type;
3435 mState = state;
3436 mAddress = address;
3437 mName = name;
3438 }
3439 }
3440
3441 public void setWiredDeviceConnectionState(int type, int state, String address,
3442 String name) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003443 synchronized (mConnectedDevices) {
Paul McLean10804eb2015-01-28 11:16:35 -08003444 int delay = checkSendBecomingNoisyIntent(type, state);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003445 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003446 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Paul McLean10804eb2015-01-28 11:16:35 -08003447 0,
3448 0,
3449 new WiredDeviceConnectionState(type, state, address, name),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003450 delay);
3451 }
3452 }
3453
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003454 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003455 {
3456 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003457 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
3458 throw new IllegalArgumentException("invalid profile " + profile);
3459 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003460 synchronized (mConnectedDevices) {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003461 if (profile == BluetoothProfile.A2DP) {
3462 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3463 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
3464 } else {
3465 delay = 0;
3466 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003467 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003468 (profile == BluetoothProfile.A2DP ?
3469 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003470 state,
3471 0,
3472 device,
3473 delay);
3474 }
3475 return delay;
3476 }
3477
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003478 ///////////////////////////////////////////////////////////////////////////
3479 // Inner classes
3480 ///////////////////////////////////////////////////////////////////////////
3481
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003482 // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
3483 // 1 mScoclient OR mSafeMediaVolumeState
3484 // 2 mSetModeDeathHandlers
3485 // 3 mSettingsLock
3486 // 4 VolumeStreamState.class
3487 // 5 mCameraSoundForced
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003488 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003489 private final int mStreamType;
3490
RoboErik4197cb62015-01-21 15:45:32 -08003491 private boolean mIsMuted;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003492 private String mVolumeIndexSettingName;
Eric Laurenta553c252009-07-17 12:17:14 -07003493 private int mIndexMax;
Eric Laurent3172d5e2012-05-09 11:38:16 -07003494 private final ConcurrentHashMap<Integer, Integer> mIndex =
3495 new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003496
Eric Laurenta553c252009-07-17 12:17:14 -07003497 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003498
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003499 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003500
3501 mStreamType = streamType;
Jared Suttles59820132009-08-13 21:50:52 -05003502 mIndexMax = MAX_STREAM_VOLUME[streamType];
Eric Laurenta553c252009-07-17 12:17:14 -07003503 AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
3504 mIndexMax *= 10;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003505
Eric Laurent33902db2012-10-07 16:15:07 -07003506 readSettings();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003507 }
3508
Eric Laurent42b041e2013-03-29 11:36:03 -07003509 public String getSettingNameForDevice(int device) {
3510 String name = mVolumeIndexSettingName;
Eric Laurent948d3272014-05-16 15:18:45 -07003511 String suffix = AudioSystem.getOutputDeviceName(device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003512 if (suffix.isEmpty()) {
3513 return name;
3514 }
3515 return name + "_" + suffix;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003516 }
3517
Eric Laurentfdbee862014-05-12 15:26:12 -07003518 public void readSettings() {
3519 synchronized (VolumeStreamState.class) {
Wally Yauda392902014-11-28 12:40:30 -08003520 // force maximum volume on all streams if fixed volume property
3521 // or master volume property is set
3522 if (mUseFixedVolume || mUseMasterVolume) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003523 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
3524 return;
3525 }
3526 // do not read system stream volume from settings: this stream is always aliased
3527 // to another stream type and its volume is never persisted. Values in settings can
3528 // only be stale values
3529 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3530 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
John Spurlock61560172015-02-06 19:46:04 -05003531 int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
Eric Laurentfdbee862014-05-12 15:26:12 -07003532 synchronized (mCameraSoundForced) {
3533 if (mCameraSoundForced) {
3534 index = mIndexMax;
3535 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003536 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003537 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
3538 return;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003539 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003540
Eric Laurentfdbee862014-05-12 15:26:12 -07003541 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
3542
3543 for (int i = 0; remainingDevices != 0; i++) {
3544 int device = (1 << i);
3545 if ((device & remainingDevices) == 0) {
3546 continue;
3547 }
3548 remainingDevices &= ~device;
3549
3550 // retrieve current volume for device
3551 String name = getSettingNameForDevice(device);
3552 // if no volume stored for current stream and device, use default volume if default
3553 // device, continue otherwise
3554 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
John Spurlock61560172015-02-06 19:46:04 -05003555 AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
Eric Laurentfdbee862014-05-12 15:26:12 -07003556 int index = Settings.System.getIntForUser(
3557 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3558 if (index == -1) {
3559 continue;
3560 }
3561
Eric Laurent212532b2014-07-21 15:43:18 -07003562 mIndex.put(device, getValidIndex(10 * index));
Eric Laurentdd45d012012-10-08 09:04:34 -07003563 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003564 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003565 }
3566
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003567 // must be called while synchronized VolumeStreamState.class
3568 public void applyDeviceVolume_syncVSS(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003569 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003570 if (mIsMuted) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003571 index = 0;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003572 } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported)
3573 || ((device & mFullVolumeDevices) != 0)) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003574 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07003575 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07003576 index = (getIndex(device) + 5)/10;
3577 }
3578 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003579 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003580
Eric Laurentfdbee862014-05-12 15:26:12 -07003581 public void applyAllVolumes() {
3582 synchronized (VolumeStreamState.class) {
3583 // apply default volume first: by convention this will reset all
3584 // devices volumes in audio policy manager to the supplied value
3585 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003586 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003587 index = 0;
3588 } else {
3589 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3590 }
3591 AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3592 // then apply device specific volumes
3593 Set set = mIndex.entrySet();
3594 Iterator i = set.iterator();
3595 while (i.hasNext()) {
3596 Map.Entry entry = (Map.Entry)i.next();
3597 int device = ((Integer)entry.getKey()).intValue();
3598 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
RoboErik4197cb62015-01-21 15:45:32 -08003599 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003600 index = 0;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003601 } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3602 mAvrcpAbsVolSupported)
3603 || ((device & mFullVolumeDevices) != 0))
3604 {
Eric Laurentfdbee862014-05-12 15:26:12 -07003605 index = (mIndexMax + 5)/10;
3606 } else {
3607 index = ((Integer)entry.getValue() + 5)/10;
3608 }
3609 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07003610 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003611 }
3612 }
3613 }
3614
3615 public boolean adjustIndex(int deltaIndex, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003616 return setIndex(getIndex(device) + deltaIndex,
3617 device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003618 }
3619
Eric Laurentfdbee862014-05-12 15:26:12 -07003620 public boolean setIndex(int index, int device) {
3621 synchronized (VolumeStreamState.class) {
3622 int oldIndex = getIndex(device);
3623 index = getValidIndex(index);
3624 synchronized (mCameraSoundForced) {
3625 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3626 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07003627 }
3628 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003629 mIndex.put(device, index);
3630
3631 if (oldIndex != index) {
3632 // Apply change to all streams using this one as alias
3633 // if changing volume of current device, also change volume of current
3634 // device on aliased stream
3635 boolean currentDevice = (device == getDeviceForStream(mStreamType));
3636 int numStreamTypes = AudioSystem.getNumStreamTypes();
3637 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3638 if (streamType != mStreamType &&
3639 mStreamVolumeAlias[streamType] == mStreamType) {
3640 int scaledIndex = rescaleIndex(index, mStreamType, streamType);
3641 mStreamStates[streamType].setIndex(scaledIndex,
3642 device);
3643 if (currentDevice) {
3644 mStreamStates[streamType].setIndex(scaledIndex,
3645 getDeviceForStream(streamType));
3646 }
3647 }
3648 }
3649 return true;
3650 } else {
3651 return false;
3652 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003653 }
3654 }
3655
Eric Laurentfdbee862014-05-12 15:26:12 -07003656 public int getIndex(int device) {
3657 synchronized (VolumeStreamState.class) {
3658 Integer index = mIndex.get(device);
3659 if (index == null) {
3660 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
3661 index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
3662 }
3663 return index.intValue();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003664 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07003665 }
3666
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003667 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07003668 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003669 }
3670
Eric Laurentfdbee862014-05-12 15:26:12 -07003671 public void setAllIndexes(VolumeStreamState srcStream) {
3672 synchronized (VolumeStreamState.class) {
3673 int srcStreamType = srcStream.getStreamType();
3674 // apply default device volume from source stream to all devices first in case
3675 // some devices are present in this stream state but not in source stream state
3676 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003677 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurentfdbee862014-05-12 15:26:12 -07003678 Set set = mIndex.entrySet();
3679 Iterator i = set.iterator();
3680 while (i.hasNext()) {
3681 Map.Entry entry = (Map.Entry)i.next();
3682 entry.setValue(index);
3683 }
3684 // Now apply actual volume for devices in source stream state
3685 set = srcStream.mIndex.entrySet();
3686 i = set.iterator();
3687 while (i.hasNext()) {
3688 Map.Entry entry = (Map.Entry)i.next();
3689 int device = ((Integer)entry.getKey()).intValue();
3690 index = ((Integer)entry.getValue()).intValue();
3691 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07003692
Eric Laurentfdbee862014-05-12 15:26:12 -07003693 setIndex(index, device);
3694 }
Eric Laurent6d517662012-04-23 18:42:39 -07003695 }
3696 }
3697
Eric Laurentfdbee862014-05-12 15:26:12 -07003698 public void setAllIndexesToMax() {
3699 synchronized (VolumeStreamState.class) {
3700 Set set = mIndex.entrySet();
3701 Iterator i = set.iterator();
3702 while (i.hasNext()) {
3703 Map.Entry entry = (Map.Entry)i.next();
3704 entry.setValue(mIndexMax);
3705 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003706 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003707 }
3708
RoboErik4197cb62015-01-21 15:45:32 -08003709 public void mute(boolean state) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003710 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08003711 if (state != mIsMuted) {
3712 mIsMuted = state;
3713 // Set the new mute volume. This propagates the values to
3714 // the audio system, otherwise the volume won't be changed
3715 // at the lower level.
3716 sendMsg(mAudioHandler,
3717 MSG_SET_ALL_VOLUMES,
3718 SENDMSG_QUEUE,
3719 0,
3720 0,
3721 this, 0);
Eric Laurentfdbee862014-05-12 15:26:12 -07003722 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003723 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003724 }
3725
Eric Laurent6d517662012-04-23 18:42:39 -07003726 public int getStreamType() {
3727 return mStreamType;
3728 }
3729
Eric Laurent212532b2014-07-21 15:43:18 -07003730 public void checkFixedVolumeDevices() {
3731 synchronized (VolumeStreamState.class) {
3732 // ignore settings for fixed volume devices: volume should always be at max or 0
3733 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
3734 Set set = mIndex.entrySet();
3735 Iterator i = set.iterator();
3736 while (i.hasNext()) {
3737 Map.Entry entry = (Map.Entry)i.next();
3738 int device = ((Integer)entry.getKey()).intValue();
3739 int index = ((Integer)entry.getValue()).intValue();
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003740 if (((device & mFullVolumeDevices) != 0)
3741 || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
Eric Laurent212532b2014-07-21 15:43:18 -07003742 entry.setValue(mIndexMax);
3743 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003744 applyDeviceVolume_syncVSS(device);
Eric Laurent212532b2014-07-21 15:43:18 -07003745 }
3746 }
3747 }
3748 }
3749
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003750 private int getValidIndex(int index) {
3751 if (index < 0) {
3752 return 0;
Wally Yauda392902014-11-28 12:40:30 -08003753 } else if (mUseFixedVolume || mUseMasterVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07003754 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003755 }
3756
3757 return index;
3758 }
3759
Eric Laurentbffc3d12012-05-07 17:43:49 -07003760 private void dump(PrintWriter pw) {
RoboErik4197cb62015-01-21 15:45:32 -08003761 pw.print(" Muted: ");
3762 pw.println(mIsMuted);
John Spurlock2b29bc42014-08-26 16:40:35 -04003763 pw.print(" Max: ");
3764 pw.println((mIndexMax + 5) / 10);
Eric Laurentbffc3d12012-05-07 17:43:49 -07003765 pw.print(" Current: ");
3766 Set set = mIndex.entrySet();
3767 Iterator i = set.iterator();
3768 while (i.hasNext()) {
3769 Map.Entry entry = (Map.Entry)i.next();
John Spurlock2b29bc42014-08-26 16:40:35 -04003770 final int device = (Integer) entry.getKey();
3771 pw.print(Integer.toHexString(device));
3772 final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
3773 : AudioSystem.getOutputDeviceName(device);
3774 if (!deviceName.isEmpty()) {
3775 pw.print(" (");
3776 pw.print(deviceName);
3777 pw.print(")");
3778 }
3779 pw.print(": ");
3780 final int index = (((Integer) entry.getValue()) + 5) / 10;
3781 pw.print(index);
3782 if (i.hasNext()) {
3783 pw.print(", ");
3784 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003785 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003786 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003787 }
3788
3789 /** Thread that handles native AudioSystem control. */
3790 private class AudioSystemThread extends Thread {
3791 AudioSystemThread() {
3792 super("AudioService");
3793 }
3794
3795 @Override
3796 public void run() {
3797 // Set this thread up so the handler will work on it
3798 Looper.prepare();
3799
3800 synchronized(AudioService.this) {
3801 mAudioHandler = new AudioHandler();
3802
3803 // Notify that the handler has been created
3804 AudioService.this.notify();
3805 }
3806
3807 // Listen for volume change requests that are set by VolumePanel
3808 Looper.loop();
3809 }
3810 }
3811
3812 /** Handles internal volume messages in separate volume thread. */
3813 private class AudioHandler extends Handler {
3814
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003815 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003816
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003817 synchronized (VolumeStreamState.class) {
3818 // Apply volume
3819 streamState.applyDeviceVolume_syncVSS(device);
Eric Laurenta553c252009-07-17 12:17:14 -07003820
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003821 // Apply change to all streams using this one as alias
3822 int numStreamTypes = AudioSystem.getNumStreamTypes();
3823 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3824 if (streamType != streamState.mStreamType &&
3825 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
3826 // Make sure volume is also maxed out on A2DP device for aliased stream
3827 // that may have a different device selected
3828 int streamDevice = getDeviceForStream(streamType);
3829 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
3830 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
3831 mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
3832 }
3833 mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
Eric Laurentcd772d02013-10-30 18:31:07 -07003834 }
Eric Laurenta553c252009-07-17 12:17:14 -07003835 }
3836 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003837 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08003838 sendMsg(mAudioHandler,
3839 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08003840 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003841 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07003842 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08003843 streamState,
3844 PERSIST_DELAY);
3845
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003846 }
3847
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003848 private void setAllVolumes(VolumeStreamState streamState) {
3849
3850 // Apply volume
3851 streamState.applyAllVolumes();
3852
3853 // Apply change to all streams using this one as alias
3854 int numStreamTypes = AudioSystem.getNumStreamTypes();
3855 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3856 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07003857 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003858 mStreamStates[streamType].applyAllVolumes();
3859 }
3860 }
3861 }
3862
Eric Laurent42b041e2013-03-29 11:36:03 -07003863 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003864 if (mUseFixedVolume) {
3865 return;
3866 }
Eric Laurent212532b2014-07-21 15:43:18 -07003867 if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
3868 return;
3869 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003870 System.putIntForUser(mContentResolver,
3871 streamState.getSettingNameForDevice(device),
3872 (streamState.getIndex(device) + 5)/ 10,
3873 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003874 }
3875
Glenn Kastenba195eb2011-12-13 09:30:40 -08003876 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003877 if (mUseFixedVolume) {
3878 return;
3879 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07003880 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003881 }
3882
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003883 private boolean onLoadSoundEffects() {
3884 int status;
3885
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003886 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07003887 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003888 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
3889 return false;
3890 }
3891
3892 if (mSoundPool != null) {
3893 return true;
3894 }
3895
3896 loadTouchSoundAssets();
3897
Jean-Michel Trivi55a30c42014-07-20 17:56:11 -07003898 mSoundPool = new SoundPool.Builder()
3899 .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
3900 .setAudioAttributes(new AudioAttributes.Builder()
3901 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
3902 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
3903 .build())
3904 .build();
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003905 mSoundPoolCallBack = null;
3906 mSoundPoolListenerThread = new SoundPoolListenerThread();
3907 mSoundPoolListenerThread.start();
3908 int attempts = 3;
3909 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
3910 try {
3911 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07003912 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003913 } catch (InterruptedException e) {
3914 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
3915 }
3916 }
3917
3918 if (mSoundPoolCallBack == null) {
3919 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
3920 if (mSoundPoolLooper != null) {
3921 mSoundPoolLooper.quit();
3922 mSoundPoolLooper = null;
3923 }
3924 mSoundPoolListenerThread = null;
3925 mSoundPool.release();
3926 mSoundPool = null;
3927 return false;
3928 }
3929 /*
3930 * poolId table: The value -1 in this table indicates that corresponding
3931 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
3932 * Once loaded, the value in poolId is the sample ID and the same
3933 * sample can be reused for another effect using the same file.
3934 */
3935 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3936 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3937 poolId[fileIdx] = -1;
3938 }
3939 /*
3940 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
3941 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
3942 * this indicates we have a valid sample loaded for this effect.
3943 */
3944
3945 int numSamples = 0;
3946 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3947 // Do not load sample if this effect uses the MediaPlayer
3948 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
3949 continue;
3950 }
3951 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
3952 String filePath = Environment.getRootDirectory()
3953 + SOUND_EFFECTS_PATH
3954 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
3955 int sampleId = mSoundPool.load(filePath, 0);
3956 if (sampleId <= 0) {
3957 Log.w(TAG, "Soundpool could not load file: "+filePath);
3958 } else {
3959 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
3960 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
3961 numSamples++;
3962 }
3963 } else {
3964 SOUND_EFFECT_FILES_MAP[effect][1] =
3965 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
3966 }
3967 }
3968 // wait for all samples to be loaded
3969 if (numSamples > 0) {
3970 mSoundPoolCallBack.setSamples(poolId);
3971
3972 attempts = 3;
3973 status = 1;
3974 while ((status == 1) && (attempts-- > 0)) {
3975 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07003976 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003977 status = mSoundPoolCallBack.status();
3978 } catch (InterruptedException e) {
3979 Log.w(TAG, "Interrupted while waiting sound pool callback.");
3980 }
3981 }
3982 } else {
3983 status = -1;
3984 }
3985
3986 if (mSoundPoolLooper != null) {
3987 mSoundPoolLooper.quit();
3988 mSoundPoolLooper = null;
3989 }
3990 mSoundPoolListenerThread = null;
3991 if (status != 0) {
3992 Log.w(TAG,
3993 "onLoadSoundEffects(), Error "+status+ " while loading samples");
3994 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3995 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
3996 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3997 }
3998 }
3999
4000 mSoundPool.release();
4001 mSoundPool = null;
4002 }
4003 }
4004 return (status == 0);
4005 }
4006
4007 /**
4008 * Unloads samples from the sound pool.
4009 * This method can be called to free some memory when
4010 * sound effects are disabled.
4011 */
4012 private void onUnloadSoundEffects() {
4013 synchronized (mSoundEffectsLock) {
4014 if (mSoundPool == null) {
4015 return;
4016 }
4017
4018 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4019 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4020 poolId[fileIdx] = 0;
4021 }
4022
4023 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4024 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
4025 continue;
4026 }
4027 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
4028 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
4029 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4030 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
4031 }
4032 }
4033 mSoundPool.release();
4034 mSoundPool = null;
4035 }
4036 }
4037
4038 private void onPlaySoundEffect(int effectType, int volume) {
4039 synchronized (mSoundEffectsLock) {
4040
4041 onLoadSoundEffects();
4042
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004043 if (mSoundPool == null) {
4044 return;
4045 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004046 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08004047 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004048 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07004049 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004050 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07004051 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004052 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004053
4054 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004055 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
4056 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004057 } else {
4058 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004059 try {
Eric Laurente78fced2013-03-15 16:03:47 -07004060 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
4061 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004062 mediaPlayer.setDataSource(filePath);
4063 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
4064 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08004065 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004066 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
4067 public void onCompletion(MediaPlayer mp) {
4068 cleanupPlayer(mp);
4069 }
4070 });
4071 mediaPlayer.setOnErrorListener(new OnErrorListener() {
4072 public boolean onError(MediaPlayer mp, int what, int extra) {
4073 cleanupPlayer(mp);
4074 return true;
4075 }
4076 });
4077 mediaPlayer.start();
4078 } catch (IOException ex) {
4079 Log.w(TAG, "MediaPlayer IOException: "+ex);
4080 } catch (IllegalArgumentException ex) {
4081 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
4082 } catch (IllegalStateException ex) {
4083 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004084 }
4085 }
4086 }
4087 }
4088
4089 private void cleanupPlayer(MediaPlayer mp) {
4090 if (mp != null) {
4091 try {
4092 mp.stop();
4093 mp.release();
4094 } catch (IllegalStateException ex) {
4095 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
4096 }
4097 }
4098 }
4099
Eric Laurentfa640152011-03-12 15:59:51 -08004100 private void setForceUse(int usage, int config) {
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004101 synchronized (mConnectedDevices) {
4102 setForceUseInt_SyncDevices(usage, config);
4103 }
Eric Laurentfa640152011-03-12 15:59:51 -08004104 }
4105
Eric Laurent05274f32012-11-29 12:48:18 -08004106 private void onPersistSafeVolumeState(int state) {
4107 Settings.Global.putInt(mContentResolver,
4108 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
4109 state);
4110 }
4111
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004112 @Override
4113 public void handleMessage(Message msg) {
Eric Laurentafbb0472011-12-15 09:04:23 -08004114 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004115
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004116 case MSG_SET_DEVICE_VOLUME:
4117 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
4118 break;
4119
4120 case MSG_SET_ALL_VOLUMES:
4121 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004122 break;
4123
4124 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07004125 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004126 break;
4127
Mike Lockwood5c55a052011-12-15 17:21:44 -05004128 case MSG_PERSIST_MASTER_VOLUME:
Eric Laurent83a017b2013-03-19 18:15:31 -07004129 if (mUseFixedVolume) {
4130 return;
4131 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004132 Settings.System.putFloatForUser(mContentResolver,
4133 Settings.System.VOLUME_MASTER,
RoboErik8a2cfc32014-05-16 11:19:38 -07004134 msg.arg1 / (float)1000.0,
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004135 UserHandle.USER_CURRENT);
Mike Lockwood5c55a052011-12-15 17:21:44 -05004136 break;
4137
Justin Koh57978ed2012-04-03 17:37:58 -07004138 case MSG_PERSIST_MASTER_VOLUME_MUTE:
Eric Laurent83a017b2013-03-19 18:15:31 -07004139 if (mUseFixedVolume) {
4140 return;
4141 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004142 Settings.System.putIntForUser(mContentResolver,
4143 Settings.System.VOLUME_MASTER_MUTE,
4144 msg.arg1,
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004145 msg.arg2);
Justin Koh57978ed2012-04-03 17:37:58 -07004146 break;
4147
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004148 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08004149 // note that the value persisted is the current ringer mode, not the
4150 // value of ringer mode as of the time the request was made to persist
John Spurlock661f2cf2014-11-17 10:29:10 -05004151 persistRingerMode(getRingerModeInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004152 break;
4153
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004154 case MSG_MEDIA_SERVER_DIED:
Eric Laurenteb4b8a22014-07-21 13:10:07 -07004155 if (!mSystemReady ||
4156 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Eric Laurent89e74ba2009-09-30 18:26:36 -07004157 Log.e(TAG, "Media server died.");
Eric Laurentafbb0472011-12-15 09:04:23 -08004158 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent89e74ba2009-09-30 18:26:36 -07004159 null, 500);
Eric Laurentdfb881f2013-07-18 14:41:39 -07004160 break;
Eric Laurent89e74ba2009-09-30 18:26:36 -07004161 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004162 Log.e(TAG, "Media server started.");
Eric Laurentdfb881f2013-07-18 14:41:39 -07004163
Eric Laurent3c652ca2010-06-21 20:46:26 -07004164 // indicate to audio HAL that we start the reconfiguration phase after a media
4165 // server crash
Eric Laurentdfb881f2013-07-18 14:41:39 -07004166 // Note that we only execute this when the media server
Eric Laurent3c652ca2010-06-21 20:46:26 -07004167 // process restarts after a crash, not the first time it is started.
4168 AudioSystem.setParameters("restarting=true");
4169
Glenn Kastenfd116ad2013-07-12 17:10:39 -07004170 readAndSetLowRamDevice();
4171
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004172 // Restore device connection states
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004173 synchronized (mConnectedDevices) {
4174 Set set = mConnectedDevices.entrySet();
4175 Iterator i = set.iterator();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004176 while (i.hasNext()) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004177 Map.Entry device = (Map.Entry)i.next();
4178 AudioSystem.setDeviceConnectionState(
4179 ((Integer)device.getKey()).intValue(),
4180 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004181 (String)device.getValue(),
4182 "unknown-device");
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004183 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004184 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004185 // Restore call state
4186 AudioSystem.setPhoneState(mMode);
4187
Eric Laurentd5603c12009-08-06 08:49:39 -07004188 // Restore forced usage for communcations and record
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004189 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
Eric Laurentd5603c12009-08-06 08:49:39 -07004190 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
Eric Laurentdd45d012012-10-08 09:04:34 -07004191 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
4192 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004193
Eric Laurenta553c252009-07-17 12:17:14 -07004194 // Restore stream volumes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004195 int numStreamTypes = AudioSystem.getNumStreamTypes();
4196 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004197 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004198 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004199
4200 streamState.applyAllVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004201 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004202
4203 // Restore ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05004204 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3c652ca2010-06-21 20:46:26 -07004205
Mike Lockwood90631542012-01-06 11:20:37 -05004206 // Restore master volume
4207 restoreMasterVolume();
4208
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004209 // Reset device orientation (if monitored for this device)
Eric Laurentd640bd32012-09-28 18:01:48 -07004210 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004211 setOrientationForAudioSystem();
4212 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004213 if (mMonitorRotation) {
4214 setRotationForAudioSystem();
4215 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004216
Eric Laurent78472112012-05-21 08:57:21 -07004217 synchronized (mBluetoothA2dpEnabledLock) {
4218 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
4219 mBluetoothA2dpEnabled ?
4220 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
4221 }
Eric Laurentbff5ca52012-11-02 16:48:26 -07004222
4223 synchronized (mSettingsLock) {
4224 AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
4225 mDockAudioMediaEnabled ?
4226 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
4227 }
Eric Laurent212532b2014-07-21 15:43:18 -07004228 if (mHdmiManager != null) {
4229 synchronized (mHdmiManager) {
4230 if (mHdmiTvClient != null) {
4231 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
4232 }
4233 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004234 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08004235
4236 synchronized (mAudioPolicies) {
4237 for(AudioPolicyProxy policy : mAudioPolicies.values()) {
4238 policy.connectMixes();
4239 }
4240 }
4241
Eric Laurent3c652ca2010-06-21 20:46:26 -07004242 // indicate the end of reconfiguration phase to audio HAL
4243 AudioSystem.setParameters("restarting=false");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004244 break;
4245
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004246 case MSG_UNLOAD_SOUND_EFFECTS:
4247 onUnloadSoundEffects();
4248 break;
4249
Eric Laurent117b7bb2011-01-16 17:07:27 -08004250 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004251 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
4252 // can take several dozens of milliseconds to complete
4253 boolean loaded = onLoadSoundEffects();
4254 if (msg.obj != null) {
4255 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
4256 synchronized (reply) {
4257 reply.mStatus = loaded ? 0 : -1;
4258 reply.notify();
4259 }
4260 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08004261 break;
4262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004263 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004264 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004265 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004266
4267 case MSG_BTA2DP_DOCK_TIMEOUT:
4268 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004269 synchronized (mConnectedDevices) {
4270 makeA2dpDeviceUnavailableNow( (String) msg.obj );
4271 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004272 break;
Eric Laurentfa640152011-03-12 15:59:51 -08004273
4274 case MSG_SET_FORCE_USE:
Eric Laurentc390bed2012-07-03 12:24:05 -07004275 case MSG_SET_FORCE_BT_A2DP_USE:
Eric Laurentfa640152011-03-12 15:59:51 -08004276 setForceUse(msg.arg1, msg.arg2);
4277 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07004278
Eric Laurentdc03c612011-04-01 10:59:41 -07004279 case MSG_BT_HEADSET_CNCT_FAILED:
4280 resetBluetoothSco();
4281 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004282
4283 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
Paul McLean10804eb2015-01-28 11:16:35 -08004284 { WiredDeviceConnectionState connectState =
4285 (WiredDeviceConnectionState)msg.obj;
4286 onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
4287 connectState.mAddress, connectState.mName);
4288 mAudioEventWakeLock.release();
4289 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004290 break;
4291
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004292 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
4293 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
4294 mAudioEventWakeLock.release();
4295 break;
4296
4297 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
4298 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004299 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004300 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004301
4302 case MSG_REPORT_NEW_ROUTES: {
4303 int N = mRoutesObservers.beginBroadcast();
4304 if (N > 0) {
4305 AudioRoutesInfo routes;
4306 synchronized (mCurAudioRoutes) {
4307 routes = new AudioRoutesInfo(mCurAudioRoutes);
4308 }
4309 while (N > 0) {
4310 N--;
4311 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
4312 try {
4313 obs.dispatchAudioRoutesChanged(routes);
4314 } catch (RemoteException e) {
4315 }
4316 }
4317 }
4318 mRoutesObservers.finishBroadcast();
4319 break;
4320 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004321
Eric Laurentc34dcc12012-09-10 13:51:52 -07004322 case MSG_CHECK_MUSIC_ACTIVE:
4323 onCheckMusicActive();
4324 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004325
4326 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
4327 onSendBecomingNoisyIntent();
4328 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07004329
4330 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
4331 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
4332 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
4333 break;
Eric Laurent05274f32012-11-29 12:48:18 -08004334 case MSG_PERSIST_SAFE_VOLUME_STATE:
4335 onPersistSafeVolumeState(msg.arg1);
4336 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08004337
Eric Laurent2a57ca92013-03-07 17:29:27 -08004338 case MSG_BROADCAST_BT_CONNECTION_STATE:
4339 onBroadcastScoConnectionState(msg.arg1);
4340 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004341
4342 case MSG_SYSTEM_READY:
4343 onSystemReady();
4344 break;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004345
4346 case MSG_PERSIST_MUSIC_ACTIVE_MS:
4347 final int musicActiveMs = msg.arg1;
4348 Settings.Secure.putIntForUser(mContentResolver,
4349 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
4350 UserHandle.USER_CURRENT);
4351 break;
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004352 case MSG_PERSIST_MICROPHONE_MUTE:
4353 Settings.System.putIntForUser(mContentResolver,
4354 Settings.System.MICROPHONE_MUTE,
4355 msg.arg1,
4356 msg.arg2);
4357 break;
RoboErik5452e252015-02-06 15:33:53 -08004358 case MSG_UNMUTE_STREAM:
4359 onUnmuteStream(msg.arg1, msg.arg2);
4360 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004361 }
4362 }
4363 }
4364
Jason Parekhb1096152009-03-24 17:48:25 -07004365 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07004366
Jason Parekhb1096152009-03-24 17:48:25 -07004367 SettingsObserver() {
4368 super(new Handler());
4369 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4370 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004371 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4372 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07004373 }
4374
4375 @Override
4376 public void onChange(boolean selfChange) {
4377 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08004378 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
4379 // However there appear to be some missing locks around mRingerModeMutedStreams
4380 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
4381 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07004382 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004383 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07004384 /*
4385 * Ensure all stream types that should be affected by ringer mode
4386 * are in the proper state.
4387 */
John Spurlock661f2cf2014-11-17 10:29:10 -05004388 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurenta553c252009-07-17 12:17:14 -07004389 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004390 readDockAudioSettings(mContentResolver);
Eric Laurenta553c252009-07-17 12:17:14 -07004391 }
Jason Parekhb1096152009-03-24 17:48:25 -07004392 }
Jason Parekhb1096152009-03-24 17:48:25 -07004393 }
Eric Laurenta553c252009-07-17 12:17:14 -07004394
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004395 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004396 private void makeA2dpDeviceAvailable(String address) {
Eric Laurent78472112012-05-21 08:57:21 -07004397 // enable A2DP before notifying A2DP connection to avoid unecessary processing in
4398 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004399 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4400 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4401 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Eric Laurent78472112012-05-21 08:57:21 -07004402 setBluetoothA2dpOnInt(true);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004403 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4404 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004405 address,
4406 "a2dp-device");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004407 // Reset A2DP suspend state each time a new sink is connected
4408 AudioSystem.setParameters("A2dpSuspended=false");
4409 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
4410 address);
4411 }
4412
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004413 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004414 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07004415 }
4416
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004417 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004418 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004419 synchronized (mA2dpAvrcpLock) {
4420 mAvrcpAbsVolSupported = false;
4421 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004422 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4423 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004424 address,
4425 "a2dp-device");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004426 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
RoboErik5535ea82014-09-25 14:53:16 -07004427 synchronized (mCurAudioRoutes) {
4428 // Remove A2DP routes as well
John Spurlock61560172015-02-06 19:46:04 -05004429 if (mCurAudioRoutes.bluetoothName != null) {
4430 mCurAudioRoutes.bluetoothName = null;
RoboErik5535ea82014-09-25 14:53:16 -07004431 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4432 SENDMSG_NOOP, 0, 0, null, 0);
4433 }
4434 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004435 }
4436
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004437 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004438 private void makeA2dpDeviceUnavailableLater(String address) {
Eric Laurent3b591262010-04-20 07:01:00 -07004439 // prevent any activity on the A2DP audio output to avoid unwanted
4440 // reconnection of the sink.
4441 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004442 // the device will be made unavailable later, so consider it disconnected right away
4443 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
4444 // send the delayed message to make the device unavailable later
4445 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
4446 mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
4447
4448 }
4449
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004450 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004451 private void makeA2dpSrcAvailable(String address) {
4452 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
4453 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004454 address,
4455 "a2dp-device");
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004456 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
4457 address);
4458 }
4459
4460 // must be called synchronized on mConnectedDevices
4461 private void makeA2dpSrcUnavailable(String address) {
4462 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
4463 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004464 address,
4465 "a2dp-device");
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004466 mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
4467 }
4468
4469 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004470 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004471 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4472 }
4473
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004474 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004475 private boolean hasScheduledA2dpDockTimeout() {
4476 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4477 }
4478
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004479 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004480 {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004481 if (DEBUG_VOL) {
4482 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
4483 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004484 if (btDevice == null) {
4485 return;
4486 }
4487 String address = btDevice.getAddress();
4488 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4489 address = "";
4490 }
John Du5a0cf7a2013-07-19 11:30:34 -07004491
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004492 synchronized (mConnectedDevices) {
4493 boolean isConnected =
4494 (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
4495 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
4496
4497 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4498 if (btDevice.isBluetoothDock()) {
4499 if (state == BluetoothProfile.STATE_DISCONNECTED) {
4500 // introduction of a delay for transient disconnections of docks when
4501 // power is rapidly turned off/on, this message will be canceled if
4502 // we reconnect the dock under a preset delay
4503 makeA2dpDeviceUnavailableLater(address);
4504 // the next time isConnected is evaluated, it will be false for the dock
4505 }
4506 } else {
4507 makeA2dpDeviceUnavailableNow(address);
4508 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07004509 synchronized (mCurAudioRoutes) {
John Spurlock61560172015-02-06 19:46:04 -05004510 if (mCurAudioRoutes.bluetoothName != null) {
4511 mCurAudioRoutes.bluetoothName = null;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004512 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4513 SENDMSG_NOOP, 0, 0, null, 0);
4514 }
4515 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004516 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4517 if (btDevice.isBluetoothDock()) {
4518 // this could be a reconnection after a transient disconnection
4519 cancelA2dpDeviceTimeout();
4520 mDockAddress = address;
4521 } else {
4522 // this could be a connection of another A2DP device before the timeout of
4523 // a dock: cancel the dock timeout, and make the dock unavailable now
4524 if(hasScheduledA2dpDockTimeout()) {
4525 cancelA2dpDeviceTimeout();
4526 makeA2dpDeviceUnavailableNow(mDockAddress);
4527 }
4528 }
4529 makeA2dpDeviceAvailable(address);
Dianne Hackborn632ca412012-06-14 19:34:10 -07004530 synchronized (mCurAudioRoutes) {
4531 String name = btDevice.getAliasName();
John Spurlock61560172015-02-06 19:46:04 -05004532 if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
4533 mCurAudioRoutes.bluetoothName = name;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004534 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4535 SENDMSG_NOOP, 0, 0, null, 0);
4536 }
4537 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004538 }
4539 }
4540 }
4541
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004542 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
4543 {
4544 if (DEBUG_VOL) {
4545 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
4546 }
4547 if (btDevice == null) {
4548 return;
4549 }
4550 String address = btDevice.getAddress();
4551 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4552 address = "";
4553 }
4554
4555 synchronized (mConnectedDevices) {
4556 boolean isConnected =
4557 (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
4558 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));
4559
4560 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4561 makeA2dpSrcUnavailable(address);
4562 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4563 makeA2dpSrcAvailable(address);
4564 }
4565 }
4566 }
4567
John Du5a0cf7a2013-07-19 11:30:34 -07004568 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
4569 // address is not used for now, but may be used when multiple a2dp devices are supported
4570 synchronized (mA2dpAvrcpLock) {
4571 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004572 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07004573 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4574 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4575 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4576 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4577 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07004578 }
4579 }
4580
Paul McLean10804eb2015-01-28 11:16:35 -08004581 private boolean handleDeviceConnection(boolean connect, int device, String address, String deviceName) {
4582 Slog.i(TAG, "handleDeviceConnection(" + connect +
4583 " dev:" + Integer.toHexString(device) +
RoboErik5452e252015-02-06 15:33:53 -08004584 " address:" + address +
Paul McLean10804eb2015-01-28 11:16:35 -08004585 " name:" + deviceName + ")");
Eric Laurent59f48272012-04-05 19:42:21 -07004586 synchronized (mConnectedDevices) {
4587 boolean isConnected = (mConnectedDevices.containsKey(device) &&
Paul McLean10804eb2015-01-28 11:16:35 -08004588 (address.isEmpty() || mConnectedDevices.get(device).equals(address)));
Eric Laurent59f48272012-04-05 19:42:21 -07004589
Paul McLean10804eb2015-01-28 11:16:35 -08004590 if (isConnected && !connect) {
Eric Laurent59f48272012-04-05 19:42:21 -07004591 AudioSystem.setDeviceConnectionState(device,
4592 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004593 address, deviceName);
Eric Laurent59f48272012-04-05 19:42:21 -07004594 mConnectedDevices.remove(device);
4595 return true;
Paul McLean10804eb2015-01-28 11:16:35 -08004596 } else if (!isConnected && connect) {
Eric Laurent59f48272012-04-05 19:42:21 -07004597 AudioSystem.setDeviceConnectionState(device,
4598 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004599 address, deviceName);
4600 mConnectedDevices.put(new Integer(device), address);
Eric Laurent59f48272012-04-05 19:42:21 -07004601 return true;
4602 }
4603 }
4604 return false;
4605 }
4606
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004607 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4608 // sent if none of these devices is connected.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004609 // Access synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004610 int mBecomingNoisyIntentDevices =
4611 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07004612 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07004613 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004614 AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004615
4616 // must be called before removing the device from mConnectedDevices
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004617 // Called synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004618 private int checkSendBecomingNoisyIntent(int device, int state) {
4619 int delay = 0;
4620 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4621 int devices = 0;
4622 for (int dev : mConnectedDevices.keySet()) {
Eric Laurent27c30e42014-08-27 12:36:33 -07004623 if (((dev & AudioSystem.DEVICE_BIT_IN) == 0) &&
4624 ((dev & mBecomingNoisyIntentDevices) != 0)) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004625 devices |= dev;
4626 }
4627 }
4628 if (devices == device) {
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004629 sendMsg(mAudioHandler,
4630 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4631 SENDMSG_REPLACE,
4632 0,
4633 0,
4634 null,
4635 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004636 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004637 }
4638 }
4639
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004640 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
4641 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004642 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004643 synchronized (mLastDeviceConnectMsgTime) {
4644 long time = SystemClock.uptimeMillis();
4645 if (mLastDeviceConnectMsgTime > time) {
Matthew Xiec525cf72015-01-22 20:13:17 -08004646 delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004647 }
4648 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004649 }
4650 return delay;
4651 }
4652
Paul McLean10804eb2015-01-28 11:16:35 -08004653 private void sendDeviceConnectionIntent(int device, int state, String address, String deviceName)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004654 {
Paul McLean10804eb2015-01-28 11:16:35 -08004655 Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
4656 " state:0x" + Integer.toHexString(state) +
4657 " address:" + address +
4658 " name:" + deviceName + ");");
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004659 Intent intent = new Intent();
4660
Paul McLean10804eb2015-01-28 11:16:35 -08004661 intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
4662 intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
4663 intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
4664
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004665 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4666
Dianne Hackborn632ca412012-06-14 19:34:10 -07004667 int connType = 0;
4668
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004669 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004670 connType = AudioRoutesInfo.MAIN_HEADSET;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004671 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4672 intent.putExtra("microphone", 1);
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004673 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
4674 device == AudioSystem.DEVICE_OUT_LINE) {
4675 /*do apps care about line-out vs headphones?*/
Dianne Hackborn632ca412012-06-14 19:34:10 -07004676 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004677 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4678 intent.putExtra("microphone", 0);
Eric Laurent6fa42452015-01-09 15:09:40 -08004679 } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
4680 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004681 connType = AudioRoutesInfo.MAIN_HDMI;
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004682 configureHdmiPlugIntent(intent, state);
Paul McLean10804eb2015-01-28 11:16:35 -08004683 } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE) {
4684 connType = AudioRoutesInfo.MAIN_USB;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004685 }
4686
Dianne Hackborn632ca412012-06-14 19:34:10 -07004687 synchronized (mCurAudioRoutes) {
4688 if (connType != 0) {
John Spurlock61560172015-02-06 19:46:04 -05004689 int newConn = mCurAudioRoutes.mainType;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004690 if (state != 0) {
4691 newConn |= connType;
4692 } else {
4693 newConn &= ~connType;
4694 }
John Spurlock61560172015-02-06 19:46:04 -05004695 if (newConn != mCurAudioRoutes.mainType) {
4696 mCurAudioRoutes.mainType = newConn;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004697 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4698 SENDMSG_NOOP, 0, 0, null, 0);
4699 }
4700 }
4701 }
4702
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004703 final long ident = Binder.clearCallingIdentity();
4704 try {
4705 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
4706 } finally {
4707 Binder.restoreCallingIdentity(ident);
4708 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004709 }
4710
Paul McLean10804eb2015-01-28 11:16:35 -08004711 private void onSetWiredDeviceConnectionState(int device, int state, String address,
4712 String deviceName)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004713 {
Paul McLean10804eb2015-01-28 11:16:35 -08004714 Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
4715 + " state:" + Integer.toHexString(state)
4716 + " address:" + address
4717 + " deviceName:" + deviceName + ");");
4718
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004719 synchronized (mConnectedDevices) {
4720 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004721 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4722 (device == AudioSystem.DEVICE_OUT_LINE))) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004723 setBluetoothA2dpOnInt(true);
4724 }
Eric Laurentae4506e2014-05-29 16:04:32 -07004725 boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
4726 (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
4727 ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
Paul McLean10804eb2015-01-28 11:16:35 -08004728 handleDeviceConnection(state == 1, device, address, deviceName);
Eric Laurentf1a457d2012-09-20 16:27:23 -07004729 if (state != 0) {
4730 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004731 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4732 (device == AudioSystem.DEVICE_OUT_LINE)) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07004733 setBluetoothA2dpOnInt(false);
4734 }
4735 if ((device & mSafeMediaVolumeDevices) != 0) {
4736 sendMsg(mAudioHandler,
4737 MSG_CHECK_MUSIC_ACTIVE,
4738 SENDMSG_REPLACE,
4739 0,
4740 0,
4741 null,
4742 MUSIC_ACTIVE_POLL_PERIOD_MS);
4743 }
Eric Laurent212532b2014-07-21 15:43:18 -07004744 // Television devices without CEC service apply software volume on HDMI output
4745 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4746 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
4747 checkAllFixedVolumeDevices();
4748 if (mHdmiManager != null) {
4749 synchronized (mHdmiManager) {
4750 if (mHdmiPlaybackClient != null) {
4751 mHdmiCecSink = false;
4752 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
4753 }
4754 }
4755 }
4756 }
4757 } else {
4758 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4759 if (mHdmiManager != null) {
4760 synchronized (mHdmiManager) {
4761 mHdmiCecSink = false;
4762 }
4763 }
4764 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004765 }
Paul McLean10804eb2015-01-28 11:16:35 -08004766 if (!isUsb && device != AudioSystem.DEVICE_IN_WIRED_HEADSET) {
4767 sendDeviceConnectionIntent(device, state, address, deviceName);
Mike Lockwooddb454842012-09-18 11:16:57 -07004768 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004769 }
4770 }
4771
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004772 private void configureHdmiPlugIntent(Intent intent, int state) {
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004773 intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
4774 intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004775 if (state == 1) {
4776 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
4777 int[] portGeneration = new int[1];
4778 int status = AudioSystem.listAudioPorts(ports, portGeneration);
4779 if (status == AudioManager.SUCCESS) {
4780 for (AudioPort port : ports) {
4781 if (port instanceof AudioDevicePort) {
4782 final AudioDevicePort devicePort = (AudioDevicePort) port;
Eric Laurent6fa42452015-01-09 15:09:40 -08004783 if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
4784 devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004785 // format the list of supported encodings
4786 int[] formats = devicePort.formats();
4787 if (formats.length > 0) {
4788 ArrayList<Integer> encodingList = new ArrayList(1);
4789 for (int format : formats) {
4790 // a format in the list can be 0, skip it
4791 if (format != AudioFormat.ENCODING_INVALID) {
4792 encodingList.add(format);
4793 }
4794 }
4795 int[] encodingArray = new int[encodingList.size()];
4796 for (int i = 0 ; i < encodingArray.length ; i++) {
4797 encodingArray[i] = encodingList.get(i);
4798 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004799 intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004800 }
4801 // find the maximum supported number of channels
4802 int maxChannels = 0;
4803 for (int mask : devicePort.channelMasks()) {
4804 int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
4805 if (channelCount > maxChannels) {
4806 maxChannels = channelCount;
4807 }
4808 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004809 intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004810 }
4811 }
4812 }
4813 }
4814 }
4815 }
4816
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004817 /* cache of the address of the last dock the device was connected to */
4818 private String mDockAddress;
4819
Eric Laurenta553c252009-07-17 12:17:14 -07004820 /**
4821 * Receiver for misc intent broadcasts the Phone app cares about.
4822 */
4823 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4824 @Override
4825 public void onReceive(Context context, Intent intent) {
4826 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07004827 int outDevice;
4828 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07004829 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07004830
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004831 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4832 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4833 Intent.EXTRA_DOCK_STATE_UNDOCKED);
4834 int config;
4835 switch (dockState) {
4836 case Intent.EXTRA_DOCK_STATE_DESK:
4837 config = AudioSystem.FORCE_BT_DESK_DOCK;
4838 break;
4839 case Intent.EXTRA_DOCK_STATE_CAR:
4840 config = AudioSystem.FORCE_BT_CAR_DOCK;
4841 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004842 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08004843 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004844 break;
4845 case Intent.EXTRA_DOCK_STATE_HE_DESK:
4846 config = AudioSystem.FORCE_DIGITAL_DOCK;
4847 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004848 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4849 default:
4850 config = AudioSystem.FORCE_NONE;
4851 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08004852 // Low end docks have a menu to enable or disable audio
4853 // (see mDockAudioMediaEnabled)
4854 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
4855 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
4856 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
4857 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
4858 }
4859 mDockState = dockState;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004860 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
Eric Laurent59f48272012-04-05 19:42:21 -07004861 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004862 BluetoothProfile.STATE_DISCONNECTED);
Eric Laurentae4506e2014-05-29 16:04:32 -07004863 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
4864 inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
Nick Pellya56d1c72009-08-19 14:49:29 -07004865 String address = null;
Eric Laurentdca56b92011-09-02 14:20:56 -07004866
4867 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
4868 if (btDevice == null) {
4869 return;
4870 }
4871
4872 address = btDevice.getAddress();
4873 BluetoothClass btClass = btDevice.getBluetoothClass();
4874 if (btClass != null) {
4875 switch (btClass.getDeviceClass()) {
4876 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
4877 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
Eric Laurentae4506e2014-05-29 16:04:32 -07004878 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurentdca56b92011-09-02 14:20:56 -07004879 break;
4880 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
Eric Laurentae4506e2014-05-29 16:04:32 -07004881 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurentdca56b92011-09-02 14:20:56 -07004882 break;
Eric Laurentd5603c12009-08-06 08:49:39 -07004883 }
4884 }
4885
Eric Laurentdca56b92011-09-02 14:20:56 -07004886 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4887 address = "";
4888 }
Eric Laurentd5603c12009-08-06 08:49:39 -07004889
Eric Laurent59f48272012-04-05 19:42:21 -07004890 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
Paul McLean10804eb2015-01-28 11:16:35 -08004891 boolean success =
4892 handleDeviceConnection(connected, outDevice, address, "Bluetooth Headset") &&
4893 handleDeviceConnection(connected, inDevice, address, "Bluetooth Headset");
Eric Laurentae4506e2014-05-29 16:04:32 -07004894 if (success) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004895 synchronized (mScoClients) {
Eric Laurent59f48272012-04-05 19:42:21 -07004896 if (connected) {
4897 mBluetoothHeadsetDevice = btDevice;
4898 } else {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004899 mBluetoothHeadsetDevice = null;
4900 resetBluetoothSco();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004901 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004902 }
Eric Laurenta553c252009-07-17 12:17:14 -07004903 }
Paul McLeandf361462014-04-10 16:02:55 -07004904 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004905 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07004906 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004907 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004908 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07004909 // broadcast intent if the connection was initated by AudioService
4910 if (!mScoClients.isEmpty() &&
4911 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
4912 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
4913 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004914 broadcast = true;
4915 }
4916 switch (btState) {
4917 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004918 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07004919 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4920 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4921 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004922 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004923 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004924 break;
4925 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004926 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08004927 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07004928 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08004929 break;
4930 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07004931 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4932 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4933 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004934 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004935 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004936 default:
4937 // do not broadcast CONNECTING or invalid state
4938 broadcast = false;
4939 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004940 }
4941 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004942 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07004943 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07004944 //FIXME: this is to maintain compatibility with deprecated intent
4945 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08004946 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07004947 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004948 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08004949 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004950 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06004951 if (mMonitorRotation) {
4952 mOrientationListener.onOrientationChanged(0); //argument is ignored anyway
4953 mOrientationListener.enable();
4954 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004955 AudioSystem.setParameters("screen_state=on");
4956 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06004957 if (mMonitorRotation) {
4958 //reduce wakeups (save current) by only listening when display is on
4959 mOrientationListener.disable();
4960 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004961 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07004962 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004963 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004964 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004965 // attempt to stop music playback for background user
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004966 sendMsg(mAudioHandler,
4967 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4968 SENDMSG_REPLACE,
4969 0,
4970 0,
4971 null,
4972 0);
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004973 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004974 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004975
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004976 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004977 readAudioSettings(true /*userSwitch*/);
4978 // preserve STREAM_MUSIC volume from one user to the next.
4979 sendMsg(mAudioHandler,
4980 MSG_SET_ALL_VOLUMES,
4981 SENDMSG_QUEUE,
4982 0,
4983 0,
4984 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Eric Laurenta553c252009-07-17 12:17:14 -07004985 }
4986 }
Paul McLeanc837a452014-04-09 09:04:43 -07004987 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004988
4989 //==========================================================================================
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004990 // RemoteControlDisplay / RemoteControlClient / Remote info
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004991 //==========================================================================================
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004992 public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
4993 ComponentName listenerComp) {
4994 return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
4995 }
4996
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004997 public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004998 return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004999 }
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005000
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005001 public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005002 mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005003 }
5004
5005 public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005006 mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005007 }
5008
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07005009 public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
5010 boolean wantsSync) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005011 mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
5012 }
5013
John Spurlock3346a802014-05-20 16:25:37 -04005014 @Override
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005015 public void setRemoteStreamVolume(int index) {
John Spurlock3346a802014-05-20 16:25:37 -04005016 enforceSelfOrSystemUI("set the remote stream volume");
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005017 mMediaFocusControl.setRemoteStreamVolume(index);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005018 }
5019
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005020 //==========================================================================================
5021 // Audio Focus
5022 //==========================================================================================
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005023 public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005024 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005025 IAudioPolicyCallback pcb) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005026 // permission checks
5027 if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
John Spurlock61560172015-02-06 19:46:04 -05005028 if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005029 if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
5030 android.Manifest.permission.MODIFY_PHONE_STATE)) {
5031 Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
5032 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5033 }
5034 } else {
5035 // only a registered audio policy can be used to lock focus
5036 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005037 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
5038 Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005039 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5040 }
5041 }
5042 }
5043 }
5044
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005045 return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
5046 clientId, callingPackageName, flags);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005047 }
5048
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005049 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
5050 return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005051 }
5052
5053 public void unregisterAudioFocusClient(String clientId) {
5054 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005055 }
5056
Jean-Michel Trivi23805662013-07-31 14:19:18 -07005057 public int getCurrentAudioFocus() {
5058 return mMediaFocusControl.getCurrentAudioFocus();
5059 }
5060
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005061 //==========================================================================================
5062 // Device orientation
5063 //==========================================================================================
5064 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005065 * Handles device configuration changes that may map to a change in the orientation
5066 * or orientation.
5067 * Monitoring orientation and rotation is optional, and is defined by the definition and value
5068 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005069 */
5070 private void handleConfigurationChanged(Context context) {
5071 try {
5072 // reading new orientation "safely" (i.e. under try catch) in case anything
5073 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07005074 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005075 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07005076 if (mMonitorOrientation) {
5077 int newOrientation = config.orientation;
5078 if (newOrientation != mDeviceOrientation) {
5079 mDeviceOrientation = newOrientation;
5080 setOrientationForAudioSystem();
5081 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005082 }
Eric Laurentd640bd32012-09-28 18:01:48 -07005083 sendMsg(mAudioHandler,
5084 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
5085 SENDMSG_REPLACE,
5086 0,
5087 0,
5088 null,
5089 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07005090
5091 boolean cameraSoundForced = mContext.getResources().getBoolean(
5092 com.android.internal.R.bool.config_camera_sound_forced);
5093 synchronized (mSettingsLock) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005094 boolean cameraSoundForcedChanged = false;
Eric Laurentdd45d012012-10-08 09:04:34 -07005095 synchronized (mCameraSoundForced) {
5096 if (cameraSoundForced != mCameraSoundForced) {
5097 mCameraSoundForced = cameraSoundForced;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005098 cameraSoundForcedChanged = true;
Eric Laurentdd45d012012-10-08 09:04:34 -07005099 }
5100 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005101 if (cameraSoundForcedChanged) {
5102 if (!isPlatformTelevision()) {
5103 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
5104 if (cameraSoundForced) {
5105 s.setAllIndexesToMax();
5106 mRingerModeAffectedStreams &=
5107 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5108 } else {
5109 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
5110 mRingerModeAffectedStreams |=
5111 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5112 }
5113 // take new state into account for streams muted by ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05005114 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005115 }
5116
5117 sendMsg(mAudioHandler,
5118 MSG_SET_FORCE_USE,
5119 SENDMSG_QUEUE,
5120 AudioSystem.FOR_SYSTEM,
5121 cameraSoundForced ?
5122 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
5123 null,
5124 0);
5125
5126 sendMsg(mAudioHandler,
5127 MSG_SET_ALL_VOLUMES,
5128 SENDMSG_QUEUE,
5129 0,
5130 0,
5131 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
5132 }
Eric Laurentdd45d012012-10-08 09:04:34 -07005133 }
John Spurlock3346a802014-05-20 16:25:37 -04005134 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005135 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005136 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005137 }
5138 }
5139
5140 private void setOrientationForAudioSystem() {
5141 switch (mDeviceOrientation) {
5142 case Configuration.ORIENTATION_LANDSCAPE:
5143 //Log.i(TAG, "orientation is landscape");
5144 AudioSystem.setParameters("orientation=landscape");
5145 break;
5146 case Configuration.ORIENTATION_PORTRAIT:
5147 //Log.i(TAG, "orientation is portrait");
5148 AudioSystem.setParameters("orientation=portrait");
5149 break;
5150 case Configuration.ORIENTATION_SQUARE:
5151 //Log.i(TAG, "orientation is square");
5152 AudioSystem.setParameters("orientation=square");
5153 break;
5154 case Configuration.ORIENTATION_UNDEFINED:
5155 //Log.i(TAG, "orientation is undefined");
5156 AudioSystem.setParameters("orientation=undefined");
5157 break;
5158 default:
5159 Log.e(TAG, "Unknown orientation");
5160 }
5161 }
5162
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005163 private void setRotationForAudioSystem() {
5164 switch (mDeviceRotation) {
5165 case Surface.ROTATION_0:
5166 AudioSystem.setParameters("rotation=0");
5167 break;
5168 case Surface.ROTATION_90:
5169 AudioSystem.setParameters("rotation=90");
5170 break;
5171 case Surface.ROTATION_180:
5172 AudioSystem.setParameters("rotation=180");
5173 break;
5174 case Surface.ROTATION_270:
5175 AudioSystem.setParameters("rotation=270");
5176 break;
5177 default:
5178 Log.e(TAG, "Unknown device rotation");
5179 }
5180 }
5181
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005182
Eric Laurent78472112012-05-21 08:57:21 -07005183 // Handles request to override default use of A2DP for media.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005184 // Must be called synchronized on mConnectedDevices
Eric Laurent78472112012-05-21 08:57:21 -07005185 public void setBluetoothA2dpOnInt(boolean on) {
5186 synchronized (mBluetoothA2dpEnabledLock) {
5187 mBluetoothA2dpEnabled = on;
Eric Laurentc390bed2012-07-03 12:24:05 -07005188 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005189 setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
Eric Laurentc390bed2012-07-03 12:24:05 -07005190 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
Eric Laurent78472112012-05-21 08:57:21 -07005191 }
5192 }
5193
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005194 // Must be called synchronized on mConnectedDevices
5195 private void setForceUseInt_SyncDevices(int usage, int config) {
5196 switch (usage) {
5197 case AudioSystem.FOR_MEDIA:
5198 if (config == AudioSystem.FORCE_NO_BT_A2DP) {
5199 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ALL_A2DP;
5200 } else { // config == AudioSystem.FORCE_NONE
5201 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
5202 }
5203 break;
5204 case AudioSystem.FOR_DOCK:
5205 if (config == AudioSystem.FORCE_ANALOG_DOCK) {
5206 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5207 } else { // config == AudioSystem.FORCE_NONE
5208 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5209 }
5210 break;
5211 default:
5212 // usage doesn't affect the broadcast of ACTION_AUDIO_BECOMING_NOISY
5213 }
5214 AudioSystem.setForceUse(usage, config);
5215 }
5216
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005217 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07005218 public void setRingtonePlayer(IRingtonePlayer player) {
5219 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5220 mRingtonePlayer = player;
5221 }
5222
5223 @Override
5224 public IRingtonePlayer getRingtonePlayer() {
5225 return mRingtonePlayer;
5226 }
5227
5228 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07005229 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5230 synchronized (mCurAudioRoutes) {
5231 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5232 mRoutesObservers.register(observer);
5233 return routes;
5234 }
5235 }
5236
Eric Laurentc34dcc12012-09-10 13:51:52 -07005237
5238 //==========================================================================================
5239 // Safe media volume management.
5240 // MUSIC stream volume level is limited when headphones are connected according to safety
5241 // regulation. When the user attempts to raise the volume above the limit, a warning is
5242 // displayed and the user has to acknowlegde before the volume is actually changed.
5243 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
5244 // property. Platforms with a different limit must set this property accordingly in their
5245 // overlay.
5246 //==========================================================================================
5247
Eric Laurentd640bd32012-09-28 18:01:48 -07005248 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
5249 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
5250 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
5251 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
5252 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
5253 // (when user opts out).
John Spurlock35134602014-07-24 18:10:48 -04005254 private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
5255 private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
5256 private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed
5257 private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
Eric Laurentd640bd32012-09-28 18:01:48 -07005258 private Integer mSafeMediaVolumeState;
5259
5260 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005261 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07005262 private int mSafeMediaVolumeIndex;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005263 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
5264 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
5265 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
5266 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
5267 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
5268 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
5269 private int mMusicActiveMs;
5270 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
5271 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07005272 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07005273
5274 private void setSafeMediaVolumeEnabled(boolean on) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005275 synchronized (mSafeMediaVolumeState) {
5276 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
5277 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
5278 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
5279 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
5280 enforceSafeMediaVolume();
5281 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
5282 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005283 mMusicActiveMs = 1; // nonzero = confirmed
5284 saveMusicActiveMs();
Eric Laurentd640bd32012-09-28 18:01:48 -07005285 sendMsg(mAudioHandler,
5286 MSG_CHECK_MUSIC_ACTIVE,
5287 SENDMSG_REPLACE,
5288 0,
5289 0,
5290 null,
5291 MUSIC_ACTIVE_POLL_PERIOD_MS);
5292 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005293 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005294 }
5295 }
5296
5297 private void enforceSafeMediaVolume() {
5298 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07005299 int devices = mSafeMediaVolumeDevices;
5300 int i = 0;
5301
5302 while (devices != 0) {
5303 int device = 1 << i++;
5304 if ((device & devices) == 0) {
5305 continue;
5306 }
Eric Laurent42b041e2013-03-29 11:36:03 -07005307 int index = streamState.getIndex(device);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005308 if (index > mSafeMediaVolumeIndex) {
Eric Laurent42b041e2013-03-29 11:36:03 -07005309 streamState.setIndex(mSafeMediaVolumeIndex, device);
5310 sendMsg(mAudioHandler,
5311 MSG_SET_DEVICE_VOLUME,
5312 SENDMSG_QUEUE,
5313 device,
5314 0,
5315 streamState,
5316 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005317 }
5318 devices &= ~device;
5319 }
5320 }
5321
5322 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005323 synchronized (mSafeMediaVolumeState) {
5324 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07005325 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
5326 ((device & mSafeMediaVolumeDevices) != 0) &&
5327 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005328 return false;
5329 }
5330 return true;
5331 }
5332 }
5333
John Spurlock3346a802014-05-20 16:25:37 -04005334 @Override
Eric Laurentc34dcc12012-09-10 13:51:52 -07005335 public void disableSafeMediaVolume() {
John Spurlock3346a802014-05-20 16:25:37 -04005336 enforceSelfOrSystemUI("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07005337 synchronized (mSafeMediaVolumeState) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005338 setSafeMediaVolumeEnabled(false);
Eric Laurentfde16d52012-12-03 14:42:39 -08005339 if (mPendingVolumeCommand != null) {
5340 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
5341 mPendingVolumeCommand.mIndex,
5342 mPendingVolumeCommand.mFlags,
5343 mPendingVolumeCommand.mDevice);
5344 mPendingVolumeCommand = null;
5345 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005346 }
5347 }
5348
Jungshik Jang41d97462014-06-30 22:26:29 +09005349 //==========================================================================================
5350 // Hdmi Cec system audio mode.
5351 // If Hdmi Cec's system audio mode is on, audio service should notify volume change
5352 // to HdmiControlService so that audio recevier can handle volume change.
5353 //==========================================================================================
5354
Eric Laurent212532b2014-07-21 15:43:18 -07005355 private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
5356 public void onComplete(int status) {
5357 if (mHdmiManager != null) {
5358 synchronized (mHdmiManager) {
5359 mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
5360 // Television devices without CEC service apply software volume on HDMI output
5361 if (isPlatformTelevision() && !mHdmiCecSink) {
5362 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5363 }
5364 checkAllFixedVolumeDevices();
5365 }
5366 }
5367 }
5368 };
5369
Jungshik Jang41d97462014-06-30 22:26:29 +09005370 // If HDMI-CEC system audio is supported
5371 private boolean mHdmiSystemAudioSupported = false;
5372 // Set only when device is tv.
5373 private HdmiTvClient mHdmiTvClient;
Eric Laurent0b03f992014-11-18 18:08:02 -08005374 // true if the device has system feature PackageManager.FEATURE_LEANBACK.
Eric Laurent212532b2014-07-21 15:43:18 -07005375 // cached HdmiControlManager interface
5376 private HdmiControlManager mHdmiManager;
5377 // Set only when device is a set-top box.
5378 private HdmiPlaybackClient mHdmiPlaybackClient;
5379 // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5380 private boolean mHdmiCecSink;
5381
5382 private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
Jungshik Jang41d97462014-06-30 22:26:29 +09005383
5384 @Override
Jungshik Jang12307ca2014-07-15 19:27:56 +09005385 public int setHdmiSystemAudioSupported(boolean on) {
Eric Laurent212532b2014-07-21 15:43:18 -07005386 int device = AudioSystem.DEVICE_NONE;
5387 if (mHdmiManager != null) {
5388 synchronized (mHdmiManager) {
5389 if (mHdmiTvClient == null) {
5390 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5391 return device;
5392 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005393
Eric Laurent212532b2014-07-21 15:43:18 -07005394 synchronized (mHdmiTvClient) {
5395 if (mHdmiSystemAudioSupported != on) {
5396 mHdmiSystemAudioSupported = on;
5397 AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5398 on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5399 AudioSystem.FORCE_NONE);
5400 }
5401 device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
5402 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005403 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005404 }
Eric Laurent212532b2014-07-21 15:43:18 -07005405 return device;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005406 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005407
Terry Heoe7d6d972014-09-04 21:05:28 +09005408 @Override
5409 public boolean isHdmiSystemAudioSupported() {
5410 return mHdmiSystemAudioSupported;
5411 }
5412
Eric Laurentdd45d012012-10-08 09:04:34 -07005413 //==========================================================================================
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005414 // Accessibility: taking touch exploration into account for selecting the default
5415 // stream override timeout when adjusting volume
5416 //==========================================================================================
5417 private static class StreamOverride
5418 implements AccessibilityManager.TouchExplorationStateChangeListener {
5419
5420 // AudioService.getActiveStreamType() will return:
5421 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
5422 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
5423 // stopped
5424 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
5425 private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
5426
5427 static int sDelayMs;
5428
5429 static void init(Context ctxt) {
5430 AccessibilityManager accessibilityManager =
5431 (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
5432 updateDefaultStreamOverrideDelay(
5433 accessibilityManager.isTouchExplorationEnabled());
5434 accessibilityManager.addTouchExplorationStateChangeListener(
5435 new StreamOverride());
5436 }
5437
5438 @Override
5439 public void onTouchExplorationStateChanged(boolean enabled) {
5440 updateDefaultStreamOverrideDelay(enabled);
5441 }
5442
5443 private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
5444 if (touchExploreEnabled) {
5445 sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
5446 } else {
5447 sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
5448 }
5449 if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
5450 + " stream override delay is now " + sDelayMs + " ms");
5451 }
5452 }
5453
5454 //==========================================================================================
Eric Laurentdd45d012012-10-08 09:04:34 -07005455 // Camera shutter sound policy.
5456 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5457 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5458 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5459 //==========================================================================================
5460
5461 // cached value of com.android.internal.R.bool.config_camera_sound_forced
5462 private Boolean mCameraSoundForced;
5463
5464 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5465 public boolean isCameraSoundForced() {
5466 synchronized (mCameraSoundForced) {
5467 return mCameraSoundForced;
5468 }
5469 }
5470
5471 private static final String[] RINGER_MODE_NAMES = new String[] {
5472 "SILENT",
5473 "VIBRATE",
5474 "NORMAL"
5475 };
5476
5477 private void dumpRingerMode(PrintWriter pw) {
5478 pw.println("\nRinger mode: ");
John Spurlock661f2cf2014-11-17 10:29:10 -05005479 pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
5480 pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
Eric Laurentdd45d012012-10-08 09:04:34 -07005481 pw.print("- ringer mode affected streams = 0x");
5482 pw.println(Integer.toHexString(mRingerModeAffectedStreams));
5483 pw.print("- ringer mode muted streams = 0x");
5484 pw.println(Integer.toHexString(mRingerModeMutedStreams));
John Spurlock661f2cf2014-11-17 10:29:10 -05005485 pw.print("- delegate = "); pw.println(mRingerModeDelegate);
Eric Laurentdd45d012012-10-08 09:04:34 -07005486 }
5487
Dianne Hackborn632ca412012-06-14 19:34:10 -07005488 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005489 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07005490 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5491
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005492 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07005493 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07005494 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005495 pw.println("\nAudio routes:");
John Spurlock61560172015-02-06 19:46:04 -05005496 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
5497 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
John Spurlock35134602014-07-24 18:10:48 -04005498
5499 pw.println("\nOther state:");
John Spurlock3346a802014-05-20 16:25:37 -04005500 pw.print(" mVolumeController="); pw.println(mVolumeController);
John Spurlock35134602014-07-24 18:10:48 -04005501 pw.print(" mSafeMediaVolumeState=");
5502 pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
5503 pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
5504 pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
5505 pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005506 pw.print(" mMcc="); pw.println(mMcc);
John Spurlock661f2cf2014-11-17 10:29:10 -05005507 pw.print(" mHasVibrator="); pw.println(mHasVibrator);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005508
5509 dumpAudioPolicies(pw);
John Spurlock35134602014-07-24 18:10:48 -04005510 }
5511
5512 private static String safeMediaVolumeStateToString(Integer state) {
5513 switch(state) {
5514 case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
5515 case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
5516 case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
5517 case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
5518 }
5519 return null;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005520 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07005521
5522 // Inform AudioFlinger of our device's low RAM attribute
5523 private static void readAndSetLowRamDevice()
5524 {
5525 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
5526 if (status != 0) {
5527 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
5528 }
5529 }
John Spurlock3346a802014-05-20 16:25:37 -04005530
5531 private void enforceSelfOrSystemUI(String action) {
5532 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
5533 "Only SystemUI can " + action);
5534 }
5535
5536 @Override
5537 public void setVolumeController(final IVolumeController controller) {
5538 enforceSelfOrSystemUI("set the volume controller");
5539
5540 // return early if things are not actually changing
5541 if (mVolumeController.isSameBinder(controller)) {
5542 return;
5543 }
5544
5545 // dismiss the old volume controller
5546 mVolumeController.postDismiss();
5547 if (controller != null) {
5548 // we are about to register a new controller, listen for its death
5549 try {
5550 controller.asBinder().linkToDeath(new DeathRecipient() {
5551 @Override
5552 public void binderDied() {
5553 if (mVolumeController.isSameBinder(controller)) {
5554 Log.w(TAG, "Current remote volume controller died, unregistering");
5555 setVolumeController(null);
5556 }
5557 }
5558 }, 0);
5559 } catch (RemoteException e) {
5560 // noop
5561 }
5562 }
5563 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04005564 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
5565 }
5566
5567 @Override
5568 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
5569 enforceSelfOrSystemUI("notify about volume controller visibility");
5570
5571 // return early if the controller is not current
5572 if (!mVolumeController.isSameBinder(controller)) {
5573 return;
5574 }
5575
5576 mVolumeController.setVisible(visible);
5577 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04005578 }
RoboErikd09bd0c2014-06-24 17:45:19 -07005579
5580 public static class VolumeController {
5581 private static final String TAG = "VolumeController";
5582
5583 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04005584 private boolean mVisible;
5585 private long mNextLongPress;
5586 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07005587
5588 public void setController(IVolumeController controller) {
5589 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04005590 mVisible = false;
5591 }
5592
5593 public void loadSettings(ContentResolver cr) {
5594 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
5595 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
5596 }
5597
RoboErik4197cb62015-01-21 15:45:32 -08005598 public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
5599 if (isMute) {
5600 return false;
5601 }
John Spurlock33f4e042014-07-11 13:10:58 -04005602 boolean suppress = false;
5603 if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
5604 final long now = SystemClock.uptimeMillis();
5605 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
5606 // ui will become visible
5607 if (mNextLongPress < now) {
5608 mNextLongPress = now + mLongPressTimeout;
5609 }
5610 suppress = true;
5611 } else if (mNextLongPress > 0) { // in a long-press
5612 if (now > mNextLongPress) {
5613 // long press triggered, no more suppression
5614 mNextLongPress = 0;
5615 } else {
5616 // keep suppressing until the long press triggers
5617 suppress = true;
5618 }
5619 }
5620 }
5621 return suppress;
5622 }
5623
5624 public void setVisible(boolean visible) {
5625 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07005626 }
5627
5628 public boolean isSameBinder(IVolumeController controller) {
5629 return Objects.equals(asBinder(), binder(controller));
5630 }
5631
5632 public IBinder asBinder() {
5633 return binder(mController);
5634 }
5635
5636 private static IBinder binder(IVolumeController controller) {
5637 return controller == null ? null : controller.asBinder();
5638 }
5639
5640 @Override
5641 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04005642 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07005643 }
5644
5645 public void postDisplaySafeVolumeWarning(int flags) {
5646 if (mController == null)
5647 return;
5648 try {
5649 mController.displaySafeVolumeWarning(flags);
5650 } catch (RemoteException e) {
5651 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
5652 }
5653 }
5654
5655 public void postVolumeChanged(int streamType, int flags) {
5656 if (mController == null)
5657 return;
5658 try {
5659 mController.volumeChanged(streamType, flags);
5660 } catch (RemoteException e) {
5661 Log.w(TAG, "Error calling volumeChanged", e);
5662 }
5663 }
5664
5665 public void postMasterVolumeChanged(int flags) {
5666 if (mController == null)
5667 return;
5668 try {
5669 mController.masterVolumeChanged(flags);
5670 } catch (RemoteException e) {
5671 Log.w(TAG, "Error calling masterVolumeChanged", e);
5672 }
5673 }
5674
5675 public void postMasterMuteChanged(int flags) {
5676 if (mController == null)
5677 return;
5678 try {
5679 mController.masterMuteChanged(flags);
5680 } catch (RemoteException e) {
5681 Log.w(TAG, "Error calling masterMuteChanged", e);
5682 }
5683 }
5684
5685 public void setLayoutDirection(int layoutDirection) {
5686 if (mController == null)
5687 return;
5688 try {
5689 mController.setLayoutDirection(layoutDirection);
5690 } catch (RemoteException e) {
5691 Log.w(TAG, "Error calling setLayoutDirection", e);
5692 }
5693 }
5694
5695 public void postDismiss() {
5696 if (mController == null)
5697 return;
5698 try {
5699 mController.dismiss();
5700 } catch (RemoteException e) {
5701 Log.w(TAG, "Error calling dismiss", e);
5702 }
5703 }
5704 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005705
RoboErik0dac35a2014-08-12 15:48:49 -07005706 /**
5707 * Interface for system components to get some extra functionality through
5708 * LocalServices.
5709 */
5710 final class AudioServiceInternal extends AudioManagerInternal {
John Spurlock661f2cf2014-11-17 10:29:10 -05005711 @Override
5712 public void setRingerModeDelegate(RingerModeDelegate delegate) {
5713 mRingerModeDelegate = delegate;
5714 if (mRingerModeDelegate != null) {
5715 setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
5716 }
5717 }
RoboErik272e1612014-09-05 11:39:29 -07005718
5719 @Override
5720 public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
5721 String callingPackage, int uid) {
5722 // direction and stream type swap here because the public
5723 // adjustSuggested has a different order than the other methods.
5724 adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage, uid);
5725 }
5726
RoboErik0dac35a2014-08-12 15:48:49 -07005727 @Override
5728 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
5729 String callingPackage, int uid) {
5730 adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
5731 }
5732
5733 @Override
5734 public void setStreamVolumeForUid(int streamType, int direction, int flags,
5735 String callingPackage, int uid) {
5736 setStreamVolume(streamType, direction, flags, callingPackage, uid);
5737 }
RoboErik519c7742014-11-18 10:59:09 -08005738
5739 @Override
5740 public void adjustMasterVolumeForUid(int steps, int flags, String callingPackage,
5741 int uid) {
5742 adjustMasterVolume(steps, flags, callingPackage, uid);
5743 }
John Spurlock661f2cf2014-11-17 10:29:10 -05005744
5745 @Override
5746 public int getRingerModeInternal() {
5747 return AudioService.this.getRingerModeInternal();
5748 }
5749
5750 @Override
5751 public void setRingerModeInternal(int ringerMode, String caller) {
5752 AudioService.this.setRingerModeInternal(ringerMode, caller);
5753 }
RoboErik0dac35a2014-08-12 15:48:49 -07005754 }
5755
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005756 //==========================================================================================
5757 // Audio policy management
5758 //==========================================================================================
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005759 public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
5760 boolean hasFocusListener) {
5761 if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
5762 + " with config:" + policyConfig);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005763 String regId = null;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005764 // error handling
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005765 boolean hasPermissionForPolicy =
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005766 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005767 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5768 if (!hasPermissionForPolicy) {
5769 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
5770 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005771 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005772 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005773
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005774 synchronized (mAudioPolicies) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005775 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005776 if (mAudioPolicies.containsKey(pcb.asBinder())) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005777 Slog.e(TAG, "Cannot re-register policy");
5778 return null;
5779 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005780 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
5781 pcb.asBinder().linkToDeath(app, 0/*flags*/);
5782 regId = app.getRegistrationId();
5783 mAudioPolicies.put(pcb.asBinder(), app);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005784 } catch (RemoteException e) {
5785 // audio policy owner has already died!
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005786 Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005787 " binder death", e);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005788 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005789 }
5790 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005791 return regId;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005792 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005793
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005794 public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
5795 if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005796 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005797 AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005798 if (app == null) {
5799 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
5800 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005801 return;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005802 } else {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005803 pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005804 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005805 app.release();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005806 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005807 // TODO implement clearing mix attribute matching info in native audio policy
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005808 }
5809
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005810 public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
5811 if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
5812 + " policy " + pcb.asBinder());
5813 // error handling
5814 boolean hasPermissionForPolicy =
5815 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
5816 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5817 if (!hasPermissionForPolicy) {
5818 Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
5819 + Binder.getCallingPid() + " / uid "
5820 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
5821 return AudioManager.ERROR;
5822 }
5823
5824 synchronized (mAudioPolicies) {
5825 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
5826 Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
5827 return AudioManager.ERROR;
5828 }
5829 final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
5830 if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5831 // is there already one policy managing ducking?
5832 for(AudioPolicyProxy policy : mAudioPolicies.values()) {
5833 if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5834 Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
5835 return AudioManager.ERROR;
5836 }
5837 }
5838 }
5839 app.mFocusDuckBehavior = duckingBehavior;
5840 mMediaFocusControl.setDuckingInExtPolicyAvailable(
5841 duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
5842 }
5843 return AudioManager.SUCCESS;
5844 }
5845
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005846 private void dumpAudioPolicies(PrintWriter pw) {
5847 pw.println("\nAudio policies:");
5848 synchronized (mAudioPolicies) {
5849 for(AudioPolicyProxy policy : mAudioPolicies.values()) {
5850 pw.println(policy.toLogFriendlyString());
5851 }
5852 }
5853 }
5854
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005855 //======================
5856 // Audio policy proxy
5857 //======================
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005858 /**
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005859 * This internal class inherits from AudioPolicyConfig, each instance contains all the
5860 * mixes of an AudioPolicy and their configurations.
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005861 */
5862 public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005863 private static final String TAG = "AudioPolicyProxy";
5864 AudioPolicyConfig mConfig;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005865 IAudioPolicyCallback mPolicyToken;
5866 boolean mHasFocusListener;
5867 /**
5868 * Audio focus ducking behavior for an audio policy.
5869 * This variable reflects the value that was successfully set in
5870 * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
5871 * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
5872 * is handling ducking for audio focus.
5873 */
5874 int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
5875
5876 AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
5877 boolean hasFocusListener) {
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005878 super(config);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005879 setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005880 mPolicyToken = token;
5881 mHasFocusListener = hasFocusListener;
5882 if (mHasFocusListener) {
5883 mMediaFocusControl.addFocusFollower(mPolicyToken);
5884 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08005885 connectMixes();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005886 }
5887
5888 public void binderDied() {
5889 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005890 Log.i(TAG, "audio policy " + mPolicyToken + " died");
5891 release();
5892 mAudioPolicies.remove(mPolicyToken.asBinder());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005893 }
5894 }
5895
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005896 String getRegistrationId() {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005897 return getRegistration();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005898 }
5899
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005900 void release() {
5901 if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5902 mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
5903 }
5904 if (mHasFocusListener) {
5905 mMediaFocusControl.removeFocusFollower(mPolicyToken);
5906 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08005907 AudioSystem.registerPolicyMixes(mMixes, false);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005908 }
5909
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08005910 void connectMixes() {
5911 AudioSystem.registerPolicyMixes(mMixes, true);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005912 }
5913 };
5914
5915 private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
5916 new HashMap<IBinder, AudioPolicyProxy>();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005917 private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005918}