blob: 95cbf10dc6e9599d6ccb3f929950c9d5b47b4017 [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;
Fyodor Kupolovbcb6c1e2015-05-11 12:05:15 -070023import static android.os.Process.FIRST_APPLICATION_UID;
Amith Yamasanic696a532011-10-28 17:02:37 -070024
Fyodor Kupolovb5013302015-04-17 17:59:14 -070025import android.Manifest;
Glenn Kastenfd116ad2013-07-12 17:10:39 -070026import android.app.ActivityManager;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070027import android.app.ActivityManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.app.ActivityManagerNative;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070029import android.app.AppGlobals;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -070030import android.app.AppOpsManager;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070031import android.bluetooth.BluetoothA2dp;
32import android.bluetooth.BluetoothAdapter;
33import android.bluetooth.BluetoothClass;
34import android.bluetooth.BluetoothDevice;
35import android.bluetooth.BluetoothHeadset;
36import android.bluetooth.BluetoothProfile;
Nick Pellybd022f42009-08-14 18:33:38 -070037import android.content.BroadcastReceiver;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070038import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.content.ContentResolver;
40import android.content.Context;
41import android.content.Intent;
Eric Laurenta553c252009-07-17 12:17:14 -070042import android.content.IntentFilter;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070043import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.content.pm.PackageManager;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070045import android.content.pm.UserInfo;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -070046import android.content.res.Configuration;
Eric Laurente78fced2013-03-15 16:03:47 -070047import android.content.res.Resources;
48import android.content.res.XmlResourceParser;
Jason Parekhb1096152009-03-24 17:48:25 -070049import android.database.ContentObserver;
Jungshik Jang41d97462014-06-30 22:26:29 +090050import android.hardware.hdmi.HdmiControlManager;
Eric Laurent212532b2014-07-21 15:43:18 -070051import android.hardware.hdmi.HdmiPlaybackClient;
Jungshik Jang41d97462014-06-30 22:26:29 +090052import android.hardware.hdmi.HdmiTvClient;
Paul McLeanc837a452014-04-09 09:04:43 -070053import android.hardware.usb.UsbManager;
John Spurlock61560172015-02-06 19:46:04 -050054import android.media.AudioAttributes;
55import android.media.AudioDevicePort;
56import android.media.AudioSystem;
57import android.media.AudioFormat;
58import android.media.AudioManager;
59import android.media.AudioManagerInternal;
60import android.media.AudioPort;
61import android.media.AudioRoutesInfo;
John Spurlock61560172015-02-06 19:46:04 -050062import android.media.IAudioFocusDispatcher;
63import android.media.IAudioRoutesObserver;
64import android.media.IAudioService;
65import android.media.IRemoteControlDisplay;
66import android.media.IRingtonePlayer;
67import android.media.IVolumeController;
68import android.media.MediaPlayer;
69import android.media.SoundPool;
John Spurlocka48d7792015-03-03 17:35:57 -050070import android.media.VolumePolicy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071import android.media.MediaPlayer.OnCompletionListener;
72import android.media.MediaPlayer.OnErrorListener;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -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;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070090import android.os.UserManager;
Eric Laurentbffc3d12012-05-07 17:43:49 -070091import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092import android.provider.Settings;
93import android.provider.Settings.System;
Tyler Gunnef9f6f92014-09-12 22:16:17 -070094import android.telecom.TelecomManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070095import android.text.TextUtils;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070096import android.util.AndroidRuntimeException;
John Spurlock8c3dc852015-04-23 21:32:37 -040097import android.util.ArrayMap;
98import android.util.ArraySet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099import android.util.Log;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400100import android.util.MathUtils;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -0700101import android.util.Slog;
John Spurlock2bb02ec2015-03-02 13:13:06 -0500102import android.util.SparseIntArray;
Jean-Michel Trivid327f212010-03-16 21:44:33 -0700103import android.view.KeyEvent;
RoboErik519c7742014-11-18 10:59:09 -0800104import android.view.OrientationEventListener;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700105import android.view.Surface;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700106import android.view.WindowManager;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700107import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108
Eric Laurente78fced2013-03-15 16:03:47 -0700109import com.android.internal.util.XmlUtils;
John Spurlock90874332015-03-10 16:00:54 -0400110import com.android.server.EventLogTags;
RoboErik0dac35a2014-08-12 15:48:49 -0700111import com.android.server.LocalServices;
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700112import com.android.server.pm.UserManagerService;
Eric Laurente78fced2013-03-15 16:03:47 -0700113
114import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800116import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117import java.io.IOException;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800118import java.io.PrintWriter;
Eric Laurente78fced2013-03-15 16:03:47 -0700119import java.lang.reflect.Field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120import java.util.ArrayList;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700121import java.util.HashMap;
122import java.util.Iterator;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -0700123import java.util.List;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700124import java.util.NoSuchElementException;
RoboErikd09bd0c2014-06-24 17:45:19 -0700125import java.util.Objects;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126
127/**
128 * The implementation of the volume manager service.
129 * <p>
130 * This implementation focuses on delivering a responsive UI. Most methods are
131 * asynchronous to external calls. For example, the task of setting a volume
132 * will update our internal state, but in a separate thread will set the system
133 * volume and later persist to the database. Similarly, setting the ringer mode
134 * will update the state and broadcast a change and in a separate thread later
135 * persist the ringer mode.
136 *
137 * @hide
138 */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700139public class AudioService extends IAudioService.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140
141 private static final String TAG = "AudioService";
142
Jean-Michel Trivi339567d2014-07-29 09:53:34 -0700143 /** Debug audio mode */
144 protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -0700145
146 /** Debug audio policy feature */
147 protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);
148
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700149 /** Debug volumes */
John Spurlockae641c92014-06-30 18:11:40 -0400150 protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700151
Paul McLean394a8e12015-03-03 10:29:19 -0700152 /** debug calls to devices APIs */
153 protected static final boolean DEBUG_DEVICES = Log.isLoggable(TAG + ".DEVICES", Log.DEBUG);
154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 /** How long to delay before persisting a change in volume/ringer mode. */
RoboErik45edba12012-03-27 17:54:36 -0700156 private static final int PERSIST_DELAY = 500;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157
RoboErik5452e252015-02-06 15:33:53 -0800158 /** How long to delay after a volume down event before unmuting a stream */
159 private static final int UNMUTE_STREAM_DELAY = 350;
160
John Spurlock3346a802014-05-20 16:25:37 -0400161 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400162 * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
163 */
164 private static final int FLAG_ADJUST_VOLUME = 1;
165
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700166 private final Context mContext;
167 private final ContentResolver mContentResolver;
168 private final AppOpsManager mAppOps;
Eric Laurent212532b2014-07-21 15:43:18 -0700169
Eric Laurent212532b2014-07-21 15:43:18 -0700170 // the platform type affects volume and silent mode behavior
171 private final int mPlatformType;
172
173 private boolean isPlatformVoice() {
John Spurlock61560172015-02-06 19:46:04 -0500174 return mPlatformType == AudioSystem.PLATFORM_VOICE;
Eric Laurent212532b2014-07-21 15:43:18 -0700175 }
176
177 private boolean isPlatformTelevision() {
John Spurlock61560172015-02-06 19:46:04 -0500178 return mPlatformType == AudioSystem.PLATFORM_TELEVISION;
Eric Laurent212532b2014-07-21 15:43:18 -0700179 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800180
John Spurlock3346a802014-05-20 16:25:37 -0400181 /** The controller for the volume UI. */
182 private final VolumeController mVolumeController = new VolumeController();
John Spurlockcdb57ae2015-02-11 19:04:11 -0500183 private final ControllerService mControllerService = new ControllerService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184
185 // sendMsg() flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 /** If the msg is already queued, replace it with this one. */
187 private static final int SENDMSG_REPLACE = 0;
188 /** If the msg is already queued, ignore this one and leave the old. */
189 private static final int SENDMSG_NOOP = 1;
190 /** If the msg is already queued, queue this one and leave the old. */
191 private static final int SENDMSG_QUEUE = 2;
192
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700193 // AudioHandler messages
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800194 private static final int MSG_SET_DEVICE_VOLUME = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 private static final int MSG_PERSIST_VOLUME = 1;
196 private static final int MSG_PERSIST_RINGER_MODE = 3;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700197 private static final int MSG_MEDIA_SERVER_DIED = 4;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700198 private static final int MSG_PLAY_SOUND_EFFECT = 5;
199 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
200 private static final int MSG_LOAD_SOUND_EFFECTS = 7;
201 private static final int MSG_SET_FORCE_USE = 8;
202 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
203 private static final int MSG_SET_ALL_VOLUMES = 10;
204 private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
205 private static final int MSG_REPORT_NEW_ROUTES = 12;
206 private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
207 private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
208 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
209 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
210 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
211 private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
212 private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
213 private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700214 private static final int MSG_SYSTEM_READY = 21;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400215 private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
Julia Reynoldsb53453f2014-08-22 11:42:43 -0400216 private static final int MSG_PERSIST_MICROPHONE_MUTE = 23;
RoboErik5452e252015-02-06 15:33:53 -0800217 private static final int MSG_UNMUTE_STREAM = 24;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -0700218 private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 25;
Eric Laurent0867bed2015-05-20 14:49:08 -0700219 private static final int MSG_INDICATE_SYSTEM_READY = 26;
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
Eric Laurent0867bed2015-05-20 14:49:08 -0700232 // retry delay in case of failure to indicate system ready to AudioFlinger
233 private static final int INDICATE_SYSTEM_READY_RETRY_DELAY_MS = 1000;
234
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 /** @see AudioSystemThread */
236 private AudioSystemThread mAudioSystemThread;
237 /** @see AudioHandler */
238 private AudioHandler mAudioHandler;
239 /** @see VolumeStreamState */
240 private VolumeStreamState[] mStreamStates;
Jason Parekhb1096152009-03-24 17:48:25 -0700241 private SettingsObserver mSettingsObserver;
Eric Laurenta553c252009-07-17 12:17:14 -0700242
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700243 private int mMode = AudioSystem.MODE_NORMAL;
Glenn Kastenba195eb2011-12-13 09:30:40 -0800244 // protects mRingerMode
245 private final Object mSettingsLock = new Object();
Eric Laurent45c90ce2012-04-24 18:44:22 -0700246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 private SoundPool mSoundPool;
Glenn Kasten30c918c2011-11-10 17:56:41 -0800248 private final Object mSoundEffectsLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 private static final int NUM_SOUNDPOOL_CHANNELS = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250
251 /* Sound effect file names */
252 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
Eric Laurente78fced2013-03-15 16:03:47 -0700253 private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254
255 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
256 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
257 * uses soundpool (second column) */
Eric Laurente78fced2013-03-15 16:03:47 -0700258 private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259
John Spurlockb6e19e32015-03-10 21:33:44 -0400260 /** Maximum volume index values for audio streams */
Eric Laurent91377de2014-10-10 15:24:04 -0700261 private static int[] MAX_STREAM_VOLUME = new int[] {
Eric Laurent6ee99522009-08-25 06:30:59 -0700262 5, // STREAM_VOICE_CALL
263 7, // STREAM_SYSTEM
264 7, // STREAM_RING
265 15, // STREAM_MUSIC
266 7, // STREAM_ALARM
267 7, // STREAM_NOTIFICATION
268 15, // STREAM_BLUETOOTH_SCO
269 7, // STREAM_SYSTEM_ENFORCED
270 15, // STREAM_DTMF
271 15 // STREAM_TTS
Jared Suttles59820132009-08-13 21:50:52 -0500272 };
Eric Laurent91377de2014-10-10 15:24:04 -0700273
John Spurlockb6e19e32015-03-10 21:33:44 -0400274 /** Minimum volume index values for audio streams */
275 private static int[] MIN_STREAM_VOLUME = new int[] {
276 1, // STREAM_VOICE_CALL
277 0, // STREAM_SYSTEM
278 0, // STREAM_RING
279 0, // STREAM_MUSIC
280 0, // STREAM_ALARM
281 0, // STREAM_NOTIFICATION
282 1, // STREAM_BLUETOOTH_SCO
283 0, // STREAM_SYSTEM_ENFORCED
284 0, // STREAM_DTMF
285 0 // STREAM_TTS
286 };
287
Eric Laurent6d517662012-04-23 18:42:39 -0700288 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
Eric Laurenta553c252009-07-17 12:17:14 -0700289 * of another stream: This avoids multiplying the volume settings for hidden
290 * stream types that follow other stream behavior for volume settings
Eric Laurent6d517662012-04-23 18:42:39 -0700291 * NOTE: do not create loops in aliases!
292 * Some streams alias to different streams according to device category (phone or tablet) or
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700293 * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
Eric Laurent212532b2014-07-21 15:43:18 -0700294 * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
295 * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
296 * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
297 private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700298 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
299 AudioSystem.STREAM_RING, // STREAM_SYSTEM
300 AudioSystem.STREAM_RING, // STREAM_RING
301 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
302 AudioSystem.STREAM_ALARM, // STREAM_ALARM
303 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
304 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
305 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
306 AudioSystem.STREAM_RING, // STREAM_DTMF
307 AudioSystem.STREAM_MUSIC // STREAM_TTS
Eric Laurenta553c252009-07-17 12:17:14 -0700308 };
Eric Laurent212532b2014-07-21 15:43:18 -0700309 private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
310 AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL
311 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
312 AudioSystem.STREAM_MUSIC, // STREAM_RING
313 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
314 AudioSystem.STREAM_MUSIC, // STREAM_ALARM
315 AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
316 AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO
317 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
318 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
319 AudioSystem.STREAM_MUSIC // STREAM_TTS
320 };
321 private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700322 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
John Spurlock4f0f1202014-08-05 13:28:33 -0400323 AudioSystem.STREAM_RING, // STREAM_SYSTEM
Eric Laurent6d517662012-04-23 18:42:39 -0700324 AudioSystem.STREAM_RING, // STREAM_RING
325 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
326 AudioSystem.STREAM_ALARM, // STREAM_ALARM
327 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
328 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
John Spurlock4f0f1202014-08-05 13:28:33 -0400329 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
330 AudioSystem.STREAM_RING, // STREAM_DTMF
Eric Laurent6d517662012-04-23 18:42:39 -0700331 AudioSystem.STREAM_MUSIC // STREAM_TTS
332 };
333 private int[] mStreamVolumeAlias;
Eric Laurenta553c252009-07-17 12:17:14 -0700334
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700335 /**
336 * Map AudioSystem.STREAM_* constants to app ops. This should be used
337 * after mapping through mStreamVolumeAlias.
338 */
John Spurlock59dc9c12015-03-02 11:20:15 -0500339 private static final int[] STREAM_VOLUME_OPS = new int[] {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700340 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL
341 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM
342 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING
343 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC
344 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM
345 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION
346 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO
347 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED
348 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF
349 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS
350 };
351
Eric Laurent83a017b2013-03-19 18:15:31 -0700352 private final boolean mUseFixedVolume;
353
Glenn Kasten30c918c2011-11-10 17:56:41 -0800354 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 public void onError(int error) {
356 switch (error) {
357 case AudioSystem.AUDIO_STATUS_SERVER_DIED:
Eric Laurentdfb881f2013-07-18 14:41:39 -0700358 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
359 SENDMSG_NOOP, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 break;
361 default:
362 break;
363 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700364 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 };
366
367 /**
368 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
369 * {@link AudioManager#RINGER_MODE_SILENT}, or
370 * {@link AudioManager#RINGER_MODE_VIBRATE}.
371 */
Glenn Kastenba195eb2011-12-13 09:30:40 -0800372 // protected by mSettingsLock
John Spurlock661f2cf2014-11-17 10:29:10 -0500373 private int mRingerMode; // internal ringer mode, affects muting of underlying streams
374 private int mRingerModeExternal = -1; // reported ringer mode to outside clients (AudioManager)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375
Eric Laurent9bcf4012009-06-12 06:09:28 -0700376 /** @see System#MODE_RINGER_STREAMS_AFFECTED */
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700377 private int mRingerModeAffectedStreams = 0;
Eric Laurent9bcf4012009-06-12 06:09:28 -0700378
Eric Laurent5b4e6542010-03-19 20:02:21 -0700379 // Streams currently muted by ringer mode
380 private int mRingerModeMutedStreams;
381
John Spurlock3ce37252015-02-17 13:20:45 -0500382 /** Streams that can be muted. Do not resolve to aliases when checking.
383 * @see System#MUTE_STREAMS_AFFECTED */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 private int mMuteAffectedStreams;
385
386 /**
Eric Laurentbffc3d12012-05-07 17:43:49 -0700387 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
388 * mVibrateSetting is just maintained during deprecation period but vibration policy is
389 * now only controlled by mHasVibrator and mRingerMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 */
391 private int mVibrateSetting;
392
Eric Laurentbffc3d12012-05-07 17:43:49 -0700393 // Is there a vibrator
394 private final boolean mHasVibrator;
395
Eric Laurenta553c252009-07-17 12:17:14 -0700396 // Broadcast receiver for device connections intent broadcasts
397 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
398
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700399 // Devices currently connected
Paul McLean394a8e12015-03-03 10:29:19 -0700400 // Use makeDeviceListKey() to make a unique key for this list.
401 private class DeviceListSpec {
402 int mDeviceType;
403 String mDeviceName;
404 String mDeviceAddress;
405
406 public DeviceListSpec(int deviceType, String deviceName, String deviceAddress) {
407 mDeviceType = deviceType;
408 mDeviceName = deviceName;
409 mDeviceAddress = deviceAddress;
410 }
411
412 public String toString() {
413 return "[type:0x" + Integer.toHexString(mDeviceType) + " name:" + mDeviceName
414 + " address:" + mDeviceAddress + "]";
415 }
416 }
417
418 // Generate a unique key for the mConnectedDevices List by composing the device "type"
419 // and the "address" associated with a specific instance of that device type
420 private String makeDeviceListKey(int device, String deviceAddress) {
421 return "0x" + Integer.toHexString(device) + ":" + deviceAddress;
422 }
423
John Spurlock8c3dc852015-04-23 21:32:37 -0400424 private final ArrayMap<String, DeviceListSpec> mConnectedDevices = new ArrayMap<>();
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700425
426 // Forced device usage for communications
427 private int mForcedUseForComm;
428
Eric Laurent9272b4b2010-01-23 17:12:59 -0800429 // List of binder death handlers for setMode() client processes.
430 // The last process to have called setMode() is at the top of the list.
Glenn Kasten30c918c2011-11-10 17:56:41 -0800431 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
Eric Laurenteb14a782009-12-17 03:12:59 -0800432
Eric Laurent3def1ee2010-03-17 23:26:26 -0700433 // List of clients having issued a SCO start request
Glenn Kasten30c918c2011-11-10 17:56:41 -0800434 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
Eric Laurent3def1ee2010-03-17 23:26:26 -0700435
436 // BluetoothHeadset API to control SCO connection
437 private BluetoothHeadset mBluetoothHeadset;
438
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700439 // Bluetooth headset device
440 private BluetoothDevice mBluetoothHeadsetDevice;
Eric Laurent3def1ee2010-03-17 23:26:26 -0700441
Eric Laurent62ef7672010-11-24 10:58:32 -0800442 // Indicate if SCO audio connection is currently active and if the initiator is
443 // audio service (internal) or bluetooth headset (external)
444 private int mScoAudioState;
445 // SCO audio state is not active
446 private static final int SCO_STATE_INACTIVE = 0;
Eric Laurentdc03c612011-04-01 10:59:41 -0700447 // SCO audio activation request waiting for headset service to connect
448 private static final int SCO_STATE_ACTIVATE_REQ = 1;
Eric Laurent25fc29b2013-04-05 12:13:54 -0700449 // SCO audio state is active or starting due to a request from AudioManager API
Eric Laurentdc03c612011-04-01 10:59:41 -0700450 private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
451 // SCO audio deactivation request waiting for headset service to connect
452 private static final int SCO_STATE_DEACTIVATE_REQ = 5;
453
Eric Laurent62ef7672010-11-24 10:58:32 -0800454 // SCO audio state is active due to an action in BT handsfree (either voice recognition or
455 // in call audio)
456 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
Eric Laurentdc03c612011-04-01 10:59:41 -0700457 // Deactivation request for all SCO connections (initiated by audio mode change)
458 // waiting for headset service to connect
459 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
460
Eric Laurentc18c9132013-04-12 17:24:56 -0700461 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
462 // originated from an app targeting an API version before JB MR2 and raw audio after that.
463 private int mScoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -0700464 // SCO audio mode is undefined
465 private static final int SCO_MODE_UNDEFINED = -1;
Eric Laurentc18c9132013-04-12 17:24:56 -0700466 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
467 private static final int SCO_MODE_VIRTUAL_CALL = 0;
468 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
469 private static final int SCO_MODE_RAW = 1;
Liejun Taof4e51d82014-07-16 11:18:29 -0700470 // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
471 private static final int SCO_MODE_VR = 2;
472
473 private static final int SCO_MODE_MAX = 2;
Eric Laurentc18c9132013-04-12 17:24:56 -0700474
Eric Laurentdc03c612011-04-01 10:59:41 -0700475 // Current connection state indicated by bluetooth headset
476 private int mScoConnectionState;
Eric Laurent62ef7672010-11-24 10:58:32 -0800477
Eric Laurenta60e2122010-12-28 16:49:07 -0800478 // true if boot sequence has been completed
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700479 private boolean mSystemReady;
Yasuhiro Matsuda4ced7192015-07-10 22:08:44 +0900480 // true if Intent.ACTION_USER_SWITCHED has ever been received
481 private boolean mUserSwitchedReceived;
Eric Laurenta60e2122010-12-28 16:49:07 -0800482 // listener for SoundPool sample load completion indication
483 private SoundPoolCallback mSoundPoolCallBack;
484 // thread for SoundPool listener
485 private SoundPoolListenerThread mSoundPoolListenerThread;
486 // message looper for SoundPool listener
487 private Looper mSoundPoolLooper = null;
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700488 // volume applied to sound played with playSoundEffect()
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700489 private static int sSoundEffectVolumeDb;
Eric Laurent25101b02011-02-02 09:33:30 -0800490 // previous volume adjustment direction received by checkForRingerModeChange()
491 private int mPrevVolDirection = AudioManager.ADJUST_SAME;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700492 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
493 // is controlled by Vol keys.
494 private int mVolumeControlStream = -1;
495 private final Object mForceControlStreamLock = new Object();
496 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
497 // server process so in theory it is not necessary to monitor the client death.
498 // However it is good to be ready for future evolutions.
499 private ForceControlStreamClient mForceControlStreamClient = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700500 // Used to play ringtones outside system_server
501 private volatile IRingtonePlayer mRingtonePlayer;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800502
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700503 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700504 private int mDeviceRotation = Surface.ROTATION_0;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700505
Eric Laurent78472112012-05-21 08:57:21 -0700506 // Request to override default use of A2DP for media.
507 private boolean mBluetoothA2dpEnabled;
508 private final Object mBluetoothA2dpEnabledLock = new Object();
509
Dianne Hackborn632ca412012-06-14 19:34:10 -0700510 // Monitoring of audio routes. Protected by mCurAudioRoutes.
511 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
512 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
513 = new RemoteCallbackList<IAudioRoutesObserver>();
514
Eric Laurent4bbcc652012-09-24 14:26:30 -0700515 // Devices for which the volume is fixed and VolumePanel slider should be disabled
Eric Laurent212532b2014-07-21 15:43:18 -0700516 int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700517 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Eric Laurent212532b2014-07-21 15:43:18 -0700518 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
519 AudioSystem.DEVICE_OUT_HDMI_ARC |
520 AudioSystem.DEVICE_OUT_SPDIF |
521 AudioSystem.DEVICE_OUT_AUX_LINE;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700522 int mFullVolumeDevices = 0;
Eric Laurent4bbcc652012-09-24 14:26:30 -0700523
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700524 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700525 private final boolean mMonitorOrientation;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700526 private final boolean mMonitorRotation;
Eric Laurentd640bd32012-09-28 18:01:48 -0700527
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700528 private boolean mDockAudioMediaEnabled = true;
529
Eric Laurent08ed1b92012-11-05 14:54:12 -0800530 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
531
Eric Laurentfde16d52012-12-03 14:42:39 -0800532 // Used when safe volume warning message display is requested by setStreamVolume(). In this
533 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
534 // and used later when/if disableSafeMediaVolume() is called.
535 private StreamVolumeCommand mPendingVolumeCommand;
536
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700537 private PowerManager.WakeLock mAudioEventWakeLock;
538
539 private final MediaFocusControl mMediaFocusControl;
540
John Du5a0cf7a2013-07-19 11:30:34 -0700541 // Reference to BluetoothA2dp to query for AbsoluteVolume.
542 private BluetoothA2dp mA2dp;
seunghwan.hong4fe77952014-10-29 17:43:20 +0900543 // lock always taken synchronized on mConnectedDevices
John Du5a0cf7a2013-07-19 11:30:34 -0700544 private final Object mA2dpAvrcpLock = new Object();
545 // If absolute volume is supported in AVRCP device
546 private boolean mAvrcpAbsVolSupported = false;
547
Jon Eklund318f0fe2014-01-23 17:53:48 -0600548 private AudioOrientationEventListener mOrientationListener;
549
Eric Laurentadbe8bf2014-11-03 18:26:32 -0800550 private static Long mLastDeviceConnectMsgTime = new Long(0);
551
John Spurlock661f2cf2014-11-17 10:29:10 -0500552 private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
John Spurlocka48d7792015-03-03 17:35:57 -0500553 private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
John Spurlock07e72432015-03-13 11:46:52 -0400554 private long mLoweredFromNormalToVibrateTime;
John Spurlock661f2cf2014-11-17 10:29:10 -0500555
Paul McLean10804eb2015-01-28 11:16:35 -0800556 // Intent "extra" data keys.
557 public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName";
558 public static final String CONNECT_INTENT_KEY_STATE = "state";
559 public static final String CONNECT_INTENT_KEY_ADDRESS = "address";
560 public static final String CONNECT_INTENT_KEY_HAS_PLAYBACK = "hasPlayback";
561 public static final String CONNECT_INTENT_KEY_HAS_CAPTURE = "hasCapture";
562 public static final String CONNECT_INTENT_KEY_HAS_MIDI = "hasMIDI";
563 public static final String CONNECT_INTENT_KEY_DEVICE_CLASS = "class";
564
565 // Defines the format for the connection "address" for ALSA devices
566 public static String makeAlsaAddressString(int card, int device) {
567 return "card=" + card + ";device=" + device + ";";
568 }
569
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800570 ///////////////////////////////////////////////////////////////////////////
571 // Construction
572 ///////////////////////////////////////////////////////////////////////////
573
574 /** @hide */
575 public AudioService(Context context) {
576 mContext = context;
577 mContentResolver = context.getContentResolver();
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700578 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700579
John Spurlock61560172015-02-06 19:46:04 -0500580 mPlatformType = AudioSystem.getPlatformType(context);
Jared Suttles59820132009-08-13 21:50:52 -0500581
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700582 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700583 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700584
Eric Laurentbffc3d12012-05-07 17:43:49 -0700585 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
586 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
587
John Spurlockb6e19e32015-03-10 21:33:44 -0400588 // Initialize volume
Eric Laurent91377de2014-10-10 15:24:04 -0700589 int maxVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps",
590 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
591 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
592 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500593 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700594 }
595 maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
596 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
597 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
598 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500599 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700600 }
Jared Suttles59820132009-08-13 21:50:52 -0500601
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700602 sSoundEffectVolumeDb = context.getResources().getInteger(
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700603 com.android.internal.R.integer.config_soundEffectVolumeDb);
Eric Laurent25101b02011-02-02 09:33:30 -0800604
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700605 mForcedUseForComm = AudioSystem.FORCE_NONE;
Eric Laurentdd45d012012-10-08 09:04:34 -0700606
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 createAudioSystemThread();
Eric Laurentdd45d012012-10-08 09:04:34 -0700608
Eric Laurentdfb881f2013-07-18 14:41:39 -0700609 AudioSystem.setErrorCallback(mAudioSystemCallback);
610
John Spurlock5e783732015-02-19 10:28:59 -0500611 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -0700612 mCameraSoundForced = new Boolean(cameraSoundForced);
613 sendMsg(mAudioHandler,
614 MSG_SET_FORCE_USE,
615 SENDMSG_QUEUE,
616 AudioSystem.FOR_SYSTEM,
617 cameraSoundForced ?
618 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
619 null,
620 0);
621
Eric Laurent05274f32012-11-29 12:48:18 -0800622 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
623 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
624 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
625 // The default safe volume index read here will be replaced by the actual value when
626 // the mcc is read by onConfigureSafeVolume()
627 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
628 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
629
Eric Laurent83a017b2013-03-19 18:15:31 -0700630 mUseFixedVolume = mContext.getResources().getBoolean(
631 com.android.internal.R.bool.config_useFixedVolume);
632
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700633 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
634 // array initialized by updateStreamVolumeAlias()
John Spurlock90874332015-03-10 16:00:54 -0400635 updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 readPersistedSettings();
Eric Laurentc1d41662011-07-19 11:21:13 -0700637 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700638 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700639
John Spurlockb6e19e32015-03-10 21:33:44 -0400640 mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
641 mContext, mVolumeController, this);
642
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700643 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700644
645 // Call setRingerModeInt() to apply correct mute
646 // state on streams affected by ringer mode.
647 mRingerModeMutedStreams = 0;
John Spurlock661f2cf2014-11-17 10:29:10 -0500648 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3891c4c2010-04-20 09:40:57 -0700649
Eric Laurenta553c252009-07-17 12:17:14 -0700650 // Register for device connection intent broadcasts.
651 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700652 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700653 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
654 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700655 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
656 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700657 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700658 intentFilter.addAction(Intent.ACTION_USER_BACKGROUND);
659 intentFilter.addAction(Intent.ACTION_USER_FOREGROUND);
Paul McLeanc837a452014-04-09 09:04:43 -0700660 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700661
Eric Laurentd640bd32012-09-28 18:01:48 -0700662 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700663 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700664 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
665 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700666 Log.v(TAG, "monitoring device orientation");
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700667 // initialize orientation in AudioSystem
668 setOrientationForAudioSystem();
669 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700670 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
671 if (mMonitorRotation) {
672 mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
673 .getDefaultDisplay().getRotation();
674 Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
Jon Eklund318f0fe2014-01-23 17:53:48 -0600675
676 mOrientationListener = new AudioOrientationEventListener(mContext);
677 mOrientationListener.enable();
678
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700679 // initialize rotation in AudioSystem
680 setRotationForAudioSystem();
681 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700682
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700683 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null);
Jared Suttles59820132009-08-13 21:50:52 -0500684
RoboErik0dac35a2014-08-12 15:48:49 -0700685 LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 }
687
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700688 public void systemReady() {
689 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
690 0, 0, null, 0);
691 }
692
693 public void onSystemReady() {
694 mSystemReady = true;
695 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
696 0, 0, null, 0);
697
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700698 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
699 resetBluetoothSco();
700 getBluetoothHeadset();
701 //FIXME: this is to maintain compatibility with deprecated intent
702 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
703 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
704 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
705 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
706 sendStickyBroadcastToAll(newIntent);
707
708 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
709 if (adapter != null) {
710 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
711 BluetoothProfile.A2DP);
712 }
713
Eric Laurent212532b2014-07-21 15:43:18 -0700714 mHdmiManager =
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900715 (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700716 if (mHdmiManager != null) {
717 synchronized (mHdmiManager) {
718 mHdmiTvClient = mHdmiManager.getTvClient();
Jungshik Jangc9ff9682014-09-15 17:41:06 +0900719 if (mHdmiTvClient != null) {
720 mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
721 }
Eric Laurent212532b2014-07-21 15:43:18 -0700722 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
723 mHdmiCecSink = false;
724 }
725 }
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900726
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700727 sendMsg(mAudioHandler,
728 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
729 SENDMSG_REPLACE,
730 0,
731 0,
John Spurlock90874332015-03-10 16:00:54 -0400732 TAG,
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700733 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700734
735 StreamOverride.init(mContext);
John Spurlockcdb57ae2015-02-11 19:04:11 -0500736 mControllerService.init();
Eric Laurent0867bed2015-05-20 14:49:08 -0700737 onIndicateSystemReady();
738 }
739
740 void onIndicateSystemReady() {
741 if (AudioSystem.systemReady() == AudioSystem.SUCCESS) {
742 return;
743 }
744 sendMsg(mAudioHandler,
745 MSG_INDICATE_SYSTEM_READY,
746 SENDMSG_REPLACE,
747 0,
748 0,
749 null,
750 INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
751 }
752
753 public void onMediaServerDied() {
754 if (!mSystemReady ||
755 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
756 Log.e(TAG, "Media server died.");
757 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
758 null, 500);
759 return;
760 }
761 Log.e(TAG, "Media server started.");
762
763 // indicate to audio HAL that we start the reconfiguration phase after a media
764 // server crash
765 // Note that we only execute this when the media server
766 // process restarts after a crash, not the first time it is started.
767 AudioSystem.setParameters("restarting=true");
768
769 readAndSetLowRamDevice();
770
771 // Restore device connection states
772 synchronized (mConnectedDevices) {
773 for (int i = 0; i < mConnectedDevices.size(); i++) {
774 DeviceListSpec spec = mConnectedDevices.valueAt(i);
775 AudioSystem.setDeviceConnectionState(
776 spec.mDeviceType,
777 AudioSystem.DEVICE_STATE_AVAILABLE,
778 spec.mDeviceAddress,
779 spec.mDeviceName);
780 }
781 }
782 // Restore call state
783 AudioSystem.setPhoneState(mMode);
784
785 // Restore forced usage for communcations and record
786 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
787 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
788 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
789 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
790
791 // Restore stream volumes
792 int numStreamTypes = AudioSystem.getNumStreamTypes();
793 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
794 VolumeStreamState streamState = mStreamStates[streamType];
795 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
796
797 streamState.applyAllVolumes();
798 }
799
800 // Restore ringer mode
801 setRingerModeInt(getRingerModeInternal(), false);
802
803 // Reset device orientation (if monitored for this device)
804 if (mMonitorOrientation) {
805 setOrientationForAudioSystem();
806 }
807 if (mMonitorRotation) {
808 setRotationForAudioSystem();
809 }
810
811 synchronized (mBluetoothA2dpEnabledLock) {
812 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
813 mBluetoothA2dpEnabled ?
814 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
815 }
816
817 synchronized (mSettingsLock) {
818 AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
819 mDockAudioMediaEnabled ?
820 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
821 }
822 if (mHdmiManager != null) {
823 synchronized (mHdmiManager) {
824 if (mHdmiTvClient != null) {
825 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
826 }
827 }
828 }
829
830 synchronized (mAudioPolicies) {
831 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
832 policy.connectMixes();
833 }
834 }
835
836 onIndicateSystemReady();
837 // indicate the end of reconfiguration phase to audio HAL
838 AudioSystem.setParameters("restarting=false");
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700839 }
840
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800841 private void createAudioSystemThread() {
842 mAudioSystemThread = new AudioSystemThread();
843 mAudioSystemThread.start();
844 waitForAudioHandlerCreation();
845 }
846
847 /** Waits for the volume handler to be created by the other thread. */
848 private void waitForAudioHandlerCreation() {
849 synchronized(this) {
850 while (mAudioHandler == null) {
851 try {
852 // Wait for mAudioHandler to be set by the other thread
853 wait();
854 } catch (InterruptedException e) {
855 Log.e(TAG, "Interrupted while waiting on volume handler.");
856 }
857 }
858 }
859 }
860
Eric Laurent24482012012-05-10 09:41:17 -0700861 private void checkAllAliasStreamVolumes() {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700862 synchronized (VolumeStreamState.class) {
863 int numStreamTypes = AudioSystem.getNumStreamTypes();
864 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
865 if (streamType != mStreamVolumeAlias[streamType]) {
866 mStreamStates[streamType].
John Spurlock90874332015-03-10 16:00:54 -0400867 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]],
868 TAG);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700869 }
870 // apply stream volume
RoboErik4197cb62015-01-21 15:45:32 -0800871 if (!mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700872 mStreamStates[streamType].applyAllVolumes();
873 }
Eric Laurent24482012012-05-10 09:41:17 -0700874 }
875 }
876 }
877
Eric Laurent212532b2014-07-21 15:43:18 -0700878 private void checkAllFixedVolumeDevices()
879 {
880 int numStreamTypes = AudioSystem.getNumStreamTypes();
881 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
882 mStreamStates[streamType].checkFixedVolumeDevices();
883 }
884 }
885
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700886 private void checkAllFixedVolumeDevices(int streamType) {
887 mStreamStates[streamType].checkFixedVolumeDevices();
888 }
889
John Spurlockb6e19e32015-03-10 21:33:44 -0400890 private void checkMuteAffectedStreams() {
891 // any stream with a min level > 0 is not muteable by definition
892 for (int i = 0; i < mStreamStates.length; i++) {
893 final VolumeStreamState vss = mStreamStates[i];
894 if (vss.mIndexMin > 0) {
895 mMuteAffectedStreams &= ~(1 << vss.mStreamType);
896 }
897 }
898 }
899
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800900 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 int numStreamTypes = AudioSystem.getNumStreamTypes();
902 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
903
904 for (int i = 0; i < numStreamTypes; i++) {
Eric Laurent6d517662012-04-23 18:42:39 -0700905 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -0700906 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800907
Eric Laurent212532b2014-07-21 15:43:18 -0700908 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -0700909 checkAllAliasStreamVolumes();
John Spurlockb6e19e32015-03-10 21:33:44 -0400910 checkMuteAffectedStreams();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 }
912
Eric Laurentbffc3d12012-05-07 17:43:49 -0700913 private void dumpStreamStates(PrintWriter pw) {
914 pw.println("\nStream volumes (device: index)");
915 int numStreamTypes = AudioSystem.getNumStreamTypes();
916 for (int i = 0; i < numStreamTypes; i++) {
John Spurlock61560172015-02-06 19:46:04 -0500917 pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":");
Eric Laurentbffc3d12012-05-07 17:43:49 -0700918 mStreamStates[i].dump(pw);
919 pw.println("");
920 }
Eric Laurentdd45d012012-10-08 09:04:34 -0700921 pw.print("\n- mute affected streams = 0x");
922 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -0700923 }
924
John Spurlock90874332015-03-10 16:00:54 -0400925 private void updateStreamVolumeAlias(boolean updateVolumes, String caller) {
Eric Laurent6d517662012-04-23 18:42:39 -0700926 int dtmfStreamAlias;
Eric Laurent212532b2014-07-21 15:43:18 -0700927
928 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -0500929 case AudioSystem.PLATFORM_VOICE:
Eric Laurent212532b2014-07-21 15:43:18 -0700930 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
Eric Laurent6d517662012-04-23 18:42:39 -0700931 dtmfStreamAlias = AudioSystem.STREAM_RING;
Eric Laurent212532b2014-07-21 15:43:18 -0700932 break;
John Spurlock61560172015-02-06 19:46:04 -0500933 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -0700934 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
935 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
936 break;
937 default:
938 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
Eric Laurent6d517662012-04-23 18:42:39 -0700939 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
940 }
Eric Laurent212532b2014-07-21 15:43:18 -0700941
942 if (isPlatformTelevision()) {
943 mRingerModeAffectedStreams = 0;
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700944 } else {
Eric Laurent212532b2014-07-21 15:43:18 -0700945 if (isInCommunication()) {
946 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
947 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
948 } else {
949 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
950 }
Eric Laurent6d517662012-04-23 18:42:39 -0700951 }
Eric Laurent212532b2014-07-21 15:43:18 -0700952
Eric Laurent6d517662012-04-23 18:42:39 -0700953 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
954 if (updateVolumes) {
John Spurlock90874332015-03-10 16:00:54 -0400955 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
956 caller);
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700957 // apply stream mute states according to new value of mRingerModeAffectedStreams
John Spurlock661f2cf2014-11-17 10:29:10 -0500958 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent6d517662012-04-23 18:42:39 -0700959 sendMsg(mAudioHandler,
960 MSG_SET_ALL_VOLUMES,
961 SENDMSG_QUEUE,
962 0,
963 0,
964 mStreamStates[AudioSystem.STREAM_DTMF], 0);
965 }
966 }
967
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700968 private void readDockAudioSettings(ContentResolver cr)
969 {
970 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -0700971 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700972
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700973 sendMsg(mAudioHandler,
974 MSG_SET_FORCE_USE,
975 SENDMSG_QUEUE,
976 AudioSystem.FOR_DOCK,
977 mDockAudioMediaEnabled ?
978 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
979 null,
980 0);
981 }
982
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 private void readPersistedSettings() {
984 final ContentResolver cr = mContentResolver;
985
Eric Laurentbffc3d12012-05-07 17:43:49 -0700986 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700987 Settings.Global.getInt(
988 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -0700989 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -0700990 // sanity check in case the settings are restored from a device with incompatible
991 // ringer modes
John Spurlock97559372014-10-24 16:27:36 -0400992 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -0800993 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700994 }
995 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
996 ringerMode = AudioManager.RINGER_MODE_SILENT;
997 }
998 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700999 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -08001000 }
Eric Laurent212532b2014-07-21 15:43:18 -07001001 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001002 ringerMode = AudioManager.RINGER_MODE_NORMAL;
1003 }
Glenn Kastenba195eb2011-12-13 09:30:40 -08001004 synchronized(mSettingsLock) {
1005 mRingerMode = ringerMode;
John Spurlock661f2cf2014-11-17 10:29:10 -05001006 if (mRingerModeExternal == -1) {
1007 mRingerModeExternal = mRingerMode;
1008 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009
Eric Laurentdd45d012012-10-08 09:04:34 -07001010 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
1011 // are still needed while setVibrateSetting() and getVibrateSetting() are being
1012 // deprecated.
John Spurlock61560172015-02-06 19:46:04 -05001013 mVibrateSetting = AudioSystem.getValueForVibrateSetting(0,
Eric Laurentdd45d012012-10-08 09:04:34 -07001014 AudioManager.VIBRATE_TYPE_NOTIFICATION,
1015 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
1016 : AudioManager.VIBRATE_SETTING_OFF);
John Spurlock61560172015-02-06 19:46:04 -05001017 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting,
Eric Laurentdd45d012012-10-08 09:04:34 -07001018 AudioManager.VIBRATE_TYPE_RINGER,
1019 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
1020 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021
Eric Laurent24e0d9b2013-10-03 18:15:07 -07001022 updateRingerModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001023 readDockAudioSettings(cr);
Eric Laurent402f7f22011-02-04 12:30:32 -08001024 }
Eric Laurentc1d41662011-07-19 11:21:13 -07001025
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001026 mMuteAffectedStreams = System.getIntForUser(cr,
John Spurlock61560172015-02-06 19:46:04 -05001027 System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
John Spurlock24c05182015-02-05 12:30:36 -05001028 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001029
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001030 boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
John Spurlockee5ad722015-03-03 16:17:21 -05001031 0, UserHandle.USER_CURRENT) == 1;
Eric Laurent83a017b2013-03-19 18:15:31 -07001032 if (mUseFixedVolume) {
1033 masterMute = false;
1034 AudioSystem.setMasterVolume(1.0f);
1035 }
Justin Koh57978ed2012-04-03 17:37:58 -07001036 AudioSystem.setMasterMute(masterMute);
1037 broadcastMasterMuteStatus(masterMute);
1038
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001039 boolean microphoneMute =
1040 System.getIntForUser(cr, System.MICROPHONE_MUTE, 0, UserHandle.USER_CURRENT) == 1;
1041 AudioSystem.muteMicrophone(microphoneMute);
1042
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 // Each stream will read its own persisted settings
1044
John Spurlockbcc10872014-11-28 15:29:21 -05001045 // Broadcast the sticky intents
1046 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
1047 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048
1049 // Broadcast vibrate settings
1050 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
1051 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07001052
John Spurlock33f4e042014-07-11 13:10:58 -04001053 // Load settings for the volume controller
1054 mVolumeController.loadSettings(cr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 }
1056
Eric Laurenta553c252009-07-17 12:17:14 -07001057 private int rescaleIndex(int index, int srcStream, int dstStream) {
1058 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
1059 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001060
Jon Eklund318f0fe2014-01-23 17:53:48 -06001061 private class AudioOrientationEventListener
1062 extends OrientationEventListener {
1063 public AudioOrientationEventListener(Context context) {
1064 super(context);
1065 }
1066
1067 @Override
1068 public void onOrientationChanged(int orientation) {
1069 //Even though we're responding to phone orientation events,
1070 //use display rotation so audio stays in sync with video/dialogs
1071 int newRotation = ((WindowManager) mContext.getSystemService(
1072 Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
1073 if (newRotation != mDeviceRotation) {
1074 mDeviceRotation = newRotation;
1075 setRotationForAudioSystem();
1076 }
1077 }
1078 }
1079
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001080 ///////////////////////////////////////////////////////////////////////////
1081 // IPC methods
1082 ///////////////////////////////////////////////////////////////////////////
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 /** @see AudioManager#adjustVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001084 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001085 String callingPackage, String caller) {
RoboErik272e1612014-09-05 11:39:29 -07001086 adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
John Spurlock90874332015-03-10 16:00:54 -04001087 caller, Binder.getCallingUid());
RoboErik272e1612014-09-05 11:39:29 -07001088 }
1089
1090 private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001091 String callingPackage, String caller, int uid) {
1092 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType
1093 + ", flags=" + flags + ", caller=" + caller);
Eric Laurent402f7f22011-02-04 12:30:32 -08001094 int streamType;
RoboErik4197cb62015-01-21 15:45:32 -08001095 boolean isMute = isMuteAdjust(direction);
Eric Laurent45c90ce2012-04-24 18:44:22 -07001096 if (mVolumeControlStream != -1) {
1097 streamType = mVolumeControlStream;
Eric Laurent402f7f22011-02-04 12:30:32 -08001098 } else {
1099 streamType = getActiveStreamType(suggestedStreamType);
1100 }
John Spurlock0a376af2015-03-26 16:24:12 -04001101 ensureValidStreamType(streamType);
John Spurlock33f4e042014-07-11 13:10:58 -04001102 final int resolvedStream = mStreamVolumeAlias[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103
RoboErik2811dd32014-08-12 09:48:13 -07001104 // Play sounds on STREAM_RING only.
1105 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
John Spurlock33f4e042014-07-11 13:10:58 -04001106 resolvedStream != AudioSystem.STREAM_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107 flags &= ~AudioManager.FLAG_PLAY_SOUND;
1108 }
1109
John Spurlock33f4e042014-07-11 13:10:58 -04001110 // For notifications/ring, show the ui before making any adjustments
RoboErik4197cb62015-01-21 15:45:32 -08001111 // Don't suppress mute/unmute requests
1112 if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
John Spurlock33f4e042014-07-11 13:10:58 -04001113 direction = 0;
1114 flags &= ~AudioManager.FLAG_PLAY_SOUND;
1115 flags &= ~AudioManager.FLAG_VIBRATE;
1116 if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
1117 }
1118
John Spurlock90874332015-03-10 16:00:54 -04001119 adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 }
1121
1122 /** @see AudioManager#adjustStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001123 public void adjustStreamVolume(int streamType, int direction, int flags,
1124 String callingPackage) {
John Spurlock90874332015-03-10 16:00:54 -04001125 adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage,
1126 Binder.getCallingUid());
RoboErik0dac35a2014-08-12 15:48:49 -07001127 }
1128
1129 private void adjustStreamVolume(int streamType, int direction, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001130 String callingPackage, String caller, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001131 if (mUseFixedVolume) {
1132 return;
1133 }
John Spurlock90874332015-03-10 16:00:54 -04001134 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream=" + streamType + ", dir=" + direction
1135 + ", flags=" + flags + ", caller=" + caller);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07001136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 ensureValidDirection(direction);
1138 ensureValidStreamType(streamType);
1139
RoboErik4197cb62015-01-21 15:45:32 -08001140 boolean isMuteAdjust = isMuteAdjust(direction);
1141
John Spurlock3ce37252015-02-17 13:20:45 -05001142 if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
1143 return;
1144 }
1145
Eric Laurent96a33d12011-11-08 10:31:57 -08001146 // use stream type alias here so that streams with same alias have the same behavior,
1147 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
1148 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
Eric Laurent6d517662012-04-23 18:42:39 -07001149 int streamTypeAlias = mStreamVolumeAlias[streamType];
RoboErik4197cb62015-01-21 15:45:32 -08001150
Eric Laurentb024c302011-10-14 17:19:27 -07001151 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001152
1153 final int device = getDeviceForStream(streamTypeAlias);
Eric Laurent3ef75492012-11-28 12:12:23 -08001154
Eric Laurent42b041e2013-03-29 11:36:03 -07001155 int aliasIndex = streamState.getIndex(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 boolean adjustVolume = true;
Eric Laurent3ef75492012-11-28 12:12:23 -08001157 int step;
Eric Laurent24482012012-05-10 09:41:17 -07001158
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001159 // skip a2dp absolute volume control request when the device
1160 // is not an a2dp device
1161 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1162 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1163 return;
1164 }
1165
Kenny Guy70e0c582015-06-30 19:18:28 +01001166 // If we are being called by the system (e.g. hardware keys) check for current user
1167 // so we handle user restrictions correctly.
1168 if (uid == android.os.Process.SYSTEM_UID) {
1169 uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
1170 }
John Spurlock59dc9c12015-03-02 11:20:15 -05001171 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001172 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001173 return;
1174 }
1175
Eric Laurentfde16d52012-12-03 14:42:39 -08001176 // reset any pending volume command
1177 synchronized (mSafeMediaVolumeState) {
1178 mPendingVolumeCommand = null;
1179 }
1180
Eric Laurent3ef75492012-11-28 12:12:23 -08001181 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1182 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1183 ((device & mFixedVolumeDevices) != 0)) {
1184 flags |= AudioManager.FLAG_FIXED_VOLUME;
1185
1186 // Always toggle between max safe volume and 0 for fixed volume devices where safe
1187 // volume is enforced, and max and 0 for the others.
1188 // This is simulated by stepping by the full allowed volume range
1189 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1190 (device & mSafeMediaVolumeDevices) != 0) {
1191 step = mSafeMediaVolumeIndex;
1192 } else {
1193 step = streamState.getMaxIndex();
1194 }
1195 if (aliasIndex != 0) {
1196 aliasIndex = step;
1197 }
1198 } else {
1199 // convert one UI step (+/-1) into a number of internal units on the stream alias
1200 step = rescaleIndex(10, streamType, streamTypeAlias);
1201 }
1202
Eric Laurent42b041e2013-03-29 11:36:03 -07001203 // If either the client forces allowing ringer modes for this adjustment,
1204 // or the stream type is one that is affected by ringer modes
1205 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlockee5ad722015-03-03 16:17:21 -05001206 (streamTypeAlias == getUiSoundsStreamType())) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001207 int ringerMode = getRingerModeInternal();
Eric Laurent42b041e2013-03-29 11:36:03 -07001208 // do not vibrate if already in vibrate mode
1209 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
1210 flags &= ~AudioManager.FLAG_VIBRATE;
Eric Laurent3ef75492012-11-28 12:12:23 -08001211 }
RoboErik5452e252015-02-06 15:33:53 -08001212 // Check if the ringer mode handles this adjustment. If it does we don't
1213 // need to adjust the volume further.
John Spurlock50ced3f2015-05-11 16:00:09 -04001214 final int result = checkForRingerModeChange(aliasIndex, direction, step,
1215 streamState.mIsMuted);
John Spurlocka11b4af2014-06-01 11:52:23 -04001216 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
1217 // If suppressing a volume adjustment in silent mode, display the UI hint
1218 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
1219 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
1220 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001221 // If suppressing a volume down adjustment in vibrate mode, display the UI hint
1222 if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
1223 flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
1224 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001225 }
John Spurlock50ced3f2015-05-11 16:00:09 -04001226 // If the ringermode is suppressing media, prevent changes
1227 if (streamTypeAlias == AudioSystem.STREAM_MUSIC
1228 && (mRingerModeMutedStreams & (1 << AudioSystem.STREAM_MUSIC)) != 0) {
1229 adjustVolume = false;
1230 }
Eric Laurent3ef75492012-11-28 12:12:23 -08001231
Eric Laurent42b041e2013-03-29 11:36:03 -07001232 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001233
Eric Laurent42b041e2013-03-29 11:36:03 -07001234 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
RoboErik5452e252015-02-06 15:33:53 -08001235 mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001236
John Du5a0cf7a2013-07-19 11:30:34 -07001237 // Check if volume update should be send to AVRCP
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001238 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1239 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1240 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1241 synchronized (mA2dpAvrcpLock) {
1242 if (mA2dp != null && mAvrcpAbsVolSupported) {
1243 mA2dp.adjustAvrcpAbsoluteVolume(direction);
1244 }
John Du5a0cf7a2013-07-19 11:30:34 -07001245 }
1246 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001247
RoboErik4197cb62015-01-21 15:45:32 -08001248 if (isMuteAdjust) {
1249 boolean state;
1250 if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
1251 state = !streamState.mIsMuted;
1252 } else {
1253 state = direction == AudioManager.ADJUST_MUTE;
1254 }
1255 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1256 setSystemAudioMute(state);
1257 }
1258 for (int stream = 0; stream < mStreamStates.length; stream++) {
1259 if (streamTypeAlias == mStreamVolumeAlias[stream]) {
1260 mStreamStates[stream].mute(state);
RoboErik4197cb62015-01-21 15:45:32 -08001261 }
1262 }
1263 } else if ((direction == AudioManager.ADJUST_RAISE) &&
Eric Laurent42b041e2013-03-29 11:36:03 -07001264 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
RoboErik4197cb62015-01-21 15:45:32 -08001265 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -04001266 mVolumeController.postDisplaySafeVolumeWarning(flags);
John Spurlock90874332015-03-10 16:00:54 -04001267 } else if (streamState.adjustIndex(direction * step, device, caller)
1268 || streamState.mIsMuted) {
RoboErik4197cb62015-01-21 15:45:32 -08001269 // Post message to set system volume (it in turn will post a
1270 // message to persist).
1271 if (streamState.mIsMuted) {
1272 // Unmute the stream if it was previously muted
RoboErik5452e252015-02-06 15:33:53 -08001273 if (direction == AudioManager.ADJUST_RAISE) {
1274 // unmute immediately for volume up
1275 streamState.mute(false);
1276 } else if (direction == AudioManager.ADJUST_LOWER) {
John Spurlocka48d7792015-03-03 17:35:57 -05001277 if (mPlatformType == AudioSystem.PLATFORM_TELEVISION) {
1278 sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
1279 streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
1280 }
RoboErik5452e252015-02-06 15:33:53 -08001281 }
RoboErik4197cb62015-01-21 15:45:32 -08001282 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001283 sendMsg(mAudioHandler,
1284 MSG_SET_DEVICE_VOLUME,
1285 SENDMSG_QUEUE,
1286 device,
1287 0,
1288 streamState,
1289 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001290 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001291
RoboErik4197cb62015-01-21 15:45:32 -08001292 // Check if volume update should be sent to Hdmi system audio.
Jungshik Jang41d97462014-06-30 22:26:29 +09001293 int newIndex = mStreamStates[streamType].getIndex(device);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001294 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1295 setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
1296 }
Eric Laurent212532b2014-07-21 15:43:18 -07001297 if (mHdmiManager != null) {
1298 synchronized (mHdmiManager) {
Eric Laurent212532b2014-07-21 15:43:18 -07001299 // mHdmiCecSink true => mHdmiPlaybackClient != null
1300 if (mHdmiCecSink &&
1301 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1302 oldIndex != newIndex) {
1303 synchronized (mHdmiPlaybackClient) {
1304 int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
RoboErik4197cb62015-01-21 15:45:32 -08001305 KeyEvent.KEYCODE_VOLUME_UP;
Eric Laurent212532b2014-07-21 15:43:18 -07001306 mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1307 mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1308 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001309 }
1310 }
1311 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001312 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001313 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001314 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001315 }
1316
RoboErik5452e252015-02-06 15:33:53 -08001317 // Called after a delay when volume down is pressed while muted
1318 private void onUnmuteStream(int stream, int flags) {
1319 VolumeStreamState streamState = mStreamStates[stream];
1320 streamState.mute(false);
1321
1322 final int device = getDeviceForStream(stream);
1323 final int index = mStreamStates[stream].getIndex(device);
1324 sendVolumeUpdate(stream, index, index, flags);
1325 }
1326
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001327 private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
1328 if (mHdmiManager == null
1329 || mHdmiTvClient == null
1330 || oldVolume == newVolume
1331 || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
1332
1333 // Sets the audio volume of AVR when we are in system audio mode. The new volume info
1334 // is tranformed to HDMI-CEC commands and passed through CEC bus.
1335 synchronized (mHdmiManager) {
1336 if (!mHdmiSystemAudioSupported) return;
1337 synchronized (mHdmiTvClient) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001338 final long token = Binder.clearCallingIdentity();
1339 try {
Jinsuk Kim7a9ba422015-02-16 16:47:38 +09001340 mHdmiTvClient.setSystemAudioVolume(oldVolume, newVolume, maxVolume);
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001341 } finally {
1342 Binder.restoreCallingIdentity(token);
1343 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001344 }
1345 }
1346 }
1347
Eric Laurentfde16d52012-12-03 14:42:39 -08001348 // StreamVolumeCommand contains the information needed to defer the process of
1349 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1350 class StreamVolumeCommand {
1351 public final int mStreamType;
1352 public final int mIndex;
1353 public final int mFlags;
1354 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001355
Eric Laurentfde16d52012-12-03 14:42:39 -08001356 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1357 mStreamType = streamType;
1358 mIndex = index;
1359 mFlags = flags;
1360 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001361 }
John Spurlock35134602014-07-24 18:10:48 -04001362
1363 @Override
1364 public String toString() {
1365 return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1366 .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1367 .append(mDevice).append('}').toString();
1368 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001369 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001370
John Spurlock90874332015-03-10 16:00:54 -04001371 private void onSetStreamVolume(int streamType, int index, int flags, int device,
1372 String caller) {
John Spurlock75ae23c2015-06-02 16:26:43 -04001373 final int stream = mStreamVolumeAlias[streamType];
1374 setStreamVolumeInt(stream, index, device, false, caller);
John Spurlockee5ad722015-03-03 16:17:21 -05001375 // setting volume on ui sounds stream type also controls silent mode
Eric Laurent3ef75492012-11-28 12:12:23 -08001376 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlock75ae23c2015-06-02 16:26:43 -04001377 (stream == getUiSoundsStreamType())) {
Eric Laurent3ef75492012-11-28 12:12:23 -08001378 int newRingerMode;
1379 if (index == 0) {
1380 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlocka48d7792015-03-03 17:35:57 -05001381 : mVolumePolicy.volumeDownToEnterSilent ? AudioManager.RINGER_MODE_SILENT
John Spurlock86005342014-05-23 11:58:00 -04001382 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001383 } else {
1384 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1385 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001386 setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/);
Eric Laurent3ef75492012-11-28 12:12:23 -08001387 }
John Spurlock75ae23c2015-06-02 16:26:43 -04001388 // setting non-zero volume for a muted stream unmutes the stream and vice versa
1389 mStreamStates[stream].mute(index == 0);
Eric Laurentfde16d52012-12-03 14:42:39 -08001390 }
1391
1392 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001393 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
John Spurlock90874332015-03-10 16:00:54 -04001394 setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
1395 Binder.getCallingUid());
RoboErik0dac35a2014-08-12 15:48:49 -07001396 }
1397
1398 private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
John Spurlock90874332015-03-10 16:00:54 -04001399 String caller, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001400 if (mUseFixedVolume) {
1401 return;
1402 }
1403
Eric Laurentfde16d52012-12-03 14:42:39 -08001404 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001405 int streamTypeAlias = mStreamVolumeAlias[streamType];
1406 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001407
1408 final int device = getDeviceForStream(streamType);
1409 int oldIndex;
1410
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001411 // skip a2dp absolute volume control request when the device
1412 // is not an a2dp device
1413 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1414 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1415 return;
1416 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001417 // If we are being called by the system (e.g. hardware keys) check for current user
1418 // so we handle user restrictions correctly.
1419 if (uid == android.os.Process.SYSTEM_UID) {
1420 uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
1421 }
John Spurlock59dc9c12015-03-02 11:20:15 -05001422 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001423 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001424 return;
1425 }
1426
Eric Laurentfde16d52012-12-03 14:42:39 -08001427 synchronized (mSafeMediaVolumeState) {
1428 // reset any pending volume command
1429 mPendingVolumeCommand = null;
1430
Eric Laurent42b041e2013-03-29 11:36:03 -07001431 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001432
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001433 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001434
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001435 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1436 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1437 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1438 synchronized (mA2dpAvrcpLock) {
1439 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001440 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001441 }
John Du5a0cf7a2013-07-19 11:30:34 -07001442 }
1443 }
1444
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001445 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1446 setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
Jungshik Jang41d97462014-06-30 22:26:29 +09001447 }
1448
Eric Laurentfde16d52012-12-03 14:42:39 -08001449 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001450 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001451 ((device & mFixedVolumeDevices) != 0)) {
1452 flags |= AudioManager.FLAG_FIXED_VOLUME;
1453
1454 // volume is either 0 or max allowed for fixed volume devices
1455 if (index != 0) {
1456 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1457 (device & mSafeMediaVolumeDevices) != 0) {
1458 index = mSafeMediaVolumeIndex;
1459 } else {
1460 index = streamState.getMaxIndex();
1461 }
1462 }
1463 }
1464
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001465 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001466 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001467 mPendingVolumeCommand = new StreamVolumeCommand(
1468 streamType, index, flags, device);
1469 } else {
John Spurlock90874332015-03-10 16:00:54 -04001470 onSetStreamVolume(streamType, index, flags, device, caller);
Eric Laurent42b041e2013-03-29 11:36:03 -07001471 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001472 }
1473 }
Eric Laurent25101b02011-02-02 09:33:30 -08001474 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001475 }
1476
Eric Laurent45c90ce2012-04-24 18:44:22 -07001477 /** @see AudioManager#forceVolumeControlStream(int) */
1478 public void forceVolumeControlStream(int streamType, IBinder cb) {
1479 synchronized(mForceControlStreamLock) {
1480 mVolumeControlStream = streamType;
1481 if (mVolumeControlStream == -1) {
1482 if (mForceControlStreamClient != null) {
1483 mForceControlStreamClient.release();
1484 mForceControlStreamClient = null;
1485 }
1486 } else {
1487 mForceControlStreamClient = new ForceControlStreamClient(cb);
1488 }
1489 }
1490 }
1491
1492 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1493 private IBinder mCb; // To be notified of client's death
1494
1495 ForceControlStreamClient(IBinder cb) {
1496 if (cb != null) {
1497 try {
1498 cb.linkToDeath(this, 0);
1499 } catch (RemoteException e) {
1500 // Client has died!
1501 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1502 cb = null;
1503 }
1504 }
1505 mCb = cb;
1506 }
1507
1508 public void binderDied() {
1509 synchronized(mForceControlStreamLock) {
1510 Log.w(TAG, "SCO client died");
1511 if (mForceControlStreamClient != this) {
1512 Log.w(TAG, "unregistered control stream client died");
1513 } else {
1514 mForceControlStreamClient = null;
1515 mVolumeControlStream = -1;
1516 }
1517 }
1518 }
1519
1520 public void release() {
1521 if (mCb != null) {
1522 mCb.unlinkToDeath(this, 0);
1523 mCb = null;
1524 }
1525 }
1526 }
1527
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001528 private void sendBroadcastToAll(Intent intent) {
Christopher Tate267603f2015-01-20 14:21:21 -08001529 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
John Spurlock86490862015-02-25 11:22:52 -05001530 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001531 final long ident = Binder.clearCallingIdentity();
1532 try {
1533 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1534 } finally {
1535 Binder.restoreCallingIdentity(ident);
1536 }
1537 }
1538
1539 private void sendStickyBroadcastToAll(Intent intent) {
John Spurlock86490862015-02-25 11:22:52 -05001540 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001541 final long ident = Binder.clearCallingIdentity();
1542 try {
1543 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1544 } finally {
1545 Binder.restoreCallingIdentity(ident);
1546 }
1547 }
1548
Kenny Guy70e0c582015-06-30 19:18:28 +01001549 private int getCurrentUserId() {
1550 final long ident = Binder.clearCallingIdentity();
1551 try {
1552 UserInfo currentUser = ActivityManagerNative.getDefault().getCurrentUser();
1553 return currentUser.id;
1554 } catch (RemoteException e) {
1555 // Activity manager not running, nothing we can do assume user 0.
1556 } finally {
1557 Binder.restoreCallingIdentity(ident);
1558 }
1559 return UserHandle.USER_OWNER;
1560 }
1561
Eric Laurent25101b02011-02-02 09:33:30 -08001562 // UI update and Broadcast Intent
1563 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
John Spurlock72966d62015-06-18 15:45:07 -04001564 streamType = mStreamVolumeAlias[streamType];
Eric Laurent25101b02011-02-02 09:33:30 -08001565
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001566 if (streamType == AudioSystem.STREAM_MUSIC) {
1567 flags = updateFlagsForSystemAudio(flags);
Jungshik Jang1a6be6e2014-09-16 11:04:54 +09001568 }
John Spurlock3346a802014-05-20 16:25:37 -04001569 mVolumeController.postVolumeChanged(streamType, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001570 }
1571
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001572 // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
1573 // receives volume notification from Audio Receiver.
1574 private int updateFlagsForSystemAudio(int flags) {
1575 if (mHdmiTvClient != null) {
1576 synchronized (mHdmiTvClient) {
1577 if (mHdmiSystemAudioSupported &&
1578 ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
1579 flags &= ~AudioManager.FLAG_SHOW_UI;
1580 }
1581 }
1582 }
1583 return flags;
1584 }
1585
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001586 // UI update and Broadcast Intent
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001587 private void sendMasterMuteUpdate(boolean muted, int flags) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001588 mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
Justin Koh57978ed2012-04-03 17:37:58 -07001589 broadcastMasterMuteStatus(muted);
1590 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001591
Justin Koh57978ed2012-04-03 17:37:58 -07001592 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001593 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1594 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001595 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1596 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001597 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001598 }
1599
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001600 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001601 * Sets the stream state's index, and posts a message to set system volume.
1602 * This will not call out to the UI. Assumes a valid stream type.
1603 *
1604 * @param streamType Type of the stream
1605 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001606 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607 * @param force If true, set the volume even if the desired volume is same
1608 * as the current volume.
1609 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001610 private void setStreamVolumeInt(int streamType,
1611 int index,
1612 int device,
John Spurlock90874332015-03-10 16:00:54 -04001613 boolean force,
1614 String caller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001615 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07001616
John Spurlock90874332015-03-10 16:00:54 -04001617 if (streamState.setIndex(index, device, caller) || force) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001618 // Post message to set system volume (it in turn will post a message
1619 // to persist).
1620 sendMsg(mAudioHandler,
1621 MSG_SET_DEVICE_VOLUME,
1622 SENDMSG_QUEUE,
1623 device,
1624 0,
1625 streamState,
1626 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001627 }
1628 }
1629
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001630 private void setSystemAudioMute(boolean state) {
1631 if (mHdmiManager == null || mHdmiTvClient == null) return;
1632 synchronized (mHdmiManager) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001633 if (!mHdmiSystemAudioSupported) return;
1634 synchronized (mHdmiTvClient) {
1635 final long token = Binder.clearCallingIdentity();
1636 try {
1637 mHdmiTvClient.setSystemAudioMute(state);
1638 } finally {
1639 Binder.restoreCallingIdentity(token);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001640 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001641 }
1642 }
1643 }
1644
Eric Laurent25101b02011-02-02 09:33:30 -08001645 /** get stream mute state. */
1646 public boolean isStreamMute(int streamType) {
RoboErik7c82ced2014-12-04 17:39:08 -08001647 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1648 streamType = getActiveStreamType(streamType);
1649 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001650 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08001651 return mStreamStates[streamType].mIsMuted;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001652 }
Eric Laurent25101b02011-02-02 09:33:30 -08001653 }
1654
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07001655 private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
1656 private IBinder mICallback; // To be notified of client's death
1657
1658 RmtSbmxFullVolDeathHandler(IBinder cb) {
1659 mICallback = cb;
1660 try {
1661 cb.linkToDeath(this, 0/*flags*/);
1662 } catch (RemoteException e) {
1663 Log.e(TAG, "can't link to death", e);
1664 }
1665 }
1666
1667 boolean isHandlerFor(IBinder cb) {
1668 return mICallback.equals(cb);
1669 }
1670
1671 void forget() {
1672 try {
1673 mICallback.unlinkToDeath(this, 0/*flags*/);
1674 } catch (NoSuchElementException e) {
1675 Log.e(TAG, "error unlinking to death", e);
1676 }
1677 }
1678
1679 public void binderDied() {
1680 Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
1681 forceRemoteSubmixFullVolume(false, mICallback);
1682 }
1683 }
1684
1685 /**
1686 * call must be synchronized on mRmtSbmxFullVolDeathHandlers
1687 * @return true if there is a registered death handler, false otherwise */
1688 private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1689 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1690 while (it.hasNext()) {
1691 final RmtSbmxFullVolDeathHandler handler = it.next();
1692 if (handler.isHandlerFor(cb)) {
1693 handler.forget();
1694 mRmtSbmxFullVolDeathHandlers.remove(handler);
1695 return true;
1696 }
1697 }
1698 return false;
1699 }
1700
1701 /** call synchronized on mRmtSbmxFullVolDeathHandlers */
1702 private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1703 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1704 while (it.hasNext()) {
1705 if (it.next().isHandlerFor(cb)) {
1706 return true;
1707 }
1708 }
1709 return false;
1710 }
1711
1712 private int mRmtSbmxFullVolRefCount = 0;
1713 private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
1714 new ArrayList<RmtSbmxFullVolDeathHandler>();
1715
1716 public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
1717 if (cb == null) {
1718 return;
1719 }
1720 if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
1721 android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
1722 Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
1723 return;
1724 }
1725 synchronized(mRmtSbmxFullVolDeathHandlers) {
1726 boolean applyRequired = false;
1727 if (startForcing) {
1728 if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
1729 mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
1730 if (mRmtSbmxFullVolRefCount == 0) {
1731 mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1732 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1733 applyRequired = true;
1734 }
1735 mRmtSbmxFullVolRefCount++;
1736 }
1737 } else {
1738 if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
1739 mRmtSbmxFullVolRefCount--;
1740 if (mRmtSbmxFullVolRefCount == 0) {
1741 mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1742 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1743 applyRequired = true;
1744 }
1745 }
1746 }
1747 if (applyRequired) {
1748 // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
1749 checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
1750 mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
1751 }
1752 }
1753 }
1754
Kenny Guy70e0c582015-06-30 19:18:28 +01001755 private void setMasterMuteInternal(boolean mute, int flags, String callingPackage, int uid,
1756 int userId) {
1757 // If we are being called by the system check for user we are going to change
1758 // so we handle user restrictions correctly.
1759 if (uid == android.os.Process.SYSTEM_UID) {
1760 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
1761 }
RoboErik7c82ced2014-12-04 17:39:08 -08001762 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
1763 != AppOpsManager.MODE_ALLOWED) {
Julia Reynolds4a21b252014-06-04 11:11:43 -04001764 return;
1765 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001766 if (userId != UserHandle.getCallingUserId() &&
1767 mContext.checkCallingOrSelfPermission(
1768 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1769 != PackageManager.PERMISSION_GRANTED) {
1770 return;
1771 }
1772 if (getCurrentUserId() == userId) {
1773 if (mute != AudioSystem.getMasterMute()) {
1774 setSystemAudioMute(mute);
1775 AudioSystem.setMasterMute(mute);
1776 // Post a persist master volume msg
1777 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, mute ? 1
1778 : 0, userId, null, PERSIST_DELAY);
1779 sendMasterMuteUpdate(mute, flags);
RoboErik7c82ced2014-12-04 17:39:08 -08001780
Kenny Guy70e0c582015-06-30 19:18:28 +01001781 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1782 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute);
1783 sendBroadcastToAll(intent);
1784 }
1785 } else {
1786 // If not the current user just persist the setting which will be loaded
1787 // on user switch.
1788 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, mute ? 1
1789 : 0, userId, null, PERSIST_DELAY);
Jason Simmons1ce5b262012-02-02 13:00:17 -08001790 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08001791 }
1792
1793 /** get master mute state. */
1794 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08001795 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001796 }
1797
Kenny Guy70e0c582015-06-30 19:18:28 +01001798 public void setMasterMute(boolean mute, int flags, String callingPackage, int userId) {
1799 setMasterMuteInternal(mute, flags, callingPackage, Binder.getCallingUid(),
1800 userId);
John Spurlockee5ad722015-03-03 16:17:21 -05001801 }
1802
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001803 /** @see AudioManager#getStreamVolume(int) */
1804 public int getStreamVolume(int streamType) {
1805 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001806 int device = getDeviceForStream(streamType);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001807 synchronized (VolumeStreamState.class) {
1808 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001809
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001810 // by convention getStreamVolume() returns 0 when a stream is muted.
RoboErik4197cb62015-01-21 15:45:32 -08001811 if (mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001812 index = 0;
1813 }
1814 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
1815 (device & mFixedVolumeDevices) != 0) {
1816 index = mStreamStates[streamType].getMaxIndex();
1817 }
1818 return (index + 5) / 10;
Eric Laurent42b041e2013-03-29 11:36:03 -07001819 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001820 }
1821
1822 /** @see AudioManager#getStreamMaxVolume(int) */
1823 public int getStreamMaxVolume(int streamType) {
1824 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07001825 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001826 }
1827
John Spurlockb6e19e32015-03-10 21:33:44 -04001828 /** @see AudioManager#getStreamMinVolume(int) */
1829 public int getStreamMinVolume(int streamType) {
1830 ensureValidStreamType(streamType);
1831 return (mStreamStates[streamType].getMinIndex() + 5) / 10;
1832 }
1833
Eric Laurent25101b02011-02-02 09:33:30 -08001834 /** Get last audible volume before stream was muted. */
1835 public int getLastAudibleStreamVolume(int streamType) {
1836 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001837 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001838 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08001839 }
1840
John Spurlockee5ad722015-03-03 16:17:21 -05001841 /** @see AudioManager#getUiSoundsStreamType() */
1842 public int getUiSoundsStreamType() {
John Spurlock4f0f1202014-08-05 13:28:33 -04001843 return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
Eric Laurent6d517662012-04-23 18:42:39 -07001844 }
1845
Kenny Guy70e0c582015-06-30 19:18:28 +01001846 /** @see AudioManager#setMicrophoneMute(boolean, int) */
1847 public void setMicrophoneMute(boolean on, String callingPackage, int userId) {
1848 // If we are being called by the system check for user we are going to change
1849 // so we handle user restrictions correctly.
1850 int uid = Binder.getCallingUid();
1851 if (uid == android.os.Process.SYSTEM_UID) {
1852 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
1853 }
1854 if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, uid, callingPackage)
1855 != AppOpsManager.MODE_ALLOWED) {
Emily Bernier22c921a2014-05-28 11:01:32 -04001856 return;
1857 }
Jean-Michel Trivi4a4fea02014-08-29 18:14:09 -07001858 if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
1859 return;
1860 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001861 if (userId != UserHandle.getCallingUserId() &&
1862 mContext.checkCallingOrSelfPermission(
1863 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1864 != PackageManager.PERMISSION_GRANTED) {
1865 return;
1866 }
Emily Bernier22c921a2014-05-28 11:01:32 -04001867
Kenny Guy70e0c582015-06-30 19:18:28 +01001868 // If mute is for current user actually mute, else just persist the setting
1869 // which will be loaded on user switch.
1870 if (getCurrentUserId() == userId) {
1871 AudioSystem.muteMicrophone(on);
1872 }
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001873 // Post a persist microphone msg.
1874 sendMsg(mAudioHandler, MSG_PERSIST_MICROPHONE_MUTE, SENDMSG_REPLACE, on ? 1
Kenny Guy70e0c582015-06-30 19:18:28 +01001875 : 0, userId, null, PERSIST_DELAY);
Emily Bernier22c921a2014-05-28 11:01:32 -04001876 }
1877
John Spurlock661f2cf2014-11-17 10:29:10 -05001878 @Override
1879 public int getRingerModeExternal() {
1880 synchronized(mSettingsLock) {
1881 return mRingerModeExternal;
1882 }
1883 }
1884
1885 @Override
1886 public int getRingerModeInternal() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001887 synchronized(mSettingsLock) {
1888 return mRingerMode;
1889 }
1890 }
1891
1892 private void ensureValidRingerMode(int ringerMode) {
John Spurlock97559372014-10-24 16:27:36 -04001893 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001894 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1895 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001896 }
1897
John Spurlock97559372014-10-24 16:27:36 -04001898 /** @see AudioManager#isValidRingerMode(int) */
1899 public boolean isValidRingerMode(int ringerMode) {
1900 return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
1901 }
1902
John Spurlock661f2cf2014-11-17 10:29:10 -05001903 public void setRingerModeExternal(int ringerMode, String caller) {
John Spurlockaf88a192014-12-23 16:14:44 -05001904 setRingerMode(ringerMode, caller, true /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05001905 }
1906
1907 public void setRingerModeInternal(int ringerMode, String caller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05001908 enforceVolumeController("setRingerModeInternal");
John Spurlockaf88a192014-12-23 16:14:44 -05001909 setRingerMode(ringerMode, caller, false /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05001910 }
1911
1912 private void setRingerMode(int ringerMode, String caller, boolean external) {
Eric Laurent212532b2014-07-21 15:43:18 -07001913 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001914 return;
1915 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001916 if (caller == null || caller.length() == 0) {
1917 throw new IllegalArgumentException("Bad caller: " + caller);
1918 }
John Spurlock97559372014-10-24 16:27:36 -04001919 ensureValidRingerMode(ringerMode);
Eric Laurent24482012012-05-10 09:41:17 -07001920 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1921 ringerMode = AudioManager.RINGER_MODE_SILENT;
1922 }
John Spurlockaf88a192014-12-23 16:14:44 -05001923 final long identity = Binder.clearCallingIdentity();
1924 try {
1925 synchronized (mSettingsLock) {
1926 final int ringerModeInternal = getRingerModeInternal();
1927 final int ringerModeExternal = getRingerModeExternal();
1928 if (external) {
1929 setRingerModeExt(ringerMode);
1930 if (mRingerModeDelegate != null) {
1931 ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
John Spurlocka48d7792015-03-03 17:35:57 -05001932 ringerMode, caller, ringerModeInternal, mVolumePolicy);
John Spurlockaf88a192014-12-23 16:14:44 -05001933 }
1934 if (ringerMode != ringerModeInternal) {
1935 setRingerModeInt(ringerMode, true /*persist*/);
1936 }
1937 } else /*internal*/ {
1938 if (ringerMode != ringerModeInternal) {
1939 setRingerModeInt(ringerMode, true /*persist*/);
1940 }
1941 if (mRingerModeDelegate != null) {
1942 ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
John Spurlocka48d7792015-03-03 17:35:57 -05001943 ringerMode, caller, ringerModeExternal, mVolumePolicy);
John Spurlockaf88a192014-12-23 16:14:44 -05001944 }
1945 setRingerModeExt(ringerMode);
John Spurlock57627792014-12-11 11:29:54 -05001946 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001947 }
John Spurlockaf88a192014-12-23 16:14:44 -05001948 } finally {
1949 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001950 }
1951 }
1952
John Spurlock661f2cf2014-11-17 10:29:10 -05001953 private void setRingerModeExt(int ringerMode) {
1954 synchronized(mSettingsLock) {
1955 if (ringerMode == mRingerModeExternal) return;
1956 mRingerModeExternal = ringerMode;
John Spurlocke5b42d92014-10-15 12:03:48 -04001957 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001958 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05001959 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
John Spurlocke5b42d92014-10-15 12:03:48 -04001960 }
1961
John Spurlock50ced3f2015-05-11 16:00:09 -04001962 private void muteRingerModeStreams() {
Eric Laurent5b4e6542010-03-19 20:02:21 -07001963 // Mute stream if not previously muted by ringer mode and ringer mode
1964 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
1965 // Unmute stream if previously muted by ringer mode and ringer mode
1966 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07001967 int numStreamTypes = AudioSystem.getNumStreamTypes();
John Spurlock50ced3f2015-05-11 16:00:09 -04001968 final boolean ringerModeMute = mRingerMode == AudioManager.RINGER_MODE_VIBRATE
1969 || mRingerMode == AudioManager.RINGER_MODE_SILENT;
Eric Laurent5b4e6542010-03-19 20:02:21 -07001970 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001971 final boolean isMuted = isStreamMutedByRingerMode(streamType);
1972 final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
1973 if (isMuted == shouldMute) continue;
1974 if (!shouldMute) {
1975 // unmute
1976 // ring and notifications volume should never be 0 when not silenced
John Spurlockd9c75db2015-04-28 11:19:13 -04001977 if (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001978 synchronized (VolumeStreamState.class) {
John Spurlocka48d7792015-03-03 17:35:57 -05001979 final VolumeStreamState vss = mStreamStates[streamType];
1980 for (int i = 0; i < vss.mIndexMap.size(); i++) {
1981 int device = vss.mIndexMap.keyAt(i);
1982 int value = vss.mIndexMap.valueAt(i);
John Spurlock2bb02ec2015-03-02 13:13:06 -05001983 if (value == 0) {
John Spurlocka48d7792015-03-03 17:35:57 -05001984 vss.setIndex(10, device, TAG);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001985 }
1986 }
Eric Laurent9e0d25f2015-02-12 17:28:53 -08001987 // Persist volume for stream ring when it is changed here
1988 final int device = getDeviceForStream(streamType);
1989 sendMsg(mAudioHandler,
1990 MSG_PERSIST_VOLUME,
1991 SENDMSG_QUEUE,
1992 device,
1993 0,
1994 mStreamStates[streamType],
1995 PERSIST_DELAY);
Eric Laurentb024c302011-10-14 17:19:27 -07001996 }
Eric Laurent9bcf4012009-06-12 06:09:28 -07001997 }
RoboErik4197cb62015-01-21 15:45:32 -08001998 mStreamStates[streamType].mute(false);
John Spurlock661f2cf2014-11-17 10:29:10 -05001999 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent5b4e6542010-03-19 20:02:21 -07002000 } else {
John Spurlock661f2cf2014-11-17 10:29:10 -05002001 // mute
RoboErik4197cb62015-01-21 15:45:32 -08002002 mStreamStates[streamType].mute(true);
John Spurlock661f2cf2014-11-17 10:29:10 -05002003 mRingerModeMutedStreams |= (1 << streamType);
Jason Parekhb1096152009-03-24 17:48:25 -07002004 }
2005 }
John Spurlock50ced3f2015-05-11 16:00:09 -04002006 }
2007
2008 private void setRingerModeInt(int ringerMode, boolean persist) {
2009 final boolean change;
2010 synchronized(mSettingsLock) {
2011 change = mRingerMode != ringerMode;
2012 mRingerMode = ringerMode;
2013 }
2014
2015 muteRingerModeStreams();
Eric Laurenta553c252009-07-17 12:17:14 -07002016
Jason Parekhb1096152009-03-24 17:48:25 -07002017 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07002018 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002019 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07002020 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
2021 }
John Spurlockbcc10872014-11-28 15:29:21 -05002022 if (change) {
2023 // Send sticky broadcast
2024 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
2025 }
Jason Parekhb1096152009-03-24 17:48:25 -07002026 }
2027
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002028 /** @see AudioManager#shouldVibrate(int) */
2029 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002030 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002031
2032 switch (getVibrateSetting(vibrateType)) {
2033
2034 case AudioManager.VIBRATE_SETTING_ON:
John Spurlock57627792014-12-11 11:29:54 -05002035 return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002036
2037 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
John Spurlock57627792014-12-11 11:29:54 -05002038 return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002039
2040 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04002041 // return false, even for incoming calls
2042 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002043
2044 default:
2045 return false;
2046 }
2047 }
2048
2049 /** @see AudioManager#getVibrateSetting(int) */
2050 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002051 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002052 return (mVibrateSetting >> (vibrateType * 2)) & 3;
2053 }
2054
2055 /** @see AudioManager#setVibrateSetting(int, int) */
2056 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
2057
Eric Laurentbffc3d12012-05-07 17:43:49 -07002058 if (!mHasVibrator) return;
2059
John Spurlock61560172015-02-06 19:46:04 -05002060 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
2061 vibrateSetting);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002062
2063 // Broadcast change
2064 broadcastVibrateSetting(vibrateType);
2065
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002066 }
2067
Eric Laurent9272b4b2010-01-23 17:12:59 -08002068 private class SetModeDeathHandler implements IBinder.DeathRecipient {
2069 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002070 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002071 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
2072
Eric Laurent9f103de2011-09-08 15:04:23 -07002073 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08002074 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07002075 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002076 }
2077
2078 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07002079 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002080 synchronized(mSetModeDeathHandlers) {
2081 Log.w(TAG, "setMode() client died");
2082 int index = mSetModeDeathHandlers.indexOf(this);
2083 if (index < 0) {
2084 Log.w(TAG, "unregistered setMode() client died");
2085 } else {
John Spurlock90874332015-03-10 16:00:54 -04002086 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid, TAG);
Eric Laurent9272b4b2010-01-23 17:12:59 -08002087 }
2088 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002089 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2090 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002091 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07002092 final long ident = Binder.clearCallingIdentity();
2093 disconnectBluetoothSco(newModeOwnerPid);
2094 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07002095 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08002096 }
2097
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002098 public int getPid() {
2099 return mPid;
2100 }
2101
Eric Laurent9272b4b2010-01-23 17:12:59 -08002102 public void setMode(int mode) {
2103 mMode = mode;
2104 }
2105
2106 public int getMode() {
2107 return mMode;
2108 }
2109
2110 public IBinder getBinder() {
2111 return mCb;
2112 }
2113 }
2114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002115 /** @see AudioManager#setMode(int) */
John Spurlock90874332015-03-10 16:00:54 -04002116 public void setMode(int mode, IBinder cb, String callingPackage) {
2117 if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ", callingPackage=" + callingPackage + ")"); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002118 if (!checkAudioSettingsPermission("setMode()")) {
2119 return;
2120 }
Eric Laurenta553c252009-07-17 12:17:14 -07002121
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07002122 if ( (mode == AudioSystem.MODE_IN_CALL) &&
2123 (mContext.checkCallingOrSelfPermission(
2124 android.Manifest.permission.MODIFY_PHONE_STATE)
2125 != PackageManager.PERMISSION_GRANTED)) {
2126 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
2127 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
2128 return;
2129 }
2130
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08002131 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07002132 return;
2133 }
2134
Eric Laurentd7454be2011-09-14 08:45:58 -07002135 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002136 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07002137 if (mode == AudioSystem.MODE_CURRENT) {
2138 mode = mMode;
2139 }
John Spurlock90874332015-03-10 16:00:54 -04002140 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid(), callingPackage);
Eric Laurent9f103de2011-09-08 15:04:23 -07002141 }
2142 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2143 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002144 if (newModeOwnerPid != 0) {
2145 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07002146 }
2147 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002148
Eric Laurent9f103de2011-09-08 15:04:23 -07002149 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07002150 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07002151 // any mode other than NORMAL.
John Spurlock90874332015-03-10 16:00:54 -04002152 private int setModeInt(int mode, IBinder cb, int pid, String caller) {
2153 if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ", caller="
2154 + caller + ")"); }
Eric Laurentd7454be2011-09-14 08:45:58 -07002155 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002156 if (cb == null) {
2157 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07002158 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07002159 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002160
Eric Laurent9f103de2011-09-08 15:04:23 -07002161 SetModeDeathHandler hdlr = null;
2162 Iterator iter = mSetModeDeathHandlers.iterator();
2163 while (iter.hasNext()) {
2164 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
2165 if (h.getPid() == pid) {
2166 hdlr = h;
2167 // Remove from client list so that it is re-inserted at top of list
2168 iter.remove();
2169 hdlr.getBinder().unlinkToDeath(hdlr, 0);
2170 break;
2171 }
2172 }
2173 int status = AudioSystem.AUDIO_STATUS_OK;
2174 do {
2175 if (mode == AudioSystem.MODE_NORMAL) {
2176 // get new mode from client at top the list if any
2177 if (!mSetModeDeathHandlers.isEmpty()) {
2178 hdlr = mSetModeDeathHandlers.get(0);
2179 cb = hdlr.getBinder();
2180 mode = hdlr.getMode();
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002181 if (DEBUG_MODE) {
2182 Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
2183 + hdlr.mPid);
2184 }
Eric Laurentb9c9d262009-05-06 08:13:20 -07002185 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002186 } else {
2187 if (hdlr == null) {
2188 hdlr = new SetModeDeathHandler(cb, pid);
2189 }
2190 // Register for client death notification
2191 try {
2192 cb.linkToDeath(hdlr, 0);
2193 } catch (RemoteException e) {
2194 // Client has died!
2195 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
2196 }
2197
2198 // Last client to call setMode() is always at top of client list
2199 // as required by SetModeDeathHandler.binderDied()
2200 mSetModeDeathHandlers.add(0, hdlr);
2201 hdlr.setMode(mode);
2202 }
2203
2204 if (mode != mMode) {
2205 status = AudioSystem.setPhoneState(mode);
2206 if (status == AudioSystem.AUDIO_STATUS_OK) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002207 if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002208 mMode = mode;
2209 } else {
2210 if (hdlr != null) {
2211 mSetModeDeathHandlers.remove(hdlr);
2212 cb.unlinkToDeath(hdlr, 0);
2213 }
2214 // force reading new top of mSetModeDeathHandlers stack
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002215 if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002216 mode = AudioSystem.MODE_NORMAL;
2217 }
2218 } else {
2219 status = AudioSystem.AUDIO_STATUS_OK;
2220 }
2221 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
2222
2223 if (status == AudioSystem.AUDIO_STATUS_OK) {
2224 if (mode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002225 if (mSetModeDeathHandlers.isEmpty()) {
2226 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
2227 } else {
2228 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2229 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002230 }
2231 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002232 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07002233 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
John Spurlock90874332015-03-10 16:00:54 -04002234 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, caller);
Eric Laurent6d517662012-04-23 18:42:39 -07002235
John Spurlock90874332015-03-10 16:00:54 -04002236 updateStreamVolumeAlias(true /*updateVolumes*/, caller);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002237 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002238 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002239 }
2240
2241 /** @see AudioManager#getMode() */
2242 public int getMode() {
2243 return mMode;
2244 }
2245
Eric Laurente78fced2013-03-15 16:03:47 -07002246 //==========================================================================================
2247 // Sound Effects
2248 //==========================================================================================
2249
2250 private static final String TAG_AUDIO_ASSETS = "audio_assets";
2251 private static final String ATTR_VERSION = "version";
2252 private static final String TAG_GROUP = "group";
2253 private static final String ATTR_GROUP_NAME = "name";
2254 private static final String TAG_ASSET = "asset";
2255 private static final String ATTR_ASSET_ID = "id";
2256 private static final String ATTR_ASSET_FILE = "file";
2257
2258 private static final String ASSET_FILE_VERSION = "1.0";
2259 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
2260
Glenn Kasten167d1a22013-07-23 16:24:41 -07002261 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002262
2263 class LoadSoundEffectReply {
2264 public int mStatus = 1;
2265 };
2266
Eric Laurente78fced2013-03-15 16:03:47 -07002267 private void loadTouchSoundAssetDefaults() {
2268 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
2269 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
2270 SOUND_EFFECT_FILES_MAP[i][0] = 0;
2271 SOUND_EFFECT_FILES_MAP[i][1] = -1;
2272 }
2273 }
2274
2275 private void loadTouchSoundAssets() {
2276 XmlResourceParser parser = null;
2277
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002278 // only load assets once.
2279 if (!SOUND_EFFECT_FILES.isEmpty()) {
2280 return;
2281 }
2282
Eric Laurente78fced2013-03-15 16:03:47 -07002283 loadTouchSoundAssetDefaults();
2284
2285 try {
2286 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
2287
2288 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
2289 String version = parser.getAttributeValue(null, ATTR_VERSION);
2290 boolean inTouchSoundsGroup = false;
2291
2292 if (ASSET_FILE_VERSION.equals(version)) {
2293 while (true) {
2294 XmlUtils.nextElement(parser);
2295 String element = parser.getName();
2296 if (element == null) {
2297 break;
2298 }
2299 if (element.equals(TAG_GROUP)) {
2300 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
2301 if (GROUP_TOUCH_SOUNDS.equals(name)) {
2302 inTouchSoundsGroup = true;
2303 break;
2304 }
2305 }
2306 }
2307 while (inTouchSoundsGroup) {
2308 XmlUtils.nextElement(parser);
2309 String element = parser.getName();
2310 if (element == null) {
2311 break;
2312 }
2313 if (element.equals(TAG_ASSET)) {
2314 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
2315 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
2316 int fx;
2317
2318 try {
2319 Field field = AudioManager.class.getField(id);
2320 fx = field.getInt(null);
2321 } catch (Exception e) {
2322 Log.w(TAG, "Invalid touch sound ID: "+id);
2323 continue;
2324 }
2325
2326 int i = SOUND_EFFECT_FILES.indexOf(file);
2327 if (i == -1) {
2328 i = SOUND_EFFECT_FILES.size();
2329 SOUND_EFFECT_FILES.add(file);
2330 }
2331 SOUND_EFFECT_FILES_MAP[fx][0] = i;
2332 } else {
2333 break;
2334 }
2335 }
2336 }
2337 } catch (Resources.NotFoundException e) {
2338 Log.w(TAG, "audio assets file not found", e);
2339 } catch (XmlPullParserException e) {
2340 Log.w(TAG, "XML parser exception reading touch sound assets", e);
2341 } catch (IOException e) {
2342 Log.w(TAG, "I/O exception reading touch sound assets", e);
2343 } finally {
2344 if (parser != null) {
2345 parser.close();
2346 }
2347 }
2348 }
2349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002350 /** @see AudioManager#playSoundEffect(int) */
2351 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002352 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002353 }
2354
2355 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002356 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07002357 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
2358 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
2359 return;
2360 }
2361
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002362 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002363 effectType, (int) (volume * 1000), null, 0);
2364 }
2365
2366 /**
2367 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08002368 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002369 */
2370 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002371 int attempts = 3;
2372 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08002373
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002374 synchronized (reply) {
2375 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
2376 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08002377 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07002378 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002379 } catch (InterruptedException e) {
2380 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08002381 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002382 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002383 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002384 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002385 }
2386
2387 /**
2388 * Unloads samples from the sound pool.
2389 * This method can be called to free some memory when
2390 * sound effects are disabled.
2391 */
2392 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002393 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002394 }
2395
Eric Laurenta60e2122010-12-28 16:49:07 -08002396 class SoundPoolListenerThread extends Thread {
2397 public SoundPoolListenerThread() {
2398 super("SoundPoolListenerThread");
2399 }
2400
2401 @Override
2402 public void run() {
2403
2404 Looper.prepare();
2405 mSoundPoolLooper = Looper.myLooper();
2406
2407 synchronized (mSoundEffectsLock) {
2408 if (mSoundPool != null) {
2409 mSoundPoolCallBack = new SoundPoolCallback();
2410 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2411 }
2412 mSoundEffectsLock.notify();
2413 }
2414 Looper.loop();
2415 }
2416 }
2417
2418 private final class SoundPoolCallback implements
2419 android.media.SoundPool.OnLoadCompleteListener {
2420
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002421 int mStatus = 1; // 1 means neither error nor last sample loaded yet
2422 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08002423
2424 public int status() {
2425 return mStatus;
2426 }
2427
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002428 public void setSamples(int[] samples) {
2429 for (int i = 0; i < samples.length; i++) {
2430 // do not wait ack for samples rejected upfront by SoundPool
2431 if (samples[i] > 0) {
2432 mSamples.add(samples[i]);
2433 }
2434 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002435 }
2436
2437 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2438 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002439 int i = mSamples.indexOf(sampleId);
2440 if (i >= 0) {
2441 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08002442 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002443 if ((status != 0) || mSamples. isEmpty()) {
2444 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08002445 mSoundEffectsLock.notify();
2446 }
2447 }
2448 }
2449 }
2450
Eric Laurent4050c932009-07-08 02:52:14 -07002451 /** @see AudioManager#reloadAudioSettings() */
2452 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002453 readAudioSettings(false /*userSwitch*/);
2454 }
2455
2456 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07002457 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2458 readPersistedSettings();
2459
2460 // restore volume settings
2461 int numStreamTypes = AudioSystem.getNumStreamTypes();
2462 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2463 VolumeStreamState streamState = mStreamStates[streamType];
2464
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002465 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2466 continue;
2467 }
2468
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002469 streamState.readSettings();
2470 synchronized (VolumeStreamState.class) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002471 // unmute stream that was muted but is not affect by mute anymore
RoboErik4197cb62015-01-21 15:45:32 -08002472 if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07002473 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
RoboErik4197cb62015-01-21 15:45:32 -08002474 streamState.mIsMuted = false;
Eric Laurent4050c932009-07-08 02:52:14 -07002475 }
Eric Laurent4050c932009-07-08 02:52:14 -07002476 }
2477 }
2478
Eric Laurent33902db2012-10-07 16:15:07 -07002479 // apply new ringer mode before checking volume for alias streams so that streams
2480 // muted by ringer mode have the correct volume
John Spurlock661f2cf2014-11-17 10:29:10 -05002481 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent33902db2012-10-07 16:15:07 -07002482
Eric Laurent212532b2014-07-21 15:43:18 -07002483 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07002484 checkAllAliasStreamVolumes();
John Spurlockb6e19e32015-03-10 21:33:44 -04002485 checkMuteAffectedStreams();
Eric Laurent24482012012-05-10 09:41:17 -07002486
Eric Laurentd640bd32012-09-28 18:01:48 -07002487 synchronized (mSafeMediaVolumeState) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002488 mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2489 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2490 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
Eric Laurentd640bd32012-09-28 18:01:48 -07002491 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
John Spurlock90874332015-03-10 16:00:54 -04002492 enforceSafeMediaVolume(TAG);
Eric Laurentf1a457d2012-09-20 16:27:23 -07002493 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07002494 }
Eric Laurent4050c932009-07-08 02:52:14 -07002495 }
2496
Dianne Hackborn961cae92013-03-20 14:59:43 -07002497 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002498 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002499 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2500 return;
2501 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002502
2503 if (on) {
2504 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2505 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2506 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
2507 }
2508 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2509 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2510 mForcedUseForComm = AudioSystem.FORCE_NONE;
2511 }
Eric Laurentfa640152011-03-12 15:59:51 -08002512
Eric Laurentafbb0472011-12-15 09:04:23 -08002513 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002514 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002515 }
2516
2517 /** @see AudioManager#isSpeakerphoneOn() */
2518 public boolean isSpeakerphoneOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002519 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002520 }
2521
Dianne Hackborn961cae92013-03-20 14:59:43 -07002522 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002523 public void setBluetoothScoOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002524 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2525 return;
2526 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002527
2528 if (on) {
2529 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2530 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2531 mForcedUseForComm = AudioSystem.FORCE_NONE;
2532 }
Eric Laurentfa640152011-03-12 15:59:51 -08002533
Eric Laurentafbb0472011-12-15 09:04:23 -08002534 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002535 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08002536 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002537 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002538 }
2539
2540 /** @see AudioManager#isBluetoothScoOn() */
2541 public boolean isBluetoothScoOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002542 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002543 }
2544
Dianne Hackborn961cae92013-03-20 14:59:43 -07002545 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07002546 public void setBluetoothA2dpOn(boolean on) {
Eric Laurentc390bed2012-07-03 12:24:05 -07002547 synchronized (mBluetoothA2dpEnabledLock) {
2548 mBluetoothA2dpEnabled = on;
2549 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2550 AudioSystem.FOR_MEDIA,
2551 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2552 null, 0);
2553 }
Eric Laurent78472112012-05-21 08:57:21 -07002554 }
2555
2556 /** @see AudioManager#isBluetoothA2dpOn() */
2557 public boolean isBluetoothA2dpOn() {
2558 synchronized (mBluetoothA2dpEnabledLock) {
2559 return mBluetoothA2dpEnabled;
2560 }
2561 }
2562
Eric Laurent3def1ee2010-03-17 23:26:26 -07002563 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07002564 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
2565 int scoAudioMode =
2566 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
Liejun Taof4e51d82014-07-16 11:18:29 -07002567 SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
Eric Laurent83900752014-05-15 15:14:22 -07002568 startBluetoothScoInt(cb, scoAudioMode);
2569 }
2570
2571 /** @see AudioManager#startBluetoothScoVirtualCall() */
2572 public void startBluetoothScoVirtualCall(IBinder cb) {
2573 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
2574 }
2575
2576 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07002577 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002578 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002579 return;
2580 }
Eric Laurent854938a2011-02-22 12:05:20 -08002581 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002582 // The calling identity must be cleared before calling ScoClient.incCount().
2583 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2584 // and this must be done on behalf of system server to make sure permissions are granted.
2585 // The caller identity must be cleared after getScoClient() because it is needed if a new
2586 // client is created.
2587 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07002588 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08002589 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002590 }
2591
2592 /** @see AudioManager#stopBluetoothSco() */
2593 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07002594 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002595 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002596 return;
2597 }
Eric Laurent854938a2011-02-22 12:05:20 -08002598 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002599 // The calling identity must be cleared before calling ScoClient.decCount().
2600 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2601 // and this must be done on behalf of system server to make sure permissions are granted.
2602 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08002603 if (client != null) {
2604 client.decCount();
2605 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08002606 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002607 }
2608
Eric Laurent78472112012-05-21 08:57:21 -07002609
Eric Laurent3def1ee2010-03-17 23:26:26 -07002610 private class ScoClient implements IBinder.DeathRecipient {
2611 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002612 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002613 private int mStartcount; // number of SCO connections started by this client
2614
2615 ScoClient(IBinder cb) {
2616 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002617 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002618 mStartcount = 0;
2619 }
2620
2621 public void binderDied() {
2622 synchronized(mScoClients) {
2623 Log.w(TAG, "SCO client died");
2624 int index = mScoClients.indexOf(this);
2625 if (index < 0) {
2626 Log.w(TAG, "unregistered SCO client died");
2627 } else {
2628 clearCount(true);
2629 mScoClients.remove(this);
2630 }
2631 }
2632 }
2633
Eric Laurent83900752014-05-15 15:14:22 -07002634 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002635 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07002636 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002637 if (mStartcount == 0) {
2638 try {
2639 mCb.linkToDeath(this, 0);
2640 } catch (RemoteException e) {
2641 // client has already died!
2642 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
2643 }
2644 }
2645 mStartcount++;
2646 }
2647 }
2648
2649 public void decCount() {
2650 synchronized(mScoClients) {
2651 if (mStartcount == 0) {
2652 Log.w(TAG, "ScoClient.decCount() already 0");
2653 } else {
2654 mStartcount--;
2655 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002656 try {
2657 mCb.unlinkToDeath(this, 0);
2658 } catch (NoSuchElementException e) {
2659 Log.w(TAG, "decCount() going to 0 but not registered to binder");
2660 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002661 }
Eric Laurentc18c9132013-04-12 17:24:56 -07002662 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002663 }
2664 }
2665 }
2666
2667 public void clearCount(boolean stopSco) {
2668 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002669 if (mStartcount != 0) {
2670 try {
2671 mCb.unlinkToDeath(this, 0);
2672 } catch (NoSuchElementException e) {
2673 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2674 }
2675 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002676 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002677 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002678 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002679 }
2680 }
2681 }
2682
2683 public int getCount() {
2684 return mStartcount;
2685 }
2686
2687 public IBinder getBinder() {
2688 return mCb;
2689 }
2690
Eric Laurentd7454be2011-09-14 08:45:58 -07002691 public int getPid() {
2692 return mCreatorPid;
2693 }
2694
Eric Laurent3def1ee2010-03-17 23:26:26 -07002695 public int totalCount() {
2696 synchronized(mScoClients) {
2697 int count = 0;
2698 int size = mScoClients.size();
2699 for (int i = 0; i < size; i++) {
2700 count += mScoClients.get(i).getCount();
2701 }
2702 return count;
2703 }
2704 }
2705
Eric Laurent83900752014-05-15 15:14:22 -07002706 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08002707 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07002708 if (totalCount() == 0) {
2709 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2710 // Make sure that the state transitions to CONNECTING even if we cannot initiate
2711 // the connection.
2712 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2713 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002714 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07002715 synchronized(mSetModeDeathHandlers) {
2716 if ((mSetModeDeathHandlers.isEmpty() ||
2717 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2718 (mScoAudioState == SCO_STATE_INACTIVE ||
2719 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2720 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07002721 mScoAudioMode = scoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -07002722 if (scoAudioMode == SCO_MODE_UNDEFINED) {
Andre Eisenbach570cc532014-10-28 17:03:18 -07002723 if (mBluetoothHeadsetDevice != null) {
2724 mScoAudioMode = new Integer(Settings.Global.getInt(
2725 mContentResolver,
2726 "bluetooth_sco_channel_"+
2727 mBluetoothHeadsetDevice.getAddress(),
2728 SCO_MODE_VIRTUAL_CALL));
2729 if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2730 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2731 }
2732 } else {
2733 mScoAudioMode = SCO_MODE_RAW;
Liejun Taof4e51d82014-07-16 11:18:29 -07002734 }
2735 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002736 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002737 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002738 if (mScoAudioMode == SCO_MODE_RAW) {
2739 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002740 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002741 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2742 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002743 } else if (mScoAudioMode == SCO_MODE_VR) {
2744 status = mBluetoothHeadset.startVoiceRecognition(
2745 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002746 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002747
Eric Laurentc18c9132013-04-12 17:24:56 -07002748 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07002749 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2750 } else {
2751 broadcastScoConnectionState(
2752 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2753 }
2754 } else if (getBluetoothHeadset()) {
2755 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07002756 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002757 } else {
2758 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2759 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002760 }
2761 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07002762 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002763 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002764 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002765 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002766 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2767 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2768 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07002769 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002770 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002771 if (mScoAudioMode == SCO_MODE_RAW) {
2772 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002773 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002774 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2775 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002776 } else if (mScoAudioMode == SCO_MODE_VR) {
2777 status = mBluetoothHeadset.stopVoiceRecognition(
2778 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002779 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002780
Eric Laurentc18c9132013-04-12 17:24:56 -07002781 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002782 mScoAudioState = SCO_STATE_INACTIVE;
2783 broadcastScoConnectionState(
2784 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2785 }
2786 } else if (getBluetoothHeadset()) {
2787 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2788 }
2789 } else {
2790 mScoAudioState = SCO_STATE_INACTIVE;
2791 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2792 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002793 }
2794 }
2795 }
2796 }
2797
Eric Laurent62ef7672010-11-24 10:58:32 -08002798 private void checkScoAudioState() {
2799 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002800 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08002801 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2802 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2803 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2804 }
2805 }
2806
Eric Laurent854938a2011-02-22 12:05:20 -08002807 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002808 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002809 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002810 int size = mScoClients.size();
2811 for (int i = 0; i < size; i++) {
2812 client = mScoClients.get(i);
2813 if (client.getBinder() == cb)
2814 return client;
2815 }
Eric Laurent854938a2011-02-22 12:05:20 -08002816 if (create) {
2817 client = new ScoClient(cb);
2818 mScoClients.add(client);
2819 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002820 return client;
2821 }
2822 }
2823
Eric Laurentd7454be2011-09-14 08:45:58 -07002824 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002825 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002826 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002827 int size = mScoClients.size();
2828 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08002829 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07002830 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08002831 cl.clearCount(stopSco);
2832 } else {
2833 savedClient = cl;
2834 }
2835 }
2836 mScoClients.clear();
2837 if (savedClient != null) {
2838 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002839 }
2840 }
2841 }
2842
Eric Laurentdc03c612011-04-01 10:59:41 -07002843 private boolean getBluetoothHeadset() {
2844 boolean result = false;
2845 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2846 if (adapter != null) {
2847 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2848 BluetoothProfile.HEADSET);
2849 }
2850 // If we could not get a bluetooth headset proxy, send a failure message
2851 // without delay to reset the SCO audio state and clear SCO clients.
2852 // If we could get a proxy, send a delayed failure message that will reset our state
2853 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08002854 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002855 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2856 return result;
2857 }
2858
Eric Laurentd7454be2011-09-14 08:45:58 -07002859 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002860 synchronized(mScoClients) {
2861 checkScoAudioState();
2862 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2863 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2864 if (mBluetoothHeadsetDevice != null) {
2865 if (mBluetoothHeadset != null) {
2866 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07002867 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002868 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002869 SENDMSG_REPLACE, 0, 0, null, 0);
2870 }
2871 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2872 getBluetoothHeadset()) {
2873 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2874 }
2875 }
2876 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07002877 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07002878 }
2879 }
2880 }
2881
2882 private void resetBluetoothSco() {
2883 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002884 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07002885 mScoAudioState = SCO_STATE_INACTIVE;
2886 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2887 }
2888 }
2889
2890 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08002891 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
2892 SENDMSG_QUEUE, state, 0, null, 0);
2893 }
2894
2895 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002896 if (state != mScoConnectionState) {
2897 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2898 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2899 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2900 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002901 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07002902 mScoConnectionState = state;
2903 }
2904 }
2905
Eric Laurent98859b22015-06-12 14:35:59 -07002906 void setBtScoDeviceConnectionState(BluetoothDevice btDevice, int state) {
2907 if (btDevice == null) {
2908 return;
2909 }
2910
2911 String address = btDevice.getAddress();
2912 BluetoothClass btClass = btDevice.getBluetoothClass();
2913 int outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
2914 int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
2915 if (btClass != null) {
2916 switch (btClass.getDeviceClass()) {
2917 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
2918 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
2919 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
2920 break;
2921 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
2922 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
2923 break;
2924 }
2925 }
2926
2927 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
2928 address = "";
2929 }
2930
2931 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
2932
2933 String btDeviceName = btDevice.getName();
2934 boolean success =
2935 handleDeviceConnection(connected, outDevice, address, btDeviceName) &&
2936 handleDeviceConnection(connected, inDevice, address, btDeviceName);
2937 if (success) {
2938 synchronized (mScoClients) {
2939 if (connected) {
2940 mBluetoothHeadsetDevice = btDevice;
2941 } else {
2942 mBluetoothHeadsetDevice = null;
2943 resetBluetoothSco();
2944 }
2945 }
2946 }
2947 }
2948
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002949 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
2950 new BluetoothProfile.ServiceListener() {
2951 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002952 BluetoothDevice btDevice;
2953 List<BluetoothDevice> deviceList;
2954 switch(profile) {
2955 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09002956 synchronized (mConnectedDevices) {
2957 synchronized (mA2dpAvrcpLock) {
2958 mA2dp = (BluetoothA2dp) proxy;
2959 deviceList = mA2dp.getConnectedDevices();
2960 if (deviceList.size() > 0) {
2961 btDevice = deviceList.get(0);
John Du5a0cf7a2013-07-19 11:30:34 -07002962 int state = mA2dp.getConnectionState(btDevice);
2963 int delay = checkSendBecomingNoisyIntent(
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002964 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2965 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
John Du5a0cf7a2013-07-19 11:30:34 -07002966 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002967 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07002968 state,
2969 0,
2970 btDevice,
2971 delay);
2972 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002973 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002974 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002975 break;
2976
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002977 case BluetoothProfile.A2DP_SINK:
2978 deviceList = proxy.getConnectedDevices();
2979 if (deviceList.size() > 0) {
2980 btDevice = deviceList.get(0);
2981 synchronized (mConnectedDevices) {
2982 int state = proxy.getConnectionState(btDevice);
2983 queueMsgUnderWakeLock(mAudioHandler,
2984 MSG_SET_A2DP_SRC_CONNECTION_STATE,
2985 state,
2986 0,
2987 btDevice,
2988 0 /* delay */);
2989 }
2990 }
2991 break;
2992
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002993 case BluetoothProfile.HEADSET:
2994 synchronized (mScoClients) {
2995 // Discard timeout message
2996 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
2997 mBluetoothHeadset = (BluetoothHeadset) proxy;
2998 deviceList = mBluetoothHeadset.getConnectedDevices();
2999 if (deviceList.size() > 0) {
3000 mBluetoothHeadsetDevice = deviceList.get(0);
3001 } else {
3002 mBluetoothHeadsetDevice = null;
3003 }
3004 // Refresh SCO audio state
3005 checkScoAudioState();
3006 // Continue pending action if any
3007 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
3008 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
3009 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
3010 boolean status = false;
3011 if (mBluetoothHeadsetDevice != null) {
3012 switch (mScoAudioState) {
3013 case SCO_STATE_ACTIVATE_REQ:
3014 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07003015 if (mScoAudioMode == SCO_MODE_RAW) {
3016 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003017 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003018 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
3019 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003020 } else if (mScoAudioMode == SCO_MODE_VR) {
3021 status = mBluetoothHeadset.startVoiceRecognition(
3022 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003023 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003024 break;
3025 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07003026 if (mScoAudioMode == SCO_MODE_RAW) {
3027 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003028 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003029 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
3030 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003031 } else if (mScoAudioMode == SCO_MODE_VR) {
3032 status = mBluetoothHeadset.stopVoiceRecognition(
3033 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003034 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003035 break;
3036 case SCO_STATE_DEACTIVATE_EXT_REQ:
3037 status = mBluetoothHeadset.stopVoiceRecognition(
3038 mBluetoothHeadsetDevice);
3039 }
3040 }
3041 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08003042 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003043 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07003044 }
3045 }
Eric Laurentdc03c612011-04-01 10:59:41 -07003046 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003047 break;
3048
3049 default:
3050 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003051 }
3052 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07003053 public void onServiceDisconnected(int profile) {
John Spurlock8c3dc852015-04-23 21:32:37 -04003054 ArraySet<String> toRemove = null;
Paul McLean394a8e12015-03-03 10:29:19 -07003055 switch (profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003056 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09003057 synchronized (mConnectedDevices) {
3058 synchronized (mA2dpAvrcpLock) {
Paul McLean394a8e12015-03-03 10:29:19 -07003059 // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
John Spurlock8c3dc852015-04-23 21:32:37 -04003060 for (int i = 0; i < mConnectedDevices.size(); i++) {
3061 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
Paul McLean394a8e12015-03-03 10:29:19 -07003062 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
John Spurlock8c3dc852015-04-23 21:32:37 -04003063 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
3064 toRemove.add(deviceSpec.mDeviceAddress);
3065 }
3066 }
3067 if (toRemove != null) {
Eric Laurentd138e4e2015-05-15 16:41:15 -07003068 int delay = checkSendBecomingNoisyIntent(
3069 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3070 0);
John Spurlock8c3dc852015-04-23 21:32:37 -04003071 for (int i = 0; i < toRemove.size(); i++) {
Eric Laurentd138e4e2015-05-15 16:41:15 -07003072 makeA2dpDeviceUnavailableLater(toRemove.valueAt(i), delay);
Paul McLean394a8e12015-03-03 10:29:19 -07003073 }
John Du5a0cf7a2013-07-19 11:30:34 -07003074 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003075 }
3076 }
3077 break;
3078
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003079 case BluetoothProfile.A2DP_SINK:
3080 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07003081 // Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
John Spurlock8c3dc852015-04-23 21:32:37 -04003082 for(int i = 0; i < mConnectedDevices.size(); i++) {
3083 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
Paul McLean394a8e12015-03-03 10:29:19 -07003084 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) {
John Spurlock8c3dc852015-04-23 21:32:37 -04003085 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
3086 toRemove.add(deviceSpec.mDeviceAddress);
3087 }
3088 }
3089 if (toRemove != null) {
3090 for (int i = 0; i < toRemove.size(); i++) {
3091 makeA2dpSrcUnavailable(toRemove.valueAt(i));
Paul McLean394a8e12015-03-03 10:29:19 -07003092 }
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003093 }
3094 }
3095 break;
3096
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003097 case BluetoothProfile.HEADSET:
3098 synchronized (mScoClients) {
Eric Laurent98859b22015-06-12 14:35:59 -07003099 if (mBluetoothHeadsetDevice != null) {
3100 setBtScoDeviceConnectionState(mBluetoothHeadsetDevice,
3101 BluetoothProfile.STATE_DISCONNECTED);
3102 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003103 mBluetoothHeadset = null;
3104 }
3105 break;
3106
3107 default:
3108 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003109 }
3110 }
3111 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003112
John Spurlock90874332015-03-10 16:00:54 -04003113 private void onCheckMusicActive(String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07003114 synchronized (mSafeMediaVolumeState) {
3115 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07003116 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
3117
3118 if ((device & mSafeMediaVolumeDevices) != 0) {
3119 sendMsg(mAudioHandler,
3120 MSG_CHECK_MUSIC_ACTIVE,
3121 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07003122 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07003123 0,
John Spurlock90874332015-03-10 16:00:54 -04003124 caller,
Eric Laurentc34dcc12012-09-10 13:51:52 -07003125 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07003126 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07003127 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
3128 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07003129 // Approximate cumulative active music time
3130 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
3131 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
John Spurlock90874332015-03-10 16:00:54 -04003132 setSafeMediaVolumeEnabled(true, caller);
Eric Laurentc34dcc12012-09-10 13:51:52 -07003133 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07003134 }
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003135 saveMusicActiveMs();
Eric Laurentc34dcc12012-09-10 13:51:52 -07003136 }
3137 }
3138 }
3139 }
3140 }
3141
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003142 private void saveMusicActiveMs() {
3143 mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
3144 }
3145
John Spurlock90874332015-03-10 16:00:54 -04003146 private void onConfigureSafeVolume(boolean force, String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07003147 synchronized (mSafeMediaVolumeState) {
3148 int mcc = mContext.getResources().getConfiguration().mcc;
3149 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
3150 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
3151 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
John Spurlock35134602014-07-24 18:10:48 -04003152 boolean safeMediaVolumeEnabled =
3153 SystemProperties.getBoolean("audio.safemedia.force", false)
3154 || mContext.getResources().getBoolean(
3155 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08003156
Ricardo Garcia3a30a762015-06-23 15:54:45 -07003157 boolean safeMediaVolumeBypass =
3158 SystemProperties.getBoolean("audio.safemedia.bypass", false);
3159
Eric Laurent05274f32012-11-29 12:48:18 -08003160 // The persisted state is either "disabled" or "active": this is the state applied
3161 // next time we boot and cannot be "inactive"
3162 int persistedState;
Ricardo Garcia3a30a762015-06-23 15:54:45 -07003163 if (safeMediaVolumeEnabled && !safeMediaVolumeBypass) {
Eric Laurent05274f32012-11-29 12:48:18 -08003164 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
3165 // The state can already be "inactive" here if the user has forced it before
3166 // the 30 seconds timeout for forced configuration. In this case we don't reset
3167 // it to "active".
3168 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003169 if (mMusicActiveMs == 0) {
3170 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
John Spurlock90874332015-03-10 16:00:54 -04003171 enforceSafeMediaVolume(caller);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003172 } else {
3173 // We have existing playback time recorded, already confirmed.
3174 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
3175 }
Eric Laurent05274f32012-11-29 12:48:18 -08003176 }
Eric Laurentd640bd32012-09-28 18:01:48 -07003177 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08003178 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07003179 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
3180 }
3181 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08003182 sendMsg(mAudioHandler,
3183 MSG_PERSIST_SAFE_VOLUME_STATE,
3184 SENDMSG_QUEUE,
3185 persistedState,
3186 0,
3187 null,
3188 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07003189 }
3190 }
3191 }
3192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003193 ///////////////////////////////////////////////////////////////////////////
3194 // Internal methods
3195 ///////////////////////////////////////////////////////////////////////////
3196
3197 /**
3198 * Checks if the adjustment should change ringer mode instead of just
3199 * adjusting volume. If so, this will set the proper ringer mode and volume
3200 * indices on the stream states.
3201 */
John Spurlocka48d7792015-03-03 17:35:57 -05003202 private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted) {
3203 final boolean isTv = mPlatformType == AudioSystem.PLATFORM_TELEVISION;
John Spurlocka11b4af2014-06-01 11:52:23 -04003204 int result = FLAG_ADJUST_VOLUME;
John Spurlock661f2cf2014-11-17 10:29:10 -05003205 int ringerMode = getRingerModeInternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003206
Eric Laurentbffc3d12012-05-07 17:43:49 -07003207 switch (ringerMode) {
3208 case RINGER_MODE_NORMAL:
3209 if (direction == AudioManager.ADJUST_LOWER) {
3210 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07003211 // "step" is the delta in internal index units corresponding to a
3212 // change of 1 in UI index units.
3213 // Because of rounding when rescaling from one stream index range to its alias
3214 // index range, we cannot simply test oldIndex == step:
3215 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
3216 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003217 ringerMode = RINGER_MODE_VIBRATE;
John Spurlock07e72432015-03-13 11:46:52 -04003218 mLoweredFromNormalToVibrateTime = SystemClock.uptimeMillis();
Eric Laurentbffc3d12012-05-07 17:43:49 -07003219 }
3220 } else {
John Spurlockd9c75db2015-04-28 11:19:13 -04003221 if (oldIndex == step && mVolumePolicy.volumeDownToEnterSilent) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003222 ringerMode = RINGER_MODE_SILENT;
3223 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07003224 }
John Spurlocka48d7792015-03-03 17:35:57 -05003225 } else if (isTv && (direction == AudioManager.ADJUST_TOGGLE_MUTE
3226 || direction == AudioManager.ADJUST_MUTE)) {
RoboErik5452e252015-02-06 15:33:53 -08003227 if (mHasVibrator) {
3228 ringerMode = RINGER_MODE_VIBRATE;
3229 } else {
3230 ringerMode = RINGER_MODE_SILENT;
3231 }
3232 // Setting the ringer mode will toggle mute
3233 result &= ~FLAG_ADJUST_VOLUME;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003234 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003235 break;
3236 case RINGER_MODE_VIBRATE:
3237 if (!mHasVibrator) {
3238 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
3239 "but no vibrator is present");
3240 break;
3241 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003242 if ((direction == AudioManager.ADJUST_LOWER)) {
RoboErik5452e252015-02-06 15:33:53 -08003243 // This is the case we were muted with the volume turned up
John Spurlocka48d7792015-03-03 17:35:57 -05003244 if (isTv && oldIndex >= 2 * step && isMuted) {
RoboErik5452e252015-02-06 15:33:53 -08003245 ringerMode = RINGER_MODE_NORMAL;
3246 } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
John Spurlocka48d7792015-03-03 17:35:57 -05003247 if (mVolumePolicy.volumeDownToEnterSilent) {
John Spurlock07e72432015-03-13 11:46:52 -04003248 final long diff = SystemClock.uptimeMillis()
3249 - mLoweredFromNormalToVibrateTime;
John Spurlockd9c75db2015-04-28 11:19:13 -04003250 if (diff > mVolumePolicy.vibrateToSilentDebounce
3251 && mRingerModeDelegate.canVolumeDownEnterSilent()) {
John Spurlock07e72432015-03-13 11:46:52 -04003252 ringerMode = RINGER_MODE_SILENT;
3253 }
John Spurlock795a5142014-12-08 14:09:35 -05003254 } else {
3255 result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
3256 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003257 }
RoboErik5452e252015-02-06 15:33:53 -08003258 } else if (direction == AudioManager.ADJUST_RAISE
3259 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3260 || direction == AudioManager.ADJUST_UNMUTE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003261 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07003262 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003263 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003264 break;
3265 case RINGER_MODE_SILENT:
John Spurlocka48d7792015-03-03 17:35:57 -05003266 if (isTv && direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
RoboErik5452e252015-02-06 15:33:53 -08003267 // This is the case we were muted with the volume turned up
3268 ringerMode = RINGER_MODE_NORMAL;
3269 } else if (direction == AudioManager.ADJUST_RAISE
3270 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3271 || direction == AudioManager.ADJUST_UNMUTE) {
John Spurlocka48d7792015-03-03 17:35:57 -05003272 if (!mVolumePolicy.volumeUpToExitSilent) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003273 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003274 } else {
RoboErik5452e252015-02-06 15:33:53 -08003275 if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003276 ringerMode = RINGER_MODE_VIBRATE;
3277 } else {
RoboErik5452e252015-02-06 15:33:53 -08003278 // If we don't have a vibrator or they were toggling mute
3279 // go straight back to normal.
John Spurlocka11b4af2014-06-01 11:52:23 -04003280 ringerMode = RINGER_MODE_NORMAL;
3281 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003282 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05003283 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003284 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003285 break;
3286 default:
3287 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
3288 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003289 }
3290
John Spurlock661f2cf2014-11-17 10:29:10 -05003291 setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003292
Eric Laurent25101b02011-02-02 09:33:30 -08003293 mPrevVolDirection = direction;
3294
John Spurlocka11b4af2014-06-01 11:52:23 -04003295 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003296 }
3297
John Spurlock3346a802014-05-20 16:25:37 -04003298 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003299 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07003300 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003301 }
3302
Eric Laurent5b4e6542010-03-19 20:02:21 -07003303 private boolean isStreamMutedByRingerMode(int streamType) {
3304 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
3305 }
3306
John Spurlock50ced3f2015-05-11 16:00:09 -04003307 private boolean updateRingerModeAffectedStreams() {
3308 int ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003309 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3310 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
3311 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
3312 UserHandle.USER_CURRENT);
3313
John Spurlock50ced3f2015-05-11 16:00:09 -04003314 if (mPlatformType == AudioSystem.PLATFORM_TELEVISION) {
3315 ringerModeAffectedStreams = 0;
3316 } else if (mRingerModeDelegate != null) {
3317 ringerModeAffectedStreams = mRingerModeDelegate
3318 .getRingerModeAffectedStreams(ringerModeAffectedStreams);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003319 }
3320 synchronized (mCameraSoundForced) {
3321 if (mCameraSoundForced) {
3322 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3323 } else {
3324 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3325 }
3326 }
3327 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
3328 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
3329 } else {
3330 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
3331 }
3332
3333 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3334 Settings.System.putIntForUser(mContentResolver,
3335 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3336 ringerModeAffectedStreams,
3337 UserHandle.USER_CURRENT);
3338 mRingerModeAffectedStreams = ringerModeAffectedStreams;
3339 return true;
3340 }
3341 return false;
3342 }
3343
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05003344 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003345 public boolean isStreamAffectedByMute(int streamType) {
3346 return (mMuteAffectedStreams & (1 << streamType)) != 0;
3347 }
3348
3349 private void ensureValidDirection(int direction) {
RoboErik4197cb62015-01-21 15:45:32 -08003350 switch (direction) {
3351 case AudioManager.ADJUST_LOWER:
3352 case AudioManager.ADJUST_RAISE:
3353 case AudioManager.ADJUST_SAME:
3354 case AudioManager.ADJUST_MUTE:
3355 case AudioManager.ADJUST_UNMUTE:
3356 case AudioManager.ADJUST_TOGGLE_MUTE:
3357 break;
3358 default:
3359 throw new IllegalArgumentException("Bad direction " + direction);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003360 }
3361 }
3362
3363 private void ensureValidStreamType(int streamType) {
3364 if (streamType < 0 || streamType >= mStreamStates.length) {
3365 throw new IllegalArgumentException("Bad stream type " + streamType);
3366 }
3367 }
3368
RoboErik4197cb62015-01-21 15:45:32 -08003369 private boolean isMuteAdjust(int adjust) {
3370 return adjust == AudioManager.ADJUST_MUTE || adjust == AudioManager.ADJUST_UNMUTE
3371 || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
3372 }
3373
Eric Laurent6d517662012-04-23 18:42:39 -07003374 private boolean isInCommunication() {
Nancy Chen0eb1e402014-08-21 22:52:29 -07003375 boolean IsInCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003376
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003377 TelecomManager telecomManager =
3378 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
Eric Laurent38edfda2014-12-18 17:38:04 -08003379
3380 final long ident = Binder.clearCallingIdentity();
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003381 IsInCall = telecomManager.isInCall();
Eric Laurent38edfda2014-12-18 17:38:04 -08003382 Binder.restoreCallingIdentity(ident);
Santos Cordon9eb45932014-06-27 12:28:43 -07003383
Nancy Chen0eb1e402014-08-21 22:52:29 -07003384 return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
Eric Laurent6d517662012-04-23 18:42:39 -07003385 }
Eric Laurent25101b02011-02-02 09:33:30 -08003386
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003387 /**
3388 * For code clarity for getActiveStreamType(int)
3389 * @param delay_ms max time since last STREAM_MUSIC activity to consider
3390 * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
3391 * in the last "delay_ms" ms.
3392 */
3393 private boolean isAfMusicActiveRecently(int delay_ms) {
3394 return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
3395 || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
3396 }
3397
Eric Laurent6d517662012-04-23 18:42:39 -07003398 private int getActiveStreamType(int suggestedStreamType) {
Eric Laurent212532b2014-07-21 15:43:18 -07003399 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003400 case AudioSystem.PLATFORM_VOICE:
Eric Laurent6d517662012-04-23 18:42:39 -07003401 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003402 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3403 == AudioSystem.FORCE_BT_SCO) {
3404 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
3405 return AudioSystem.STREAM_BLUETOOTH_SCO;
3406 } else {
3407 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
3408 return AudioSystem.STREAM_VOICE_CALL;
3409 }
Eric Laurent25101b02011-02-02 09:33:30 -08003410 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003411 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003412 if (DEBUG_VOL)
3413 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3414 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003415 } else {
3416 if (DEBUG_VOL)
3417 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
3418 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003419 }
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003420 } else if (isAfMusicActiveRecently(0)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003421 if (DEBUG_VOL)
3422 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3423 return AudioSystem.STREAM_MUSIC;
Eric Laurent25101b02011-02-02 09:33:30 -08003424 }
Eric Laurent212532b2014-07-21 15:43:18 -07003425 break;
John Spurlock61560172015-02-06 19:46:04 -05003426 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -07003427 if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
RoboErik2811dd32014-08-12 09:48:13 -07003428 // TV always defaults to STREAM_MUSIC
Eric Laurent212532b2014-07-21 15:43:18 -07003429 return AudioSystem.STREAM_MUSIC;
Eric Laurent212532b2014-07-21 15:43:18 -07003430 }
3431 break;
3432 default:
Eric Laurent6d517662012-04-23 18:42:39 -07003433 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003434 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3435 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003436 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08003437 return AudioSystem.STREAM_BLUETOOTH_SCO;
3438 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003439 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08003440 return AudioSystem.STREAM_VOICE_CALL;
3441 }
3442 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003443 StreamOverride.sDelayMs) ||
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003444 AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003445 StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003446 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08003447 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003448 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003449 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003450 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
3451 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003452 } else {
John Spurlockeb1d88d2014-07-19 14:49:19 -04003453 if (DEBUG_VOL) Log.v(TAG,
3454 "getActiveStreamType: using STREAM_NOTIFICATION as default");
3455 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003456 }
Joe Onoratoc7fcba42011-01-05 16:53:11 -08003457 }
Eric Laurent212532b2014-07-21 15:43:18 -07003458 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003459 }
Eric Laurent212532b2014-07-21 15:43:18 -07003460 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
3461 + suggestedStreamType);
3462 return suggestedStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003463 }
3464
John Spurlockbcc10872014-11-28 15:29:21 -05003465 private void broadcastRingerMode(String action, int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003466 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05003467 Intent broadcast = new Intent(action);
Glenn Kastenba195eb2011-12-13 09:30:40 -08003468 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003469 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
3470 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003471 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003472 }
3473
3474 private void broadcastVibrateSetting(int vibrateType) {
3475 // Send broadcast
3476 if (ActivityManagerNative.isSystemReady()) {
3477 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
3478 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
3479 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003480 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003481 }
3482 }
3483
3484 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003485 /**
3486 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
3487 * Note that the wake lock needs to be released after the message has been handled.
3488 */
3489 private void queueMsgUnderWakeLock(Handler handler, int msg,
3490 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003491 final long ident = Binder.clearCallingIdentity();
3492 // Always acquire the wake lock as AudioService because it is released by the
3493 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003494 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003495 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003496 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
3497 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003498
Eric Laurentafbb0472011-12-15 09:04:23 -08003499 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003500 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003501
3502 if (existingMsgPolicy == SENDMSG_REPLACE) {
3503 handler.removeMessages(msg);
3504 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
3505 return;
3506 }
Eric Laurentadbe8bf2014-11-03 18:26:32 -08003507 synchronized (mLastDeviceConnectMsgTime) {
3508 long time = SystemClock.uptimeMillis() + delay;
3509 handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
3510 if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
3511 msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
3512 msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
3513 mLastDeviceConnectMsgTime = time;
3514 }
3515 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003516 }
3517
3518 boolean checkAudioSettingsPermission(String method) {
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07003519 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003520 == PackageManager.PERMISSION_GRANTED) {
3521 return true;
3522 }
3523 String msg = "Audio Settings Permission Denial: " + method + " from pid="
3524 + Binder.getCallingPid()
3525 + ", uid=" + Binder.getCallingUid();
3526 Log.w(TAG, msg);
3527 return false;
3528 }
3529
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003530 private int getDeviceForStream(int stream) {
John Spurlock8a52c442015-03-26 14:23:58 -04003531 int device = getDevicesForStream(stream);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003532 if ((device & (device - 1)) != 0) {
3533 // Multiple device selection is either:
3534 // - speaker + one other device: give priority to speaker in this case.
3535 // - one A2DP device + another device: happens with duplicated output. In this case
3536 // retain the device on the A2DP output as the other must not correspond to an active
3537 // selection if not the speaker.
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003538 // - HDMI-CEC system audio mode only output: give priority to available item in order.
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003539 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
3540 device = AudioSystem.DEVICE_OUT_SPEAKER;
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003541 } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
3542 device = AudioSystem.DEVICE_OUT_HDMI_ARC;
3543 } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
3544 device = AudioSystem.DEVICE_OUT_SPDIF;
3545 } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
3546 device = AudioSystem.DEVICE_OUT_AUX_LINE;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003547 } else {
3548 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
3549 }
3550 }
3551 return device;
3552 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003553
John Spurlock8a52c442015-03-26 14:23:58 -04003554 private int getDevicesForStream(int stream) {
3555 return getDevicesForStream(stream, true /*checkOthers*/);
3556 }
3557
3558 private int getDevicesForStream(int stream, boolean checkOthers) {
3559 ensureValidStreamType(stream);
3560 synchronized (VolumeStreamState.class) {
3561 return mStreamStates[stream].observeDevicesForStream_syncVSS(checkOthers);
3562 }
3563 }
3564
3565 private void observeDevicesForStreams(int skipStream) {
3566 synchronized (VolumeStreamState.class) {
3567 for (int stream = 0; stream < mStreamStates.length; stream++) {
3568 if (stream != skipStream) {
3569 mStreamStates[stream].observeDevicesForStream_syncVSS(false /*checkOthers*/);
3570 }
3571 }
3572 }
3573 }
3574
Paul McLean10804eb2015-01-28 11:16:35 -08003575 /*
3576 * A class just for packaging up a set of connection parameters.
3577 */
3578 private class WiredDeviceConnectionState {
John Spurlock90874332015-03-10 16:00:54 -04003579 public final int mType;
3580 public final int mState;
3581 public final String mAddress;
3582 public final String mName;
3583 public final String mCaller;
Paul McLean10804eb2015-01-28 11:16:35 -08003584
John Spurlock90874332015-03-10 16:00:54 -04003585 public WiredDeviceConnectionState(int type, int state, String address, String name,
3586 String caller) {
Paul McLean10804eb2015-01-28 11:16:35 -08003587 mType = type;
3588 mState = state;
3589 mAddress = address;
3590 mName = name;
John Spurlock90874332015-03-10 16:00:54 -04003591 mCaller = caller;
Paul McLean10804eb2015-01-28 11:16:35 -08003592 }
3593 }
3594
John Spurlock90874332015-03-10 16:00:54 -04003595 public void setWiredDeviceConnectionState(int type, int state, String address, String name,
3596 String caller) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003597 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07003598 if (DEBUG_DEVICES) {
3599 Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
3600 + address + ")");
3601 }
Paul McLean10804eb2015-01-28 11:16:35 -08003602 int delay = checkSendBecomingNoisyIntent(type, state);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003603 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003604 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Paul McLean10804eb2015-01-28 11:16:35 -08003605 0,
3606 0,
John Spurlock90874332015-03-10 16:00:54 -04003607 new WiredDeviceConnectionState(type, state, address, name, caller),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003608 delay);
3609 }
3610 }
3611
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003612 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003613 {
3614 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003615 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
3616 throw new IllegalArgumentException("invalid profile " + profile);
3617 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003618 synchronized (mConnectedDevices) {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003619 if (profile == BluetoothProfile.A2DP) {
3620 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3621 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
3622 } else {
3623 delay = 0;
3624 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003625 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003626 (profile == BluetoothProfile.A2DP ?
3627 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003628 state,
3629 0,
3630 device,
3631 delay);
3632 }
3633 return delay;
3634 }
3635
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003636 ///////////////////////////////////////////////////////////////////////////
3637 // Inner classes
3638 ///////////////////////////////////////////////////////////////////////////
3639
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003640 // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
3641 // 1 mScoclient OR mSafeMediaVolumeState
3642 // 2 mSetModeDeathHandlers
3643 // 3 mSettingsLock
3644 // 4 VolumeStreamState.class
3645 // 5 mCameraSoundForced
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003646 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003647 private final int mStreamType;
John Spurlockb6e19e32015-03-10 21:33:44 -04003648 private final int mIndexMin;
3649 private final int mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003650
RoboErik4197cb62015-01-21 15:45:32 -08003651 private boolean mIsMuted;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003652 private String mVolumeIndexSettingName;
John Spurlock8a52c442015-03-26 14:23:58 -04003653 private int mObservedDevices;
John Spurlockb6e19e32015-03-10 21:33:44 -04003654
John Spurlock2bb02ec2015-03-02 13:13:06 -05003655 private final SparseIntArray mIndexMap = new SparseIntArray(8);
John Spurlockf63860c2015-02-19 09:46:27 -05003656 private final Intent mVolumeChanged;
John Spurlock8a52c442015-03-26 14:23:58 -04003657 private final Intent mStreamDevicesChanged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003658
Eric Laurenta553c252009-07-17 12:17:14 -07003659 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003660
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003661 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003662
3663 mStreamType = streamType;
John Spurlockb6e19e32015-03-10 21:33:44 -04003664 mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;
3665 mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;
3666 AudioSystem.initStreamVolume(streamType, mIndexMin / 10, mIndexMax / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003667
Eric Laurent33902db2012-10-07 16:15:07 -07003668 readSettings();
John Spurlockf63860c2015-02-19 09:46:27 -05003669 mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
3670 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
John Spurlock8a52c442015-03-26 14:23:58 -04003671 mStreamDevicesChanged = new Intent(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
3672 mStreamDevicesChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
3673 }
3674
3675 public int observeDevicesForStream_syncVSS(boolean checkOthers) {
3676 final int devices = AudioSystem.getDevicesForStream(mStreamType);
3677 if (devices == mObservedDevices) {
3678 return devices;
3679 }
3680 final int prevDevices = mObservedDevices;
3681 mObservedDevices = devices;
3682 if (checkOthers) {
3683 // one stream's devices have changed, check the others
3684 observeDevicesForStreams(mStreamType);
3685 }
3686 // log base stream changes to the event log
3687 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
3688 EventLogTags.writeStreamDevicesChanged(mStreamType, prevDevices, devices);
3689 }
3690 sendBroadcastToAll(mStreamDevicesChanged
3691 .putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, prevDevices)
3692 .putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, devices));
3693 return devices;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003694 }
3695
Eric Laurent42b041e2013-03-29 11:36:03 -07003696 public String getSettingNameForDevice(int device) {
3697 String name = mVolumeIndexSettingName;
Eric Laurent948d3272014-05-16 15:18:45 -07003698 String suffix = AudioSystem.getOutputDeviceName(device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003699 if (suffix.isEmpty()) {
3700 return name;
3701 }
3702 return name + "_" + suffix;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003703 }
3704
Eric Laurentfdbee862014-05-12 15:26:12 -07003705 public void readSettings() {
3706 synchronized (VolumeStreamState.class) {
John Spurlockee5ad722015-03-03 16:17:21 -05003707 // force maximum volume on all streams if fixed volume property is set
3708 if (mUseFixedVolume) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003709 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07003710 return;
3711 }
3712 // do not read system stream volume from settings: this stream is always aliased
3713 // to another stream type and its volume is never persisted. Values in settings can
3714 // only be stale values
3715 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3716 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
John Spurlock61560172015-02-06 19:46:04 -05003717 int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
Eric Laurentfdbee862014-05-12 15:26:12 -07003718 synchronized (mCameraSoundForced) {
3719 if (mCameraSoundForced) {
3720 index = mIndexMax;
3721 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003722 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003723 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003724 return;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003725 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003726
Eric Laurentfdbee862014-05-12 15:26:12 -07003727 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
3728
3729 for (int i = 0; remainingDevices != 0; i++) {
3730 int device = (1 << i);
3731 if ((device & remainingDevices) == 0) {
3732 continue;
3733 }
3734 remainingDevices &= ~device;
3735
3736 // retrieve current volume for device
3737 String name = getSettingNameForDevice(device);
3738 // if no volume stored for current stream and device, use default volume if default
3739 // device, continue otherwise
3740 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
John Spurlock61560172015-02-06 19:46:04 -05003741 AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
Eric Laurentfdbee862014-05-12 15:26:12 -07003742 int index = Settings.System.getIntForUser(
3743 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3744 if (index == -1) {
3745 continue;
3746 }
3747
John Spurlock2bb02ec2015-03-02 13:13:06 -05003748 mIndexMap.put(device, getValidIndex(10 * index));
Eric Laurentdd45d012012-10-08 09:04:34 -07003749 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003750 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003751 }
3752
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003753 // must be called while synchronized VolumeStreamState.class
3754 public void applyDeviceVolume_syncVSS(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003755 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003756 if (mIsMuted) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003757 index = 0;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003758 } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported)
3759 || ((device & mFullVolumeDevices) != 0)) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003760 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07003761 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07003762 index = (getIndex(device) + 5)/10;
3763 }
3764 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003765 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003766
Eric Laurentfdbee862014-05-12 15:26:12 -07003767 public void applyAllVolumes() {
3768 synchronized (VolumeStreamState.class) {
3769 // apply default volume first: by convention this will reset all
3770 // devices volumes in audio policy manager to the supplied value
3771 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003772 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003773 index = 0;
3774 } else {
3775 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3776 }
3777 AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3778 // then apply device specific volumes
John Spurlock2bb02ec2015-03-02 13:13:06 -05003779 for (int i = 0; i < mIndexMap.size(); i++) {
3780 int device = mIndexMap.keyAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07003781 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
RoboErik4197cb62015-01-21 15:45:32 -08003782 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003783 index = 0;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003784 } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3785 mAvrcpAbsVolSupported)
3786 || ((device & mFullVolumeDevices) != 0))
3787 {
Eric Laurentfdbee862014-05-12 15:26:12 -07003788 index = (mIndexMax + 5)/10;
3789 } else {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003790 index = (mIndexMap.valueAt(i) + 5)/10;
Eric Laurentfdbee862014-05-12 15:26:12 -07003791 }
3792 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07003793 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003794 }
3795 }
3796 }
3797
John Spurlock90874332015-03-10 16:00:54 -04003798 public boolean adjustIndex(int deltaIndex, int device, String caller) {
3799 return setIndex(getIndex(device) + deltaIndex, device, caller);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003800 }
3801
John Spurlock90874332015-03-10 16:00:54 -04003802 public boolean setIndex(int index, int device, String caller) {
John Spurlockf63860c2015-02-19 09:46:27 -05003803 boolean changed = false;
3804 int oldIndex;
Eric Laurentfdbee862014-05-12 15:26:12 -07003805 synchronized (VolumeStreamState.class) {
John Spurlockf63860c2015-02-19 09:46:27 -05003806 oldIndex = getIndex(device);
Eric Laurentfdbee862014-05-12 15:26:12 -07003807 index = getValidIndex(index);
3808 synchronized (mCameraSoundForced) {
3809 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3810 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07003811 }
3812 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003813 mIndexMap.put(device, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003814
John Spurlockf63860c2015-02-19 09:46:27 -05003815 changed = oldIndex != index;
3816 if (changed) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003817 // Apply change to all streams using this one as alias
3818 // if changing volume of current device, also change volume of current
3819 // device on aliased stream
3820 boolean currentDevice = (device == getDeviceForStream(mStreamType));
3821 int numStreamTypes = AudioSystem.getNumStreamTypes();
3822 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3823 if (streamType != mStreamType &&
3824 mStreamVolumeAlias[streamType] == mStreamType) {
3825 int scaledIndex = rescaleIndex(index, mStreamType, streamType);
John Spurlock90874332015-03-10 16:00:54 -04003826 mStreamStates[streamType].setIndex(scaledIndex, device, caller);
Eric Laurentfdbee862014-05-12 15:26:12 -07003827 if (currentDevice) {
3828 mStreamStates[streamType].setIndex(scaledIndex,
John Spurlock90874332015-03-10 16:00:54 -04003829 getDeviceForStream(streamType), caller);
Eric Laurentfdbee862014-05-12 15:26:12 -07003830 }
3831 }
3832 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003833 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003834 }
John Spurlockf63860c2015-02-19 09:46:27 -05003835 if (changed) {
3836 oldIndex = (oldIndex + 5) / 10;
3837 index = (index + 5) / 10;
John Spurlock90874332015-03-10 16:00:54 -04003838 // log base stream changes to the event log
3839 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
3840 if (caller == null) {
3841 Log.w(TAG, "No caller for volume_changed event", new Throwable());
3842 }
3843 EventLogTags.writeVolumeChanged(mStreamType, oldIndex, index, mIndexMax / 10,
3844 caller);
3845 }
3846 // fire changed intents for all streams
John Spurlockf63860c2015-02-19 09:46:27 -05003847 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
3848 mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
Jean-Michel Trivi560877d2015-06-25 17:38:35 -07003849 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
3850 mStreamVolumeAlias[mStreamType]);
John Spurlockf63860c2015-02-19 09:46:27 -05003851 sendBroadcastToAll(mVolumeChanged);
3852 }
3853 return changed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003854 }
3855
Eric Laurentfdbee862014-05-12 15:26:12 -07003856 public int getIndex(int device) {
3857 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003858 int index = mIndexMap.get(device, -1);
3859 if (index == -1) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003860 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
John Spurlock2bb02ec2015-03-02 13:13:06 -05003861 index = mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurentfdbee862014-05-12 15:26:12 -07003862 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003863 return index;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003864 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07003865 }
3866
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003867 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07003868 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003869 }
3870
John Spurlockb6e19e32015-03-10 21:33:44 -04003871 public int getMinIndex() {
3872 return mIndexMin;
3873 }
3874
John Spurlock90874332015-03-10 16:00:54 -04003875 public void setAllIndexes(VolumeStreamState srcStream, String caller) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003876 synchronized (VolumeStreamState.class) {
3877 int srcStreamType = srcStream.getStreamType();
3878 // apply default device volume from source stream to all devices first in case
3879 // some devices are present in this stream state but not in source stream state
3880 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003881 index = rescaleIndex(index, srcStreamType, mStreamType);
John Spurlock2bb02ec2015-03-02 13:13:06 -05003882 for (int i = 0; i < mIndexMap.size(); i++) {
3883 mIndexMap.put(mIndexMap.keyAt(i), index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003884 }
3885 // Now apply actual volume for devices in source stream state
John Spurlock2bb02ec2015-03-02 13:13:06 -05003886 SparseIntArray srcMap = srcStream.mIndexMap;
3887 for (int i = 0; i < srcMap.size(); i++) {
3888 int device = srcMap.keyAt(i);
3889 index = srcMap.valueAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07003890 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07003891
John Spurlock90874332015-03-10 16:00:54 -04003892 setIndex(index, device, caller);
Eric Laurentfdbee862014-05-12 15:26:12 -07003893 }
Eric Laurent6d517662012-04-23 18:42:39 -07003894 }
3895 }
3896
Eric Laurentfdbee862014-05-12 15:26:12 -07003897 public void setAllIndexesToMax() {
3898 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003899 for (int i = 0; i < mIndexMap.size(); i++) {
3900 mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07003901 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003902 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003903 }
3904
RoboErik4197cb62015-01-21 15:45:32 -08003905 public void mute(boolean state) {
John Spurlock22b9ee12015-02-18 22:51:44 -05003906 boolean changed = false;
Eric Laurentfdbee862014-05-12 15:26:12 -07003907 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08003908 if (state != mIsMuted) {
John Spurlock22b9ee12015-02-18 22:51:44 -05003909 changed = true;
RoboErik4197cb62015-01-21 15:45:32 -08003910 mIsMuted = state;
John Spurlock22b9ee12015-02-18 22:51:44 -05003911
RoboErik4197cb62015-01-21 15:45:32 -08003912 // Set the new mute volume. This propagates the values to
3913 // the audio system, otherwise the volume won't be changed
3914 // at the lower level.
3915 sendMsg(mAudioHandler,
3916 MSG_SET_ALL_VOLUMES,
3917 SENDMSG_QUEUE,
3918 0,
3919 0,
3920 this, 0);
Eric Laurentfdbee862014-05-12 15:26:12 -07003921 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003922 }
John Spurlock22b9ee12015-02-18 22:51:44 -05003923 if (changed) {
3924 // Stream mute changed, fire the intent.
3925 Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
3926 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
3927 intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
3928 sendBroadcastToAll(intent);
3929 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003930 }
3931
Eric Laurent6d517662012-04-23 18:42:39 -07003932 public int getStreamType() {
3933 return mStreamType;
3934 }
3935
Eric Laurent212532b2014-07-21 15:43:18 -07003936 public void checkFixedVolumeDevices() {
3937 synchronized (VolumeStreamState.class) {
3938 // ignore settings for fixed volume devices: volume should always be at max or 0
3939 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003940 for (int i = 0; i < mIndexMap.size(); i++) {
3941 int device = mIndexMap.keyAt(i);
3942 int index = mIndexMap.valueAt(i);
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003943 if (((device & mFullVolumeDevices) != 0)
3944 || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003945 mIndexMap.put(device, mIndexMax);
Eric Laurent212532b2014-07-21 15:43:18 -07003946 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003947 applyDeviceVolume_syncVSS(device);
Eric Laurent212532b2014-07-21 15:43:18 -07003948 }
3949 }
3950 }
3951 }
3952
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003953 private int getValidIndex(int index) {
John Spurlockb6e19e32015-03-10 21:33:44 -04003954 if (index < mIndexMin) {
3955 return mIndexMin;
John Spurlockee5ad722015-03-03 16:17:21 -05003956 } else if (mUseFixedVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07003957 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003958 }
3959
3960 return index;
3961 }
3962
Eric Laurentbffc3d12012-05-07 17:43:49 -07003963 private void dump(PrintWriter pw) {
RoboErik4197cb62015-01-21 15:45:32 -08003964 pw.print(" Muted: ");
3965 pw.println(mIsMuted);
John Spurlockb6e19e32015-03-10 21:33:44 -04003966 pw.print(" Min: ");
3967 pw.println((mIndexMin + 5) / 10);
John Spurlock2b29bc42014-08-26 16:40:35 -04003968 pw.print(" Max: ");
3969 pw.println((mIndexMax + 5) / 10);
Eric Laurentbffc3d12012-05-07 17:43:49 -07003970 pw.print(" Current: ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05003971 for (int i = 0; i < mIndexMap.size(); i++) {
3972 if (i > 0) {
3973 pw.print(", ");
3974 }
3975 final int device = mIndexMap.keyAt(i);
John Spurlock2b29bc42014-08-26 16:40:35 -04003976 pw.print(Integer.toHexString(device));
3977 final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
3978 : AudioSystem.getOutputDeviceName(device);
3979 if (!deviceName.isEmpty()) {
3980 pw.print(" (");
3981 pw.print(deviceName);
3982 pw.print(")");
3983 }
3984 pw.print(": ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05003985 final int index = (mIndexMap.valueAt(i) + 5) / 10;
John Spurlock2b29bc42014-08-26 16:40:35 -04003986 pw.print(index);
Eric Laurentbffc3d12012-05-07 17:43:49 -07003987 }
John Spurlockb32fc972015-03-05 13:58:00 -05003988 pw.println();
3989 pw.print(" Devices: ");
John Spurlock8a52c442015-03-26 14:23:58 -04003990 final int devices = getDevicesForStream(mStreamType);
John Spurlockb32fc972015-03-05 13:58:00 -05003991 int device, i = 0, n = 0;
John Spurlock1ff1e6e2015-03-09 14:21:20 -04003992 // iterate all devices from 1 to DEVICE_OUT_DEFAULT exclusive
3993 // (the default device is not returned by getDevicesForStream)
3994 while ((device = 1 << i) != AudioSystem.DEVICE_OUT_DEFAULT) {
John Spurlockb32fc972015-03-05 13:58:00 -05003995 if ((devices & device) != 0) {
3996 if (n++ > 0) {
3997 pw.print(", ");
3998 }
3999 pw.print(AudioSystem.getOutputDeviceName(device));
4000 }
4001 i++;
4002 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07004003 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004004 }
4005
4006 /** Thread that handles native AudioSystem control. */
4007 private class AudioSystemThread extends Thread {
4008 AudioSystemThread() {
4009 super("AudioService");
4010 }
4011
4012 @Override
4013 public void run() {
4014 // Set this thread up so the handler will work on it
4015 Looper.prepare();
4016
4017 synchronized(AudioService.this) {
4018 mAudioHandler = new AudioHandler();
4019
4020 // Notify that the handler has been created
4021 AudioService.this.notify();
4022 }
4023
4024 // Listen for volume change requests that are set by VolumePanel
4025 Looper.loop();
4026 }
4027 }
4028
4029 /** Handles internal volume messages in separate volume thread. */
4030 private class AudioHandler extends Handler {
4031
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004032 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004033
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004034 synchronized (VolumeStreamState.class) {
4035 // Apply volume
4036 streamState.applyDeviceVolume_syncVSS(device);
Eric Laurenta553c252009-07-17 12:17:14 -07004037
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004038 // Apply change to all streams using this one as alias
4039 int numStreamTypes = AudioSystem.getNumStreamTypes();
4040 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4041 if (streamType != streamState.mStreamType &&
4042 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
4043 // Make sure volume is also maxed out on A2DP device for aliased stream
4044 // that may have a different device selected
4045 int streamDevice = getDeviceForStream(streamType);
4046 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
4047 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
4048 mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
4049 }
4050 mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
Eric Laurentcd772d02013-10-30 18:31:07 -07004051 }
Eric Laurenta553c252009-07-17 12:17:14 -07004052 }
4053 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004054 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08004055 sendMsg(mAudioHandler,
4056 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08004057 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004058 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07004059 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08004060 streamState,
4061 PERSIST_DELAY);
4062
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004063 }
4064
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004065 private void setAllVolumes(VolumeStreamState streamState) {
4066
4067 // Apply volume
4068 streamState.applyAllVolumes();
4069
4070 // Apply change to all streams using this one as alias
4071 int numStreamTypes = AudioSystem.getNumStreamTypes();
4072 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4073 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07004074 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004075 mStreamStates[streamType].applyAllVolumes();
4076 }
4077 }
4078 }
4079
Eric Laurent42b041e2013-03-29 11:36:03 -07004080 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07004081 if (mUseFixedVolume) {
4082 return;
4083 }
Eric Laurent212532b2014-07-21 15:43:18 -07004084 if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
4085 return;
4086 }
Eric Laurent42b041e2013-03-29 11:36:03 -07004087 System.putIntForUser(mContentResolver,
4088 streamState.getSettingNameForDevice(device),
4089 (streamState.getIndex(device) + 5)/ 10,
4090 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004091 }
4092
Glenn Kastenba195eb2011-12-13 09:30:40 -08004093 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07004094 if (mUseFixedVolume) {
4095 return;
4096 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07004097 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004098 }
4099
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004100 private boolean onLoadSoundEffects() {
4101 int status;
4102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004103 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004104 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004105 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
4106 return false;
4107 }
4108
4109 if (mSoundPool != null) {
4110 return true;
4111 }
4112
4113 loadTouchSoundAssets();
4114
Jean-Michel Trivi55a30c42014-07-20 17:56:11 -07004115 mSoundPool = new SoundPool.Builder()
4116 .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
4117 .setAudioAttributes(new AudioAttributes.Builder()
4118 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
4119 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
4120 .build())
4121 .build();
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004122 mSoundPoolCallBack = null;
4123 mSoundPoolListenerThread = new SoundPoolListenerThread();
4124 mSoundPoolListenerThread.start();
4125 int attempts = 3;
4126 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
4127 try {
4128 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07004129 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004130 } catch (InterruptedException e) {
4131 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
4132 }
4133 }
4134
4135 if (mSoundPoolCallBack == null) {
4136 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
4137 if (mSoundPoolLooper != null) {
4138 mSoundPoolLooper.quit();
4139 mSoundPoolLooper = null;
4140 }
4141 mSoundPoolListenerThread = null;
4142 mSoundPool.release();
4143 mSoundPool = null;
4144 return false;
4145 }
4146 /*
4147 * poolId table: The value -1 in this table indicates that corresponding
4148 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
4149 * Once loaded, the value in poolId is the sample ID and the same
4150 * sample can be reused for another effect using the same file.
4151 */
4152 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4153 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4154 poolId[fileIdx] = -1;
4155 }
4156 /*
4157 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
4158 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
4159 * this indicates we have a valid sample loaded for this effect.
4160 */
4161
4162 int numSamples = 0;
4163 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4164 // Do not load sample if this effect uses the MediaPlayer
4165 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
4166 continue;
4167 }
4168 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
4169 String filePath = Environment.getRootDirectory()
4170 + SOUND_EFFECTS_PATH
4171 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
4172 int sampleId = mSoundPool.load(filePath, 0);
4173 if (sampleId <= 0) {
4174 Log.w(TAG, "Soundpool could not load file: "+filePath);
4175 } else {
4176 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
4177 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
4178 numSamples++;
4179 }
4180 } else {
4181 SOUND_EFFECT_FILES_MAP[effect][1] =
4182 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
4183 }
4184 }
4185 // wait for all samples to be loaded
4186 if (numSamples > 0) {
4187 mSoundPoolCallBack.setSamples(poolId);
4188
4189 attempts = 3;
4190 status = 1;
4191 while ((status == 1) && (attempts-- > 0)) {
4192 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07004193 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004194 status = mSoundPoolCallBack.status();
4195 } catch (InterruptedException e) {
4196 Log.w(TAG, "Interrupted while waiting sound pool callback.");
4197 }
4198 }
4199 } else {
4200 status = -1;
4201 }
4202
4203 if (mSoundPoolLooper != null) {
4204 mSoundPoolLooper.quit();
4205 mSoundPoolLooper = null;
4206 }
4207 mSoundPoolListenerThread = null;
4208 if (status != 0) {
4209 Log.w(TAG,
4210 "onLoadSoundEffects(), Error "+status+ " while loading samples");
4211 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4212 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
4213 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4214 }
4215 }
4216
4217 mSoundPool.release();
4218 mSoundPool = null;
4219 }
4220 }
4221 return (status == 0);
4222 }
4223
4224 /**
4225 * Unloads samples from the sound pool.
4226 * This method can be called to free some memory when
4227 * sound effects are disabled.
4228 */
4229 private void onUnloadSoundEffects() {
4230 synchronized (mSoundEffectsLock) {
4231 if (mSoundPool == null) {
4232 return;
4233 }
4234
4235 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4236 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4237 poolId[fileIdx] = 0;
4238 }
4239
4240 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4241 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
4242 continue;
4243 }
4244 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
4245 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
4246 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4247 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
4248 }
4249 }
4250 mSoundPool.release();
4251 mSoundPool = null;
4252 }
4253 }
4254
4255 private void onPlaySoundEffect(int effectType, int volume) {
4256 synchronized (mSoundEffectsLock) {
4257
4258 onLoadSoundEffects();
4259
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004260 if (mSoundPool == null) {
4261 return;
4262 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004263 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08004264 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004265 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07004266 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004267 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07004268 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004269 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004270
4271 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004272 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
4273 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004274 } else {
4275 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004276 try {
Eric Laurente78fced2013-03-15 16:03:47 -07004277 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
4278 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004279 mediaPlayer.setDataSource(filePath);
4280 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
4281 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08004282 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004283 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
4284 public void onCompletion(MediaPlayer mp) {
4285 cleanupPlayer(mp);
4286 }
4287 });
4288 mediaPlayer.setOnErrorListener(new OnErrorListener() {
4289 public boolean onError(MediaPlayer mp, int what, int extra) {
4290 cleanupPlayer(mp);
4291 return true;
4292 }
4293 });
4294 mediaPlayer.start();
4295 } catch (IOException ex) {
4296 Log.w(TAG, "MediaPlayer IOException: "+ex);
4297 } catch (IllegalArgumentException ex) {
4298 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
4299 } catch (IllegalStateException ex) {
4300 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004301 }
4302 }
4303 }
4304 }
4305
4306 private void cleanupPlayer(MediaPlayer mp) {
4307 if (mp != null) {
4308 try {
4309 mp.stop();
4310 mp.release();
4311 } catch (IllegalStateException ex) {
4312 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
4313 }
4314 }
4315 }
4316
Eric Laurentfa640152011-03-12 15:59:51 -08004317 private void setForceUse(int usage, int config) {
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004318 synchronized (mConnectedDevices) {
4319 setForceUseInt_SyncDevices(usage, config);
4320 }
Eric Laurentfa640152011-03-12 15:59:51 -08004321 }
4322
Eric Laurent05274f32012-11-29 12:48:18 -08004323 private void onPersistSafeVolumeState(int state) {
4324 Settings.Global.putInt(mContentResolver,
4325 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
4326 state);
4327 }
4328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004329 @Override
4330 public void handleMessage(Message msg) {
Eric Laurentafbb0472011-12-15 09:04:23 -08004331 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004332
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004333 case MSG_SET_DEVICE_VOLUME:
4334 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
4335 break;
4336
4337 case MSG_SET_ALL_VOLUMES:
4338 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004339 break;
4340
4341 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07004342 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004343 break;
4344
Justin Koh57978ed2012-04-03 17:37:58 -07004345 case MSG_PERSIST_MASTER_VOLUME_MUTE:
Eric Laurent83a017b2013-03-19 18:15:31 -07004346 if (mUseFixedVolume) {
4347 return;
4348 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004349 Settings.System.putIntForUser(mContentResolver,
4350 Settings.System.VOLUME_MASTER_MUTE,
4351 msg.arg1,
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004352 msg.arg2);
Justin Koh57978ed2012-04-03 17:37:58 -07004353 break;
4354
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004355 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08004356 // note that the value persisted is the current ringer mode, not the
4357 // value of ringer mode as of the time the request was made to persist
John Spurlock661f2cf2014-11-17 10:29:10 -05004358 persistRingerMode(getRingerModeInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004359 break;
4360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004361 case MSG_MEDIA_SERVER_DIED:
Eric Laurent0867bed2015-05-20 14:49:08 -07004362 onMediaServerDied();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004363 break;
4364
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004365 case MSG_UNLOAD_SOUND_EFFECTS:
4366 onUnloadSoundEffects();
4367 break;
4368
Eric Laurent117b7bb2011-01-16 17:07:27 -08004369 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004370 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
4371 // can take several dozens of milliseconds to complete
4372 boolean loaded = onLoadSoundEffects();
4373 if (msg.obj != null) {
4374 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
4375 synchronized (reply) {
4376 reply.mStatus = loaded ? 0 : -1;
4377 reply.notify();
4378 }
4379 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08004380 break;
4381
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004382 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004383 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004384 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004385
4386 case MSG_BTA2DP_DOCK_TIMEOUT:
4387 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004388 synchronized (mConnectedDevices) {
4389 makeA2dpDeviceUnavailableNow( (String) msg.obj );
4390 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004391 break;
Eric Laurentfa640152011-03-12 15:59:51 -08004392
4393 case MSG_SET_FORCE_USE:
Eric Laurentc390bed2012-07-03 12:24:05 -07004394 case MSG_SET_FORCE_BT_A2DP_USE:
Eric Laurentfa640152011-03-12 15:59:51 -08004395 setForceUse(msg.arg1, msg.arg2);
4396 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07004397
Eric Laurentdc03c612011-04-01 10:59:41 -07004398 case MSG_BT_HEADSET_CNCT_FAILED:
4399 resetBluetoothSco();
4400 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004401
4402 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
Paul McLean10804eb2015-01-28 11:16:35 -08004403 { WiredDeviceConnectionState connectState =
4404 (WiredDeviceConnectionState)msg.obj;
4405 onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
John Spurlock90874332015-03-10 16:00:54 -04004406 connectState.mAddress, connectState.mName, connectState.mCaller);
Paul McLean10804eb2015-01-28 11:16:35 -08004407 mAudioEventWakeLock.release();
4408 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004409 break;
4410
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004411 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
4412 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
4413 mAudioEventWakeLock.release();
4414 break;
4415
4416 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
4417 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004418 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004419 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004420
4421 case MSG_REPORT_NEW_ROUTES: {
4422 int N = mRoutesObservers.beginBroadcast();
4423 if (N > 0) {
4424 AudioRoutesInfo routes;
4425 synchronized (mCurAudioRoutes) {
4426 routes = new AudioRoutesInfo(mCurAudioRoutes);
4427 }
4428 while (N > 0) {
4429 N--;
4430 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
4431 try {
4432 obs.dispatchAudioRoutesChanged(routes);
4433 } catch (RemoteException e) {
4434 }
4435 }
4436 }
4437 mRoutesObservers.finishBroadcast();
John Spurlock8a52c442015-03-26 14:23:58 -04004438 observeDevicesForStreams(-1);
Dianne Hackborn632ca412012-06-14 19:34:10 -07004439 break;
4440 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004441
Eric Laurentc34dcc12012-09-10 13:51:52 -07004442 case MSG_CHECK_MUSIC_ACTIVE:
John Spurlock90874332015-03-10 16:00:54 -04004443 onCheckMusicActive((String) msg.obj);
Eric Laurentc34dcc12012-09-10 13:51:52 -07004444 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004445
4446 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
4447 onSendBecomingNoisyIntent();
4448 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07004449
4450 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
4451 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
John Spurlock90874332015-03-10 16:00:54 -04004452 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED),
4453 (String) msg.obj);
Eric Laurentd640bd32012-09-28 18:01:48 -07004454 break;
Eric Laurent05274f32012-11-29 12:48:18 -08004455 case MSG_PERSIST_SAFE_VOLUME_STATE:
4456 onPersistSafeVolumeState(msg.arg1);
4457 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08004458
Eric Laurent2a57ca92013-03-07 17:29:27 -08004459 case MSG_BROADCAST_BT_CONNECTION_STATE:
4460 onBroadcastScoConnectionState(msg.arg1);
4461 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004462
4463 case MSG_SYSTEM_READY:
4464 onSystemReady();
4465 break;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004466
Eric Laurent0867bed2015-05-20 14:49:08 -07004467 case MSG_INDICATE_SYSTEM_READY:
4468 onIndicateSystemReady();
4469 break;
4470
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004471 case MSG_PERSIST_MUSIC_ACTIVE_MS:
4472 final int musicActiveMs = msg.arg1;
4473 Settings.Secure.putIntForUser(mContentResolver,
4474 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
4475 UserHandle.USER_CURRENT);
4476 break;
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004477 case MSG_PERSIST_MICROPHONE_MUTE:
4478 Settings.System.putIntForUser(mContentResolver,
4479 Settings.System.MICROPHONE_MUTE,
4480 msg.arg1,
4481 msg.arg2);
4482 break;
RoboErik5452e252015-02-06 15:33:53 -08004483 case MSG_UNMUTE_STREAM:
4484 onUnmuteStream(msg.arg1, msg.arg2);
4485 break;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07004486 case MSG_DYN_POLICY_MIX_STATE_UPDATE:
4487 onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1);
4488 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004489 }
4490 }
4491 }
4492
Jason Parekhb1096152009-03-24 17:48:25 -07004493 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07004494
Jason Parekhb1096152009-03-24 17:48:25 -07004495 SettingsObserver() {
4496 super(new Handler());
4497 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4498 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004499 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4500 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07004501 }
4502
4503 @Override
4504 public void onChange(boolean selfChange) {
4505 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08004506 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
4507 // However there appear to be some missing locks around mRingerModeMutedStreams
4508 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
4509 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07004510 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004511 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07004512 /*
4513 * Ensure all stream types that should be affected by ringer mode
4514 * are in the proper state.
4515 */
John Spurlock661f2cf2014-11-17 10:29:10 -05004516 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurenta553c252009-07-17 12:17:14 -07004517 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004518 readDockAudioSettings(mContentResolver);
Eric Laurenta553c252009-07-17 12:17:14 -07004519 }
Jason Parekhb1096152009-03-24 17:48:25 -07004520 }
Jason Parekhb1096152009-03-24 17:48:25 -07004521 }
Eric Laurenta553c252009-07-17 12:17:14 -07004522
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004523 // must be called synchronized on mConnectedDevices
Paul McLean20eec5b2015-05-09 13:02:18 -07004524 private void makeA2dpDeviceAvailable(String address, String name) {
Eric Laurent78472112012-05-21 08:57:21 -07004525 // enable A2DP before notifying A2DP connection to avoid unecessary processing in
4526 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004527 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4528 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4529 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Eric Laurent78472112012-05-21 08:57:21 -07004530 setBluetoothA2dpOnInt(true);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004531 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004532 AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004533 // Reset A2DP suspend state each time a new sink is connected
4534 AudioSystem.setParameters("A2dpSuspended=false");
Paul McLean394a8e12015-03-03 10:29:19 -07004535 mConnectedDevices.put(
4536 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
Paul McLean20eec5b2015-05-09 13:02:18 -07004537 new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
Paul McLean394a8e12015-03-03 10:29:19 -07004538 address));
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004539 }
4540
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004541 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004542 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07004543 }
4544
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004545 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004546 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004547 synchronized (mA2dpAvrcpLock) {
4548 mAvrcpAbsVolSupported = false;
4549 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004550 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004551 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004552 mConnectedDevices.remove(
4553 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
RoboErik5535ea82014-09-25 14:53:16 -07004554 synchronized (mCurAudioRoutes) {
4555 // Remove A2DP routes as well
John Spurlock61560172015-02-06 19:46:04 -05004556 if (mCurAudioRoutes.bluetoothName != null) {
4557 mCurAudioRoutes.bluetoothName = null;
RoboErik5535ea82014-09-25 14:53:16 -07004558 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4559 SENDMSG_NOOP, 0, 0, null, 0);
4560 }
4561 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004562 }
4563
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004564 // must be called synchronized on mConnectedDevices
Eric Laurentd138e4e2015-05-15 16:41:15 -07004565 private void makeA2dpDeviceUnavailableLater(String address, int delayMs) {
Eric Laurent3b591262010-04-20 07:01:00 -07004566 // prevent any activity on the A2DP audio output to avoid unwanted
4567 // reconnection of the sink.
4568 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004569 // the device will be made unavailable later, so consider it disconnected right away
Paul McLean394a8e12015-03-03 10:29:19 -07004570 mConnectedDevices.remove(
4571 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004572 // send the delayed message to make the device unavailable later
4573 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
Eric Laurentd138e4e2015-05-15 16:41:15 -07004574 mAudioHandler.sendMessageDelayed(msg, delayMs);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004575
4576 }
4577
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004578 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004579 private void makeA2dpSrcAvailable(String address) {
4580 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004581 AudioSystem.DEVICE_STATE_AVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004582 mConnectedDevices.put(
4583 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
Paul McLean20eec5b2015-05-09 13:02:18 -07004584 new DeviceListSpec(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "",
Paul McLean394a8e12015-03-03 10:29:19 -07004585 address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004586 }
4587
4588 // must be called synchronized on mConnectedDevices
4589 private void makeA2dpSrcUnavailable(String address) {
4590 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004591 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004592 mConnectedDevices.remove(
4593 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004594 }
4595
4596 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004597 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004598 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4599 }
4600
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004601 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004602 private boolean hasScheduledA2dpDockTimeout() {
4603 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4604 }
4605
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004606 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004607 {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004608 if (DEBUG_VOL) {
4609 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
4610 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004611 if (btDevice == null) {
4612 return;
4613 }
4614 String address = btDevice.getAddress();
4615 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4616 address = "";
4617 }
John Du5a0cf7a2013-07-19 11:30:34 -07004618
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004619 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004620 String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4621 btDevice.getAddress());
4622 DeviceListSpec deviceSpec = mConnectedDevices.get(key);
4623 boolean isConnected = deviceSpec != null;
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004624
4625 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4626 if (btDevice.isBluetoothDock()) {
4627 if (state == BluetoothProfile.STATE_DISCONNECTED) {
4628 // introduction of a delay for transient disconnections of docks when
4629 // power is rapidly turned off/on, this message will be canceled if
4630 // we reconnect the dock under a preset delay
Eric Laurentd138e4e2015-05-15 16:41:15 -07004631 makeA2dpDeviceUnavailableLater(address, BTA2DP_DOCK_TIMEOUT_MILLIS);
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004632 // the next time isConnected is evaluated, it will be false for the dock
4633 }
4634 } else {
4635 makeA2dpDeviceUnavailableNow(address);
4636 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07004637 synchronized (mCurAudioRoutes) {
John Spurlock61560172015-02-06 19:46:04 -05004638 if (mCurAudioRoutes.bluetoothName != null) {
4639 mCurAudioRoutes.bluetoothName = null;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004640 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4641 SENDMSG_NOOP, 0, 0, null, 0);
4642 }
4643 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004644 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4645 if (btDevice.isBluetoothDock()) {
4646 // this could be a reconnection after a transient disconnection
4647 cancelA2dpDeviceTimeout();
4648 mDockAddress = address;
4649 } else {
4650 // this could be a connection of another A2DP device before the timeout of
4651 // a dock: cancel the dock timeout, and make the dock unavailable now
4652 if(hasScheduledA2dpDockTimeout()) {
4653 cancelA2dpDeviceTimeout();
4654 makeA2dpDeviceUnavailableNow(mDockAddress);
4655 }
4656 }
Paul McLean20eec5b2015-05-09 13:02:18 -07004657 makeA2dpDeviceAvailable(address, btDevice.getName());
Dianne Hackborn632ca412012-06-14 19:34:10 -07004658 synchronized (mCurAudioRoutes) {
4659 String name = btDevice.getAliasName();
John Spurlock61560172015-02-06 19:46:04 -05004660 if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
4661 mCurAudioRoutes.bluetoothName = name;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004662 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4663 SENDMSG_NOOP, 0, 0, null, 0);
4664 }
4665 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004666 }
4667 }
4668 }
4669
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004670 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
4671 {
4672 if (DEBUG_VOL) {
4673 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
4674 }
4675 if (btDevice == null) {
4676 return;
4677 }
4678 String address = btDevice.getAddress();
4679 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4680 address = "";
4681 }
4682
4683 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004684 String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
4685 DeviceListSpec deviceSpec = mConnectedDevices.get(key);
4686 boolean isConnected = deviceSpec != null;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004687
4688 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4689 makeA2dpSrcUnavailable(address);
4690 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4691 makeA2dpSrcAvailable(address);
4692 }
4693 }
4694 }
4695
John Du5a0cf7a2013-07-19 11:30:34 -07004696 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
4697 // address is not used for now, but may be used when multiple a2dp devices are supported
4698 synchronized (mA2dpAvrcpLock) {
4699 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004700 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07004701 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4702 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4703 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4704 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4705 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07004706 }
4707 }
4708
Paul McLean394a8e12015-03-03 10:29:19 -07004709 private boolean handleDeviceConnection(boolean connect, int device, String address,
4710 String deviceName) {
4711 if (DEBUG_DEVICES) {
4712 Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device)
4713 + " address:" + address + " name:" + deviceName + ")");
4714 }
Eric Laurent59f48272012-04-05 19:42:21 -07004715 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004716 String deviceKey = makeDeviceListKey(device, address);
4717 if (DEBUG_DEVICES) {
4718 Slog.i(TAG, "deviceKey:" + deviceKey);
4719 }
4720 DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
4721 boolean isConnected = deviceSpec != null;
4722 if (DEBUG_DEVICES) {
4723 Slog.i(TAG, "deviceSpec:" + deviceSpec + " is(already)Connected:" + isConnected);
4724 }
4725 if (connect && !isConnected) {
4726 AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_AVAILABLE,
4727 address, deviceName);
4728 mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
4729 return true;
4730 } else if (!connect && isConnected) {
4731 AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_UNAVAILABLE,
4732 address, deviceName);
4733 mConnectedDevices.remove(deviceKey);
4734 return true;
Eric Laurent59f48272012-04-05 19:42:21 -07004735 }
4736 }
4737 return false;
4738 }
4739
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004740 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4741 // sent if none of these devices is connected.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004742 // Access synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004743 int mBecomingNoisyIntentDevices =
4744 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07004745 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07004746 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004747 AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004748
4749 // must be called before removing the device from mConnectedDevices
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004750 // Called synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004751 private int checkSendBecomingNoisyIntent(int device, int state) {
4752 int delay = 0;
4753 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4754 int devices = 0;
John Spurlock8c3dc852015-04-23 21:32:37 -04004755 for (int i = 0; i < mConnectedDevices.size(); i++) {
4756 int dev = mConnectedDevices.valueAt(i).mDeviceType;
Paul McLean394a8e12015-03-03 10:29:19 -07004757 if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
4758 && ((dev & mBecomingNoisyIntentDevices) != 0)) {
4759 devices |= dev;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004760 }
4761 }
4762 if (devices == device) {
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004763 sendMsg(mAudioHandler,
4764 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4765 SENDMSG_REPLACE,
4766 0,
4767 0,
4768 null,
4769 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004770 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004771 }
4772 }
4773
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004774 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
4775 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004776 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004777 synchronized (mLastDeviceConnectMsgTime) {
4778 long time = SystemClock.uptimeMillis();
4779 if (mLastDeviceConnectMsgTime > time) {
Matthew Xiec525cf72015-01-22 20:13:17 -08004780 delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004781 }
4782 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004783 }
4784 return delay;
4785 }
4786
Paul McLean394a8e12015-03-03 10:29:19 -07004787 private void sendDeviceConnectionIntent(int device, int state, String address,
4788 String deviceName) {
4789 if (DEBUG_DEVICES) {
4790 Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
4791 " state:0x" + Integer.toHexString(state) + " address:" + address +
4792 " name:" + deviceName + ");");
4793 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004794 Intent intent = new Intent();
4795
Paul McLean10804eb2015-01-28 11:16:35 -08004796 intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
4797 intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
4798 intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
4799
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004800 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4801
Dianne Hackborn632ca412012-06-14 19:34:10 -07004802 int connType = 0;
4803
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004804 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004805 connType = AudioRoutesInfo.MAIN_HEADSET;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004806 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4807 intent.putExtra("microphone", 1);
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004808 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
4809 device == AudioSystem.DEVICE_OUT_LINE) {
4810 /*do apps care about line-out vs headphones?*/
Dianne Hackborn632ca412012-06-14 19:34:10 -07004811 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004812 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4813 intent.putExtra("microphone", 0);
Eric Laurent6fa42452015-01-09 15:09:40 -08004814 } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
4815 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004816 connType = AudioRoutesInfo.MAIN_HDMI;
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004817 configureHdmiPlugIntent(intent, state);
Paul McLean10804eb2015-01-28 11:16:35 -08004818 } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE) {
4819 connType = AudioRoutesInfo.MAIN_USB;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004820 }
4821
Dianne Hackborn632ca412012-06-14 19:34:10 -07004822 synchronized (mCurAudioRoutes) {
4823 if (connType != 0) {
John Spurlock61560172015-02-06 19:46:04 -05004824 int newConn = mCurAudioRoutes.mainType;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004825 if (state != 0) {
4826 newConn |= connType;
4827 } else {
4828 newConn &= ~connType;
4829 }
John Spurlock61560172015-02-06 19:46:04 -05004830 if (newConn != mCurAudioRoutes.mainType) {
4831 mCurAudioRoutes.mainType = newConn;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004832 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4833 SENDMSG_NOOP, 0, 0, null, 0);
4834 }
4835 }
4836 }
4837
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004838 final long ident = Binder.clearCallingIdentity();
4839 try {
4840 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
4841 } finally {
4842 Binder.restoreCallingIdentity(ident);
4843 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004844 }
4845
Paul McLean10804eb2015-01-28 11:16:35 -08004846 private void onSetWiredDeviceConnectionState(int device, int state, String address,
John Spurlock90874332015-03-10 16:00:54 -04004847 String deviceName, String caller) {
Paul McLean394a8e12015-03-03 10:29:19 -07004848 if (DEBUG_DEVICES) {
John Spurlock90874332015-03-10 16:00:54 -04004849 Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
4850 + " state:" + Integer.toHexString(state)
4851 + " address:" + address
4852 + " deviceName:" + deviceName
4853 + " caller: " + caller + ");");
Paul McLean394a8e12015-03-03 10:29:19 -07004854 }
Paul McLean10804eb2015-01-28 11:16:35 -08004855
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004856 synchronized (mConnectedDevices) {
4857 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004858 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4859 (device == AudioSystem.DEVICE_OUT_LINE))) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004860 setBluetoothA2dpOnInt(true);
4861 }
Eric Laurentae4506e2014-05-29 16:04:32 -07004862 boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
4863 (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
4864 ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
Paul McLean10804eb2015-01-28 11:16:35 -08004865 handleDeviceConnection(state == 1, device, address, deviceName);
Eric Laurentf1a457d2012-09-20 16:27:23 -07004866 if (state != 0) {
4867 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004868 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4869 (device == AudioSystem.DEVICE_OUT_LINE)) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07004870 setBluetoothA2dpOnInt(false);
4871 }
4872 if ((device & mSafeMediaVolumeDevices) != 0) {
4873 sendMsg(mAudioHandler,
4874 MSG_CHECK_MUSIC_ACTIVE,
4875 SENDMSG_REPLACE,
4876 0,
4877 0,
John Spurlock90874332015-03-10 16:00:54 -04004878 caller,
Eric Laurentf1a457d2012-09-20 16:27:23 -07004879 MUSIC_ACTIVE_POLL_PERIOD_MS);
4880 }
Eric Laurent212532b2014-07-21 15:43:18 -07004881 // Television devices without CEC service apply software volume on HDMI output
4882 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4883 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
4884 checkAllFixedVolumeDevices();
4885 if (mHdmiManager != null) {
4886 synchronized (mHdmiManager) {
4887 if (mHdmiPlaybackClient != null) {
4888 mHdmiCecSink = false;
4889 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
4890 }
4891 }
4892 }
4893 }
4894 } else {
4895 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4896 if (mHdmiManager != null) {
4897 synchronized (mHdmiManager) {
4898 mHdmiCecSink = false;
4899 }
4900 }
4901 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004902 }
Paul McLean10804eb2015-01-28 11:16:35 -08004903 if (!isUsb && device != AudioSystem.DEVICE_IN_WIRED_HEADSET) {
4904 sendDeviceConnectionIntent(device, state, address, deviceName);
Mike Lockwooddb454842012-09-18 11:16:57 -07004905 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004906 }
4907 }
4908
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004909 private void configureHdmiPlugIntent(Intent intent, int state) {
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004910 intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
4911 intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004912 if (state == 1) {
4913 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
4914 int[] portGeneration = new int[1];
4915 int status = AudioSystem.listAudioPorts(ports, portGeneration);
4916 if (status == AudioManager.SUCCESS) {
4917 for (AudioPort port : ports) {
4918 if (port instanceof AudioDevicePort) {
4919 final AudioDevicePort devicePort = (AudioDevicePort) port;
Eric Laurent6fa42452015-01-09 15:09:40 -08004920 if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
4921 devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004922 // format the list of supported encodings
Eric Laurentcae34662015-05-19 16:46:52 -07004923 int[] formats = AudioFormat.filterPublicFormats(devicePort.formats());
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004924 if (formats.length > 0) {
4925 ArrayList<Integer> encodingList = new ArrayList(1);
4926 for (int format : formats) {
4927 // a format in the list can be 0, skip it
4928 if (format != AudioFormat.ENCODING_INVALID) {
4929 encodingList.add(format);
4930 }
4931 }
4932 int[] encodingArray = new int[encodingList.size()];
4933 for (int i = 0 ; i < encodingArray.length ; i++) {
4934 encodingArray[i] = encodingList.get(i);
4935 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004936 intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004937 }
4938 // find the maximum supported number of channels
4939 int maxChannels = 0;
4940 for (int mask : devicePort.channelMasks()) {
4941 int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
4942 if (channelCount > maxChannels) {
4943 maxChannels = channelCount;
4944 }
4945 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004946 intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004947 }
4948 }
4949 }
4950 }
4951 }
4952 }
4953
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004954 /* cache of the address of the last dock the device was connected to */
4955 private String mDockAddress;
4956
Eric Laurenta553c252009-07-17 12:17:14 -07004957 /**
4958 * Receiver for misc intent broadcasts the Phone app cares about.
4959 */
4960 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4961 @Override
4962 public void onReceive(Context context, Intent intent) {
4963 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07004964 int outDevice;
4965 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07004966 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07004967
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004968 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4969 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4970 Intent.EXTRA_DOCK_STATE_UNDOCKED);
4971 int config;
4972 switch (dockState) {
4973 case Intent.EXTRA_DOCK_STATE_DESK:
4974 config = AudioSystem.FORCE_BT_DESK_DOCK;
4975 break;
4976 case Intent.EXTRA_DOCK_STATE_CAR:
4977 config = AudioSystem.FORCE_BT_CAR_DOCK;
4978 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004979 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08004980 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004981 break;
4982 case Intent.EXTRA_DOCK_STATE_HE_DESK:
4983 config = AudioSystem.FORCE_DIGITAL_DOCK;
4984 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004985 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4986 default:
4987 config = AudioSystem.FORCE_NONE;
4988 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08004989 // Low end docks have a menu to enable or disable audio
4990 // (see mDockAudioMediaEnabled)
4991 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
4992 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
4993 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
4994 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
4995 }
4996 mDockState = dockState;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004997 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
Eric Laurent59f48272012-04-05 19:42:21 -07004998 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004999 BluetoothProfile.STATE_DISCONNECTED);
Eric Laurentdca56b92011-09-02 14:20:56 -07005000 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Eric Laurent0867bed2015-05-20 14:49:08 -07005001
Eric Laurent98859b22015-06-12 14:35:59 -07005002 setBtScoDeviceConnectionState(btDevice, state);
Paul McLeandf361462014-04-10 16:02:55 -07005003 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005004 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07005005 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005006 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005007 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07005008 // broadcast intent if the connection was initated by AudioService
5009 if (!mScoClients.isEmpty() &&
5010 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
5011 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
5012 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005013 broadcast = true;
5014 }
5015 switch (btState) {
5016 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07005017 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07005018 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5019 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5020 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005021 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005022 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005023 break;
5024 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07005025 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08005026 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07005027 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08005028 break;
5029 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07005030 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5031 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5032 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005033 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005034 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005035 default:
5036 // do not broadcast CONNECTING or invalid state
5037 broadcast = false;
5038 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005039 }
5040 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005041 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07005042 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07005043 //FIXME: this is to maintain compatibility with deprecated intent
5044 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08005045 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07005046 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005047 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08005048 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005049 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06005050 if (mMonitorRotation) {
5051 mOrientationListener.onOrientationChanged(0); //argument is ignored anyway
5052 mOrientationListener.enable();
5053 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005054 AudioSystem.setParameters("screen_state=on");
5055 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06005056 if (mMonitorRotation) {
5057 //reduce wakeups (save current) by only listening when display is on
5058 mOrientationListener.disable();
5059 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005060 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07005061 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005062 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07005063 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Yasuhiro Matsuda4ced7192015-07-10 22:08:44 +09005064 if (mUserSwitchedReceived) {
5065 // attempt to stop music playback for background user except on first user
5066 // switch (i.e. first boot)
5067 sendMsg(mAudioHandler,
5068 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
5069 SENDMSG_REPLACE,
5070 0,
5071 0,
5072 null,
5073 0);
5074 }
5075 mUserSwitchedReceived = true;
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07005076 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005077 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07005078
Eric Laurent5bfaeae2012-09-21 18:44:48 -07005079 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07005080 readAudioSettings(true /*userSwitch*/);
5081 // preserve STREAM_MUSIC volume from one user to the next.
5082 sendMsg(mAudioHandler,
5083 MSG_SET_ALL_VOLUMES,
5084 SENDMSG_QUEUE,
5085 0,
5086 0,
5087 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005088 } else if (action.equals(Intent.ACTION_USER_BACKGROUND)) {
5089 // Disable audio recording for the background user/profile
5090 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
5091 if (userId >= 0) {
5092 // TODO Kill recording streams instead of killing processes holding permission
5093 UserInfo userInfo = UserManagerService.getInstance().getUserInfo(userId);
5094 killBackgroundUserProcessesWithRecordAudioPermission(userInfo);
5095 }
5096 UserManagerService.getInstance().setSystemControlledUserRestriction(
5097 UserManager.DISALLOW_RECORD_AUDIO, true, userId);
5098 } else if (action.equals(Intent.ACTION_USER_FOREGROUND)) {
5099 // Enable audio recording for foreground user/profile
5100 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
5101 UserManagerService.getInstance().setSystemControlledUserRestriction(
5102 UserManager.DISALLOW_RECORD_AUDIO, false, userId);
Eric Laurenta553c252009-07-17 12:17:14 -07005103 }
5104 }
Paul McLeanc837a452014-04-09 09:04:43 -07005105 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005106
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005107 private void killBackgroundUserProcessesWithRecordAudioPermission(UserInfo oldUser) {
5108 PackageManager pm = mContext.getPackageManager();
5109 // Find the home activity of the user. It should not be killed to avoid expensive restart,
5110 // when the user switches back. For managed profiles, we should kill all recording apps
5111 ComponentName homeActivityName = null;
5112 if (!oldUser.isManagedProfile()) {
5113 homeActivityName = LocalServices.getService(ActivityManagerInternal.class)
5114 .getHomeActivityForUser(oldUser.id);
5115 }
5116 final String[] permissions = { Manifest.permission.RECORD_AUDIO };
5117 List<PackageInfo> packages;
5118 try {
5119 packages = AppGlobals.getPackageManager()
5120 .getPackagesHoldingPermissions(permissions, 0, oldUser.id).getList();
5121 } catch (RemoteException e) {
5122 throw new AndroidRuntimeException(e);
5123 }
5124 for (int j = packages.size() - 1; j >= 0; j--) {
5125 PackageInfo pkg = packages.get(j);
Fyodor Kupolovbcb6c1e2015-05-11 12:05:15 -07005126 // Skip system processes
5127 if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
5128 continue;
5129 }
Amith Yamasanic1cbaab2015-07-21 11:46:14 -07005130 // Skip packages that have permission to interact across users
5131 if (pm.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS, pkg.packageName)
5132 == PackageManager.PERMISSION_GRANTED) {
5133 continue;
5134 }
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005135 if (homeActivityName != null
5136 && pkg.packageName.equals(homeActivityName.getPackageName())
5137 && pkg.applicationInfo.isSystemApp()) {
5138 continue;
5139 }
5140 try {
5141 ActivityManagerNative.getDefault().killUid(pkg.applicationInfo.uid,
5142 "killBackgroundUserProcessesWithAudioRecordPermission");
5143 } catch (RemoteException e) {
5144 Log.w(TAG, "Error calling killUid", e);
5145 }
5146 }
5147 }
5148
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005149 //==========================================================================================
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005150 // RemoteControlDisplay / RemoteControlClient / Remote info
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005151 //==========================================================================================
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07005152 public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
5153 ComponentName listenerComp) {
5154 return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
5155 }
5156
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005157 public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07005158 return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005159 }
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005160
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005161 public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005162 mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005163 }
5164
5165 public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005166 mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005167 }
5168
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07005169 public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
5170 boolean wantsSync) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005171 mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
5172 }
5173
John Spurlock3346a802014-05-20 16:25:37 -04005174 @Override
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005175 public void setRemoteStreamVolume(int index) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005176 enforceVolumeController("set the remote stream volume");
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005177 mMediaFocusControl.setRemoteStreamVolume(index);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005178 }
5179
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005180 //==========================================================================================
5181 // Audio Focus
5182 //==========================================================================================
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005183 public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005184 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005185 IAudioPolicyCallback pcb) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005186 // permission checks
5187 if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
John Spurlock61560172015-02-06 19:46:04 -05005188 if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005189 if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
5190 android.Manifest.permission.MODIFY_PHONE_STATE)) {
5191 Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
5192 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5193 }
5194 } else {
5195 // only a registered audio policy can be used to lock focus
5196 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005197 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
5198 Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005199 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5200 }
5201 }
5202 }
5203 }
5204
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005205 return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
5206 clientId, callingPackageName, flags);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005207 }
5208
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005209 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
5210 return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005211 }
5212
5213 public void unregisterAudioFocusClient(String clientId) {
5214 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005215 }
5216
Jean-Michel Trivi23805662013-07-31 14:19:18 -07005217 public int getCurrentAudioFocus() {
5218 return mMediaFocusControl.getCurrentAudioFocus();
5219 }
5220
John Spurlock5e783732015-02-19 10:28:59 -05005221 private boolean readCameraSoundForced() {
5222 return SystemProperties.getBoolean("audio.camerasound.force", false) ||
5223 mContext.getResources().getBoolean(
5224 com.android.internal.R.bool.config_camera_sound_forced);
5225 }
5226
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005227 //==========================================================================================
5228 // Device orientation
5229 //==========================================================================================
5230 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005231 * Handles device configuration changes that may map to a change in the orientation
5232 * or orientation.
5233 * Monitoring orientation and rotation is optional, and is defined by the definition and value
5234 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005235 */
5236 private void handleConfigurationChanged(Context context) {
5237 try {
5238 // reading new orientation "safely" (i.e. under try catch) in case anything
5239 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07005240 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005241 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07005242 if (mMonitorOrientation) {
5243 int newOrientation = config.orientation;
5244 if (newOrientation != mDeviceOrientation) {
5245 mDeviceOrientation = newOrientation;
5246 setOrientationForAudioSystem();
5247 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005248 }
Eric Laurentd640bd32012-09-28 18:01:48 -07005249 sendMsg(mAudioHandler,
5250 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
5251 SENDMSG_REPLACE,
5252 0,
5253 0,
John Spurlock90874332015-03-10 16:00:54 -04005254 TAG,
Eric Laurentd640bd32012-09-28 18:01:48 -07005255 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07005256
John Spurlock5e783732015-02-19 10:28:59 -05005257 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -07005258 synchronized (mSettingsLock) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005259 boolean cameraSoundForcedChanged = false;
Eric Laurentdd45d012012-10-08 09:04:34 -07005260 synchronized (mCameraSoundForced) {
5261 if (cameraSoundForced != mCameraSoundForced) {
5262 mCameraSoundForced = cameraSoundForced;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005263 cameraSoundForcedChanged = true;
Eric Laurentdd45d012012-10-08 09:04:34 -07005264 }
5265 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005266 if (cameraSoundForcedChanged) {
5267 if (!isPlatformTelevision()) {
5268 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
5269 if (cameraSoundForced) {
5270 s.setAllIndexesToMax();
5271 mRingerModeAffectedStreams &=
5272 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5273 } else {
John Spurlock90874332015-03-10 16:00:54 -04005274 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005275 mRingerModeAffectedStreams |=
5276 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5277 }
5278 // take new state into account for streams muted by ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05005279 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005280 }
5281
5282 sendMsg(mAudioHandler,
5283 MSG_SET_FORCE_USE,
5284 SENDMSG_QUEUE,
5285 AudioSystem.FOR_SYSTEM,
5286 cameraSoundForced ?
5287 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
5288 null,
5289 0);
5290
5291 sendMsg(mAudioHandler,
5292 MSG_SET_ALL_VOLUMES,
5293 SENDMSG_QUEUE,
5294 0,
5295 0,
5296 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
5297 }
Eric Laurentdd45d012012-10-08 09:04:34 -07005298 }
John Spurlock3346a802014-05-20 16:25:37 -04005299 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005300 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005301 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005302 }
5303 }
5304
5305 private void setOrientationForAudioSystem() {
5306 switch (mDeviceOrientation) {
5307 case Configuration.ORIENTATION_LANDSCAPE:
5308 //Log.i(TAG, "orientation is landscape");
5309 AudioSystem.setParameters("orientation=landscape");
5310 break;
5311 case Configuration.ORIENTATION_PORTRAIT:
5312 //Log.i(TAG, "orientation is portrait");
5313 AudioSystem.setParameters("orientation=portrait");
5314 break;
5315 case Configuration.ORIENTATION_SQUARE:
5316 //Log.i(TAG, "orientation is square");
5317 AudioSystem.setParameters("orientation=square");
5318 break;
5319 case Configuration.ORIENTATION_UNDEFINED:
5320 //Log.i(TAG, "orientation is undefined");
5321 AudioSystem.setParameters("orientation=undefined");
5322 break;
5323 default:
5324 Log.e(TAG, "Unknown orientation");
5325 }
5326 }
5327
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005328 private void setRotationForAudioSystem() {
5329 switch (mDeviceRotation) {
5330 case Surface.ROTATION_0:
5331 AudioSystem.setParameters("rotation=0");
5332 break;
5333 case Surface.ROTATION_90:
5334 AudioSystem.setParameters("rotation=90");
5335 break;
5336 case Surface.ROTATION_180:
5337 AudioSystem.setParameters("rotation=180");
5338 break;
5339 case Surface.ROTATION_270:
5340 AudioSystem.setParameters("rotation=270");
5341 break;
5342 default:
5343 Log.e(TAG, "Unknown device rotation");
5344 }
5345 }
5346
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005347
Eric Laurent78472112012-05-21 08:57:21 -07005348 // Handles request to override default use of A2DP for media.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005349 // Must be called synchronized on mConnectedDevices
Eric Laurent78472112012-05-21 08:57:21 -07005350 public void setBluetoothA2dpOnInt(boolean on) {
5351 synchronized (mBluetoothA2dpEnabledLock) {
5352 mBluetoothA2dpEnabled = on;
Eric Laurentc390bed2012-07-03 12:24:05 -07005353 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005354 setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
Eric Laurentc390bed2012-07-03 12:24:05 -07005355 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
Eric Laurent78472112012-05-21 08:57:21 -07005356 }
5357 }
5358
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005359 // Must be called synchronized on mConnectedDevices
5360 private void setForceUseInt_SyncDevices(int usage, int config) {
5361 switch (usage) {
5362 case AudioSystem.FOR_MEDIA:
5363 if (config == AudioSystem.FORCE_NO_BT_A2DP) {
5364 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ALL_A2DP;
5365 } else { // config == AudioSystem.FORCE_NONE
5366 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
5367 }
5368 break;
5369 case AudioSystem.FOR_DOCK:
5370 if (config == AudioSystem.FORCE_ANALOG_DOCK) {
5371 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5372 } else { // config == AudioSystem.FORCE_NONE
5373 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5374 }
5375 break;
5376 default:
5377 // usage doesn't affect the broadcast of ACTION_AUDIO_BECOMING_NOISY
5378 }
5379 AudioSystem.setForceUse(usage, config);
5380 }
5381
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005382 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07005383 public void setRingtonePlayer(IRingtonePlayer player) {
5384 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5385 mRingtonePlayer = player;
5386 }
5387
5388 @Override
5389 public IRingtonePlayer getRingtonePlayer() {
5390 return mRingtonePlayer;
5391 }
5392
5393 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07005394 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5395 synchronized (mCurAudioRoutes) {
5396 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5397 mRoutesObservers.register(observer);
5398 return routes;
5399 }
5400 }
5401
Eric Laurentc34dcc12012-09-10 13:51:52 -07005402
5403 //==========================================================================================
5404 // Safe media volume management.
5405 // MUSIC stream volume level is limited when headphones are connected according to safety
5406 // regulation. When the user attempts to raise the volume above the limit, a warning is
5407 // displayed and the user has to acknowlegde before the volume is actually changed.
5408 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
5409 // property. Platforms with a different limit must set this property accordingly in their
5410 // overlay.
5411 //==========================================================================================
5412
Eric Laurentd640bd32012-09-28 18:01:48 -07005413 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
5414 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
5415 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
5416 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
5417 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
5418 // (when user opts out).
John Spurlock35134602014-07-24 18:10:48 -04005419 private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
5420 private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
5421 private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed
5422 private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
Eric Laurentd640bd32012-09-28 18:01:48 -07005423 private Integer mSafeMediaVolumeState;
5424
5425 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005426 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07005427 private int mSafeMediaVolumeIndex;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005428 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
5429 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
5430 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
5431 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
5432 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
5433 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
5434 private int mMusicActiveMs;
5435 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
5436 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07005437 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07005438
John Spurlock90874332015-03-10 16:00:54 -04005439 private void setSafeMediaVolumeEnabled(boolean on, String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005440 synchronized (mSafeMediaVolumeState) {
5441 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
5442 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
5443 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
5444 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
John Spurlock90874332015-03-10 16:00:54 -04005445 enforceSafeMediaVolume(caller);
Eric Laurentd640bd32012-09-28 18:01:48 -07005446 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
5447 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005448 mMusicActiveMs = 1; // nonzero = confirmed
5449 saveMusicActiveMs();
Eric Laurentd640bd32012-09-28 18:01:48 -07005450 sendMsg(mAudioHandler,
5451 MSG_CHECK_MUSIC_ACTIVE,
5452 SENDMSG_REPLACE,
5453 0,
5454 0,
John Spurlock90874332015-03-10 16:00:54 -04005455 caller,
Eric Laurentd640bd32012-09-28 18:01:48 -07005456 MUSIC_ACTIVE_POLL_PERIOD_MS);
5457 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005458 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005459 }
5460 }
5461
John Spurlock90874332015-03-10 16:00:54 -04005462 private void enforceSafeMediaVolume(String caller) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005463 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07005464 int devices = mSafeMediaVolumeDevices;
5465 int i = 0;
5466
5467 while (devices != 0) {
5468 int device = 1 << i++;
5469 if ((device & devices) == 0) {
5470 continue;
5471 }
Eric Laurent42b041e2013-03-29 11:36:03 -07005472 int index = streamState.getIndex(device);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005473 if (index > mSafeMediaVolumeIndex) {
John Spurlock90874332015-03-10 16:00:54 -04005474 streamState.setIndex(mSafeMediaVolumeIndex, device, caller);
Eric Laurent42b041e2013-03-29 11:36:03 -07005475 sendMsg(mAudioHandler,
5476 MSG_SET_DEVICE_VOLUME,
5477 SENDMSG_QUEUE,
5478 device,
5479 0,
5480 streamState,
5481 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005482 }
5483 devices &= ~device;
5484 }
5485 }
5486
5487 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005488 synchronized (mSafeMediaVolumeState) {
5489 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07005490 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
5491 ((device & mSafeMediaVolumeDevices) != 0) &&
5492 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005493 return false;
5494 }
5495 return true;
5496 }
5497 }
5498
John Spurlock3346a802014-05-20 16:25:37 -04005499 @Override
John Spurlock90874332015-03-10 16:00:54 -04005500 public void disableSafeMediaVolume(String callingPackage) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005501 enforceVolumeController("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07005502 synchronized (mSafeMediaVolumeState) {
John Spurlock90874332015-03-10 16:00:54 -04005503 setSafeMediaVolumeEnabled(false, callingPackage);
Eric Laurentfde16d52012-12-03 14:42:39 -08005504 if (mPendingVolumeCommand != null) {
5505 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
5506 mPendingVolumeCommand.mIndex,
5507 mPendingVolumeCommand.mFlags,
John Spurlock90874332015-03-10 16:00:54 -04005508 mPendingVolumeCommand.mDevice,
5509 callingPackage);
Eric Laurentfde16d52012-12-03 14:42:39 -08005510 mPendingVolumeCommand = null;
5511 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005512 }
5513 }
5514
Jungshik Jang41d97462014-06-30 22:26:29 +09005515 //==========================================================================================
5516 // Hdmi Cec system audio mode.
John Spurlockbc82b122015-03-02 16:12:38 -05005517 // If Hdmi Cec's system audio mode is on, audio service should send the volume change
5518 // to HdmiControlService so that the audio receiver can handle it.
Jungshik Jang41d97462014-06-30 22:26:29 +09005519 //==========================================================================================
5520
Eric Laurent212532b2014-07-21 15:43:18 -07005521 private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
5522 public void onComplete(int status) {
5523 if (mHdmiManager != null) {
5524 synchronized (mHdmiManager) {
5525 mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
5526 // Television devices without CEC service apply software volume on HDMI output
5527 if (isPlatformTelevision() && !mHdmiCecSink) {
5528 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5529 }
5530 checkAllFixedVolumeDevices();
5531 }
5532 }
5533 }
5534 };
5535
Jungshik Jang41d97462014-06-30 22:26:29 +09005536 // If HDMI-CEC system audio is supported
5537 private boolean mHdmiSystemAudioSupported = false;
5538 // Set only when device is tv.
5539 private HdmiTvClient mHdmiTvClient;
Eric Laurent0b03f992014-11-18 18:08:02 -08005540 // true if the device has system feature PackageManager.FEATURE_LEANBACK.
Eric Laurent212532b2014-07-21 15:43:18 -07005541 // cached HdmiControlManager interface
5542 private HdmiControlManager mHdmiManager;
5543 // Set only when device is a set-top box.
5544 private HdmiPlaybackClient mHdmiPlaybackClient;
5545 // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5546 private boolean mHdmiCecSink;
5547
5548 private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
Jungshik Jang41d97462014-06-30 22:26:29 +09005549
5550 @Override
Jungshik Jang12307ca2014-07-15 19:27:56 +09005551 public int setHdmiSystemAudioSupported(boolean on) {
Eric Laurent212532b2014-07-21 15:43:18 -07005552 int device = AudioSystem.DEVICE_NONE;
5553 if (mHdmiManager != null) {
5554 synchronized (mHdmiManager) {
5555 if (mHdmiTvClient == null) {
5556 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5557 return device;
5558 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005559
Eric Laurent212532b2014-07-21 15:43:18 -07005560 synchronized (mHdmiTvClient) {
5561 if (mHdmiSystemAudioSupported != on) {
5562 mHdmiSystemAudioSupported = on;
5563 AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5564 on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5565 AudioSystem.FORCE_NONE);
5566 }
John Spurlock8a52c442015-03-26 14:23:58 -04005567 device = getDevicesForStream(AudioSystem.STREAM_MUSIC);
Eric Laurent212532b2014-07-21 15:43:18 -07005568 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005569 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005570 }
Eric Laurent212532b2014-07-21 15:43:18 -07005571 return device;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005572 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005573
Terry Heoe7d6d972014-09-04 21:05:28 +09005574 @Override
5575 public boolean isHdmiSystemAudioSupported() {
5576 return mHdmiSystemAudioSupported;
5577 }
5578
Eric Laurentdd45d012012-10-08 09:04:34 -07005579 //==========================================================================================
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005580 // Accessibility: taking touch exploration into account for selecting the default
5581 // stream override timeout when adjusting volume
5582 //==========================================================================================
5583 private static class StreamOverride
5584 implements AccessibilityManager.TouchExplorationStateChangeListener {
5585
5586 // AudioService.getActiveStreamType() will return:
5587 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
5588 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
5589 // stopped
Jean-Michel Triviccffda82015-05-21 18:23:57 -07005590 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 0;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005591 private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
5592
5593 static int sDelayMs;
5594
5595 static void init(Context ctxt) {
5596 AccessibilityManager accessibilityManager =
5597 (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
5598 updateDefaultStreamOverrideDelay(
5599 accessibilityManager.isTouchExplorationEnabled());
5600 accessibilityManager.addTouchExplorationStateChangeListener(
5601 new StreamOverride());
5602 }
5603
5604 @Override
5605 public void onTouchExplorationStateChanged(boolean enabled) {
5606 updateDefaultStreamOverrideDelay(enabled);
5607 }
5608
5609 private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
5610 if (touchExploreEnabled) {
5611 sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
5612 } else {
5613 sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
5614 }
5615 if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
5616 + " stream override delay is now " + sDelayMs + " ms");
5617 }
5618 }
5619
5620 //==========================================================================================
Eric Laurentdd45d012012-10-08 09:04:34 -07005621 // Camera shutter sound policy.
5622 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5623 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5624 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5625 //==========================================================================================
5626
5627 // cached value of com.android.internal.R.bool.config_camera_sound_forced
5628 private Boolean mCameraSoundForced;
5629
5630 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5631 public boolean isCameraSoundForced() {
5632 synchronized (mCameraSoundForced) {
5633 return mCameraSoundForced;
5634 }
5635 }
5636
5637 private static final String[] RINGER_MODE_NAMES = new String[] {
5638 "SILENT",
5639 "VIBRATE",
5640 "NORMAL"
5641 };
5642
5643 private void dumpRingerMode(PrintWriter pw) {
5644 pw.println("\nRinger mode: ");
John Spurlock661f2cf2014-11-17 10:29:10 -05005645 pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
5646 pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
John Spurlock50ced3f2015-05-11 16:00:09 -04005647 dumpRingerModeStreams(pw, "affected", mRingerModeAffectedStreams);
5648 dumpRingerModeStreams(pw, "muted", mRingerModeMutedStreams);
John Spurlock661f2cf2014-11-17 10:29:10 -05005649 pw.print("- delegate = "); pw.println(mRingerModeDelegate);
Eric Laurentdd45d012012-10-08 09:04:34 -07005650 }
5651
John Spurlock50ced3f2015-05-11 16:00:09 -04005652 private void dumpRingerModeStreams(PrintWriter pw, String type, int streams) {
5653 pw.print("- ringer mode "); pw.print(type); pw.print(" streams = 0x");
5654 pw.print(Integer.toHexString(streams));
5655 if (streams != 0) {
5656 pw.print(" (");
5657 boolean first = true;
5658 for (int i = 0; i < AudioSystem.STREAM_NAMES.length; i++) {
5659 final int stream = (1 << i);
5660 if ((streams & stream) != 0) {
5661 if (!first) pw.print(',');
5662 pw.print(AudioSystem.STREAM_NAMES[i]);
5663 streams &= ~stream;
5664 first = false;
5665 }
5666 }
5667 if (streams != 0) {
5668 if (!first) pw.print(',');
5669 pw.print(streams);
5670 }
5671 pw.print(')');
5672 }
5673 pw.println();
5674 }
5675
Dianne Hackborn632ca412012-06-14 19:34:10 -07005676 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005677 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07005678 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5679
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005680 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07005681 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07005682 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005683 pw.println("\nAudio routes:");
John Spurlock61560172015-02-06 19:46:04 -05005684 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
5685 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
John Spurlock35134602014-07-24 18:10:48 -04005686
5687 pw.println("\nOther state:");
John Spurlock3346a802014-05-20 16:25:37 -04005688 pw.print(" mVolumeController="); pw.println(mVolumeController);
John Spurlock35134602014-07-24 18:10:48 -04005689 pw.print(" mSafeMediaVolumeState=");
5690 pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
5691 pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
5692 pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
5693 pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005694 pw.print(" mMcc="); pw.println(mMcc);
John Spurlock5e783732015-02-19 10:28:59 -05005695 pw.print(" mCameraSoundForced="); pw.println(mCameraSoundForced);
John Spurlock661f2cf2014-11-17 10:29:10 -05005696 pw.print(" mHasVibrator="); pw.println(mHasVibrator);
John Spurlockcdb57ae2015-02-11 19:04:11 -05005697 pw.print(" mControllerService="); pw.println(mControllerService);
John Spurlocka48d7792015-03-03 17:35:57 -05005698 pw.print(" mVolumePolicy="); pw.println(mVolumePolicy);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005699
5700 dumpAudioPolicies(pw);
John Spurlock35134602014-07-24 18:10:48 -04005701 }
5702
5703 private static String safeMediaVolumeStateToString(Integer state) {
5704 switch(state) {
5705 case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
5706 case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
5707 case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
5708 case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
5709 }
5710 return null;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005711 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07005712
5713 // Inform AudioFlinger of our device's low RAM attribute
5714 private static void readAndSetLowRamDevice()
5715 {
5716 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
5717 if (status != 0) {
5718 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
5719 }
5720 }
John Spurlock3346a802014-05-20 16:25:37 -04005721
John Spurlockcdb57ae2015-02-11 19:04:11 -05005722 private void enforceVolumeController(String action) {
5723 if (mControllerService.mUid != 0 && Binder.getCallingUid() == mControllerService.mUid) {
5724 return;
5725 }
John Spurlock3346a802014-05-20 16:25:37 -04005726 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
5727 "Only SystemUI can " + action);
5728 }
5729
5730 @Override
5731 public void setVolumeController(final IVolumeController controller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005732 enforceVolumeController("set the volume controller");
John Spurlock3346a802014-05-20 16:25:37 -04005733
5734 // return early if things are not actually changing
5735 if (mVolumeController.isSameBinder(controller)) {
5736 return;
5737 }
5738
5739 // dismiss the old volume controller
5740 mVolumeController.postDismiss();
5741 if (controller != null) {
5742 // we are about to register a new controller, listen for its death
5743 try {
5744 controller.asBinder().linkToDeath(new DeathRecipient() {
5745 @Override
5746 public void binderDied() {
5747 if (mVolumeController.isSameBinder(controller)) {
5748 Log.w(TAG, "Current remote volume controller died, unregistering");
5749 setVolumeController(null);
5750 }
5751 }
5752 }, 0);
5753 } catch (RemoteException e) {
5754 // noop
5755 }
5756 }
5757 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04005758 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
5759 }
5760
5761 @Override
5762 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005763 enforceVolumeController("notify about volume controller visibility");
John Spurlock33f4e042014-07-11 13:10:58 -04005764
5765 // return early if the controller is not current
5766 if (!mVolumeController.isSameBinder(controller)) {
5767 return;
5768 }
5769
5770 mVolumeController.setVisible(visible);
5771 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04005772 }
RoboErikd09bd0c2014-06-24 17:45:19 -07005773
John Spurlocka48d7792015-03-03 17:35:57 -05005774 @Override
5775 public void setVolumePolicy(VolumePolicy policy) {
5776 enforceVolumeController("set volume policy");
John Spurlockb02c7442015-04-14 09:32:25 -04005777 if (policy != null && !policy.equals(mVolumePolicy)) {
John Spurlocka48d7792015-03-03 17:35:57 -05005778 mVolumePolicy = policy;
John Spurlockb02c7442015-04-14 09:32:25 -04005779 if (DEBUG_VOL) Log.d(TAG, "Volume policy changed: " + mVolumePolicy);
John Spurlocka48d7792015-03-03 17:35:57 -05005780 }
5781 }
5782
RoboErikd09bd0c2014-06-24 17:45:19 -07005783 public static class VolumeController {
5784 private static final String TAG = "VolumeController";
5785
5786 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04005787 private boolean mVisible;
5788 private long mNextLongPress;
5789 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07005790
5791 public void setController(IVolumeController controller) {
5792 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04005793 mVisible = false;
5794 }
5795
5796 public void loadSettings(ContentResolver cr) {
5797 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
5798 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
5799 }
5800
RoboErik4197cb62015-01-21 15:45:32 -08005801 public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
5802 if (isMute) {
5803 return false;
5804 }
John Spurlock33f4e042014-07-11 13:10:58 -04005805 boolean suppress = false;
5806 if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
5807 final long now = SystemClock.uptimeMillis();
5808 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
5809 // ui will become visible
5810 if (mNextLongPress < now) {
5811 mNextLongPress = now + mLongPressTimeout;
5812 }
5813 suppress = true;
5814 } else if (mNextLongPress > 0) { // in a long-press
5815 if (now > mNextLongPress) {
5816 // long press triggered, no more suppression
5817 mNextLongPress = 0;
5818 } else {
5819 // keep suppressing until the long press triggers
5820 suppress = true;
5821 }
5822 }
5823 }
5824 return suppress;
5825 }
5826
5827 public void setVisible(boolean visible) {
5828 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07005829 }
5830
5831 public boolean isSameBinder(IVolumeController controller) {
5832 return Objects.equals(asBinder(), binder(controller));
5833 }
5834
5835 public IBinder asBinder() {
5836 return binder(mController);
5837 }
5838
5839 private static IBinder binder(IVolumeController controller) {
5840 return controller == null ? null : controller.asBinder();
5841 }
5842
5843 @Override
5844 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04005845 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07005846 }
5847
5848 public void postDisplaySafeVolumeWarning(int flags) {
5849 if (mController == null)
5850 return;
5851 try {
5852 mController.displaySafeVolumeWarning(flags);
5853 } catch (RemoteException e) {
5854 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
5855 }
5856 }
5857
5858 public void postVolumeChanged(int streamType, int flags) {
5859 if (mController == null)
5860 return;
5861 try {
5862 mController.volumeChanged(streamType, flags);
5863 } catch (RemoteException e) {
5864 Log.w(TAG, "Error calling volumeChanged", e);
5865 }
5866 }
5867
RoboErikd09bd0c2014-06-24 17:45:19 -07005868 public void postMasterMuteChanged(int flags) {
5869 if (mController == null)
5870 return;
5871 try {
5872 mController.masterMuteChanged(flags);
5873 } catch (RemoteException e) {
5874 Log.w(TAG, "Error calling masterMuteChanged", e);
5875 }
5876 }
5877
5878 public void setLayoutDirection(int layoutDirection) {
5879 if (mController == null)
5880 return;
5881 try {
5882 mController.setLayoutDirection(layoutDirection);
5883 } catch (RemoteException e) {
5884 Log.w(TAG, "Error calling setLayoutDirection", e);
5885 }
5886 }
5887
5888 public void postDismiss() {
5889 if (mController == null)
5890 return;
5891 try {
5892 mController.dismiss();
5893 } catch (RemoteException e) {
5894 Log.w(TAG, "Error calling dismiss", e);
5895 }
5896 }
5897 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005898
RoboErik0dac35a2014-08-12 15:48:49 -07005899 /**
5900 * Interface for system components to get some extra functionality through
5901 * LocalServices.
5902 */
5903 final class AudioServiceInternal extends AudioManagerInternal {
John Spurlock661f2cf2014-11-17 10:29:10 -05005904 @Override
5905 public void setRingerModeDelegate(RingerModeDelegate delegate) {
5906 mRingerModeDelegate = delegate;
5907 if (mRingerModeDelegate != null) {
John Spurlock50ced3f2015-05-11 16:00:09 -04005908 updateRingerModeAffectedStreams();
John Spurlock661f2cf2014-11-17 10:29:10 -05005909 setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
5910 }
5911 }
RoboErik272e1612014-09-05 11:39:29 -07005912
5913 @Override
5914 public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
5915 String callingPackage, int uid) {
5916 // direction and stream type swap here because the public
5917 // adjustSuggested has a different order than the other methods.
John Spurlock90874332015-03-10 16:00:54 -04005918 adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage,
5919 callingPackage, uid);
RoboErik272e1612014-09-05 11:39:29 -07005920 }
5921
RoboErik0dac35a2014-08-12 15:48:49 -07005922 @Override
5923 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
5924 String callingPackage, int uid) {
John Spurlock90874332015-03-10 16:00:54 -04005925 adjustStreamVolume(streamType, direction, flags, callingPackage,
5926 callingPackage, uid);
RoboErik0dac35a2014-08-12 15:48:49 -07005927 }
5928
5929 @Override
5930 public void setStreamVolumeForUid(int streamType, int direction, int flags,
5931 String callingPackage, int uid) {
John Spurlock90874332015-03-10 16:00:54 -04005932 setStreamVolume(streamType, direction, flags, callingPackage, callingPackage, uid);
RoboErik0dac35a2014-08-12 15:48:49 -07005933 }
RoboErik519c7742014-11-18 10:59:09 -08005934
5935 @Override
John Spurlock661f2cf2014-11-17 10:29:10 -05005936 public int getRingerModeInternal() {
5937 return AudioService.this.getRingerModeInternal();
5938 }
5939
5940 @Override
5941 public void setRingerModeInternal(int ringerMode, String caller) {
5942 AudioService.this.setRingerModeInternal(ringerMode, caller);
5943 }
John Spurlockcdb57ae2015-02-11 19:04:11 -05005944
5945 @Override
5946 public int getVolumeControllerUid() {
5947 return mControllerService.mUid;
5948 }
John Spurlock50ced3f2015-05-11 16:00:09 -04005949
5950 @Override
5951 public void updateRingerModeAffectedStreamsInternal() {
5952 synchronized (mSettingsLock) {
5953 if (updateRingerModeAffectedStreams()) {
5954 setRingerModeInt(getRingerModeInternal(), false);
5955 }
5956 }
5957 }
RoboErik0dac35a2014-08-12 15:48:49 -07005958 }
5959
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005960 //==========================================================================================
5961 // Audio policy management
5962 //==========================================================================================
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005963 public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
5964 boolean hasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07005965 AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
5966
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005967 if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
5968 + " with config:" + policyConfig);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005969 String regId = null;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005970 // error handling
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005971 boolean hasPermissionForPolicy =
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005972 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005973 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5974 if (!hasPermissionForPolicy) {
5975 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
5976 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005977 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005978 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005979
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005980 synchronized (mAudioPolicies) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005981 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005982 if (mAudioPolicies.containsKey(pcb.asBinder())) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005983 Slog.e(TAG, "Cannot re-register policy");
5984 return null;
5985 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005986 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
5987 pcb.asBinder().linkToDeath(app, 0/*flags*/);
5988 regId = app.getRegistrationId();
5989 mAudioPolicies.put(pcb.asBinder(), app);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005990 } catch (RemoteException e) {
5991 // audio policy owner has already died!
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005992 Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005993 " binder death", e);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005994 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005995 }
5996 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005997 return regId;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005998 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005999
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006000 public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
6001 if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006002 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006003 AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006004 if (app == null) {
6005 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
6006 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006007 return;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006008 } else {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006009 pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006010 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006011 app.release();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006012 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006013 // TODO implement clearing mix attribute matching info in native audio policy
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006014 }
6015
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006016 public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
6017 if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
6018 + " policy " + pcb.asBinder());
6019 // error handling
6020 boolean hasPermissionForPolicy =
6021 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
6022 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
6023 if (!hasPermissionForPolicy) {
6024 Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
6025 + Binder.getCallingPid() + " / uid "
6026 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
6027 return AudioManager.ERROR;
6028 }
6029
6030 synchronized (mAudioPolicies) {
6031 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
6032 Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
6033 return AudioManager.ERROR;
6034 }
6035 final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
6036 if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6037 // is there already one policy managing ducking?
Eric Laurent0867bed2015-05-20 14:49:08 -07006038 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006039 if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6040 Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
6041 return AudioManager.ERROR;
6042 }
6043 }
6044 }
6045 app.mFocusDuckBehavior = duckingBehavior;
6046 mMediaFocusControl.setDuckingInExtPolicyAvailable(
6047 duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
6048 }
6049 return AudioManager.SUCCESS;
6050 }
6051
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006052 private void dumpAudioPolicies(PrintWriter pw) {
6053 pw.println("\nAudio policies:");
6054 synchronized (mAudioPolicies) {
Eric Laurent0867bed2015-05-20 14:49:08 -07006055 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006056 pw.println(policy.toLogFriendlyString());
6057 }
6058 }
6059 }
6060
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006061 //======================
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006062 // Audio policy callback from AudioSystem
6063 //======================
6064 private final AudioSystem.DynamicPolicyCallback mDynPolicyCallback =
6065 new AudioSystem.DynamicPolicyCallback() {
6066 public void onDynamicPolicyMixStateUpdate(String regId, int state) {
6067 if (!TextUtils.isEmpty(regId)) {
6068 sendMsg(mAudioHandler, MSG_DYN_POLICY_MIX_STATE_UPDATE, SENDMSG_QUEUE,
6069 state /*arg1*/, 0 /*arg2 ignored*/, regId /*obj*/, 0 /*delay*/);
6070 }
6071 }
6072 };
6073
6074 private void onDynPolicyMixStateUpdate(String regId, int state) {
6075 if (DEBUG_AP) Log.d(TAG, "onDynamicPolicyMixStateUpdate("+ regId + ", " + state +")");
6076 synchronized (mAudioPolicies) {
6077 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
6078 for (AudioMix mix : policy.getMixes()) {
6079 if (mix.getRegistration().equals(regId)) {
6080 try {
6081 policy.mPolicyCallback.notifyMixStateUpdate(regId, state);
6082 } catch (RemoteException e) {
6083 Log.e(TAG, "Can't call notifyMixStateUpdate() on IAudioPolicyCallback "
6084 + policy.mPolicyCallback.asBinder(), e);
6085 }
6086 return;
6087 }
6088 }
6089 }
6090 }
6091
6092 }
6093
6094 //======================
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006095 // Audio policy proxy
6096 //======================
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006097 /**
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006098 * This internal class inherits from AudioPolicyConfig, each instance contains all the
6099 * mixes of an AudioPolicy and their configurations.
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006100 */
6101 public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006102 private static final String TAG = "AudioPolicyProxy";
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006103 IAudioPolicyCallback mPolicyCallback;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006104 boolean mHasFocusListener;
6105 /**
6106 * Audio focus ducking behavior for an audio policy.
6107 * This variable reflects the value that was successfully set in
6108 * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
6109 * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
6110 * is handling ducking for audio focus.
6111 */
6112 int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
6113
6114 AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
6115 boolean hasFocusListener) {
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006116 super(config);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006117 setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006118 mPolicyCallback = token;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006119 mHasFocusListener = hasFocusListener;
6120 if (mHasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006121 mMediaFocusControl.addFocusFollower(mPolicyCallback);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006122 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006123 connectMixes();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006124 }
6125
6126 public void binderDied() {
6127 synchronized (mAudioPolicies) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006128 Log.i(TAG, "audio policy " + mPolicyCallback + " died");
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006129 release();
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006130 mAudioPolicies.remove(mPolicyCallback.asBinder());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006131 }
6132 }
6133
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006134 String getRegistrationId() {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006135 return getRegistration();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006136 }
6137
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006138 void release() {
6139 if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6140 mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
6141 }
6142 if (mHasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006143 mMediaFocusControl.removeFocusFollower(mPolicyCallback);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006144 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006145 AudioSystem.registerPolicyMixes(mMixes, false);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006146 }
6147
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006148 void connectMixes() {
6149 AudioSystem.registerPolicyMixes(mMixes, true);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006150 }
6151 };
6152
6153 private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
6154 new HashMap<IBinder, AudioPolicyProxy>();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006155 private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
John Spurlockcdb57ae2015-02-11 19:04:11 -05006156
6157 private class ControllerService extends ContentObserver {
6158 private int mUid;
6159 private ComponentName mComponent;
6160
6161 public ControllerService() {
6162 super(null);
6163 }
6164
6165 @Override
6166 public String toString() {
6167 return String.format("{mUid=%d,mComponent=%s}", mUid, mComponent);
6168 }
6169
6170 public void init() {
6171 onChange(true);
6172 mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
6173 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT), false, this);
6174 }
6175
6176 @Override
6177 public void onChange(boolean selfChange) {
6178 mUid = 0;
6179 mComponent = null;
6180 final String setting = Settings.Secure.getString(mContentResolver,
6181 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
6182 if (setting == null) return;
6183 try {
6184 mComponent = ComponentName.unflattenFromString(setting);
6185 if (mComponent == null) return;
6186 mUid = mContext.getPackageManager()
6187 .getApplicationInfo(mComponent.getPackageName(), 0).uid;
6188 } catch (Exception e) {
6189 Log.w(TAG, "Error loading controller service", e);
6190 }
6191 if (DEBUG_VOL) Log.d(TAG, "Reloaded controller service: " + this);
6192 }
6193 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006194}