blob: b8cbecb48928718f3d812378ac26fcb0b9ce0fc1 [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;
John Spurlock61560172015-02-06 19:46:04 -050065import android.media.IRingtonePlayer;
66import android.media.IVolumeController;
67import android.media.MediaPlayer;
68import android.media.SoundPool;
John Spurlocka48d7792015-03-03 17:35:57 -050069import android.media.VolumePolicy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070import android.media.MediaPlayer.OnCompletionListener;
71import android.media.MediaPlayer.OnErrorListener;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -070072import android.media.audiopolicy.AudioMix;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -080073import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070074import android.media.audiopolicy.AudioPolicyConfig;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -080075import android.media.audiopolicy.IAudioPolicyCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076import android.os.Binder;
Eric Laurentc18c9132013-04-12 17:24:56 -070077import android.os.Build;
Makoto Onukid45a4a22015-11-02 17:17:38 -080078import android.os.Bundle;
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;
Makoto Onukid45a4a22015-11-02 17:17:38 -080091import android.os.UserManagerInternal;
92import android.os.UserManagerInternal.UserRestrictionsListener;
Eric Laurentbffc3d12012-05-07 17:43:49 -070093import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094import android.provider.Settings;
95import android.provider.Settings.System;
Tyler Gunnef9f6f92014-09-12 22:16:17 -070096import android.telecom.TelecomManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070097import android.text.TextUtils;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070098import android.util.AndroidRuntimeException;
John Spurlock8c3dc852015-04-23 21:32:37 -040099import android.util.ArrayMap;
100import android.util.ArraySet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101import android.util.Log;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400102import android.util.MathUtils;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -0700103import android.util.Slog;
John Spurlock2bb02ec2015-03-02 13:13:06 -0500104import android.util.SparseIntArray;
Jean-Michel Trivid327f212010-03-16 21:44:33 -0700105import android.view.KeyEvent;
RoboErik519c7742014-11-18 10:59:09 -0800106import android.view.OrientationEventListener;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700107import android.view.Surface;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700108import android.view.WindowManager;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700109import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110
Eric Laurente78fced2013-03-15 16:03:47 -0700111import com.android.internal.util.XmlUtils;
John Spurlock90874332015-03-10 16:00:54 -0400112import com.android.server.EventLogTags;
RoboErik0dac35a2014-08-12 15:48:49 -0700113import com.android.server.LocalServices;
Makoto Onukie1aef852015-10-15 17:28:35 -0700114import com.android.server.SystemService;
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700115import com.android.server.pm.UserManagerService;
Eric Laurente78fced2013-03-15 16:03:47 -0700116
117import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800119import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120import java.io.IOException;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800121import java.io.PrintWriter;
Eric Laurente78fced2013-03-15 16:03:47 -0700122import java.lang.reflect.Field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123import java.util.ArrayList;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700124import java.util.HashMap;
125import java.util.Iterator;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -0700126import java.util.List;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700127import java.util.NoSuchElementException;
RoboErikd09bd0c2014-06-24 17:45:19 -0700128import java.util.Objects;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129
130/**
131 * The implementation of the volume manager service.
132 * <p>
133 * This implementation focuses on delivering a responsive UI. Most methods are
134 * asynchronous to external calls. For example, the task of setting a volume
135 * will update our internal state, but in a separate thread will set the system
136 * volume and later persist to the database. Similarly, setting the ringer mode
137 * will update the state and broadcast a change and in a separate thread later
138 * persist the ringer mode.
139 *
140 * @hide
141 */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700142public class AudioService extends IAudioService.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143
144 private static final String TAG = "AudioService";
145
Jean-Michel Trivi339567d2014-07-29 09:53:34 -0700146 /** Debug audio mode */
147 protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -0700148
149 /** Debug audio policy feature */
150 protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);
151
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700152 /** Debug volumes */
John Spurlockae641c92014-06-30 18:11:40 -0400153 protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700154
Paul McLean394a8e12015-03-03 10:29:19 -0700155 /** debug calls to devices APIs */
156 protected static final boolean DEBUG_DEVICES = Log.isLoggable(TAG + ".DEVICES", Log.DEBUG);
157
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 /** How long to delay before persisting a change in volume/ringer mode. */
RoboErik45edba12012-03-27 17:54:36 -0700159 private static final int PERSIST_DELAY = 500;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160
RoboErik5452e252015-02-06 15:33:53 -0800161 /** How long to delay after a volume down event before unmuting a stream */
162 private static final int UNMUTE_STREAM_DELAY = 350;
163
John Spurlock3346a802014-05-20 16:25:37 -0400164 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400165 * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
166 */
167 private static final int FLAG_ADJUST_VOLUME = 1;
168
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700169 private final Context mContext;
170 private final ContentResolver mContentResolver;
171 private final AppOpsManager mAppOps;
Eric Laurent212532b2014-07-21 15:43:18 -0700172
Eric Laurent212532b2014-07-21 15:43:18 -0700173 // the platform type affects volume and silent mode behavior
174 private final int mPlatformType;
175
176 private boolean isPlatformVoice() {
John Spurlock61560172015-02-06 19:46:04 -0500177 return mPlatformType == AudioSystem.PLATFORM_VOICE;
Eric Laurent212532b2014-07-21 15:43:18 -0700178 }
179
180 private boolean isPlatformTelevision() {
John Spurlock61560172015-02-06 19:46:04 -0500181 return mPlatformType == AudioSystem.PLATFORM_TELEVISION;
Eric Laurent212532b2014-07-21 15:43:18 -0700182 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800183
John Spurlock3346a802014-05-20 16:25:37 -0400184 /** The controller for the volume UI. */
185 private final VolumeController mVolumeController = new VolumeController();
John Spurlockcdb57ae2015-02-11 19:04:11 -0500186 private final ControllerService mControllerService = new ControllerService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187
188 // sendMsg() flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 /** If the msg is already queued, replace it with this one. */
190 private static final int SENDMSG_REPLACE = 0;
191 /** If the msg is already queued, ignore this one and leave the old. */
192 private static final int SENDMSG_NOOP = 1;
193 /** If the msg is already queued, queue this one and leave the old. */
194 private static final int SENDMSG_QUEUE = 2;
195
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700196 // AudioHandler messages
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800197 private static final int MSG_SET_DEVICE_VOLUME = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 private static final int MSG_PERSIST_VOLUME = 1;
199 private static final int MSG_PERSIST_RINGER_MODE = 3;
Andy Hunged0ea402015-10-30 14:11:46 -0700200 private static final int MSG_AUDIO_SERVER_DIED = 4;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700201 private static final int MSG_PLAY_SOUND_EFFECT = 5;
202 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
203 private static final int MSG_LOAD_SOUND_EFFECTS = 7;
204 private static final int MSG_SET_FORCE_USE = 8;
205 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
206 private static final int MSG_SET_ALL_VOLUMES = 10;
207 private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
208 private static final int MSG_REPORT_NEW_ROUTES = 12;
209 private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
210 private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
211 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
212 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
213 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
214 private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
215 private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
216 private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700217 private static final int MSG_SYSTEM_READY = 21;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400218 private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
Julia Reynoldsb53453f2014-08-22 11:42:43 -0400219 private static final int MSG_PERSIST_MICROPHONE_MUTE = 23;
RoboErik5452e252015-02-06 15:33:53 -0800220 private static final int MSG_UNMUTE_STREAM = 24;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -0700221 private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 25;
Eric Laurent0867bed2015-05-20 14:49:08 -0700222 private static final int MSG_INDICATE_SYSTEM_READY = 26;
Andy Hungf04b84d2015-12-18 17:33:27 -0800223 private static final int MSG_PERSIST_MASTER_MONO = 27;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700224 // start of messages handled under wakelock
225 // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
Jean-Michel Trivie12c39b2012-06-06 10:51:58 -0700226 // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700227 private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
Mike Lockwood0a40ec22014-05-21 10:08:50 -0700228 private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
229 private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700230 // end of messages handled under wakelock
Eric Laurentafbb0472011-12-15 09:04:23 -0800231
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -0700232 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
Eric Laurentdc03c612011-04-01 10:59:41 -0700233 // Timeout for connection to bluetooth headset service
234 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
235
Eric Laurent0867bed2015-05-20 14:49:08 -0700236 // retry delay in case of failure to indicate system ready to AudioFlinger
237 private static final int INDICATE_SYSTEM_READY_RETRY_DELAY_MS = 1000;
238
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239 /** @see AudioSystemThread */
240 private AudioSystemThread mAudioSystemThread;
241 /** @see AudioHandler */
242 private AudioHandler mAudioHandler;
243 /** @see VolumeStreamState */
244 private VolumeStreamState[] mStreamStates;
Jason Parekhb1096152009-03-24 17:48:25 -0700245 private SettingsObserver mSettingsObserver;
Eric Laurenta553c252009-07-17 12:17:14 -0700246
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700247 private int mMode = AudioSystem.MODE_NORMAL;
Glenn Kastenba195eb2011-12-13 09:30:40 -0800248 // protects mRingerMode
249 private final Object mSettingsLock = new Object();
Eric Laurent45c90ce2012-04-24 18:44:22 -0700250
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 private SoundPool mSoundPool;
Glenn Kasten30c918c2011-11-10 17:56:41 -0800252 private final Object mSoundEffectsLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 private static final int NUM_SOUNDPOOL_CHANNELS = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254
255 /* Sound effect file names */
256 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
Eric Laurente78fced2013-03-15 16:03:47 -0700257 private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258
259 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
260 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
261 * uses soundpool (second column) */
Eric Laurente78fced2013-03-15 16:03:47 -0700262 private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263
John Spurlockb6e19e32015-03-10 21:33:44 -0400264 /** Maximum volume index values for audio streams */
Eric Laurent91377de2014-10-10 15:24:04 -0700265 private static int[] MAX_STREAM_VOLUME = new int[] {
Eric Laurent6ee99522009-08-25 06:30:59 -0700266 5, // STREAM_VOICE_CALL
267 7, // STREAM_SYSTEM
268 7, // STREAM_RING
269 15, // STREAM_MUSIC
270 7, // STREAM_ALARM
271 7, // STREAM_NOTIFICATION
272 15, // STREAM_BLUETOOTH_SCO
273 7, // STREAM_SYSTEM_ENFORCED
274 15, // STREAM_DTMF
275 15 // STREAM_TTS
Jared Suttles59820132009-08-13 21:50:52 -0500276 };
Eric Laurent91377de2014-10-10 15:24:04 -0700277
John Spurlockb6e19e32015-03-10 21:33:44 -0400278 /** Minimum volume index values for audio streams */
279 private static int[] MIN_STREAM_VOLUME = new int[] {
280 1, // STREAM_VOICE_CALL
281 0, // STREAM_SYSTEM
282 0, // STREAM_RING
283 0, // STREAM_MUSIC
284 0, // STREAM_ALARM
285 0, // STREAM_NOTIFICATION
Eric Laurente4381ec2015-10-29 17:52:48 -0700286 0, // STREAM_BLUETOOTH_SCO
John Spurlockb6e19e32015-03-10 21:33:44 -0400287 0, // STREAM_SYSTEM_ENFORCED
288 0, // STREAM_DTMF
289 0 // STREAM_TTS
290 };
291
Eric Laurent6d517662012-04-23 18:42:39 -0700292 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
Eric Laurenta553c252009-07-17 12:17:14 -0700293 * of another stream: This avoids multiplying the volume settings for hidden
294 * stream types that follow other stream behavior for volume settings
Eric Laurent6d517662012-04-23 18:42:39 -0700295 * NOTE: do not create loops in aliases!
296 * Some streams alias to different streams according to device category (phone or tablet) or
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700297 * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
Eric Laurent212532b2014-07-21 15:43:18 -0700298 * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
299 * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
300 * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
301 private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700302 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
303 AudioSystem.STREAM_RING, // STREAM_SYSTEM
304 AudioSystem.STREAM_RING, // STREAM_RING
305 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
306 AudioSystem.STREAM_ALARM, // STREAM_ALARM
307 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
308 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
309 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
310 AudioSystem.STREAM_RING, // STREAM_DTMF
311 AudioSystem.STREAM_MUSIC // STREAM_TTS
Eric Laurenta553c252009-07-17 12:17:14 -0700312 };
Eric Laurent212532b2014-07-21 15:43:18 -0700313 private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
314 AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL
315 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
316 AudioSystem.STREAM_MUSIC, // STREAM_RING
317 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
318 AudioSystem.STREAM_MUSIC, // STREAM_ALARM
319 AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
320 AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO
321 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
322 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
323 AudioSystem.STREAM_MUSIC // STREAM_TTS
324 };
325 private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700326 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
John Spurlock4f0f1202014-08-05 13:28:33 -0400327 AudioSystem.STREAM_RING, // STREAM_SYSTEM
Eric Laurent6d517662012-04-23 18:42:39 -0700328 AudioSystem.STREAM_RING, // STREAM_RING
329 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
330 AudioSystem.STREAM_ALARM, // STREAM_ALARM
331 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
332 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
John Spurlock4f0f1202014-08-05 13:28:33 -0400333 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
334 AudioSystem.STREAM_RING, // STREAM_DTMF
Eric Laurent6d517662012-04-23 18:42:39 -0700335 AudioSystem.STREAM_MUSIC // STREAM_TTS
336 };
337 private int[] mStreamVolumeAlias;
Eric Laurenta553c252009-07-17 12:17:14 -0700338
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700339 /**
340 * Map AudioSystem.STREAM_* constants to app ops. This should be used
341 * after mapping through mStreamVolumeAlias.
342 */
John Spurlock59dc9c12015-03-02 11:20:15 -0500343 private static final int[] STREAM_VOLUME_OPS = new int[] {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700344 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL
345 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM
346 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING
347 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC
348 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM
349 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION
350 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO
351 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED
352 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF
353 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS
354 };
355
Eric Laurent83a017b2013-03-19 18:15:31 -0700356 private final boolean mUseFixedVolume;
357
Glenn Kasten30c918c2011-11-10 17:56:41 -0800358 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 public void onError(int error) {
360 switch (error) {
361 case AudioSystem.AUDIO_STATUS_SERVER_DIED:
Andy Hunged0ea402015-10-30 14:11:46 -0700362 sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED,
Eric Laurentdfb881f2013-07-18 14:41:39 -0700363 SENDMSG_NOOP, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364 break;
365 default:
366 break;
367 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700368 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 };
370
371 /**
372 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
373 * {@link AudioManager#RINGER_MODE_SILENT}, or
374 * {@link AudioManager#RINGER_MODE_VIBRATE}.
375 */
Glenn Kastenba195eb2011-12-13 09:30:40 -0800376 // protected by mSettingsLock
John Spurlock661f2cf2014-11-17 10:29:10 -0500377 private int mRingerMode; // internal ringer mode, affects muting of underlying streams
378 private int mRingerModeExternal = -1; // reported ringer mode to outside clients (AudioManager)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379
Eric Laurent9bcf4012009-06-12 06:09:28 -0700380 /** @see System#MODE_RINGER_STREAMS_AFFECTED */
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700381 private int mRingerModeAffectedStreams = 0;
Eric Laurent9bcf4012009-06-12 06:09:28 -0700382
Eric Laurent5b4e6542010-03-19 20:02:21 -0700383 // Streams currently muted by ringer mode
384 private int mRingerModeMutedStreams;
385
John Spurlock3ce37252015-02-17 13:20:45 -0500386 /** Streams that can be muted. Do not resolve to aliases when checking.
387 * @see System#MUTE_STREAMS_AFFECTED */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388 private int mMuteAffectedStreams;
389
390 /**
Eric Laurentbffc3d12012-05-07 17:43:49 -0700391 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
392 * mVibrateSetting is just maintained during deprecation period but vibration policy is
393 * now only controlled by mHasVibrator and mRingerMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 */
395 private int mVibrateSetting;
396
Eric Laurentbffc3d12012-05-07 17:43:49 -0700397 // Is there a vibrator
398 private final boolean mHasVibrator;
399
Eric Laurenta553c252009-07-17 12:17:14 -0700400 // Broadcast receiver for device connections intent broadcasts
401 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
402
Makoto Onukid45a4a22015-11-02 17:17:38 -0800403 /** Interface for UserManagerService. */
404 private final UserManagerInternal mUserManagerInternal;
405
406 private final UserRestrictionsListener mUserRestrictionsListener =
407 new AudioServiceUserRestrictionsListener();
408
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700409 // Devices currently connected
Paul McLean394a8e12015-03-03 10:29:19 -0700410 // Use makeDeviceListKey() to make a unique key for this list.
411 private class DeviceListSpec {
412 int mDeviceType;
413 String mDeviceName;
414 String mDeviceAddress;
415
416 public DeviceListSpec(int deviceType, String deviceName, String deviceAddress) {
417 mDeviceType = deviceType;
418 mDeviceName = deviceName;
419 mDeviceAddress = deviceAddress;
420 }
421
422 public String toString() {
423 return "[type:0x" + Integer.toHexString(mDeviceType) + " name:" + mDeviceName
424 + " address:" + mDeviceAddress + "]";
425 }
426 }
427
428 // Generate a unique key for the mConnectedDevices List by composing the device "type"
429 // and the "address" associated with a specific instance of that device type
430 private String makeDeviceListKey(int device, String deviceAddress) {
431 return "0x" + Integer.toHexString(device) + ":" + deviceAddress;
432 }
433
John Spurlock8c3dc852015-04-23 21:32:37 -0400434 private final ArrayMap<String, DeviceListSpec> mConnectedDevices = new ArrayMap<>();
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700435
436 // Forced device usage for communications
437 private int mForcedUseForComm;
438
Eric Laurent9272b4b2010-01-23 17:12:59 -0800439 // List of binder death handlers for setMode() client processes.
440 // The last process to have called setMode() is at the top of the list.
Glenn Kasten30c918c2011-11-10 17:56:41 -0800441 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
Eric Laurenteb14a782009-12-17 03:12:59 -0800442
Eric Laurent3def1ee2010-03-17 23:26:26 -0700443 // List of clients having issued a SCO start request
Glenn Kasten30c918c2011-11-10 17:56:41 -0800444 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
Eric Laurent3def1ee2010-03-17 23:26:26 -0700445
446 // BluetoothHeadset API to control SCO connection
447 private BluetoothHeadset mBluetoothHeadset;
448
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700449 // Bluetooth headset device
450 private BluetoothDevice mBluetoothHeadsetDevice;
Eric Laurent3def1ee2010-03-17 23:26:26 -0700451
Eric Laurent62ef7672010-11-24 10:58:32 -0800452 // Indicate if SCO audio connection is currently active and if the initiator is
453 // audio service (internal) or bluetooth headset (external)
454 private int mScoAudioState;
455 // SCO audio state is not active
456 private static final int SCO_STATE_INACTIVE = 0;
Eric Laurentdc03c612011-04-01 10:59:41 -0700457 // SCO audio activation request waiting for headset service to connect
458 private static final int SCO_STATE_ACTIVATE_REQ = 1;
Eric Laurent25fc29b2013-04-05 12:13:54 -0700459 // SCO audio state is active or starting due to a request from AudioManager API
Eric Laurentdc03c612011-04-01 10:59:41 -0700460 private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
461 // SCO audio deactivation request waiting for headset service to connect
462 private static final int SCO_STATE_DEACTIVATE_REQ = 5;
463
Eric Laurent62ef7672010-11-24 10:58:32 -0800464 // SCO audio state is active due to an action in BT handsfree (either voice recognition or
465 // in call audio)
466 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
Eric Laurentdc03c612011-04-01 10:59:41 -0700467 // Deactivation request for all SCO connections (initiated by audio mode change)
468 // waiting for headset service to connect
469 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
470
Eric Laurentc18c9132013-04-12 17:24:56 -0700471 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
472 // originated from an app targeting an API version before JB MR2 and raw audio after that.
473 private int mScoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -0700474 // SCO audio mode is undefined
475 private static final int SCO_MODE_UNDEFINED = -1;
Eric Laurentc18c9132013-04-12 17:24:56 -0700476 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
477 private static final int SCO_MODE_VIRTUAL_CALL = 0;
478 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
479 private static final int SCO_MODE_RAW = 1;
Liejun Taof4e51d82014-07-16 11:18:29 -0700480 // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
481 private static final int SCO_MODE_VR = 2;
482
483 private static final int SCO_MODE_MAX = 2;
Eric Laurentc18c9132013-04-12 17:24:56 -0700484
Eric Laurentdc03c612011-04-01 10:59:41 -0700485 // Current connection state indicated by bluetooth headset
486 private int mScoConnectionState;
Eric Laurent62ef7672010-11-24 10:58:32 -0800487
Eric Laurenta60e2122010-12-28 16:49:07 -0800488 // true if boot sequence has been completed
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700489 private boolean mSystemReady;
Yasuhiro Matsuda4ced7192015-07-10 22:08:44 +0900490 // true if Intent.ACTION_USER_SWITCHED has ever been received
491 private boolean mUserSwitchedReceived;
Eric Laurenta60e2122010-12-28 16:49:07 -0800492 // listener for SoundPool sample load completion indication
493 private SoundPoolCallback mSoundPoolCallBack;
494 // thread for SoundPool listener
495 private SoundPoolListenerThread mSoundPoolListenerThread;
496 // message looper for SoundPool listener
497 private Looper mSoundPoolLooper = null;
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700498 // volume applied to sound played with playSoundEffect()
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700499 private static int sSoundEffectVolumeDb;
Eric Laurent25101b02011-02-02 09:33:30 -0800500 // previous volume adjustment direction received by checkForRingerModeChange()
501 private int mPrevVolDirection = AudioManager.ADJUST_SAME;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700502 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
503 // is controlled by Vol keys.
504 private int mVolumeControlStream = -1;
505 private final Object mForceControlStreamLock = new Object();
506 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
507 // server process so in theory it is not necessary to monitor the client death.
508 // However it is good to be ready for future evolutions.
509 private ForceControlStreamClient mForceControlStreamClient = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700510 // Used to play ringtones outside system_server
511 private volatile IRingtonePlayer mRingtonePlayer;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800512
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700513 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
514
Eric Laurent78472112012-05-21 08:57:21 -0700515 // Request to override default use of A2DP for media.
516 private boolean mBluetoothA2dpEnabled;
517 private final Object mBluetoothA2dpEnabledLock = new Object();
518
Dianne Hackborn632ca412012-06-14 19:34:10 -0700519 // Monitoring of audio routes. Protected by mCurAudioRoutes.
520 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
521 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
522 = new RemoteCallbackList<IAudioRoutesObserver>();
523
Eric Laurent4bbcc652012-09-24 14:26:30 -0700524 // Devices for which the volume is fixed and VolumePanel slider should be disabled
Eric Laurent212532b2014-07-21 15:43:18 -0700525 int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700526 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Eric Laurent212532b2014-07-21 15:43:18 -0700527 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
528 AudioSystem.DEVICE_OUT_HDMI_ARC |
529 AudioSystem.DEVICE_OUT_SPDIF |
530 AudioSystem.DEVICE_OUT_AUX_LINE;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700531 int mFullVolumeDevices = 0;
Eric Laurent4bbcc652012-09-24 14:26:30 -0700532
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700533 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700534 private final boolean mMonitorOrientation;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700535 private final boolean mMonitorRotation;
Eric Laurentd640bd32012-09-28 18:01:48 -0700536
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700537 private boolean mDockAudioMediaEnabled = true;
538
Eric Laurent08ed1b92012-11-05 14:54:12 -0800539 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
540
Eric Laurentfde16d52012-12-03 14:42:39 -0800541 // Used when safe volume warning message display is requested by setStreamVolume(). In this
542 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
543 // and used later when/if disableSafeMediaVolume() is called.
544 private StreamVolumeCommand mPendingVolumeCommand;
545
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700546 private PowerManager.WakeLock mAudioEventWakeLock;
547
548 private final MediaFocusControl mMediaFocusControl;
549
John Du5a0cf7a2013-07-19 11:30:34 -0700550 // Reference to BluetoothA2dp to query for AbsoluteVolume.
551 private BluetoothA2dp mA2dp;
seunghwan.hong4fe77952014-10-29 17:43:20 +0900552 // lock always taken synchronized on mConnectedDevices
John Du5a0cf7a2013-07-19 11:30:34 -0700553 private final Object mA2dpAvrcpLock = new Object();
554 // If absolute volume is supported in AVRCP device
555 private boolean mAvrcpAbsVolSupported = false;
556
Eric Laurentadbe8bf2014-11-03 18:26:32 -0800557 private static Long mLastDeviceConnectMsgTime = new Long(0);
558
John Spurlock661f2cf2014-11-17 10:29:10 -0500559 private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
John Spurlocka48d7792015-03-03 17:35:57 -0500560 private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
John Spurlock07e72432015-03-13 11:46:52 -0400561 private long mLoweredFromNormalToVibrateTime;
John Spurlock661f2cf2014-11-17 10:29:10 -0500562
Paul McLean10804eb2015-01-28 11:16:35 -0800563 // Intent "extra" data keys.
564 public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName";
565 public static final String CONNECT_INTENT_KEY_STATE = "state";
566 public static final String CONNECT_INTENT_KEY_ADDRESS = "address";
567 public static final String CONNECT_INTENT_KEY_HAS_PLAYBACK = "hasPlayback";
568 public static final String CONNECT_INTENT_KEY_HAS_CAPTURE = "hasCapture";
569 public static final String CONNECT_INTENT_KEY_HAS_MIDI = "hasMIDI";
570 public static final String CONNECT_INTENT_KEY_DEVICE_CLASS = "class";
571
572 // Defines the format for the connection "address" for ALSA devices
573 public static String makeAlsaAddressString(int card, int device) {
574 return "card=" + card + ";device=" + device + ";";
575 }
576
Makoto Onukie1aef852015-10-15 17:28:35 -0700577 public static final class Lifecycle extends SystemService {
578 private AudioService mService;
579
580 public Lifecycle(Context context) {
581 super(context);
582 mService = new AudioService(context);
583 }
584
585 @Override
586 public void onStart() {
587 publishBinderService(Context.AUDIO_SERVICE, mService);
588 }
589
590 @Override
591 public void onBootPhase(int phase) {
592 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
593 mService.systemReady();
594 }
595 }
596 }
597
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 ///////////////////////////////////////////////////////////////////////////
599 // Construction
600 ///////////////////////////////////////////////////////////////////////////
601
602 /** @hide */
603 public AudioService(Context context) {
604 mContext = context;
605 mContentResolver = context.getContentResolver();
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700606 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700607
John Spurlock61560172015-02-06 19:46:04 -0500608 mPlatformType = AudioSystem.getPlatformType(context);
Jared Suttles59820132009-08-13 21:50:52 -0500609
Makoto Onukid45a4a22015-11-02 17:17:38 -0800610 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
611
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700612 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700613 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700614
Eric Laurentbffc3d12012-05-07 17:43:49 -0700615 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
616 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
617
John Spurlockb6e19e32015-03-10 21:33:44 -0400618 // Initialize volume
Eric Laurent91377de2014-10-10 15:24:04 -0700619 int maxVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps",
620 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
621 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
622 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500623 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700624 }
625 maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
626 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
627 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
628 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500629 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700630 }
Jared Suttles59820132009-08-13 21:50:52 -0500631
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700632 sSoundEffectVolumeDb = context.getResources().getInteger(
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700633 com.android.internal.R.integer.config_soundEffectVolumeDb);
Eric Laurent25101b02011-02-02 09:33:30 -0800634
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700635 mForcedUseForComm = AudioSystem.FORCE_NONE;
Eric Laurentdd45d012012-10-08 09:04:34 -0700636
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 createAudioSystemThread();
Eric Laurentdd45d012012-10-08 09:04:34 -0700638
Eric Laurentdfb881f2013-07-18 14:41:39 -0700639 AudioSystem.setErrorCallback(mAudioSystemCallback);
640
John Spurlock5e783732015-02-19 10:28:59 -0500641 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -0700642 mCameraSoundForced = new Boolean(cameraSoundForced);
643 sendMsg(mAudioHandler,
644 MSG_SET_FORCE_USE,
645 SENDMSG_QUEUE,
646 AudioSystem.FOR_SYSTEM,
647 cameraSoundForced ?
648 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
649 null,
650 0);
651
Eric Laurent05274f32012-11-29 12:48:18 -0800652 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
653 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
654 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
655 // The default safe volume index read here will be replaced by the actual value when
656 // the mcc is read by onConfigureSafeVolume()
657 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
658 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
659
Eric Laurent83a017b2013-03-19 18:15:31 -0700660 mUseFixedVolume = mContext.getResources().getBoolean(
661 com.android.internal.R.bool.config_useFixedVolume);
662
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700663 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
664 // array initialized by updateStreamVolumeAlias()
John Spurlock90874332015-03-10 16:00:54 -0400665 updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 readPersistedSettings();
Eric Laurentc1d41662011-07-19 11:21:13 -0700667 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700668 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700669
Jean-Michel Trivid4de20d2015-11-04 14:45:54 -0800670 mMediaFocusControl = new MediaFocusControl(mContext);
John Spurlockb6e19e32015-03-10 21:33:44 -0400671
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700672 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700673
674 // Call setRingerModeInt() to apply correct mute
675 // state on streams affected by ringer mode.
676 mRingerModeMutedStreams = 0;
John Spurlock661f2cf2014-11-17 10:29:10 -0500677 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3891c4c2010-04-20 09:40:57 -0700678
Eric Laurenta553c252009-07-17 12:17:14 -0700679 // Register for device connection intent broadcasts.
680 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700681 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700682 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
683 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700684 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
685 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700686 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700687 intentFilter.addAction(Intent.ACTION_USER_BACKGROUND);
688 intentFilter.addAction(Intent.ACTION_USER_FOREGROUND);
Paul McLeanc837a452014-04-09 09:04:43 -0700689 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700690
Eric Laurentd640bd32012-09-28 18:01:48 -0700691 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700692 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700693 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
694 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700695 Log.v(TAG, "monitoring device orientation");
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700696 // initialize orientation in AudioSystem
697 setOrientationForAudioSystem();
698 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700699 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
700 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -0700701 RotationHelper.init(mContext, mAudioHandler);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700702 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700703
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700704 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null);
Jared Suttles59820132009-08-13 21:50:52 -0500705
RoboErik0dac35a2014-08-12 15:48:49 -0700706 LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
Makoto Onukid45a4a22015-11-02 17:17:38 -0800707
708 mUserManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800709 }
710
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700711 public void systemReady() {
712 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
713 0, 0, null, 0);
714 }
715
716 public void onSystemReady() {
717 mSystemReady = true;
718 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
719 0, 0, null, 0);
720
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700721 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
722 resetBluetoothSco();
723 getBluetoothHeadset();
724 //FIXME: this is to maintain compatibility with deprecated intent
725 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
726 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
727 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
728 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
729 sendStickyBroadcastToAll(newIntent);
730
731 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
732 if (adapter != null) {
733 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
734 BluetoothProfile.A2DP);
735 }
736
Eric Laurent212532b2014-07-21 15:43:18 -0700737 mHdmiManager =
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900738 (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700739 if (mHdmiManager != null) {
740 synchronized (mHdmiManager) {
741 mHdmiTvClient = mHdmiManager.getTvClient();
Jungshik Jangc9ff9682014-09-15 17:41:06 +0900742 if (mHdmiTvClient != null) {
743 mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
744 }
Eric Laurent212532b2014-07-21 15:43:18 -0700745 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
746 mHdmiCecSink = false;
747 }
748 }
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900749
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700750 sendMsg(mAudioHandler,
751 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
752 SENDMSG_REPLACE,
753 0,
754 0,
John Spurlock90874332015-03-10 16:00:54 -0400755 TAG,
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700756 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700757
758 StreamOverride.init(mContext);
John Spurlockcdb57ae2015-02-11 19:04:11 -0500759 mControllerService.init();
Eric Laurent0867bed2015-05-20 14:49:08 -0700760 onIndicateSystemReady();
761 }
762
763 void onIndicateSystemReady() {
764 if (AudioSystem.systemReady() == AudioSystem.SUCCESS) {
765 return;
766 }
767 sendMsg(mAudioHandler,
768 MSG_INDICATE_SYSTEM_READY,
769 SENDMSG_REPLACE,
770 0,
771 0,
772 null,
773 INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
774 }
775
Andy Hunged0ea402015-10-30 14:11:46 -0700776 public void onAudioServerDied() {
Eric Laurent0867bed2015-05-20 14:49:08 -0700777 if (!mSystemReady ||
778 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Andy Hunged0ea402015-10-30 14:11:46 -0700779 Log.e(TAG, "Audioserver died.");
780 sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent0867bed2015-05-20 14:49:08 -0700781 null, 500);
782 return;
783 }
Andy Hunged0ea402015-10-30 14:11:46 -0700784 Log.e(TAG, "Audioserver started.");
Eric Laurent0867bed2015-05-20 14:49:08 -0700785
786 // indicate to audio HAL that we start the reconfiguration phase after a media
787 // server crash
788 // Note that we only execute this when the media server
789 // process restarts after a crash, not the first time it is started.
790 AudioSystem.setParameters("restarting=true");
791
792 readAndSetLowRamDevice();
793
794 // Restore device connection states
795 synchronized (mConnectedDevices) {
796 for (int i = 0; i < mConnectedDevices.size(); i++) {
797 DeviceListSpec spec = mConnectedDevices.valueAt(i);
798 AudioSystem.setDeviceConnectionState(
799 spec.mDeviceType,
800 AudioSystem.DEVICE_STATE_AVAILABLE,
801 spec.mDeviceAddress,
802 spec.mDeviceName);
803 }
804 }
805 // Restore call state
806 AudioSystem.setPhoneState(mMode);
807
808 // Restore forced usage for communcations and record
809 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
810 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
811 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
812 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
813
814 // Restore stream volumes
815 int numStreamTypes = AudioSystem.getNumStreamTypes();
816 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
817 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurente4381ec2015-10-29 17:52:48 -0700818 AudioSystem.initStreamVolume(
819 streamType, streamState.mIndexMin / 10, streamState.mIndexMax / 10);
Eric Laurent0867bed2015-05-20 14:49:08 -0700820
821 streamState.applyAllVolumes();
822 }
823
Andy Hungf04b84d2015-12-18 17:33:27 -0800824 // Restore mono mode
825 final boolean masterMono = System.getIntForUser(
826 mContentResolver, System.MASTER_MONO,
827 0 /* default */, UserHandle.USER_CURRENT) == 1;
828 AudioSystem.setMasterMono(masterMono);
829
Eric Laurent0867bed2015-05-20 14:49:08 -0700830 // Restore ringer mode
831 setRingerModeInt(getRingerModeInternal(), false);
832
833 // Reset device orientation (if monitored for this device)
834 if (mMonitorOrientation) {
835 setOrientationForAudioSystem();
836 }
837 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -0700838 RotationHelper.updateOrientation();
Eric Laurent0867bed2015-05-20 14:49:08 -0700839 }
840
841 synchronized (mBluetoothA2dpEnabledLock) {
842 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
843 mBluetoothA2dpEnabled ?
844 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
845 }
846
847 synchronized (mSettingsLock) {
848 AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
849 mDockAudioMediaEnabled ?
850 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
851 }
852 if (mHdmiManager != null) {
853 synchronized (mHdmiManager) {
854 if (mHdmiTvClient != null) {
855 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
856 }
857 }
858 }
859
860 synchronized (mAudioPolicies) {
861 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
862 policy.connectMixes();
863 }
864 }
865
866 onIndicateSystemReady();
867 // indicate the end of reconfiguration phase to audio HAL
868 AudioSystem.setParameters("restarting=false");
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700869 }
870
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871 private void createAudioSystemThread() {
872 mAudioSystemThread = new AudioSystemThread();
873 mAudioSystemThread.start();
874 waitForAudioHandlerCreation();
875 }
876
877 /** Waits for the volume handler to be created by the other thread. */
878 private void waitForAudioHandlerCreation() {
879 synchronized(this) {
880 while (mAudioHandler == null) {
881 try {
882 // Wait for mAudioHandler to be set by the other thread
883 wait();
884 } catch (InterruptedException e) {
885 Log.e(TAG, "Interrupted while waiting on volume handler.");
886 }
887 }
888 }
889 }
890
Eric Laurent24482012012-05-10 09:41:17 -0700891 private void checkAllAliasStreamVolumes() {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700892 synchronized (VolumeStreamState.class) {
893 int numStreamTypes = AudioSystem.getNumStreamTypes();
894 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
895 if (streamType != mStreamVolumeAlias[streamType]) {
896 mStreamStates[streamType].
John Spurlock90874332015-03-10 16:00:54 -0400897 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]],
898 TAG);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700899 }
900 // apply stream volume
RoboErik4197cb62015-01-21 15:45:32 -0800901 if (!mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700902 mStreamStates[streamType].applyAllVolumes();
903 }
Eric Laurent24482012012-05-10 09:41:17 -0700904 }
905 }
906 }
907
Eric Laurent212532b2014-07-21 15:43:18 -0700908 private void checkAllFixedVolumeDevices()
909 {
910 int numStreamTypes = AudioSystem.getNumStreamTypes();
911 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
912 mStreamStates[streamType].checkFixedVolumeDevices();
913 }
914 }
915
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700916 private void checkAllFixedVolumeDevices(int streamType) {
917 mStreamStates[streamType].checkFixedVolumeDevices();
918 }
919
John Spurlockb6e19e32015-03-10 21:33:44 -0400920 private void checkMuteAffectedStreams() {
921 // any stream with a min level > 0 is not muteable by definition
922 for (int i = 0; i < mStreamStates.length; i++) {
923 final VolumeStreamState vss = mStreamStates[i];
924 if (vss.mIndexMin > 0) {
925 mMuteAffectedStreams &= ~(1 << vss.mStreamType);
926 }
927 }
928 }
929
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800930 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800931 int numStreamTypes = AudioSystem.getNumStreamTypes();
932 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
933
934 for (int i = 0; i < numStreamTypes; i++) {
Eric Laurent6d517662012-04-23 18:42:39 -0700935 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -0700936 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937
Eric Laurent212532b2014-07-21 15:43:18 -0700938 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -0700939 checkAllAliasStreamVolumes();
John Spurlockb6e19e32015-03-10 21:33:44 -0400940 checkMuteAffectedStreams();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 }
942
Eric Laurentbffc3d12012-05-07 17:43:49 -0700943 private void dumpStreamStates(PrintWriter pw) {
944 pw.println("\nStream volumes (device: index)");
945 int numStreamTypes = AudioSystem.getNumStreamTypes();
946 for (int i = 0; i < numStreamTypes; i++) {
John Spurlock61560172015-02-06 19:46:04 -0500947 pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":");
Eric Laurentbffc3d12012-05-07 17:43:49 -0700948 mStreamStates[i].dump(pw);
949 pw.println("");
950 }
Eric Laurentdd45d012012-10-08 09:04:34 -0700951 pw.print("\n- mute affected streams = 0x");
952 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -0700953 }
954
John Spurlock90874332015-03-10 16:00:54 -0400955 private void updateStreamVolumeAlias(boolean updateVolumes, String caller) {
Eric Laurent6d517662012-04-23 18:42:39 -0700956 int dtmfStreamAlias;
Eric Laurent212532b2014-07-21 15:43:18 -0700957
958 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -0500959 case AudioSystem.PLATFORM_VOICE:
Eric Laurent212532b2014-07-21 15:43:18 -0700960 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
Eric Laurent6d517662012-04-23 18:42:39 -0700961 dtmfStreamAlias = AudioSystem.STREAM_RING;
Eric Laurent212532b2014-07-21 15:43:18 -0700962 break;
John Spurlock61560172015-02-06 19:46:04 -0500963 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -0700964 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
965 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
966 break;
967 default:
968 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
Eric Laurent6d517662012-04-23 18:42:39 -0700969 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
970 }
Eric Laurent212532b2014-07-21 15:43:18 -0700971
972 if (isPlatformTelevision()) {
973 mRingerModeAffectedStreams = 0;
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700974 } else {
Eric Laurent212532b2014-07-21 15:43:18 -0700975 if (isInCommunication()) {
976 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
977 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
978 } else {
979 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
980 }
Eric Laurent6d517662012-04-23 18:42:39 -0700981 }
Eric Laurent212532b2014-07-21 15:43:18 -0700982
Eric Laurent6d517662012-04-23 18:42:39 -0700983 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
984 if (updateVolumes) {
John Spurlock90874332015-03-10 16:00:54 -0400985 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
986 caller);
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700987 // apply stream mute states according to new value of mRingerModeAffectedStreams
John Spurlock661f2cf2014-11-17 10:29:10 -0500988 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent6d517662012-04-23 18:42:39 -0700989 sendMsg(mAudioHandler,
990 MSG_SET_ALL_VOLUMES,
991 SENDMSG_QUEUE,
992 0,
993 0,
994 mStreamStates[AudioSystem.STREAM_DTMF], 0);
995 }
996 }
997
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700998 private void readDockAudioSettings(ContentResolver cr)
999 {
1000 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -07001001 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001002
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001003 sendMsg(mAudioHandler,
1004 MSG_SET_FORCE_USE,
1005 SENDMSG_QUEUE,
1006 AudioSystem.FOR_DOCK,
1007 mDockAudioMediaEnabled ?
1008 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
1009 null,
1010 0);
1011 }
1012
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001013 private void readPersistedSettings() {
1014 final ContentResolver cr = mContentResolver;
1015
Eric Laurentbffc3d12012-05-07 17:43:49 -07001016 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07001017 Settings.Global.getInt(
1018 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -07001019 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -07001020 // sanity check in case the settings are restored from a device with incompatible
1021 // ringer modes
John Spurlock97559372014-10-24 16:27:36 -04001022 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001023 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -07001024 }
1025 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1026 ringerMode = AudioManager.RINGER_MODE_SILENT;
1027 }
1028 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07001029 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -08001030 }
Eric Laurent212532b2014-07-21 15:43:18 -07001031 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001032 ringerMode = AudioManager.RINGER_MODE_NORMAL;
1033 }
Glenn Kastenba195eb2011-12-13 09:30:40 -08001034 synchronized(mSettingsLock) {
1035 mRingerMode = ringerMode;
John Spurlock661f2cf2014-11-17 10:29:10 -05001036 if (mRingerModeExternal == -1) {
1037 mRingerModeExternal = mRingerMode;
1038 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001039
Eric Laurentdd45d012012-10-08 09:04:34 -07001040 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
1041 // are still needed while setVibrateSetting() and getVibrateSetting() are being
1042 // deprecated.
John Spurlock61560172015-02-06 19:46:04 -05001043 mVibrateSetting = AudioSystem.getValueForVibrateSetting(0,
Eric Laurentdd45d012012-10-08 09:04:34 -07001044 AudioManager.VIBRATE_TYPE_NOTIFICATION,
1045 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
1046 : AudioManager.VIBRATE_SETTING_OFF);
John Spurlock61560172015-02-06 19:46:04 -05001047 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting,
Eric Laurentdd45d012012-10-08 09:04:34 -07001048 AudioManager.VIBRATE_TYPE_RINGER,
1049 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
1050 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051
Eric Laurent24e0d9b2013-10-03 18:15:07 -07001052 updateRingerModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001053 readDockAudioSettings(cr);
Eric Laurent402f7f22011-02-04 12:30:32 -08001054 }
Eric Laurentc1d41662011-07-19 11:21:13 -07001055
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001056 mMuteAffectedStreams = System.getIntForUser(cr,
John Spurlock61560172015-02-06 19:46:04 -05001057 System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
John Spurlock24c05182015-02-05 12:30:36 -05001058 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001059
Makoto Onukid45a4a22015-11-02 17:17:38 -08001060 final int currentUser = getCurrentUserId();
1061
1062 // In addition to checking the system setting, also check the current user restriction.
1063 // Because of the delay before persisting VOLUME_MASTER_MUTE, there's a window where
1064 // DISALLOW_ADJUST_VOLUME will be ignored when it's set right before switching users.
1065 boolean masterMute = (System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
1066 0, UserHandle.USER_CURRENT) == 1)
1067 || mUserManagerInternal.getUserRestriction(
1068 currentUser, UserManager.DISALLOW_ADJUST_VOLUME);
Eric Laurent83a017b2013-03-19 18:15:31 -07001069 if (mUseFixedVolume) {
1070 masterMute = false;
1071 AudioSystem.setMasterVolume(1.0f);
1072 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08001073 if (DEBUG_VOL) {
1074 Log.d(TAG, String.format("Master mute %s, user=%d", masterMute, currentUser));
1075 }
Jae Seo1b434da2015-11-11 18:58:51 -08001076 setSystemAudioMute(masterMute);
Justin Koh57978ed2012-04-03 17:37:58 -07001077 AudioSystem.setMasterMute(masterMute);
1078 broadcastMasterMuteStatus(masterMute);
1079
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001080 boolean microphoneMute =
Makoto Onukid45a4a22015-11-02 17:17:38 -08001081 (System.getIntForUser(cr, System.MICROPHONE_MUTE, 0, UserHandle.USER_CURRENT) == 1)
1082 || mUserManagerInternal.getUserRestriction(
1083 currentUser, UserManager.DISALLOW_UNMUTE_MICROPHONE);
1084 if (DEBUG_VOL) {
1085 Log.d(TAG, String.format("Mic mute %s, user=%d", microphoneMute, currentUser));
1086 }
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001087 AudioSystem.muteMicrophone(microphoneMute);
1088
Andy Hungf04b84d2015-12-18 17:33:27 -08001089 final boolean masterMono = System.getIntForUser(
1090 cr, System.MASTER_MONO, 0 /* default */, UserHandle.USER_CURRENT) == 1;
1091 if (DEBUG_VOL) {
1092 Log.d(TAG, String.format("Master mono %b, user=%d", masterMono, currentUser));
1093 }
1094 AudioSystem.setMasterMono(masterMono);
1095 broadcastMasterMonoStatus(masterMono);
1096
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097 // Each stream will read its own persisted settings
1098
John Spurlockbcc10872014-11-28 15:29:21 -05001099 // Broadcast the sticky intents
1100 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
1101 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001102
1103 // Broadcast vibrate settings
1104 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
1105 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07001106
John Spurlock33f4e042014-07-11 13:10:58 -04001107 // Load settings for the volume controller
1108 mVolumeController.loadSettings(cr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 }
1110
Eric Laurenta553c252009-07-17 12:17:14 -07001111 private int rescaleIndex(int index, int srcStream, int dstStream) {
1112 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
1113 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114
1115 ///////////////////////////////////////////////////////////////////////////
1116 // IPC methods
1117 ///////////////////////////////////////////////////////////////////////////
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001118 /** @see AudioManager#adjustVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001119 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001120 String callingPackage, String caller) {
RoboErik272e1612014-09-05 11:39:29 -07001121 adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
John Spurlock90874332015-03-10 16:00:54 -04001122 caller, Binder.getCallingUid());
RoboErik272e1612014-09-05 11:39:29 -07001123 }
1124
1125 private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001126 String callingPackage, String caller, int uid) {
1127 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType
1128 + ", flags=" + flags + ", caller=" + caller);
Eric Laurent402f7f22011-02-04 12:30:32 -08001129 int streamType;
RoboErik4197cb62015-01-21 15:45:32 -08001130 boolean isMute = isMuteAdjust(direction);
Eric Laurent45c90ce2012-04-24 18:44:22 -07001131 if (mVolumeControlStream != -1) {
1132 streamType = mVolumeControlStream;
Eric Laurent402f7f22011-02-04 12:30:32 -08001133 } else {
1134 streamType = getActiveStreamType(suggestedStreamType);
1135 }
John Spurlock0a376af2015-03-26 16:24:12 -04001136 ensureValidStreamType(streamType);
John Spurlock33f4e042014-07-11 13:10:58 -04001137 final int resolvedStream = mStreamVolumeAlias[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001138
RoboErik2811dd32014-08-12 09:48:13 -07001139 // Play sounds on STREAM_RING only.
1140 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
John Spurlock33f4e042014-07-11 13:10:58 -04001141 resolvedStream != AudioSystem.STREAM_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001142 flags &= ~AudioManager.FLAG_PLAY_SOUND;
1143 }
1144
John Spurlock33f4e042014-07-11 13:10:58 -04001145 // For notifications/ring, show the ui before making any adjustments
RoboErik4197cb62015-01-21 15:45:32 -08001146 // Don't suppress mute/unmute requests
1147 if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
John Spurlock33f4e042014-07-11 13:10:58 -04001148 direction = 0;
1149 flags &= ~AudioManager.FLAG_PLAY_SOUND;
1150 flags &= ~AudioManager.FLAG_VIBRATE;
1151 if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
1152 }
1153
John Spurlock90874332015-03-10 16:00:54 -04001154 adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155 }
1156
1157 /** @see AudioManager#adjustStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001158 public void adjustStreamVolume(int streamType, int direction, int flags,
1159 String callingPackage) {
John Spurlock90874332015-03-10 16:00:54 -04001160 adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage,
1161 Binder.getCallingUid());
RoboErik0dac35a2014-08-12 15:48:49 -07001162 }
1163
1164 private void adjustStreamVolume(int streamType, int direction, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001165 String callingPackage, String caller, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001166 if (mUseFixedVolume) {
1167 return;
1168 }
John Spurlock90874332015-03-10 16:00:54 -04001169 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream=" + streamType + ", dir=" + direction
1170 + ", flags=" + flags + ", caller=" + caller);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07001171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001172 ensureValidDirection(direction);
1173 ensureValidStreamType(streamType);
1174
RoboErik4197cb62015-01-21 15:45:32 -08001175 boolean isMuteAdjust = isMuteAdjust(direction);
1176
John Spurlock3ce37252015-02-17 13:20:45 -05001177 if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
1178 return;
1179 }
1180
Eric Laurent96a33d12011-11-08 10:31:57 -08001181 // use stream type alias here so that streams with same alias have the same behavior,
1182 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
1183 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
Eric Laurent6d517662012-04-23 18:42:39 -07001184 int streamTypeAlias = mStreamVolumeAlias[streamType];
RoboErik4197cb62015-01-21 15:45:32 -08001185
Eric Laurentb024c302011-10-14 17:19:27 -07001186 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001187
1188 final int device = getDeviceForStream(streamTypeAlias);
Eric Laurent3ef75492012-11-28 12:12:23 -08001189
Eric Laurent42b041e2013-03-29 11:36:03 -07001190 int aliasIndex = streamState.getIndex(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191 boolean adjustVolume = true;
Eric Laurent3ef75492012-11-28 12:12:23 -08001192 int step;
Eric Laurent24482012012-05-10 09:41:17 -07001193
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001194 // skip a2dp absolute volume control request when the device
1195 // is not an a2dp device
1196 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1197 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1198 return;
1199 }
1200
Kenny Guy70e0c582015-06-30 19:18:28 +01001201 // If we are being called by the system (e.g. hardware keys) check for current user
1202 // so we handle user restrictions correctly.
1203 if (uid == android.os.Process.SYSTEM_UID) {
1204 uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
1205 }
John Spurlock59dc9c12015-03-02 11:20:15 -05001206 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001207 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001208 return;
1209 }
1210
Eric Laurentfde16d52012-12-03 14:42:39 -08001211 // reset any pending volume command
1212 synchronized (mSafeMediaVolumeState) {
1213 mPendingVolumeCommand = null;
1214 }
1215
Eric Laurent3ef75492012-11-28 12:12:23 -08001216 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1217 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1218 ((device & mFixedVolumeDevices) != 0)) {
1219 flags |= AudioManager.FLAG_FIXED_VOLUME;
1220
1221 // Always toggle between max safe volume and 0 for fixed volume devices where safe
1222 // volume is enforced, and max and 0 for the others.
1223 // This is simulated by stepping by the full allowed volume range
1224 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1225 (device & mSafeMediaVolumeDevices) != 0) {
1226 step = mSafeMediaVolumeIndex;
1227 } else {
1228 step = streamState.getMaxIndex();
1229 }
1230 if (aliasIndex != 0) {
1231 aliasIndex = step;
1232 }
1233 } else {
1234 // convert one UI step (+/-1) into a number of internal units on the stream alias
1235 step = rescaleIndex(10, streamType, streamTypeAlias);
1236 }
1237
Eric Laurent42b041e2013-03-29 11:36:03 -07001238 // If either the client forces allowing ringer modes for this adjustment,
1239 // or the stream type is one that is affected by ringer modes
1240 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlockee5ad722015-03-03 16:17:21 -05001241 (streamTypeAlias == getUiSoundsStreamType())) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001242 int ringerMode = getRingerModeInternal();
Eric Laurent42b041e2013-03-29 11:36:03 -07001243 // do not vibrate if already in vibrate mode
1244 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
1245 flags &= ~AudioManager.FLAG_VIBRATE;
Eric Laurent3ef75492012-11-28 12:12:23 -08001246 }
RoboErik5452e252015-02-06 15:33:53 -08001247 // Check if the ringer mode handles this adjustment. If it does we don't
1248 // need to adjust the volume further.
John Spurlock50ced3f2015-05-11 16:00:09 -04001249 final int result = checkForRingerModeChange(aliasIndex, direction, step,
1250 streamState.mIsMuted);
John Spurlocka11b4af2014-06-01 11:52:23 -04001251 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
1252 // If suppressing a volume adjustment in silent mode, display the UI hint
1253 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
1254 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
1255 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001256 // If suppressing a volume down adjustment in vibrate mode, display the UI hint
1257 if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
1258 flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
1259 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001260 }
John Spurlock50ced3f2015-05-11 16:00:09 -04001261 // If the ringermode is suppressing media, prevent changes
1262 if (streamTypeAlias == AudioSystem.STREAM_MUSIC
1263 && (mRingerModeMutedStreams & (1 << AudioSystem.STREAM_MUSIC)) != 0) {
1264 adjustVolume = false;
1265 }
Eric Laurent3ef75492012-11-28 12:12:23 -08001266
Eric Laurent42b041e2013-03-29 11:36:03 -07001267 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001268
Eric Laurent42b041e2013-03-29 11:36:03 -07001269 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
RoboErik5452e252015-02-06 15:33:53 -08001270 mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001271
John Du5a0cf7a2013-07-19 11:30:34 -07001272 // Check if volume update should be send to AVRCP
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001273 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1274 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1275 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1276 synchronized (mA2dpAvrcpLock) {
1277 if (mA2dp != null && mAvrcpAbsVolSupported) {
1278 mA2dp.adjustAvrcpAbsoluteVolume(direction);
1279 }
John Du5a0cf7a2013-07-19 11:30:34 -07001280 }
1281 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001282
RoboErik4197cb62015-01-21 15:45:32 -08001283 if (isMuteAdjust) {
1284 boolean state;
1285 if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
1286 state = !streamState.mIsMuted;
1287 } else {
1288 state = direction == AudioManager.ADJUST_MUTE;
1289 }
1290 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1291 setSystemAudioMute(state);
1292 }
1293 for (int stream = 0; stream < mStreamStates.length; stream++) {
1294 if (streamTypeAlias == mStreamVolumeAlias[stream]) {
Sungmin Choi841ed0a2015-07-26 23:09:49 -07001295 if (!(readCameraSoundForced()
1296 && (mStreamStates[stream].getStreamType()
1297 == AudioSystem.STREAM_SYSTEM_ENFORCED))) {
1298 mStreamStates[stream].mute(state);
1299 }
RoboErik4197cb62015-01-21 15:45:32 -08001300 }
1301 }
1302 } else if ((direction == AudioManager.ADJUST_RAISE) &&
Eric Laurent42b041e2013-03-29 11:36:03 -07001303 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
RoboErik4197cb62015-01-21 15:45:32 -08001304 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -04001305 mVolumeController.postDisplaySafeVolumeWarning(flags);
John Spurlock90874332015-03-10 16:00:54 -04001306 } else if (streamState.adjustIndex(direction * step, device, caller)
1307 || streamState.mIsMuted) {
RoboErik4197cb62015-01-21 15:45:32 -08001308 // Post message to set system volume (it in turn will post a
1309 // message to persist).
1310 if (streamState.mIsMuted) {
1311 // Unmute the stream if it was previously muted
RoboErik5452e252015-02-06 15:33:53 -08001312 if (direction == AudioManager.ADJUST_RAISE) {
1313 // unmute immediately for volume up
1314 streamState.mute(false);
1315 } else if (direction == AudioManager.ADJUST_LOWER) {
John Spurlocka48d7792015-03-03 17:35:57 -05001316 if (mPlatformType == AudioSystem.PLATFORM_TELEVISION) {
1317 sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
1318 streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
1319 }
RoboErik5452e252015-02-06 15:33:53 -08001320 }
RoboErik4197cb62015-01-21 15:45:32 -08001321 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001322 sendMsg(mAudioHandler,
1323 MSG_SET_DEVICE_VOLUME,
1324 SENDMSG_QUEUE,
1325 device,
1326 0,
1327 streamState,
1328 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001329 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001330
RoboErik4197cb62015-01-21 15:45:32 -08001331 // Check if volume update should be sent to Hdmi system audio.
Jungshik Jang41d97462014-06-30 22:26:29 +09001332 int newIndex = mStreamStates[streamType].getIndex(device);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001333 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1334 setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
1335 }
Eric Laurent212532b2014-07-21 15:43:18 -07001336 if (mHdmiManager != null) {
1337 synchronized (mHdmiManager) {
Eric Laurent212532b2014-07-21 15:43:18 -07001338 // mHdmiCecSink true => mHdmiPlaybackClient != null
1339 if (mHdmiCecSink &&
1340 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1341 oldIndex != newIndex) {
1342 synchronized (mHdmiPlaybackClient) {
1343 int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
RoboErik4197cb62015-01-21 15:45:32 -08001344 KeyEvent.KEYCODE_VOLUME_UP;
Eric Laurent212532b2014-07-21 15:43:18 -07001345 mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1346 mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1347 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001348 }
1349 }
1350 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001351 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001352 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001353 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001354 }
1355
RoboErik5452e252015-02-06 15:33:53 -08001356 // Called after a delay when volume down is pressed while muted
1357 private void onUnmuteStream(int stream, int flags) {
1358 VolumeStreamState streamState = mStreamStates[stream];
1359 streamState.mute(false);
1360
1361 final int device = getDeviceForStream(stream);
1362 final int index = mStreamStates[stream].getIndex(device);
1363 sendVolumeUpdate(stream, index, index, flags);
1364 }
1365
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001366 private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
1367 if (mHdmiManager == null
1368 || mHdmiTvClient == null
1369 || oldVolume == newVolume
1370 || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
1371
1372 // Sets the audio volume of AVR when we are in system audio mode. The new volume info
1373 // is tranformed to HDMI-CEC commands and passed through CEC bus.
1374 synchronized (mHdmiManager) {
1375 if (!mHdmiSystemAudioSupported) return;
1376 synchronized (mHdmiTvClient) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001377 final long token = Binder.clearCallingIdentity();
1378 try {
Jinsuk Kim7a9ba422015-02-16 16:47:38 +09001379 mHdmiTvClient.setSystemAudioVolume(oldVolume, newVolume, maxVolume);
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001380 } finally {
1381 Binder.restoreCallingIdentity(token);
1382 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001383 }
1384 }
1385 }
1386
Eric Laurentfde16d52012-12-03 14:42:39 -08001387 // StreamVolumeCommand contains the information needed to defer the process of
1388 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1389 class StreamVolumeCommand {
1390 public final int mStreamType;
1391 public final int mIndex;
1392 public final int mFlags;
1393 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001394
Eric Laurentfde16d52012-12-03 14:42:39 -08001395 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1396 mStreamType = streamType;
1397 mIndex = index;
1398 mFlags = flags;
1399 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001400 }
John Spurlock35134602014-07-24 18:10:48 -04001401
1402 @Override
1403 public String toString() {
1404 return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1405 .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1406 .append(mDevice).append('}').toString();
1407 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001408 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001409
John Spurlock90874332015-03-10 16:00:54 -04001410 private void onSetStreamVolume(int streamType, int index, int flags, int device,
1411 String caller) {
John Spurlock75ae23c2015-06-02 16:26:43 -04001412 final int stream = mStreamVolumeAlias[streamType];
1413 setStreamVolumeInt(stream, index, device, false, caller);
John Spurlockee5ad722015-03-03 16:17:21 -05001414 // setting volume on ui sounds stream type also controls silent mode
Eric Laurent3ef75492012-11-28 12:12:23 -08001415 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlock75ae23c2015-06-02 16:26:43 -04001416 (stream == getUiSoundsStreamType())) {
Eric Laurent3ef75492012-11-28 12:12:23 -08001417 int newRingerMode;
1418 if (index == 0) {
1419 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlocka48d7792015-03-03 17:35:57 -05001420 : mVolumePolicy.volumeDownToEnterSilent ? AudioManager.RINGER_MODE_SILENT
John Spurlock86005342014-05-23 11:58:00 -04001421 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001422 } else {
1423 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1424 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001425 setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/);
Eric Laurent3ef75492012-11-28 12:12:23 -08001426 }
John Spurlock75ae23c2015-06-02 16:26:43 -04001427 // setting non-zero volume for a muted stream unmutes the stream and vice versa
1428 mStreamStates[stream].mute(index == 0);
Eric Laurentfde16d52012-12-03 14:42:39 -08001429 }
1430
1431 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001432 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
John Spurlock90874332015-03-10 16:00:54 -04001433 setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
1434 Binder.getCallingUid());
RoboErik0dac35a2014-08-12 15:48:49 -07001435 }
1436
1437 private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
John Spurlock90874332015-03-10 16:00:54 -04001438 String caller, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001439 if (mUseFixedVolume) {
1440 return;
1441 }
1442
Eric Laurentfde16d52012-12-03 14:42:39 -08001443 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001444 int streamTypeAlias = mStreamVolumeAlias[streamType];
1445 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001446
1447 final int device = getDeviceForStream(streamType);
1448 int oldIndex;
1449
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001450 // skip a2dp absolute volume control request when the device
1451 // is not an a2dp device
1452 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1453 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1454 return;
1455 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001456 // If we are being called by the system (e.g. hardware keys) check for current user
1457 // so we handle user restrictions correctly.
1458 if (uid == android.os.Process.SYSTEM_UID) {
1459 uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
1460 }
John Spurlock59dc9c12015-03-02 11:20:15 -05001461 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001462 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001463 return;
1464 }
1465
Eric Laurentfde16d52012-12-03 14:42:39 -08001466 synchronized (mSafeMediaVolumeState) {
1467 // reset any pending volume command
1468 mPendingVolumeCommand = null;
1469
Eric Laurent42b041e2013-03-29 11:36:03 -07001470 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001471
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001472 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001473
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001474 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1475 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1476 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1477 synchronized (mA2dpAvrcpLock) {
1478 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001479 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001480 }
John Du5a0cf7a2013-07-19 11:30:34 -07001481 }
1482 }
1483
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001484 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1485 setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
Jungshik Jang41d97462014-06-30 22:26:29 +09001486 }
1487
Eric Laurentfde16d52012-12-03 14:42:39 -08001488 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001489 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001490 ((device & mFixedVolumeDevices) != 0)) {
1491 flags |= AudioManager.FLAG_FIXED_VOLUME;
1492
1493 // volume is either 0 or max allowed for fixed volume devices
1494 if (index != 0) {
1495 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1496 (device & mSafeMediaVolumeDevices) != 0) {
1497 index = mSafeMediaVolumeIndex;
1498 } else {
1499 index = streamState.getMaxIndex();
1500 }
1501 }
1502 }
1503
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001504 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001505 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001506 mPendingVolumeCommand = new StreamVolumeCommand(
1507 streamType, index, flags, device);
1508 } else {
John Spurlock90874332015-03-10 16:00:54 -04001509 onSetStreamVolume(streamType, index, flags, device, caller);
Eric Laurent42b041e2013-03-29 11:36:03 -07001510 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001511 }
1512 }
Eric Laurent25101b02011-02-02 09:33:30 -08001513 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001514 }
1515
Eric Laurent45c90ce2012-04-24 18:44:22 -07001516 /** @see AudioManager#forceVolumeControlStream(int) */
1517 public void forceVolumeControlStream(int streamType, IBinder cb) {
1518 synchronized(mForceControlStreamLock) {
1519 mVolumeControlStream = streamType;
1520 if (mVolumeControlStream == -1) {
1521 if (mForceControlStreamClient != null) {
1522 mForceControlStreamClient.release();
1523 mForceControlStreamClient = null;
1524 }
1525 } else {
1526 mForceControlStreamClient = new ForceControlStreamClient(cb);
1527 }
1528 }
1529 }
1530
1531 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1532 private IBinder mCb; // To be notified of client's death
1533
1534 ForceControlStreamClient(IBinder cb) {
1535 if (cb != null) {
1536 try {
1537 cb.linkToDeath(this, 0);
1538 } catch (RemoteException e) {
1539 // Client has died!
1540 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1541 cb = null;
1542 }
1543 }
1544 mCb = cb;
1545 }
1546
1547 public void binderDied() {
1548 synchronized(mForceControlStreamLock) {
1549 Log.w(TAG, "SCO client died");
1550 if (mForceControlStreamClient != this) {
1551 Log.w(TAG, "unregistered control stream client died");
1552 } else {
1553 mForceControlStreamClient = null;
1554 mVolumeControlStream = -1;
1555 }
1556 }
1557 }
1558
1559 public void release() {
1560 if (mCb != null) {
1561 mCb.unlinkToDeath(this, 0);
1562 mCb = null;
1563 }
1564 }
1565 }
1566
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001567 private void sendBroadcastToAll(Intent intent) {
Christopher Tate267603f2015-01-20 14:21:21 -08001568 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
John Spurlock86490862015-02-25 11:22:52 -05001569 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001570 final long ident = Binder.clearCallingIdentity();
1571 try {
1572 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1573 } finally {
1574 Binder.restoreCallingIdentity(ident);
1575 }
1576 }
1577
1578 private void sendStickyBroadcastToAll(Intent intent) {
John Spurlock86490862015-02-25 11:22:52 -05001579 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001580 final long ident = Binder.clearCallingIdentity();
1581 try {
1582 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1583 } finally {
1584 Binder.restoreCallingIdentity(ident);
1585 }
1586 }
1587
Kenny Guy70e0c582015-06-30 19:18:28 +01001588 private int getCurrentUserId() {
1589 final long ident = Binder.clearCallingIdentity();
1590 try {
1591 UserInfo currentUser = ActivityManagerNative.getDefault().getCurrentUser();
1592 return currentUser.id;
1593 } catch (RemoteException e) {
1594 // Activity manager not running, nothing we can do assume user 0.
1595 } finally {
1596 Binder.restoreCallingIdentity(ident);
1597 }
Xiaohui Chen7c696362015-09-16 09:56:14 -07001598 return UserHandle.USER_SYSTEM;
Kenny Guy70e0c582015-06-30 19:18:28 +01001599 }
1600
Eric Laurent25101b02011-02-02 09:33:30 -08001601 // UI update and Broadcast Intent
1602 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
John Spurlock72966d62015-06-18 15:45:07 -04001603 streamType = mStreamVolumeAlias[streamType];
Eric Laurent25101b02011-02-02 09:33:30 -08001604
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001605 if (streamType == AudioSystem.STREAM_MUSIC) {
1606 flags = updateFlagsForSystemAudio(flags);
Jungshik Jang1a6be6e2014-09-16 11:04:54 +09001607 }
John Spurlock3346a802014-05-20 16:25:37 -04001608 mVolumeController.postVolumeChanged(streamType, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001609 }
1610
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001611 // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
1612 // receives volume notification from Audio Receiver.
1613 private int updateFlagsForSystemAudio(int flags) {
1614 if (mHdmiTvClient != null) {
1615 synchronized (mHdmiTvClient) {
1616 if (mHdmiSystemAudioSupported &&
1617 ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
1618 flags &= ~AudioManager.FLAG_SHOW_UI;
1619 }
1620 }
1621 }
1622 return flags;
1623 }
1624
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001625 // UI update and Broadcast Intent
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001626 private void sendMasterMuteUpdate(boolean muted, int flags) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001627 mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
Justin Koh57978ed2012-04-03 17:37:58 -07001628 broadcastMasterMuteStatus(muted);
1629 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001630
Justin Koh57978ed2012-04-03 17:37:58 -07001631 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001632 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1633 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001634 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1635 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001636 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001637 }
1638
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001639 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001640 * Sets the stream state's index, and posts a message to set system volume.
1641 * This will not call out to the UI. Assumes a valid stream type.
1642 *
1643 * @param streamType Type of the stream
1644 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001645 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001646 * @param force If true, set the volume even if the desired volume is same
1647 * as the current volume.
1648 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001649 private void setStreamVolumeInt(int streamType,
1650 int index,
1651 int device,
John Spurlock90874332015-03-10 16:00:54 -04001652 boolean force,
1653 String caller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001654 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07001655
John Spurlock90874332015-03-10 16:00:54 -04001656 if (streamState.setIndex(index, device, caller) || force) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001657 // Post message to set system volume (it in turn will post a message
1658 // to persist).
1659 sendMsg(mAudioHandler,
1660 MSG_SET_DEVICE_VOLUME,
1661 SENDMSG_QUEUE,
1662 device,
1663 0,
1664 streamState,
1665 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001666 }
1667 }
1668
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001669 private void setSystemAudioMute(boolean state) {
1670 if (mHdmiManager == null || mHdmiTvClient == null) return;
1671 synchronized (mHdmiManager) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001672 if (!mHdmiSystemAudioSupported) return;
1673 synchronized (mHdmiTvClient) {
1674 final long token = Binder.clearCallingIdentity();
1675 try {
1676 mHdmiTvClient.setSystemAudioMute(state);
1677 } finally {
1678 Binder.restoreCallingIdentity(token);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001679 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001680 }
1681 }
1682 }
1683
Eric Laurent25101b02011-02-02 09:33:30 -08001684 /** get stream mute state. */
1685 public boolean isStreamMute(int streamType) {
RoboErik7c82ced2014-12-04 17:39:08 -08001686 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1687 streamType = getActiveStreamType(streamType);
1688 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001689 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08001690 return mStreamStates[streamType].mIsMuted;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001691 }
Eric Laurent25101b02011-02-02 09:33:30 -08001692 }
1693
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07001694 private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
1695 private IBinder mICallback; // To be notified of client's death
1696
1697 RmtSbmxFullVolDeathHandler(IBinder cb) {
1698 mICallback = cb;
1699 try {
1700 cb.linkToDeath(this, 0/*flags*/);
1701 } catch (RemoteException e) {
1702 Log.e(TAG, "can't link to death", e);
1703 }
1704 }
1705
1706 boolean isHandlerFor(IBinder cb) {
1707 return mICallback.equals(cb);
1708 }
1709
1710 void forget() {
1711 try {
1712 mICallback.unlinkToDeath(this, 0/*flags*/);
1713 } catch (NoSuchElementException e) {
1714 Log.e(TAG, "error unlinking to death", e);
1715 }
1716 }
1717
1718 public void binderDied() {
1719 Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
1720 forceRemoteSubmixFullVolume(false, mICallback);
1721 }
1722 }
1723
1724 /**
1725 * call must be synchronized on mRmtSbmxFullVolDeathHandlers
1726 * @return true if there is a registered death handler, false otherwise */
1727 private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1728 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1729 while (it.hasNext()) {
1730 final RmtSbmxFullVolDeathHandler handler = it.next();
1731 if (handler.isHandlerFor(cb)) {
1732 handler.forget();
1733 mRmtSbmxFullVolDeathHandlers.remove(handler);
1734 return true;
1735 }
1736 }
1737 return false;
1738 }
1739
1740 /** call synchronized on mRmtSbmxFullVolDeathHandlers */
1741 private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1742 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1743 while (it.hasNext()) {
1744 if (it.next().isHandlerFor(cb)) {
1745 return true;
1746 }
1747 }
1748 return false;
1749 }
1750
1751 private int mRmtSbmxFullVolRefCount = 0;
1752 private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
1753 new ArrayList<RmtSbmxFullVolDeathHandler>();
1754
1755 public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
1756 if (cb == null) {
1757 return;
1758 }
1759 if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
1760 android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
1761 Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
1762 return;
1763 }
1764 synchronized(mRmtSbmxFullVolDeathHandlers) {
1765 boolean applyRequired = false;
1766 if (startForcing) {
1767 if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
1768 mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
1769 if (mRmtSbmxFullVolRefCount == 0) {
1770 mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1771 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1772 applyRequired = true;
1773 }
1774 mRmtSbmxFullVolRefCount++;
1775 }
1776 } else {
1777 if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
1778 mRmtSbmxFullVolRefCount--;
1779 if (mRmtSbmxFullVolRefCount == 0) {
1780 mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1781 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1782 applyRequired = true;
1783 }
1784 }
1785 }
1786 if (applyRequired) {
1787 // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
1788 checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
1789 mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
1790 }
1791 }
1792 }
1793
Kenny Guy70e0c582015-06-30 19:18:28 +01001794 private void setMasterMuteInternal(boolean mute, int flags, String callingPackage, int uid,
1795 int userId) {
1796 // If we are being called by the system check for user we are going to change
1797 // so we handle user restrictions correctly.
1798 if (uid == android.os.Process.SYSTEM_UID) {
1799 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
1800 }
Makoto Onuki4f160732015-10-27 17:15:38 -07001801 // If OP_AUDIO_MASTER_VOLUME is set, disallow unmuting.
1802 if (!mute && mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
RoboErik7c82ced2014-12-04 17:39:08 -08001803 != AppOpsManager.MODE_ALLOWED) {
Julia Reynolds4a21b252014-06-04 11:11:43 -04001804 return;
1805 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001806 if (userId != UserHandle.getCallingUserId() &&
1807 mContext.checkCallingOrSelfPermission(
1808 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1809 != PackageManager.PERMISSION_GRANTED) {
1810 return;
1811 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08001812 setMasterMuteInternalNoCallerCheck(mute, flags, userId);
1813 }
1814
1815 private void setMasterMuteInternalNoCallerCheck(boolean mute, int flags, int userId) {
1816 if (DEBUG_VOL) {
1817 Log.d(TAG, String.format("Master mute %s, %d, user=%d", mute, flags, userId));
1818 }
1819 if (mUseFixedVolume) {
1820 return; // If using fixed volume, we don't mute.
1821 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001822 if (getCurrentUserId() == userId) {
1823 if (mute != AudioSystem.getMasterMute()) {
1824 setSystemAudioMute(mute);
1825 AudioSystem.setMasterMute(mute);
1826 // Post a persist master volume msg
1827 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, mute ? 1
1828 : 0, userId, null, PERSIST_DELAY);
1829 sendMasterMuteUpdate(mute, flags);
RoboErik7c82ced2014-12-04 17:39:08 -08001830
Kenny Guy70e0c582015-06-30 19:18:28 +01001831 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1832 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute);
1833 sendBroadcastToAll(intent);
1834 }
1835 } else {
1836 // If not the current user just persist the setting which will be loaded
1837 // on user switch.
1838 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, mute ? 1
1839 : 0, userId, null, PERSIST_DELAY);
Jason Simmons1ce5b262012-02-02 13:00:17 -08001840 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08001841 }
1842
1843 /** get master mute state. */
1844 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08001845 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001846 }
1847
Kenny Guy70e0c582015-06-30 19:18:28 +01001848 public void setMasterMute(boolean mute, int flags, String callingPackage, int userId) {
1849 setMasterMuteInternal(mute, flags, callingPackage, Binder.getCallingUid(),
1850 userId);
John Spurlockee5ad722015-03-03 16:17:21 -05001851 }
1852
Andy Hungf04b84d2015-12-18 17:33:27 -08001853 /** @hide */
1854 public boolean isMasterMono() {
1855 return AudioSystem.getMasterMono();
1856 }
1857
1858 /** @hide */
1859 public void setMasterMono(boolean mono, String callingPackage, int userId) {
1860 int callingUid = Binder.getCallingUid();
1861 // If we are being called by the system check for user we are going to change
1862 // so we handle user restrictions correctly.
1863 if (callingUid == android.os.Process.SYSTEM_UID) {
1864 callingUid = UserHandle.getUid(userId, UserHandle.getAppId(callingUid));
1865 }
1866
1867 if (userId != UserHandle.getCallingUserId() &&
1868 mContext.checkCallingOrSelfPermission(
1869 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1870 != PackageManager.PERMISSION_GRANTED) {
1871 return;
1872 }
1873 if (DEBUG_VOL) {
1874 Log.d(TAG, String.format("Master mono %b, user=%d", mono, userId));
1875 }
1876
1877 if (getCurrentUserId() == userId) {
1878 if (mono != AudioSystem.getMasterMono()) {
1879 AudioSystem.setMasterMono(mono);
1880 // Post a persist master mono msg
1881 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_MONO, SENDMSG_REPLACE, mono ? 1
1882 : 0 /* value */, userId, null /* obj */, 0 /* delay */);
1883 // notify apps and settings
1884 broadcastMasterMonoStatus(mono);
1885 }
1886 } else {
1887 // Post a persist master mono msg
1888 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_MONO, SENDMSG_REPLACE, mono ? 1
1889 : 0 /* value */, userId, null /* obj */, 0 /* delay */);
1890 }
1891 }
1892
1893 private void broadcastMasterMonoStatus(boolean mono) {
1894 Intent intent = new Intent(AudioManager.MASTER_MONO_CHANGED_ACTION);
1895 intent.putExtra(AudioManager.EXTRA_MASTER_MONO, mono);
1896 sendBroadcastToAll(intent);
1897 }
1898
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001899 /** @see AudioManager#getStreamVolume(int) */
1900 public int getStreamVolume(int streamType) {
1901 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001902 int device = getDeviceForStream(streamType);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001903 synchronized (VolumeStreamState.class) {
1904 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001905
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001906 // by convention getStreamVolume() returns 0 when a stream is muted.
RoboErik4197cb62015-01-21 15:45:32 -08001907 if (mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001908 index = 0;
1909 }
1910 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
1911 (device & mFixedVolumeDevices) != 0) {
1912 index = mStreamStates[streamType].getMaxIndex();
1913 }
1914 return (index + 5) / 10;
Eric Laurent42b041e2013-03-29 11:36:03 -07001915 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001916 }
1917
1918 /** @see AudioManager#getStreamMaxVolume(int) */
1919 public int getStreamMaxVolume(int streamType) {
1920 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07001921 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001922 }
1923
John Spurlockb6e19e32015-03-10 21:33:44 -04001924 /** @see AudioManager#getStreamMinVolume(int) */
1925 public int getStreamMinVolume(int streamType) {
1926 ensureValidStreamType(streamType);
1927 return (mStreamStates[streamType].getMinIndex() + 5) / 10;
1928 }
1929
Eric Laurent25101b02011-02-02 09:33:30 -08001930 /** Get last audible volume before stream was muted. */
1931 public int getLastAudibleStreamVolume(int streamType) {
1932 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001933 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001934 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08001935 }
1936
John Spurlockee5ad722015-03-03 16:17:21 -05001937 /** @see AudioManager#getUiSoundsStreamType() */
1938 public int getUiSoundsStreamType() {
John Spurlock4f0f1202014-08-05 13:28:33 -04001939 return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
Eric Laurent6d517662012-04-23 18:42:39 -07001940 }
1941
Makoto Onukid45a4a22015-11-02 17:17:38 -08001942 /** @see AudioManager#setMicrophoneMute(boolean) */
1943 @Override
Kenny Guy70e0c582015-06-30 19:18:28 +01001944 public void setMicrophoneMute(boolean on, String callingPackage, int userId) {
1945 // If we are being called by the system check for user we are going to change
1946 // so we handle user restrictions correctly.
1947 int uid = Binder.getCallingUid();
1948 if (uid == android.os.Process.SYSTEM_UID) {
1949 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
1950 }
Makoto Onuki4f160732015-10-27 17:15:38 -07001951 // If OP_MUTE_MICROPHONE is set, disallow unmuting.
1952 if (!on && mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, uid, callingPackage)
Kenny Guy70e0c582015-06-30 19:18:28 +01001953 != AppOpsManager.MODE_ALLOWED) {
Emily Bernier22c921a2014-05-28 11:01:32 -04001954 return;
1955 }
Jean-Michel Trivi4a4fea02014-08-29 18:14:09 -07001956 if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
1957 return;
1958 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001959 if (userId != UserHandle.getCallingUserId() &&
1960 mContext.checkCallingOrSelfPermission(
1961 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1962 != PackageManager.PERMISSION_GRANTED) {
1963 return;
1964 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08001965 setMicrophoneMuteNoCallerCheck(on, userId);
1966 }
Emily Bernier22c921a2014-05-28 11:01:32 -04001967
Makoto Onukid45a4a22015-11-02 17:17:38 -08001968 private void setMicrophoneMuteNoCallerCheck(boolean on, int userId) {
1969 if (DEBUG_VOL) {
1970 Log.d(TAG, String.format("Mic mute %s, user=%d", on, userId));
1971 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001972 // If mute is for current user actually mute, else just persist the setting
1973 // which will be loaded on user switch.
1974 if (getCurrentUserId() == userId) {
1975 AudioSystem.muteMicrophone(on);
1976 }
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001977 // Post a persist microphone msg.
1978 sendMsg(mAudioHandler, MSG_PERSIST_MICROPHONE_MUTE, SENDMSG_REPLACE, on ? 1
Kenny Guy70e0c582015-06-30 19:18:28 +01001979 : 0, userId, null, PERSIST_DELAY);
Emily Bernier22c921a2014-05-28 11:01:32 -04001980 }
1981
John Spurlock661f2cf2014-11-17 10:29:10 -05001982 @Override
1983 public int getRingerModeExternal() {
1984 synchronized(mSettingsLock) {
1985 return mRingerModeExternal;
1986 }
1987 }
1988
1989 @Override
1990 public int getRingerModeInternal() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001991 synchronized(mSettingsLock) {
1992 return mRingerMode;
1993 }
1994 }
1995
1996 private void ensureValidRingerMode(int ringerMode) {
John Spurlock97559372014-10-24 16:27:36 -04001997 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001998 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1999 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002000 }
2001
John Spurlock97559372014-10-24 16:27:36 -04002002 /** @see AudioManager#isValidRingerMode(int) */
2003 public boolean isValidRingerMode(int ringerMode) {
2004 return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
2005 }
2006
John Spurlock661f2cf2014-11-17 10:29:10 -05002007 public void setRingerModeExternal(int ringerMode, String caller) {
John Spurlockaf88a192014-12-23 16:14:44 -05002008 setRingerMode(ringerMode, caller, true /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05002009 }
2010
2011 public void setRingerModeInternal(int ringerMode, String caller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05002012 enforceVolumeController("setRingerModeInternal");
John Spurlockaf88a192014-12-23 16:14:44 -05002013 setRingerMode(ringerMode, caller, false /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05002014 }
2015
2016 private void setRingerMode(int ringerMode, String caller, boolean external) {
Eric Laurent212532b2014-07-21 15:43:18 -07002017 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07002018 return;
2019 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002020 if (caller == null || caller.length() == 0) {
2021 throw new IllegalArgumentException("Bad caller: " + caller);
2022 }
John Spurlock97559372014-10-24 16:27:36 -04002023 ensureValidRingerMode(ringerMode);
Eric Laurent24482012012-05-10 09:41:17 -07002024 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
2025 ringerMode = AudioManager.RINGER_MODE_SILENT;
2026 }
John Spurlockaf88a192014-12-23 16:14:44 -05002027 final long identity = Binder.clearCallingIdentity();
2028 try {
2029 synchronized (mSettingsLock) {
2030 final int ringerModeInternal = getRingerModeInternal();
2031 final int ringerModeExternal = getRingerModeExternal();
2032 if (external) {
2033 setRingerModeExt(ringerMode);
2034 if (mRingerModeDelegate != null) {
2035 ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
John Spurlocka48d7792015-03-03 17:35:57 -05002036 ringerMode, caller, ringerModeInternal, mVolumePolicy);
John Spurlockaf88a192014-12-23 16:14:44 -05002037 }
2038 if (ringerMode != ringerModeInternal) {
2039 setRingerModeInt(ringerMode, true /*persist*/);
2040 }
2041 } else /*internal*/ {
2042 if (ringerMode != ringerModeInternal) {
2043 setRingerModeInt(ringerMode, true /*persist*/);
2044 }
2045 if (mRingerModeDelegate != null) {
2046 ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
John Spurlocka48d7792015-03-03 17:35:57 -05002047 ringerMode, caller, ringerModeExternal, mVolumePolicy);
John Spurlockaf88a192014-12-23 16:14:44 -05002048 }
2049 setRingerModeExt(ringerMode);
John Spurlock57627792014-12-11 11:29:54 -05002050 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002051 }
John Spurlockaf88a192014-12-23 16:14:44 -05002052 } finally {
2053 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 }
2055 }
2056
John Spurlock661f2cf2014-11-17 10:29:10 -05002057 private void setRingerModeExt(int ringerMode) {
2058 synchronized(mSettingsLock) {
2059 if (ringerMode == mRingerModeExternal) return;
2060 mRingerModeExternal = ringerMode;
John Spurlocke5b42d92014-10-15 12:03:48 -04002061 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002062 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05002063 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
John Spurlocke5b42d92014-10-15 12:03:48 -04002064 }
2065
John Spurlock50ced3f2015-05-11 16:00:09 -04002066 private void muteRingerModeStreams() {
Eric Laurent5b4e6542010-03-19 20:02:21 -07002067 // Mute stream if not previously muted by ringer mode and ringer mode
2068 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
2069 // Unmute stream if previously muted by ringer mode and ringer mode
2070 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07002071 int numStreamTypes = AudioSystem.getNumStreamTypes();
John Spurlock50ced3f2015-05-11 16:00:09 -04002072 final boolean ringerModeMute = mRingerMode == AudioManager.RINGER_MODE_VIBRATE
2073 || mRingerMode == AudioManager.RINGER_MODE_SILENT;
Eric Laurent5b4e6542010-03-19 20:02:21 -07002074 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002075 final boolean isMuted = isStreamMutedByRingerMode(streamType);
2076 final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
2077 if (isMuted == shouldMute) continue;
2078 if (!shouldMute) {
2079 // unmute
2080 // ring and notifications volume should never be 0 when not silenced
John Spurlockd9c75db2015-04-28 11:19:13 -04002081 if (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002082 synchronized (VolumeStreamState.class) {
John Spurlocka48d7792015-03-03 17:35:57 -05002083 final VolumeStreamState vss = mStreamStates[streamType];
2084 for (int i = 0; i < vss.mIndexMap.size(); i++) {
2085 int device = vss.mIndexMap.keyAt(i);
2086 int value = vss.mIndexMap.valueAt(i);
John Spurlock2bb02ec2015-03-02 13:13:06 -05002087 if (value == 0) {
John Spurlocka48d7792015-03-03 17:35:57 -05002088 vss.setIndex(10, device, TAG);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002089 }
2090 }
Eric Laurent9e0d25f2015-02-12 17:28:53 -08002091 // Persist volume for stream ring when it is changed here
2092 final int device = getDeviceForStream(streamType);
2093 sendMsg(mAudioHandler,
2094 MSG_PERSIST_VOLUME,
2095 SENDMSG_QUEUE,
2096 device,
2097 0,
2098 mStreamStates[streamType],
2099 PERSIST_DELAY);
Eric Laurentb024c302011-10-14 17:19:27 -07002100 }
Eric Laurent9bcf4012009-06-12 06:09:28 -07002101 }
RoboErik4197cb62015-01-21 15:45:32 -08002102 mStreamStates[streamType].mute(false);
John Spurlock661f2cf2014-11-17 10:29:10 -05002103 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent5b4e6542010-03-19 20:02:21 -07002104 } else {
John Spurlock661f2cf2014-11-17 10:29:10 -05002105 // mute
RoboErik4197cb62015-01-21 15:45:32 -08002106 mStreamStates[streamType].mute(true);
John Spurlock661f2cf2014-11-17 10:29:10 -05002107 mRingerModeMutedStreams |= (1 << streamType);
Jason Parekhb1096152009-03-24 17:48:25 -07002108 }
2109 }
John Spurlock50ced3f2015-05-11 16:00:09 -04002110 }
2111
2112 private void setRingerModeInt(int ringerMode, boolean persist) {
2113 final boolean change;
2114 synchronized(mSettingsLock) {
2115 change = mRingerMode != ringerMode;
2116 mRingerMode = ringerMode;
2117 }
2118
2119 muteRingerModeStreams();
Eric Laurenta553c252009-07-17 12:17:14 -07002120
Jason Parekhb1096152009-03-24 17:48:25 -07002121 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07002122 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002123 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07002124 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
2125 }
John Spurlockbcc10872014-11-28 15:29:21 -05002126 if (change) {
2127 // Send sticky broadcast
2128 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
2129 }
Jason Parekhb1096152009-03-24 17:48:25 -07002130 }
2131
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002132 /** @see AudioManager#shouldVibrate(int) */
2133 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002134 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002135
2136 switch (getVibrateSetting(vibrateType)) {
2137
2138 case AudioManager.VIBRATE_SETTING_ON:
John Spurlock57627792014-12-11 11:29:54 -05002139 return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002140
2141 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
John Spurlock57627792014-12-11 11:29:54 -05002142 return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002143
2144 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04002145 // return false, even for incoming calls
2146 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002147
2148 default:
2149 return false;
2150 }
2151 }
2152
2153 /** @see AudioManager#getVibrateSetting(int) */
2154 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002155 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002156 return (mVibrateSetting >> (vibrateType * 2)) & 3;
2157 }
2158
2159 /** @see AudioManager#setVibrateSetting(int, int) */
2160 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
2161
Eric Laurentbffc3d12012-05-07 17:43:49 -07002162 if (!mHasVibrator) return;
2163
John Spurlock61560172015-02-06 19:46:04 -05002164 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
2165 vibrateSetting);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002166
2167 // Broadcast change
2168 broadcastVibrateSetting(vibrateType);
2169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002170 }
2171
Eric Laurent9272b4b2010-01-23 17:12:59 -08002172 private class SetModeDeathHandler implements IBinder.DeathRecipient {
2173 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002174 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002175 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
2176
Eric Laurent9f103de2011-09-08 15:04:23 -07002177 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08002178 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07002179 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002180 }
2181
2182 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07002183 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002184 synchronized(mSetModeDeathHandlers) {
2185 Log.w(TAG, "setMode() client died");
2186 int index = mSetModeDeathHandlers.indexOf(this);
2187 if (index < 0) {
2188 Log.w(TAG, "unregistered setMode() client died");
2189 } else {
John Spurlock90874332015-03-10 16:00:54 -04002190 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid, TAG);
Eric Laurent9272b4b2010-01-23 17:12:59 -08002191 }
2192 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002193 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2194 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002195 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07002196 final long ident = Binder.clearCallingIdentity();
2197 disconnectBluetoothSco(newModeOwnerPid);
2198 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07002199 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08002200 }
2201
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002202 public int getPid() {
2203 return mPid;
2204 }
2205
Eric Laurent9272b4b2010-01-23 17:12:59 -08002206 public void setMode(int mode) {
2207 mMode = mode;
2208 }
2209
2210 public int getMode() {
2211 return mMode;
2212 }
2213
2214 public IBinder getBinder() {
2215 return mCb;
2216 }
2217 }
2218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002219 /** @see AudioManager#setMode(int) */
John Spurlock90874332015-03-10 16:00:54 -04002220 public void setMode(int mode, IBinder cb, String callingPackage) {
2221 if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ", callingPackage=" + callingPackage + ")"); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002222 if (!checkAudioSettingsPermission("setMode()")) {
2223 return;
2224 }
Eric Laurenta553c252009-07-17 12:17:14 -07002225
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07002226 if ( (mode == AudioSystem.MODE_IN_CALL) &&
2227 (mContext.checkCallingOrSelfPermission(
2228 android.Manifest.permission.MODIFY_PHONE_STATE)
2229 != PackageManager.PERMISSION_GRANTED)) {
2230 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
2231 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
2232 return;
2233 }
2234
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08002235 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07002236 return;
2237 }
2238
Eric Laurentd7454be2011-09-14 08:45:58 -07002239 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002240 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07002241 if (mode == AudioSystem.MODE_CURRENT) {
2242 mode = mMode;
2243 }
John Spurlock90874332015-03-10 16:00:54 -04002244 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid(), callingPackage);
Eric Laurent9f103de2011-09-08 15:04:23 -07002245 }
2246 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2247 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002248 if (newModeOwnerPid != 0) {
2249 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07002250 }
2251 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002252
Eric Laurent9f103de2011-09-08 15:04:23 -07002253 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07002254 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07002255 // any mode other than NORMAL.
John Spurlock90874332015-03-10 16:00:54 -04002256 private int setModeInt(int mode, IBinder cb, int pid, String caller) {
2257 if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ", caller="
2258 + caller + ")"); }
Eric Laurentd7454be2011-09-14 08:45:58 -07002259 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002260 if (cb == null) {
2261 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07002262 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07002263 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002264
Eric Laurent9f103de2011-09-08 15:04:23 -07002265 SetModeDeathHandler hdlr = null;
2266 Iterator iter = mSetModeDeathHandlers.iterator();
2267 while (iter.hasNext()) {
2268 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
2269 if (h.getPid() == pid) {
2270 hdlr = h;
2271 // Remove from client list so that it is re-inserted at top of list
2272 iter.remove();
2273 hdlr.getBinder().unlinkToDeath(hdlr, 0);
2274 break;
2275 }
2276 }
2277 int status = AudioSystem.AUDIO_STATUS_OK;
2278 do {
2279 if (mode == AudioSystem.MODE_NORMAL) {
2280 // get new mode from client at top the list if any
2281 if (!mSetModeDeathHandlers.isEmpty()) {
2282 hdlr = mSetModeDeathHandlers.get(0);
2283 cb = hdlr.getBinder();
2284 mode = hdlr.getMode();
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002285 if (DEBUG_MODE) {
2286 Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
2287 + hdlr.mPid);
2288 }
Eric Laurentb9c9d262009-05-06 08:13:20 -07002289 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002290 } else {
2291 if (hdlr == null) {
2292 hdlr = new SetModeDeathHandler(cb, pid);
2293 }
2294 // Register for client death notification
2295 try {
2296 cb.linkToDeath(hdlr, 0);
2297 } catch (RemoteException e) {
2298 // Client has died!
2299 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
2300 }
2301
2302 // Last client to call setMode() is always at top of client list
2303 // as required by SetModeDeathHandler.binderDied()
2304 mSetModeDeathHandlers.add(0, hdlr);
2305 hdlr.setMode(mode);
2306 }
2307
2308 if (mode != mMode) {
2309 status = AudioSystem.setPhoneState(mode);
2310 if (status == AudioSystem.AUDIO_STATUS_OK) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002311 if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002312 mMode = mode;
2313 } else {
2314 if (hdlr != null) {
2315 mSetModeDeathHandlers.remove(hdlr);
2316 cb.unlinkToDeath(hdlr, 0);
2317 }
2318 // force reading new top of mSetModeDeathHandlers stack
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002319 if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002320 mode = AudioSystem.MODE_NORMAL;
2321 }
2322 } else {
2323 status = AudioSystem.AUDIO_STATUS_OK;
2324 }
2325 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
2326
2327 if (status == AudioSystem.AUDIO_STATUS_OK) {
2328 if (mode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002329 if (mSetModeDeathHandlers.isEmpty()) {
2330 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
2331 } else {
2332 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2333 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002334 }
2335 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002336 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07002337 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
John Spurlock90874332015-03-10 16:00:54 -04002338 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, caller);
Eric Laurent6d517662012-04-23 18:42:39 -07002339
John Spurlock90874332015-03-10 16:00:54 -04002340 updateStreamVolumeAlias(true /*updateVolumes*/, caller);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002341 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002342 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002343 }
2344
2345 /** @see AudioManager#getMode() */
2346 public int getMode() {
2347 return mMode;
2348 }
2349
Eric Laurente78fced2013-03-15 16:03:47 -07002350 //==========================================================================================
2351 // Sound Effects
2352 //==========================================================================================
2353
2354 private static final String TAG_AUDIO_ASSETS = "audio_assets";
2355 private static final String ATTR_VERSION = "version";
2356 private static final String TAG_GROUP = "group";
2357 private static final String ATTR_GROUP_NAME = "name";
2358 private static final String TAG_ASSET = "asset";
2359 private static final String ATTR_ASSET_ID = "id";
2360 private static final String ATTR_ASSET_FILE = "file";
2361
2362 private static final String ASSET_FILE_VERSION = "1.0";
2363 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
2364
Glenn Kasten167d1a22013-07-23 16:24:41 -07002365 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002366
2367 class LoadSoundEffectReply {
2368 public int mStatus = 1;
2369 };
2370
Eric Laurente78fced2013-03-15 16:03:47 -07002371 private void loadTouchSoundAssetDefaults() {
2372 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
2373 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
2374 SOUND_EFFECT_FILES_MAP[i][0] = 0;
2375 SOUND_EFFECT_FILES_MAP[i][1] = -1;
2376 }
2377 }
2378
2379 private void loadTouchSoundAssets() {
2380 XmlResourceParser parser = null;
2381
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002382 // only load assets once.
2383 if (!SOUND_EFFECT_FILES.isEmpty()) {
2384 return;
2385 }
2386
Eric Laurente78fced2013-03-15 16:03:47 -07002387 loadTouchSoundAssetDefaults();
2388
2389 try {
2390 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
2391
2392 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
2393 String version = parser.getAttributeValue(null, ATTR_VERSION);
2394 boolean inTouchSoundsGroup = false;
2395
2396 if (ASSET_FILE_VERSION.equals(version)) {
2397 while (true) {
2398 XmlUtils.nextElement(parser);
2399 String element = parser.getName();
2400 if (element == null) {
2401 break;
2402 }
2403 if (element.equals(TAG_GROUP)) {
2404 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
2405 if (GROUP_TOUCH_SOUNDS.equals(name)) {
2406 inTouchSoundsGroup = true;
2407 break;
2408 }
2409 }
2410 }
2411 while (inTouchSoundsGroup) {
2412 XmlUtils.nextElement(parser);
2413 String element = parser.getName();
2414 if (element == null) {
2415 break;
2416 }
2417 if (element.equals(TAG_ASSET)) {
2418 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
2419 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
2420 int fx;
2421
2422 try {
2423 Field field = AudioManager.class.getField(id);
2424 fx = field.getInt(null);
2425 } catch (Exception e) {
2426 Log.w(TAG, "Invalid touch sound ID: "+id);
2427 continue;
2428 }
2429
2430 int i = SOUND_EFFECT_FILES.indexOf(file);
2431 if (i == -1) {
2432 i = SOUND_EFFECT_FILES.size();
2433 SOUND_EFFECT_FILES.add(file);
2434 }
2435 SOUND_EFFECT_FILES_MAP[fx][0] = i;
2436 } else {
2437 break;
2438 }
2439 }
2440 }
2441 } catch (Resources.NotFoundException e) {
2442 Log.w(TAG, "audio assets file not found", e);
2443 } catch (XmlPullParserException e) {
2444 Log.w(TAG, "XML parser exception reading touch sound assets", e);
2445 } catch (IOException e) {
2446 Log.w(TAG, "I/O exception reading touch sound assets", e);
2447 } finally {
2448 if (parser != null) {
2449 parser.close();
2450 }
2451 }
2452 }
2453
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002454 /** @see AudioManager#playSoundEffect(int) */
2455 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002456 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002457 }
2458
2459 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002460 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07002461 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
2462 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
2463 return;
2464 }
2465
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002466 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002467 effectType, (int) (volume * 1000), null, 0);
2468 }
2469
2470 /**
2471 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08002472 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002473 */
2474 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002475 int attempts = 3;
2476 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08002477
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002478 synchronized (reply) {
2479 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
2480 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08002481 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07002482 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002483 } catch (InterruptedException e) {
2484 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08002485 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002486 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002487 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002488 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002489 }
2490
2491 /**
2492 * Unloads samples from the sound pool.
2493 * This method can be called to free some memory when
2494 * sound effects are disabled.
2495 */
2496 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002497 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002498 }
2499
Eric Laurenta60e2122010-12-28 16:49:07 -08002500 class SoundPoolListenerThread extends Thread {
2501 public SoundPoolListenerThread() {
2502 super("SoundPoolListenerThread");
2503 }
2504
2505 @Override
2506 public void run() {
2507
2508 Looper.prepare();
2509 mSoundPoolLooper = Looper.myLooper();
2510
2511 synchronized (mSoundEffectsLock) {
2512 if (mSoundPool != null) {
2513 mSoundPoolCallBack = new SoundPoolCallback();
2514 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2515 }
2516 mSoundEffectsLock.notify();
2517 }
2518 Looper.loop();
2519 }
2520 }
2521
2522 private final class SoundPoolCallback implements
2523 android.media.SoundPool.OnLoadCompleteListener {
2524
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002525 int mStatus = 1; // 1 means neither error nor last sample loaded yet
2526 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08002527
2528 public int status() {
2529 return mStatus;
2530 }
2531
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002532 public void setSamples(int[] samples) {
2533 for (int i = 0; i < samples.length; i++) {
2534 // do not wait ack for samples rejected upfront by SoundPool
2535 if (samples[i] > 0) {
2536 mSamples.add(samples[i]);
2537 }
2538 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002539 }
2540
2541 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2542 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002543 int i = mSamples.indexOf(sampleId);
2544 if (i >= 0) {
2545 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08002546 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002547 if ((status != 0) || mSamples. isEmpty()) {
2548 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08002549 mSoundEffectsLock.notify();
2550 }
2551 }
2552 }
2553 }
2554
Eric Laurent4050c932009-07-08 02:52:14 -07002555 /** @see AudioManager#reloadAudioSettings() */
2556 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002557 readAudioSettings(false /*userSwitch*/);
2558 }
2559
2560 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07002561 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2562 readPersistedSettings();
2563
2564 // restore volume settings
2565 int numStreamTypes = AudioSystem.getNumStreamTypes();
2566 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2567 VolumeStreamState streamState = mStreamStates[streamType];
2568
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002569 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2570 continue;
2571 }
2572
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002573 streamState.readSettings();
2574 synchronized (VolumeStreamState.class) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002575 // unmute stream that was muted but is not affect by mute anymore
RoboErik4197cb62015-01-21 15:45:32 -08002576 if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07002577 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
RoboErik4197cb62015-01-21 15:45:32 -08002578 streamState.mIsMuted = false;
Eric Laurent4050c932009-07-08 02:52:14 -07002579 }
Eric Laurent4050c932009-07-08 02:52:14 -07002580 }
2581 }
2582
Eric Laurent33902db2012-10-07 16:15:07 -07002583 // apply new ringer mode before checking volume for alias streams so that streams
2584 // muted by ringer mode have the correct volume
John Spurlock661f2cf2014-11-17 10:29:10 -05002585 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent33902db2012-10-07 16:15:07 -07002586
Eric Laurent212532b2014-07-21 15:43:18 -07002587 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07002588 checkAllAliasStreamVolumes();
John Spurlockb6e19e32015-03-10 21:33:44 -04002589 checkMuteAffectedStreams();
Eric Laurent24482012012-05-10 09:41:17 -07002590
Eric Laurentd640bd32012-09-28 18:01:48 -07002591 synchronized (mSafeMediaVolumeState) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002592 mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2593 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2594 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
Eric Laurentd640bd32012-09-28 18:01:48 -07002595 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
John Spurlock90874332015-03-10 16:00:54 -04002596 enforceSafeMediaVolume(TAG);
Eric Laurentf1a457d2012-09-20 16:27:23 -07002597 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07002598 }
Eric Laurent4050c932009-07-08 02:52:14 -07002599 }
2600
Dianne Hackborn961cae92013-03-20 14:59:43 -07002601 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002602 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002603 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2604 return;
2605 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002606
2607 if (on) {
2608 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2609 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2610 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
2611 }
2612 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2613 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2614 mForcedUseForComm = AudioSystem.FORCE_NONE;
2615 }
Eric Laurentfa640152011-03-12 15:59:51 -08002616
Eric Laurentafbb0472011-12-15 09:04:23 -08002617 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002618 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002619 }
2620
2621 /** @see AudioManager#isSpeakerphoneOn() */
2622 public boolean isSpeakerphoneOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002623 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002624 }
2625
Dianne Hackborn961cae92013-03-20 14:59:43 -07002626 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurent48221252015-09-24 18:41:48 -07002627 public void setBluetoothScoOn(boolean on) {
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002628 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2629 return;
2630 }
Eric Laurent48221252015-09-24 18:41:48 -07002631 setBluetoothScoOnInt(on);
2632 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002633
Eric Laurent48221252015-09-24 18:41:48 -07002634 public void setBluetoothScoOnInt(boolean on) {
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002635 if (on) {
2636 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2637 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2638 mForcedUseForComm = AudioSystem.FORCE_NONE;
2639 }
Eric Laurentfa640152011-03-12 15:59:51 -08002640
Eric Laurentafbb0472011-12-15 09:04:23 -08002641 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002642 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08002643 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002644 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002645 }
2646
2647 /** @see AudioManager#isBluetoothScoOn() */
2648 public boolean isBluetoothScoOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002649 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002650 }
2651
Dianne Hackborn961cae92013-03-20 14:59:43 -07002652 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07002653 public void setBluetoothA2dpOn(boolean on) {
Eric Laurentc390bed2012-07-03 12:24:05 -07002654 synchronized (mBluetoothA2dpEnabledLock) {
2655 mBluetoothA2dpEnabled = on;
2656 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2657 AudioSystem.FOR_MEDIA,
2658 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2659 null, 0);
2660 }
Eric Laurent78472112012-05-21 08:57:21 -07002661 }
2662
2663 /** @see AudioManager#isBluetoothA2dpOn() */
2664 public boolean isBluetoothA2dpOn() {
2665 synchronized (mBluetoothA2dpEnabledLock) {
2666 return mBluetoothA2dpEnabled;
2667 }
2668 }
2669
Eric Laurent3def1ee2010-03-17 23:26:26 -07002670 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07002671 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
2672 int scoAudioMode =
2673 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
Liejun Taof4e51d82014-07-16 11:18:29 -07002674 SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
Eric Laurent83900752014-05-15 15:14:22 -07002675 startBluetoothScoInt(cb, scoAudioMode);
2676 }
2677
2678 /** @see AudioManager#startBluetoothScoVirtualCall() */
2679 public void startBluetoothScoVirtualCall(IBinder cb) {
2680 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
2681 }
2682
2683 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07002684 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002685 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002686 return;
2687 }
Eric Laurent854938a2011-02-22 12:05:20 -08002688 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002689 // The calling identity must be cleared before calling ScoClient.incCount().
2690 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2691 // and this must be done on behalf of system server to make sure permissions are granted.
2692 // The caller identity must be cleared after getScoClient() because it is needed if a new
2693 // client is created.
2694 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07002695 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08002696 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002697 }
2698
2699 /** @see AudioManager#stopBluetoothSco() */
2700 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07002701 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002702 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002703 return;
2704 }
Eric Laurent854938a2011-02-22 12:05:20 -08002705 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002706 // The calling identity must be cleared before calling ScoClient.decCount().
2707 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2708 // and this must be done on behalf of system server to make sure permissions are granted.
2709 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08002710 if (client != null) {
2711 client.decCount();
2712 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08002713 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002714 }
2715
Eric Laurent78472112012-05-21 08:57:21 -07002716
Eric Laurent3def1ee2010-03-17 23:26:26 -07002717 private class ScoClient implements IBinder.DeathRecipient {
2718 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002719 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002720 private int mStartcount; // number of SCO connections started by this client
2721
2722 ScoClient(IBinder cb) {
2723 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002724 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002725 mStartcount = 0;
2726 }
2727
2728 public void binderDied() {
2729 synchronized(mScoClients) {
2730 Log.w(TAG, "SCO client died");
2731 int index = mScoClients.indexOf(this);
2732 if (index < 0) {
2733 Log.w(TAG, "unregistered SCO client died");
2734 } else {
2735 clearCount(true);
2736 mScoClients.remove(this);
2737 }
2738 }
2739 }
2740
Eric Laurent83900752014-05-15 15:14:22 -07002741 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002742 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07002743 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002744 if (mStartcount == 0) {
2745 try {
2746 mCb.linkToDeath(this, 0);
2747 } catch (RemoteException e) {
2748 // client has already died!
2749 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
2750 }
2751 }
2752 mStartcount++;
2753 }
2754 }
2755
2756 public void decCount() {
2757 synchronized(mScoClients) {
2758 if (mStartcount == 0) {
2759 Log.w(TAG, "ScoClient.decCount() already 0");
2760 } else {
2761 mStartcount--;
2762 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002763 try {
2764 mCb.unlinkToDeath(this, 0);
2765 } catch (NoSuchElementException e) {
2766 Log.w(TAG, "decCount() going to 0 but not registered to binder");
2767 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002768 }
Eric Laurentc18c9132013-04-12 17:24:56 -07002769 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002770 }
2771 }
2772 }
2773
2774 public void clearCount(boolean stopSco) {
2775 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002776 if (mStartcount != 0) {
2777 try {
2778 mCb.unlinkToDeath(this, 0);
2779 } catch (NoSuchElementException e) {
2780 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2781 }
2782 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002783 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002784 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002785 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002786 }
2787 }
2788 }
2789
2790 public int getCount() {
2791 return mStartcount;
2792 }
2793
2794 public IBinder getBinder() {
2795 return mCb;
2796 }
2797
Eric Laurentd7454be2011-09-14 08:45:58 -07002798 public int getPid() {
2799 return mCreatorPid;
2800 }
2801
Eric Laurent3def1ee2010-03-17 23:26:26 -07002802 public int totalCount() {
2803 synchronized(mScoClients) {
2804 int count = 0;
2805 int size = mScoClients.size();
2806 for (int i = 0; i < size; i++) {
2807 count += mScoClients.get(i).getCount();
2808 }
2809 return count;
2810 }
2811 }
2812
Eric Laurent83900752014-05-15 15:14:22 -07002813 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08002814 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07002815 if (totalCount() == 0) {
2816 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2817 // Make sure that the state transitions to CONNECTING even if we cannot initiate
2818 // the connection.
2819 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2820 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002821 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07002822 synchronized(mSetModeDeathHandlers) {
2823 if ((mSetModeDeathHandlers.isEmpty() ||
2824 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2825 (mScoAudioState == SCO_STATE_INACTIVE ||
2826 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2827 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07002828 mScoAudioMode = scoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -07002829 if (scoAudioMode == SCO_MODE_UNDEFINED) {
Andre Eisenbach570cc532014-10-28 17:03:18 -07002830 if (mBluetoothHeadsetDevice != null) {
2831 mScoAudioMode = new Integer(Settings.Global.getInt(
2832 mContentResolver,
2833 "bluetooth_sco_channel_"+
2834 mBluetoothHeadsetDevice.getAddress(),
2835 SCO_MODE_VIRTUAL_CALL));
2836 if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2837 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2838 }
2839 } else {
2840 mScoAudioMode = SCO_MODE_RAW;
Liejun Taof4e51d82014-07-16 11:18:29 -07002841 }
2842 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002843 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002844 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002845 if (mScoAudioMode == SCO_MODE_RAW) {
2846 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002847 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002848 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2849 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002850 } else if (mScoAudioMode == SCO_MODE_VR) {
2851 status = mBluetoothHeadset.startVoiceRecognition(
2852 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002853 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002854
Eric Laurentc18c9132013-04-12 17:24:56 -07002855 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07002856 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2857 } else {
2858 broadcastScoConnectionState(
2859 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2860 }
2861 } else if (getBluetoothHeadset()) {
2862 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07002863 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002864 } else {
2865 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2866 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002867 }
2868 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07002869 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002870 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002871 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002872 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002873 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2874 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2875 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07002876 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002877 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002878 if (mScoAudioMode == SCO_MODE_RAW) {
2879 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002880 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002881 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2882 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002883 } else if (mScoAudioMode == SCO_MODE_VR) {
2884 status = mBluetoothHeadset.stopVoiceRecognition(
2885 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002886 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002887
Eric Laurentc18c9132013-04-12 17:24:56 -07002888 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002889 mScoAudioState = SCO_STATE_INACTIVE;
2890 broadcastScoConnectionState(
2891 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2892 }
2893 } else if (getBluetoothHeadset()) {
2894 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2895 }
2896 } else {
2897 mScoAudioState = SCO_STATE_INACTIVE;
2898 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2899 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002900 }
2901 }
2902 }
2903 }
2904
Eric Laurent62ef7672010-11-24 10:58:32 -08002905 private void checkScoAudioState() {
2906 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002907 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08002908 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2909 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2910 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2911 }
2912 }
2913
Eric Laurent854938a2011-02-22 12:05:20 -08002914 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002915 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002916 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002917 int size = mScoClients.size();
2918 for (int i = 0; i < size; i++) {
2919 client = mScoClients.get(i);
2920 if (client.getBinder() == cb)
2921 return client;
2922 }
Eric Laurent854938a2011-02-22 12:05:20 -08002923 if (create) {
2924 client = new ScoClient(cb);
2925 mScoClients.add(client);
2926 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002927 return client;
2928 }
2929 }
2930
Eric Laurentd7454be2011-09-14 08:45:58 -07002931 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002932 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002933 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002934 int size = mScoClients.size();
2935 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08002936 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07002937 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08002938 cl.clearCount(stopSco);
2939 } else {
2940 savedClient = cl;
2941 }
2942 }
2943 mScoClients.clear();
2944 if (savedClient != null) {
2945 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002946 }
2947 }
2948 }
2949
Eric Laurentdc03c612011-04-01 10:59:41 -07002950 private boolean getBluetoothHeadset() {
2951 boolean result = false;
2952 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2953 if (adapter != null) {
2954 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2955 BluetoothProfile.HEADSET);
2956 }
2957 // If we could not get a bluetooth headset proxy, send a failure message
2958 // without delay to reset the SCO audio state and clear SCO clients.
2959 // If we could get a proxy, send a delayed failure message that will reset our state
2960 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08002961 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002962 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2963 return result;
2964 }
2965
Eric Laurentd7454be2011-09-14 08:45:58 -07002966 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002967 synchronized(mScoClients) {
2968 checkScoAudioState();
2969 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2970 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2971 if (mBluetoothHeadsetDevice != null) {
2972 if (mBluetoothHeadset != null) {
2973 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07002974 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002975 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002976 SENDMSG_REPLACE, 0, 0, null, 0);
2977 }
2978 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2979 getBluetoothHeadset()) {
2980 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2981 }
2982 }
2983 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07002984 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07002985 }
2986 }
2987 }
2988
2989 private void resetBluetoothSco() {
2990 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002991 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07002992 mScoAudioState = SCO_STATE_INACTIVE;
2993 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2994 }
Eric Laurent48221252015-09-24 18:41:48 -07002995 AudioSystem.setParameters("A2dpSuspended=false");
2996 setBluetoothScoOnInt(false);
Eric Laurentdc03c612011-04-01 10:59:41 -07002997 }
2998
2999 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08003000 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
3001 SENDMSG_QUEUE, state, 0, null, 0);
3002 }
3003
3004 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07003005 if (state != mScoConnectionState) {
3006 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
3007 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
3008 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
3009 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003010 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07003011 mScoConnectionState = state;
3012 }
3013 }
3014
Eric Laurent98859b22015-06-12 14:35:59 -07003015 void setBtScoDeviceConnectionState(BluetoothDevice btDevice, int state) {
3016 if (btDevice == null) {
3017 return;
3018 }
3019
3020 String address = btDevice.getAddress();
3021 BluetoothClass btClass = btDevice.getBluetoothClass();
3022 int outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
3023 int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
3024 if (btClass != null) {
3025 switch (btClass.getDeviceClass()) {
3026 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
3027 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
3028 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
3029 break;
3030 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
3031 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
3032 break;
3033 }
3034 }
3035
3036 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
3037 address = "";
3038 }
3039
3040 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
3041
3042 String btDeviceName = btDevice.getName();
3043 boolean success =
3044 handleDeviceConnection(connected, outDevice, address, btDeviceName) &&
3045 handleDeviceConnection(connected, inDevice, address, btDeviceName);
3046 if (success) {
3047 synchronized (mScoClients) {
3048 if (connected) {
3049 mBluetoothHeadsetDevice = btDevice;
3050 } else {
3051 mBluetoothHeadsetDevice = null;
3052 resetBluetoothSco();
3053 }
3054 }
3055 }
3056 }
3057
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07003058 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
3059 new BluetoothProfile.ServiceListener() {
3060 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003061 BluetoothDevice btDevice;
3062 List<BluetoothDevice> deviceList;
3063 switch(profile) {
3064 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09003065 synchronized (mConnectedDevices) {
3066 synchronized (mA2dpAvrcpLock) {
3067 mA2dp = (BluetoothA2dp) proxy;
3068 deviceList = mA2dp.getConnectedDevices();
3069 if (deviceList.size() > 0) {
3070 btDevice = deviceList.get(0);
John Du5a0cf7a2013-07-19 11:30:34 -07003071 int state = mA2dp.getConnectionState(btDevice);
3072 int delay = checkSendBecomingNoisyIntent(
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003073 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3074 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
John Du5a0cf7a2013-07-19 11:30:34 -07003075 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003076 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07003077 state,
3078 0,
3079 btDevice,
3080 delay);
3081 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003082 }
Eric Laurent62ef7672010-11-24 10:58:32 -08003083 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003084 break;
3085
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003086 case BluetoothProfile.A2DP_SINK:
3087 deviceList = proxy.getConnectedDevices();
3088 if (deviceList.size() > 0) {
3089 btDevice = deviceList.get(0);
3090 synchronized (mConnectedDevices) {
3091 int state = proxy.getConnectionState(btDevice);
3092 queueMsgUnderWakeLock(mAudioHandler,
3093 MSG_SET_A2DP_SRC_CONNECTION_STATE,
3094 state,
3095 0,
3096 btDevice,
3097 0 /* delay */);
3098 }
3099 }
3100 break;
3101
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003102 case BluetoothProfile.HEADSET:
3103 synchronized (mScoClients) {
3104 // Discard timeout message
3105 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
3106 mBluetoothHeadset = (BluetoothHeadset) proxy;
3107 deviceList = mBluetoothHeadset.getConnectedDevices();
3108 if (deviceList.size() > 0) {
3109 mBluetoothHeadsetDevice = deviceList.get(0);
3110 } else {
3111 mBluetoothHeadsetDevice = null;
3112 }
3113 // Refresh SCO audio state
3114 checkScoAudioState();
3115 // Continue pending action if any
3116 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
3117 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
3118 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
3119 boolean status = false;
3120 if (mBluetoothHeadsetDevice != null) {
3121 switch (mScoAudioState) {
3122 case SCO_STATE_ACTIVATE_REQ:
3123 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07003124 if (mScoAudioMode == SCO_MODE_RAW) {
3125 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003126 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003127 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
3128 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003129 } else if (mScoAudioMode == SCO_MODE_VR) {
3130 status = mBluetoothHeadset.startVoiceRecognition(
3131 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003132 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003133 break;
3134 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07003135 if (mScoAudioMode == SCO_MODE_RAW) {
3136 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003137 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003138 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
3139 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003140 } else if (mScoAudioMode == SCO_MODE_VR) {
3141 status = mBluetoothHeadset.stopVoiceRecognition(
3142 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003143 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003144 break;
3145 case SCO_STATE_DEACTIVATE_EXT_REQ:
3146 status = mBluetoothHeadset.stopVoiceRecognition(
3147 mBluetoothHeadsetDevice);
3148 }
3149 }
3150 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08003151 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003152 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07003153 }
3154 }
Eric Laurentdc03c612011-04-01 10:59:41 -07003155 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003156 break;
3157
3158 default:
3159 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003160 }
3161 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07003162 public void onServiceDisconnected(int profile) {
John Spurlock8c3dc852015-04-23 21:32:37 -04003163 ArraySet<String> toRemove = null;
Paul McLean394a8e12015-03-03 10:29:19 -07003164 switch (profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003165 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09003166 synchronized (mConnectedDevices) {
3167 synchronized (mA2dpAvrcpLock) {
Paul McLean394a8e12015-03-03 10:29:19 -07003168 // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
John Spurlock8c3dc852015-04-23 21:32:37 -04003169 for (int i = 0; i < mConnectedDevices.size(); i++) {
3170 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
Paul McLean394a8e12015-03-03 10:29:19 -07003171 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
John Spurlock8c3dc852015-04-23 21:32:37 -04003172 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
3173 toRemove.add(deviceSpec.mDeviceAddress);
3174 }
3175 }
3176 if (toRemove != null) {
Eric Laurentd138e4e2015-05-15 16:41:15 -07003177 int delay = checkSendBecomingNoisyIntent(
3178 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3179 0);
John Spurlock8c3dc852015-04-23 21:32:37 -04003180 for (int i = 0; i < toRemove.size(); i++) {
Eric Laurentd138e4e2015-05-15 16:41:15 -07003181 makeA2dpDeviceUnavailableLater(toRemove.valueAt(i), delay);
Paul McLean394a8e12015-03-03 10:29:19 -07003182 }
John Du5a0cf7a2013-07-19 11:30:34 -07003183 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003184 }
3185 }
3186 break;
3187
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003188 case BluetoothProfile.A2DP_SINK:
3189 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07003190 // Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
John Spurlock8c3dc852015-04-23 21:32:37 -04003191 for(int i = 0; i < mConnectedDevices.size(); i++) {
3192 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
Paul McLean394a8e12015-03-03 10:29:19 -07003193 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) {
John Spurlock8c3dc852015-04-23 21:32:37 -04003194 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
3195 toRemove.add(deviceSpec.mDeviceAddress);
3196 }
3197 }
3198 if (toRemove != null) {
3199 for (int i = 0; i < toRemove.size(); i++) {
3200 makeA2dpSrcUnavailable(toRemove.valueAt(i));
Paul McLean394a8e12015-03-03 10:29:19 -07003201 }
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003202 }
3203 }
3204 break;
3205
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003206 case BluetoothProfile.HEADSET:
3207 synchronized (mScoClients) {
Eric Laurent98859b22015-06-12 14:35:59 -07003208 if (mBluetoothHeadsetDevice != null) {
3209 setBtScoDeviceConnectionState(mBluetoothHeadsetDevice,
3210 BluetoothProfile.STATE_DISCONNECTED);
3211 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003212 mBluetoothHeadset = null;
3213 }
3214 break;
3215
3216 default:
3217 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003218 }
3219 }
3220 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003221
John Spurlock90874332015-03-10 16:00:54 -04003222 private void onCheckMusicActive(String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07003223 synchronized (mSafeMediaVolumeState) {
3224 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07003225 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
3226
3227 if ((device & mSafeMediaVolumeDevices) != 0) {
3228 sendMsg(mAudioHandler,
3229 MSG_CHECK_MUSIC_ACTIVE,
3230 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07003231 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07003232 0,
John Spurlock90874332015-03-10 16:00:54 -04003233 caller,
Eric Laurentc34dcc12012-09-10 13:51:52 -07003234 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07003235 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07003236 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
3237 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07003238 // Approximate cumulative active music time
3239 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
3240 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
John Spurlock90874332015-03-10 16:00:54 -04003241 setSafeMediaVolumeEnabled(true, caller);
Eric Laurentc34dcc12012-09-10 13:51:52 -07003242 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07003243 }
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003244 saveMusicActiveMs();
Eric Laurentc34dcc12012-09-10 13:51:52 -07003245 }
3246 }
3247 }
3248 }
3249 }
3250
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003251 private void saveMusicActiveMs() {
3252 mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
3253 }
3254
John Spurlock90874332015-03-10 16:00:54 -04003255 private void onConfigureSafeVolume(boolean force, String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07003256 synchronized (mSafeMediaVolumeState) {
3257 int mcc = mContext.getResources().getConfiguration().mcc;
3258 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
3259 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
3260 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
John Spurlock35134602014-07-24 18:10:48 -04003261 boolean safeMediaVolumeEnabled =
3262 SystemProperties.getBoolean("audio.safemedia.force", false)
3263 || mContext.getResources().getBoolean(
3264 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08003265
Ricardo Garcia3a30a762015-06-23 15:54:45 -07003266 boolean safeMediaVolumeBypass =
3267 SystemProperties.getBoolean("audio.safemedia.bypass", false);
3268
Eric Laurent05274f32012-11-29 12:48:18 -08003269 // The persisted state is either "disabled" or "active": this is the state applied
3270 // next time we boot and cannot be "inactive"
3271 int persistedState;
Ricardo Garcia3a30a762015-06-23 15:54:45 -07003272 if (safeMediaVolumeEnabled && !safeMediaVolumeBypass) {
Eric Laurent05274f32012-11-29 12:48:18 -08003273 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
3274 // The state can already be "inactive" here if the user has forced it before
3275 // the 30 seconds timeout for forced configuration. In this case we don't reset
3276 // it to "active".
3277 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003278 if (mMusicActiveMs == 0) {
3279 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
John Spurlock90874332015-03-10 16:00:54 -04003280 enforceSafeMediaVolume(caller);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003281 } else {
3282 // We have existing playback time recorded, already confirmed.
3283 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
3284 }
Eric Laurent05274f32012-11-29 12:48:18 -08003285 }
Eric Laurentd640bd32012-09-28 18:01:48 -07003286 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08003287 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07003288 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
3289 }
3290 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08003291 sendMsg(mAudioHandler,
3292 MSG_PERSIST_SAFE_VOLUME_STATE,
3293 SENDMSG_QUEUE,
3294 persistedState,
3295 0,
3296 null,
3297 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07003298 }
3299 }
3300 }
3301
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003302 ///////////////////////////////////////////////////////////////////////////
3303 // Internal methods
3304 ///////////////////////////////////////////////////////////////////////////
3305
3306 /**
3307 * Checks if the adjustment should change ringer mode instead of just
3308 * adjusting volume. If so, this will set the proper ringer mode and volume
3309 * indices on the stream states.
3310 */
John Spurlocka48d7792015-03-03 17:35:57 -05003311 private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted) {
3312 final boolean isTv = mPlatformType == AudioSystem.PLATFORM_TELEVISION;
John Spurlocka11b4af2014-06-01 11:52:23 -04003313 int result = FLAG_ADJUST_VOLUME;
John Spurlock661f2cf2014-11-17 10:29:10 -05003314 int ringerMode = getRingerModeInternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003315
Eric Laurentbffc3d12012-05-07 17:43:49 -07003316 switch (ringerMode) {
3317 case RINGER_MODE_NORMAL:
3318 if (direction == AudioManager.ADJUST_LOWER) {
3319 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07003320 // "step" is the delta in internal index units corresponding to a
3321 // change of 1 in UI index units.
3322 // Because of rounding when rescaling from one stream index range to its alias
3323 // index range, we cannot simply test oldIndex == step:
3324 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
3325 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003326 ringerMode = RINGER_MODE_VIBRATE;
John Spurlock07e72432015-03-13 11:46:52 -04003327 mLoweredFromNormalToVibrateTime = SystemClock.uptimeMillis();
Eric Laurentbffc3d12012-05-07 17:43:49 -07003328 }
3329 } else {
John Spurlockd9c75db2015-04-28 11:19:13 -04003330 if (oldIndex == step && mVolumePolicy.volumeDownToEnterSilent) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003331 ringerMode = RINGER_MODE_SILENT;
3332 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07003333 }
John Spurlocka48d7792015-03-03 17:35:57 -05003334 } else if (isTv && (direction == AudioManager.ADJUST_TOGGLE_MUTE
3335 || direction == AudioManager.ADJUST_MUTE)) {
RoboErik5452e252015-02-06 15:33:53 -08003336 if (mHasVibrator) {
3337 ringerMode = RINGER_MODE_VIBRATE;
3338 } else {
3339 ringerMode = RINGER_MODE_SILENT;
3340 }
3341 // Setting the ringer mode will toggle mute
3342 result &= ~FLAG_ADJUST_VOLUME;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003343 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003344 break;
3345 case RINGER_MODE_VIBRATE:
3346 if (!mHasVibrator) {
3347 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
3348 "but no vibrator is present");
3349 break;
3350 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003351 if ((direction == AudioManager.ADJUST_LOWER)) {
RoboErik5452e252015-02-06 15:33:53 -08003352 // This is the case we were muted with the volume turned up
John Spurlocka48d7792015-03-03 17:35:57 -05003353 if (isTv && oldIndex >= 2 * step && isMuted) {
RoboErik5452e252015-02-06 15:33:53 -08003354 ringerMode = RINGER_MODE_NORMAL;
3355 } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
John Spurlocka48d7792015-03-03 17:35:57 -05003356 if (mVolumePolicy.volumeDownToEnterSilent) {
John Spurlock07e72432015-03-13 11:46:52 -04003357 final long diff = SystemClock.uptimeMillis()
3358 - mLoweredFromNormalToVibrateTime;
John Spurlockd9c75db2015-04-28 11:19:13 -04003359 if (diff > mVolumePolicy.vibrateToSilentDebounce
3360 && mRingerModeDelegate.canVolumeDownEnterSilent()) {
John Spurlock07e72432015-03-13 11:46:52 -04003361 ringerMode = RINGER_MODE_SILENT;
3362 }
John Spurlock795a5142014-12-08 14:09:35 -05003363 } else {
3364 result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
3365 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003366 }
RoboErik5452e252015-02-06 15:33:53 -08003367 } else if (direction == AudioManager.ADJUST_RAISE
3368 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3369 || direction == AudioManager.ADJUST_UNMUTE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003370 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07003371 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003372 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003373 break;
3374 case RINGER_MODE_SILENT:
John Spurlocka48d7792015-03-03 17:35:57 -05003375 if (isTv && direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
RoboErik5452e252015-02-06 15:33:53 -08003376 // This is the case we were muted with the volume turned up
3377 ringerMode = RINGER_MODE_NORMAL;
3378 } else if (direction == AudioManager.ADJUST_RAISE
3379 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3380 || direction == AudioManager.ADJUST_UNMUTE) {
John Spurlocka48d7792015-03-03 17:35:57 -05003381 if (!mVolumePolicy.volumeUpToExitSilent) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003382 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003383 } else {
RoboErik5452e252015-02-06 15:33:53 -08003384 if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003385 ringerMode = RINGER_MODE_VIBRATE;
3386 } else {
RoboErik5452e252015-02-06 15:33:53 -08003387 // If we don't have a vibrator or they were toggling mute
3388 // go straight back to normal.
John Spurlocka11b4af2014-06-01 11:52:23 -04003389 ringerMode = RINGER_MODE_NORMAL;
3390 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003391 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05003392 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003393 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003394 break;
3395 default:
3396 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
3397 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003398 }
3399
John Spurlock661f2cf2014-11-17 10:29:10 -05003400 setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003401
Eric Laurent25101b02011-02-02 09:33:30 -08003402 mPrevVolDirection = direction;
3403
John Spurlocka11b4af2014-06-01 11:52:23 -04003404 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003405 }
3406
John Spurlock3346a802014-05-20 16:25:37 -04003407 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003408 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07003409 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003410 }
3411
Eric Laurent5b4e6542010-03-19 20:02:21 -07003412 private boolean isStreamMutedByRingerMode(int streamType) {
3413 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
3414 }
3415
John Spurlock50ced3f2015-05-11 16:00:09 -04003416 private boolean updateRingerModeAffectedStreams() {
3417 int ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003418 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3419 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
3420 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
3421 UserHandle.USER_CURRENT);
3422
John Spurlock50ced3f2015-05-11 16:00:09 -04003423 if (mPlatformType == AudioSystem.PLATFORM_TELEVISION) {
3424 ringerModeAffectedStreams = 0;
3425 } else if (mRingerModeDelegate != null) {
3426 ringerModeAffectedStreams = mRingerModeDelegate
3427 .getRingerModeAffectedStreams(ringerModeAffectedStreams);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003428 }
3429 synchronized (mCameraSoundForced) {
3430 if (mCameraSoundForced) {
3431 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3432 } else {
3433 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3434 }
3435 }
3436 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
3437 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
3438 } else {
3439 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
3440 }
3441
3442 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3443 Settings.System.putIntForUser(mContentResolver,
3444 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3445 ringerModeAffectedStreams,
3446 UserHandle.USER_CURRENT);
3447 mRingerModeAffectedStreams = ringerModeAffectedStreams;
3448 return true;
3449 }
3450 return false;
3451 }
3452
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05003453 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003454 public boolean isStreamAffectedByMute(int streamType) {
3455 return (mMuteAffectedStreams & (1 << streamType)) != 0;
3456 }
3457
3458 private void ensureValidDirection(int direction) {
RoboErik4197cb62015-01-21 15:45:32 -08003459 switch (direction) {
3460 case AudioManager.ADJUST_LOWER:
3461 case AudioManager.ADJUST_RAISE:
3462 case AudioManager.ADJUST_SAME:
3463 case AudioManager.ADJUST_MUTE:
3464 case AudioManager.ADJUST_UNMUTE:
3465 case AudioManager.ADJUST_TOGGLE_MUTE:
3466 break;
3467 default:
3468 throw new IllegalArgumentException("Bad direction " + direction);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003469 }
3470 }
3471
3472 private void ensureValidStreamType(int streamType) {
3473 if (streamType < 0 || streamType >= mStreamStates.length) {
3474 throw new IllegalArgumentException("Bad stream type " + streamType);
3475 }
3476 }
3477
RoboErik4197cb62015-01-21 15:45:32 -08003478 private boolean isMuteAdjust(int adjust) {
3479 return adjust == AudioManager.ADJUST_MUTE || adjust == AudioManager.ADJUST_UNMUTE
3480 || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
3481 }
3482
Eric Laurent6d517662012-04-23 18:42:39 -07003483 private boolean isInCommunication() {
Nancy Chen0eb1e402014-08-21 22:52:29 -07003484 boolean IsInCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003485
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003486 TelecomManager telecomManager =
3487 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
Eric Laurent38edfda2014-12-18 17:38:04 -08003488
3489 final long ident = Binder.clearCallingIdentity();
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003490 IsInCall = telecomManager.isInCall();
Eric Laurent38edfda2014-12-18 17:38:04 -08003491 Binder.restoreCallingIdentity(ident);
Santos Cordon9eb45932014-06-27 12:28:43 -07003492
Nancy Chen0eb1e402014-08-21 22:52:29 -07003493 return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
Eric Laurent6d517662012-04-23 18:42:39 -07003494 }
Eric Laurent25101b02011-02-02 09:33:30 -08003495
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003496 /**
3497 * For code clarity for getActiveStreamType(int)
3498 * @param delay_ms max time since last STREAM_MUSIC activity to consider
3499 * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
3500 * in the last "delay_ms" ms.
3501 */
3502 private boolean isAfMusicActiveRecently(int delay_ms) {
3503 return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
3504 || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
3505 }
3506
Eric Laurent6d517662012-04-23 18:42:39 -07003507 private int getActiveStreamType(int suggestedStreamType) {
Eric Laurent212532b2014-07-21 15:43:18 -07003508 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003509 case AudioSystem.PLATFORM_VOICE:
Eric Laurent6d517662012-04-23 18:42:39 -07003510 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003511 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3512 == AudioSystem.FORCE_BT_SCO) {
3513 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
3514 return AudioSystem.STREAM_BLUETOOTH_SCO;
3515 } else {
3516 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
3517 return AudioSystem.STREAM_VOICE_CALL;
3518 }
Eric Laurent25101b02011-02-02 09:33:30 -08003519 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003520 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003521 if (DEBUG_VOL)
3522 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3523 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003524 } else {
3525 if (DEBUG_VOL)
3526 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
3527 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003528 }
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003529 } else if (isAfMusicActiveRecently(0)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003530 if (DEBUG_VOL)
3531 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3532 return AudioSystem.STREAM_MUSIC;
Eric Laurent25101b02011-02-02 09:33:30 -08003533 }
Eric Laurent212532b2014-07-21 15:43:18 -07003534 break;
John Spurlock61560172015-02-06 19:46:04 -05003535 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -07003536 if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
RoboErik2811dd32014-08-12 09:48:13 -07003537 // TV always defaults to STREAM_MUSIC
Eric Laurent212532b2014-07-21 15:43:18 -07003538 return AudioSystem.STREAM_MUSIC;
Eric Laurent212532b2014-07-21 15:43:18 -07003539 }
3540 break;
3541 default:
Eric Laurent6d517662012-04-23 18:42:39 -07003542 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003543 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3544 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003545 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08003546 return AudioSystem.STREAM_BLUETOOTH_SCO;
3547 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003548 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08003549 return AudioSystem.STREAM_VOICE_CALL;
3550 }
3551 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003552 StreamOverride.sDelayMs) ||
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003553 AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003554 StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003555 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08003556 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003557 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003558 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003559 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
3560 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003561 } else {
John Spurlockeb1d88d2014-07-19 14:49:19 -04003562 if (DEBUG_VOL) Log.v(TAG,
3563 "getActiveStreamType: using STREAM_NOTIFICATION as default");
3564 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003565 }
Joe Onoratoc7fcba42011-01-05 16:53:11 -08003566 }
Eric Laurent212532b2014-07-21 15:43:18 -07003567 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003568 }
Eric Laurent212532b2014-07-21 15:43:18 -07003569 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
3570 + suggestedStreamType);
3571 return suggestedStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003572 }
3573
John Spurlockbcc10872014-11-28 15:29:21 -05003574 private void broadcastRingerMode(String action, int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003575 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05003576 Intent broadcast = new Intent(action);
Glenn Kastenba195eb2011-12-13 09:30:40 -08003577 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003578 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
3579 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003580 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003581 }
3582
3583 private void broadcastVibrateSetting(int vibrateType) {
3584 // Send broadcast
3585 if (ActivityManagerNative.isSystemReady()) {
3586 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
3587 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
3588 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003589 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003590 }
3591 }
3592
3593 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003594 /**
3595 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
3596 * Note that the wake lock needs to be released after the message has been handled.
3597 */
3598 private void queueMsgUnderWakeLock(Handler handler, int msg,
3599 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003600 final long ident = Binder.clearCallingIdentity();
3601 // Always acquire the wake lock as AudioService because it is released by the
3602 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003603 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003604 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003605 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
3606 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003607
Eric Laurentafbb0472011-12-15 09:04:23 -08003608 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003609 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003610
3611 if (existingMsgPolicy == SENDMSG_REPLACE) {
3612 handler.removeMessages(msg);
3613 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
3614 return;
3615 }
Eric Laurentadbe8bf2014-11-03 18:26:32 -08003616 synchronized (mLastDeviceConnectMsgTime) {
3617 long time = SystemClock.uptimeMillis() + delay;
3618 handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
3619 if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
3620 msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
3621 msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
3622 mLastDeviceConnectMsgTime = time;
3623 }
3624 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003625 }
3626
3627 boolean checkAudioSettingsPermission(String method) {
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07003628 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003629 == PackageManager.PERMISSION_GRANTED) {
3630 return true;
3631 }
3632 String msg = "Audio Settings Permission Denial: " + method + " from pid="
3633 + Binder.getCallingPid()
3634 + ", uid=" + Binder.getCallingUid();
3635 Log.w(TAG, msg);
3636 return false;
3637 }
3638
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003639 private int getDeviceForStream(int stream) {
John Spurlock8a52c442015-03-26 14:23:58 -04003640 int device = getDevicesForStream(stream);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003641 if ((device & (device - 1)) != 0) {
3642 // Multiple device selection is either:
3643 // - speaker + one other device: give priority to speaker in this case.
3644 // - one A2DP device + another device: happens with duplicated output. In this case
3645 // retain the device on the A2DP output as the other must not correspond to an active
3646 // selection if not the speaker.
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003647 // - HDMI-CEC system audio mode only output: give priority to available item in order.
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003648 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
3649 device = AudioSystem.DEVICE_OUT_SPEAKER;
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003650 } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
3651 device = AudioSystem.DEVICE_OUT_HDMI_ARC;
3652 } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
3653 device = AudioSystem.DEVICE_OUT_SPDIF;
3654 } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
3655 device = AudioSystem.DEVICE_OUT_AUX_LINE;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003656 } else {
3657 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
3658 }
3659 }
3660 return device;
3661 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003662
John Spurlock8a52c442015-03-26 14:23:58 -04003663 private int getDevicesForStream(int stream) {
3664 return getDevicesForStream(stream, true /*checkOthers*/);
3665 }
3666
3667 private int getDevicesForStream(int stream, boolean checkOthers) {
3668 ensureValidStreamType(stream);
3669 synchronized (VolumeStreamState.class) {
3670 return mStreamStates[stream].observeDevicesForStream_syncVSS(checkOthers);
3671 }
3672 }
3673
3674 private void observeDevicesForStreams(int skipStream) {
3675 synchronized (VolumeStreamState.class) {
3676 for (int stream = 0; stream < mStreamStates.length; stream++) {
3677 if (stream != skipStream) {
3678 mStreamStates[stream].observeDevicesForStream_syncVSS(false /*checkOthers*/);
3679 }
3680 }
3681 }
3682 }
3683
Paul McLean10804eb2015-01-28 11:16:35 -08003684 /*
3685 * A class just for packaging up a set of connection parameters.
3686 */
3687 private class WiredDeviceConnectionState {
John Spurlock90874332015-03-10 16:00:54 -04003688 public final int mType;
3689 public final int mState;
3690 public final String mAddress;
3691 public final String mName;
3692 public final String mCaller;
Paul McLean10804eb2015-01-28 11:16:35 -08003693
John Spurlock90874332015-03-10 16:00:54 -04003694 public WiredDeviceConnectionState(int type, int state, String address, String name,
3695 String caller) {
Paul McLean10804eb2015-01-28 11:16:35 -08003696 mType = type;
3697 mState = state;
3698 mAddress = address;
3699 mName = name;
John Spurlock90874332015-03-10 16:00:54 -04003700 mCaller = caller;
Paul McLean10804eb2015-01-28 11:16:35 -08003701 }
3702 }
3703
John Spurlock90874332015-03-10 16:00:54 -04003704 public void setWiredDeviceConnectionState(int type, int state, String address, String name,
3705 String caller) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003706 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07003707 if (DEBUG_DEVICES) {
3708 Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
3709 + address + ")");
3710 }
Paul McLean10804eb2015-01-28 11:16:35 -08003711 int delay = checkSendBecomingNoisyIntent(type, state);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003712 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003713 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Paul McLean10804eb2015-01-28 11:16:35 -08003714 0,
3715 0,
John Spurlock90874332015-03-10 16:00:54 -04003716 new WiredDeviceConnectionState(type, state, address, name, caller),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003717 delay);
3718 }
3719 }
3720
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003721 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003722 {
3723 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003724 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
3725 throw new IllegalArgumentException("invalid profile " + profile);
3726 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003727 synchronized (mConnectedDevices) {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003728 if (profile == BluetoothProfile.A2DP) {
3729 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3730 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
3731 } else {
3732 delay = 0;
3733 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003734 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003735 (profile == BluetoothProfile.A2DP ?
3736 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003737 state,
3738 0,
3739 device,
3740 delay);
3741 }
3742 return delay;
3743 }
3744
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003745 ///////////////////////////////////////////////////////////////////////////
3746 // Inner classes
3747 ///////////////////////////////////////////////////////////////////////////
3748
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003749 // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
3750 // 1 mScoclient OR mSafeMediaVolumeState
3751 // 2 mSetModeDeathHandlers
3752 // 3 mSettingsLock
3753 // 4 VolumeStreamState.class
3754 // 5 mCameraSoundForced
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003755 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003756 private final int mStreamType;
John Spurlockb6e19e32015-03-10 21:33:44 -04003757 private final int mIndexMin;
3758 private final int mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003759
RoboErik4197cb62015-01-21 15:45:32 -08003760 private boolean mIsMuted;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003761 private String mVolumeIndexSettingName;
John Spurlock8a52c442015-03-26 14:23:58 -04003762 private int mObservedDevices;
John Spurlockb6e19e32015-03-10 21:33:44 -04003763
John Spurlock2bb02ec2015-03-02 13:13:06 -05003764 private final SparseIntArray mIndexMap = new SparseIntArray(8);
John Spurlockf63860c2015-02-19 09:46:27 -05003765 private final Intent mVolumeChanged;
John Spurlock8a52c442015-03-26 14:23:58 -04003766 private final Intent mStreamDevicesChanged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003767
Eric Laurenta553c252009-07-17 12:17:14 -07003768 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003769
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003770 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003771
3772 mStreamType = streamType;
John Spurlockb6e19e32015-03-10 21:33:44 -04003773 mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;
3774 mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;
3775 AudioSystem.initStreamVolume(streamType, mIndexMin / 10, mIndexMax / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003776
Eric Laurent33902db2012-10-07 16:15:07 -07003777 readSettings();
John Spurlockf63860c2015-02-19 09:46:27 -05003778 mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
3779 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
John Spurlock8a52c442015-03-26 14:23:58 -04003780 mStreamDevicesChanged = new Intent(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
3781 mStreamDevicesChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
3782 }
3783
3784 public int observeDevicesForStream_syncVSS(boolean checkOthers) {
3785 final int devices = AudioSystem.getDevicesForStream(mStreamType);
3786 if (devices == mObservedDevices) {
3787 return devices;
3788 }
3789 final int prevDevices = mObservedDevices;
3790 mObservedDevices = devices;
3791 if (checkOthers) {
3792 // one stream's devices have changed, check the others
3793 observeDevicesForStreams(mStreamType);
3794 }
3795 // log base stream changes to the event log
3796 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
3797 EventLogTags.writeStreamDevicesChanged(mStreamType, prevDevices, devices);
3798 }
3799 sendBroadcastToAll(mStreamDevicesChanged
3800 .putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, prevDevices)
3801 .putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, devices));
3802 return devices;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003803 }
3804
Eric Laurent42b041e2013-03-29 11:36:03 -07003805 public String getSettingNameForDevice(int device) {
3806 String name = mVolumeIndexSettingName;
Eric Laurent948d3272014-05-16 15:18:45 -07003807 String suffix = AudioSystem.getOutputDeviceName(device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003808 if (suffix.isEmpty()) {
3809 return name;
3810 }
3811 return name + "_" + suffix;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003812 }
3813
Eric Laurentfdbee862014-05-12 15:26:12 -07003814 public void readSettings() {
3815 synchronized (VolumeStreamState.class) {
John Spurlockee5ad722015-03-03 16:17:21 -05003816 // force maximum volume on all streams if fixed volume property is set
3817 if (mUseFixedVolume) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003818 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07003819 return;
3820 }
3821 // do not read system stream volume from settings: this stream is always aliased
3822 // to another stream type and its volume is never persisted. Values in settings can
3823 // only be stale values
3824 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3825 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
John Spurlock61560172015-02-06 19:46:04 -05003826 int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
Eric Laurentfdbee862014-05-12 15:26:12 -07003827 synchronized (mCameraSoundForced) {
3828 if (mCameraSoundForced) {
3829 index = mIndexMax;
3830 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003831 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003832 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003833 return;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003834 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003835
Eric Laurentfdbee862014-05-12 15:26:12 -07003836 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
3837
3838 for (int i = 0; remainingDevices != 0; i++) {
3839 int device = (1 << i);
3840 if ((device & remainingDevices) == 0) {
3841 continue;
3842 }
3843 remainingDevices &= ~device;
3844
3845 // retrieve current volume for device
3846 String name = getSettingNameForDevice(device);
3847 // if no volume stored for current stream and device, use default volume if default
3848 // device, continue otherwise
3849 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
John Spurlock61560172015-02-06 19:46:04 -05003850 AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
Eric Laurentfdbee862014-05-12 15:26:12 -07003851 int index = Settings.System.getIntForUser(
3852 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3853 if (index == -1) {
3854 continue;
3855 }
3856
John Spurlock2bb02ec2015-03-02 13:13:06 -05003857 mIndexMap.put(device, getValidIndex(10 * index));
Eric Laurentdd45d012012-10-08 09:04:34 -07003858 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003859 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003860 }
3861
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003862 // must be called while synchronized VolumeStreamState.class
3863 public void applyDeviceVolume_syncVSS(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003864 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003865 if (mIsMuted) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003866 index = 0;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003867 } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported)
3868 || ((device & mFullVolumeDevices) != 0)) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003869 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07003870 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07003871 index = (getIndex(device) + 5)/10;
3872 }
3873 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003874 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003875
Eric Laurentfdbee862014-05-12 15:26:12 -07003876 public void applyAllVolumes() {
3877 synchronized (VolumeStreamState.class) {
3878 // apply default volume first: by convention this will reset all
3879 // devices volumes in audio policy manager to the supplied value
3880 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003881 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003882 index = 0;
3883 } else {
3884 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3885 }
3886 AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3887 // then apply device specific volumes
John Spurlock2bb02ec2015-03-02 13:13:06 -05003888 for (int i = 0; i < mIndexMap.size(); i++) {
3889 int device = mIndexMap.keyAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07003890 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
RoboErik4197cb62015-01-21 15:45:32 -08003891 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003892 index = 0;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003893 } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3894 mAvrcpAbsVolSupported)
3895 || ((device & mFullVolumeDevices) != 0))
3896 {
Eric Laurentfdbee862014-05-12 15:26:12 -07003897 index = (mIndexMax + 5)/10;
3898 } else {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003899 index = (mIndexMap.valueAt(i) + 5)/10;
Eric Laurentfdbee862014-05-12 15:26:12 -07003900 }
3901 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07003902 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003903 }
3904 }
3905 }
3906
John Spurlock90874332015-03-10 16:00:54 -04003907 public boolean adjustIndex(int deltaIndex, int device, String caller) {
3908 return setIndex(getIndex(device) + deltaIndex, device, caller);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003909 }
3910
John Spurlock90874332015-03-10 16:00:54 -04003911 public boolean setIndex(int index, int device, String caller) {
John Spurlockf63860c2015-02-19 09:46:27 -05003912 boolean changed = false;
3913 int oldIndex;
Eric Laurentfdbee862014-05-12 15:26:12 -07003914 synchronized (VolumeStreamState.class) {
John Spurlockf63860c2015-02-19 09:46:27 -05003915 oldIndex = getIndex(device);
Eric Laurentfdbee862014-05-12 15:26:12 -07003916 index = getValidIndex(index);
3917 synchronized (mCameraSoundForced) {
3918 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3919 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07003920 }
3921 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003922 mIndexMap.put(device, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003923
John Spurlockf63860c2015-02-19 09:46:27 -05003924 changed = oldIndex != index;
3925 if (changed) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003926 // Apply change to all streams using this one as alias
3927 // if changing volume of current device, also change volume of current
3928 // device on aliased stream
3929 boolean currentDevice = (device == getDeviceForStream(mStreamType));
3930 int numStreamTypes = AudioSystem.getNumStreamTypes();
3931 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3932 if (streamType != mStreamType &&
3933 mStreamVolumeAlias[streamType] == mStreamType) {
3934 int scaledIndex = rescaleIndex(index, mStreamType, streamType);
John Spurlock90874332015-03-10 16:00:54 -04003935 mStreamStates[streamType].setIndex(scaledIndex, device, caller);
Eric Laurentfdbee862014-05-12 15:26:12 -07003936 if (currentDevice) {
3937 mStreamStates[streamType].setIndex(scaledIndex,
John Spurlock90874332015-03-10 16:00:54 -04003938 getDeviceForStream(streamType), caller);
Eric Laurentfdbee862014-05-12 15:26:12 -07003939 }
3940 }
3941 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003942 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003943 }
John Spurlockf63860c2015-02-19 09:46:27 -05003944 if (changed) {
3945 oldIndex = (oldIndex + 5) / 10;
3946 index = (index + 5) / 10;
John Spurlock90874332015-03-10 16:00:54 -04003947 // log base stream changes to the event log
3948 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
3949 if (caller == null) {
3950 Log.w(TAG, "No caller for volume_changed event", new Throwable());
3951 }
3952 EventLogTags.writeVolumeChanged(mStreamType, oldIndex, index, mIndexMax / 10,
3953 caller);
3954 }
3955 // fire changed intents for all streams
John Spurlockf63860c2015-02-19 09:46:27 -05003956 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
3957 mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
Jean-Michel Trivi560877d2015-06-25 17:38:35 -07003958 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
3959 mStreamVolumeAlias[mStreamType]);
John Spurlockf63860c2015-02-19 09:46:27 -05003960 sendBroadcastToAll(mVolumeChanged);
3961 }
3962 return changed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003963 }
3964
Eric Laurentfdbee862014-05-12 15:26:12 -07003965 public int getIndex(int device) {
3966 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003967 int index = mIndexMap.get(device, -1);
3968 if (index == -1) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003969 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
John Spurlock2bb02ec2015-03-02 13:13:06 -05003970 index = mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurentfdbee862014-05-12 15:26:12 -07003971 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003972 return index;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003973 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07003974 }
3975
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003976 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07003977 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003978 }
3979
John Spurlockb6e19e32015-03-10 21:33:44 -04003980 public int getMinIndex() {
3981 return mIndexMin;
3982 }
3983
John Spurlock90874332015-03-10 16:00:54 -04003984 public void setAllIndexes(VolumeStreamState srcStream, String caller) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003985 synchronized (VolumeStreamState.class) {
3986 int srcStreamType = srcStream.getStreamType();
3987 // apply default device volume from source stream to all devices first in case
3988 // some devices are present in this stream state but not in source stream state
3989 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003990 index = rescaleIndex(index, srcStreamType, mStreamType);
John Spurlock2bb02ec2015-03-02 13:13:06 -05003991 for (int i = 0; i < mIndexMap.size(); i++) {
3992 mIndexMap.put(mIndexMap.keyAt(i), index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003993 }
3994 // Now apply actual volume for devices in source stream state
John Spurlock2bb02ec2015-03-02 13:13:06 -05003995 SparseIntArray srcMap = srcStream.mIndexMap;
3996 for (int i = 0; i < srcMap.size(); i++) {
3997 int device = srcMap.keyAt(i);
3998 index = srcMap.valueAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07003999 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07004000
John Spurlock90874332015-03-10 16:00:54 -04004001 setIndex(index, device, caller);
Eric Laurentfdbee862014-05-12 15:26:12 -07004002 }
Eric Laurent6d517662012-04-23 18:42:39 -07004003 }
4004 }
4005
Eric Laurentfdbee862014-05-12 15:26:12 -07004006 public void setAllIndexesToMax() {
4007 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004008 for (int i = 0; i < mIndexMap.size(); i++) {
4009 mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07004010 }
Eric Laurentdd45d012012-10-08 09:04:34 -07004011 }
Eric Laurentdd45d012012-10-08 09:04:34 -07004012 }
4013
RoboErik4197cb62015-01-21 15:45:32 -08004014 public void mute(boolean state) {
John Spurlock22b9ee12015-02-18 22:51:44 -05004015 boolean changed = false;
Eric Laurentfdbee862014-05-12 15:26:12 -07004016 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08004017 if (state != mIsMuted) {
John Spurlock22b9ee12015-02-18 22:51:44 -05004018 changed = true;
RoboErik4197cb62015-01-21 15:45:32 -08004019 mIsMuted = state;
John Spurlock22b9ee12015-02-18 22:51:44 -05004020
RoboErik4197cb62015-01-21 15:45:32 -08004021 // Set the new mute volume. This propagates the values to
4022 // the audio system, otherwise the volume won't be changed
4023 // at the lower level.
4024 sendMsg(mAudioHandler,
4025 MSG_SET_ALL_VOLUMES,
4026 SENDMSG_QUEUE,
4027 0,
4028 0,
4029 this, 0);
Eric Laurentfdbee862014-05-12 15:26:12 -07004030 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004031 }
John Spurlock22b9ee12015-02-18 22:51:44 -05004032 if (changed) {
4033 // Stream mute changed, fire the intent.
4034 Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
4035 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
4036 intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
4037 sendBroadcastToAll(intent);
4038 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004039 }
4040
Eric Laurent6d517662012-04-23 18:42:39 -07004041 public int getStreamType() {
4042 return mStreamType;
4043 }
4044
Eric Laurent212532b2014-07-21 15:43:18 -07004045 public void checkFixedVolumeDevices() {
4046 synchronized (VolumeStreamState.class) {
4047 // ignore settings for fixed volume devices: volume should always be at max or 0
4048 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004049 for (int i = 0; i < mIndexMap.size(); i++) {
4050 int device = mIndexMap.keyAt(i);
4051 int index = mIndexMap.valueAt(i);
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07004052 if (((device & mFullVolumeDevices) != 0)
4053 || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004054 mIndexMap.put(device, mIndexMax);
Eric Laurent212532b2014-07-21 15:43:18 -07004055 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004056 applyDeviceVolume_syncVSS(device);
Eric Laurent212532b2014-07-21 15:43:18 -07004057 }
4058 }
4059 }
4060 }
4061
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004062 private int getValidIndex(int index) {
John Spurlockb6e19e32015-03-10 21:33:44 -04004063 if (index < mIndexMin) {
4064 return mIndexMin;
John Spurlockee5ad722015-03-03 16:17:21 -05004065 } else if (mUseFixedVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07004066 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004067 }
4068
4069 return index;
4070 }
4071
Eric Laurentbffc3d12012-05-07 17:43:49 -07004072 private void dump(PrintWriter pw) {
RoboErik4197cb62015-01-21 15:45:32 -08004073 pw.print(" Muted: ");
4074 pw.println(mIsMuted);
John Spurlockb6e19e32015-03-10 21:33:44 -04004075 pw.print(" Min: ");
4076 pw.println((mIndexMin + 5) / 10);
John Spurlock2b29bc42014-08-26 16:40:35 -04004077 pw.print(" Max: ");
4078 pw.println((mIndexMax + 5) / 10);
Eric Laurentbffc3d12012-05-07 17:43:49 -07004079 pw.print(" Current: ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05004080 for (int i = 0; i < mIndexMap.size(); i++) {
4081 if (i > 0) {
4082 pw.print(", ");
4083 }
4084 final int device = mIndexMap.keyAt(i);
John Spurlock2b29bc42014-08-26 16:40:35 -04004085 pw.print(Integer.toHexString(device));
4086 final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
4087 : AudioSystem.getOutputDeviceName(device);
4088 if (!deviceName.isEmpty()) {
4089 pw.print(" (");
4090 pw.print(deviceName);
4091 pw.print(")");
4092 }
4093 pw.print(": ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05004094 final int index = (mIndexMap.valueAt(i) + 5) / 10;
John Spurlock2b29bc42014-08-26 16:40:35 -04004095 pw.print(index);
Eric Laurentbffc3d12012-05-07 17:43:49 -07004096 }
John Spurlockb32fc972015-03-05 13:58:00 -05004097 pw.println();
4098 pw.print(" Devices: ");
John Spurlock8a52c442015-03-26 14:23:58 -04004099 final int devices = getDevicesForStream(mStreamType);
John Spurlockb32fc972015-03-05 13:58:00 -05004100 int device, i = 0, n = 0;
John Spurlock1ff1e6e2015-03-09 14:21:20 -04004101 // iterate all devices from 1 to DEVICE_OUT_DEFAULT exclusive
4102 // (the default device is not returned by getDevicesForStream)
4103 while ((device = 1 << i) != AudioSystem.DEVICE_OUT_DEFAULT) {
John Spurlockb32fc972015-03-05 13:58:00 -05004104 if ((devices & device) != 0) {
4105 if (n++ > 0) {
4106 pw.print(", ");
4107 }
4108 pw.print(AudioSystem.getOutputDeviceName(device));
4109 }
4110 i++;
4111 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07004112 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004113 }
4114
4115 /** Thread that handles native AudioSystem control. */
4116 private class AudioSystemThread extends Thread {
4117 AudioSystemThread() {
4118 super("AudioService");
4119 }
4120
4121 @Override
4122 public void run() {
4123 // Set this thread up so the handler will work on it
4124 Looper.prepare();
4125
4126 synchronized(AudioService.this) {
4127 mAudioHandler = new AudioHandler();
4128
4129 // Notify that the handler has been created
4130 AudioService.this.notify();
4131 }
4132
4133 // Listen for volume change requests that are set by VolumePanel
4134 Looper.loop();
4135 }
4136 }
4137
4138 /** Handles internal volume messages in separate volume thread. */
4139 private class AudioHandler extends Handler {
4140
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004141 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004142
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004143 synchronized (VolumeStreamState.class) {
4144 // Apply volume
4145 streamState.applyDeviceVolume_syncVSS(device);
Eric Laurenta553c252009-07-17 12:17:14 -07004146
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004147 // Apply change to all streams using this one as alias
4148 int numStreamTypes = AudioSystem.getNumStreamTypes();
4149 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4150 if (streamType != streamState.mStreamType &&
4151 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
4152 // Make sure volume is also maxed out on A2DP device for aliased stream
4153 // that may have a different device selected
4154 int streamDevice = getDeviceForStream(streamType);
4155 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
4156 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
4157 mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
4158 }
4159 mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
Eric Laurentcd772d02013-10-30 18:31:07 -07004160 }
Eric Laurenta553c252009-07-17 12:17:14 -07004161 }
4162 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004163 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08004164 sendMsg(mAudioHandler,
4165 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08004166 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004167 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07004168 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08004169 streamState,
4170 PERSIST_DELAY);
4171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004172 }
4173
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004174 private void setAllVolumes(VolumeStreamState streamState) {
4175
4176 // Apply volume
4177 streamState.applyAllVolumes();
4178
4179 // Apply change to all streams using this one as alias
4180 int numStreamTypes = AudioSystem.getNumStreamTypes();
4181 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4182 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07004183 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004184 mStreamStates[streamType].applyAllVolumes();
4185 }
4186 }
4187 }
4188
Eric Laurent42b041e2013-03-29 11:36:03 -07004189 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07004190 if (mUseFixedVolume) {
4191 return;
4192 }
Eric Laurent212532b2014-07-21 15:43:18 -07004193 if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
4194 return;
4195 }
Eric Laurent42b041e2013-03-29 11:36:03 -07004196 System.putIntForUser(mContentResolver,
4197 streamState.getSettingNameForDevice(device),
4198 (streamState.getIndex(device) + 5)/ 10,
4199 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004200 }
4201
Glenn Kastenba195eb2011-12-13 09:30:40 -08004202 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07004203 if (mUseFixedVolume) {
4204 return;
4205 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07004206 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004207 }
4208
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004209 private boolean onLoadSoundEffects() {
4210 int status;
4211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004212 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004213 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004214 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
4215 return false;
4216 }
4217
4218 if (mSoundPool != null) {
4219 return true;
4220 }
4221
4222 loadTouchSoundAssets();
4223
Jean-Michel Trivi55a30c42014-07-20 17:56:11 -07004224 mSoundPool = new SoundPool.Builder()
4225 .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
4226 .setAudioAttributes(new AudioAttributes.Builder()
4227 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
4228 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
4229 .build())
4230 .build();
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004231 mSoundPoolCallBack = null;
4232 mSoundPoolListenerThread = new SoundPoolListenerThread();
4233 mSoundPoolListenerThread.start();
4234 int attempts = 3;
4235 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
4236 try {
4237 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07004238 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004239 } catch (InterruptedException e) {
4240 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
4241 }
4242 }
4243
4244 if (mSoundPoolCallBack == null) {
4245 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
4246 if (mSoundPoolLooper != null) {
4247 mSoundPoolLooper.quit();
4248 mSoundPoolLooper = null;
4249 }
4250 mSoundPoolListenerThread = null;
4251 mSoundPool.release();
4252 mSoundPool = null;
4253 return false;
4254 }
4255 /*
4256 * poolId table: The value -1 in this table indicates that corresponding
4257 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
4258 * Once loaded, the value in poolId is the sample ID and the same
4259 * sample can be reused for another effect using the same file.
4260 */
4261 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4262 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4263 poolId[fileIdx] = -1;
4264 }
4265 /*
4266 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
4267 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
4268 * this indicates we have a valid sample loaded for this effect.
4269 */
4270
4271 int numSamples = 0;
4272 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4273 // Do not load sample if this effect uses the MediaPlayer
4274 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
4275 continue;
4276 }
4277 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
4278 String filePath = Environment.getRootDirectory()
4279 + SOUND_EFFECTS_PATH
4280 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
4281 int sampleId = mSoundPool.load(filePath, 0);
4282 if (sampleId <= 0) {
4283 Log.w(TAG, "Soundpool could not load file: "+filePath);
4284 } else {
4285 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
4286 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
4287 numSamples++;
4288 }
4289 } else {
4290 SOUND_EFFECT_FILES_MAP[effect][1] =
4291 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
4292 }
4293 }
4294 // wait for all samples to be loaded
4295 if (numSamples > 0) {
4296 mSoundPoolCallBack.setSamples(poolId);
4297
4298 attempts = 3;
4299 status = 1;
4300 while ((status == 1) && (attempts-- > 0)) {
4301 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07004302 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004303 status = mSoundPoolCallBack.status();
4304 } catch (InterruptedException e) {
4305 Log.w(TAG, "Interrupted while waiting sound pool callback.");
4306 }
4307 }
4308 } else {
4309 status = -1;
4310 }
4311
4312 if (mSoundPoolLooper != null) {
4313 mSoundPoolLooper.quit();
4314 mSoundPoolLooper = null;
4315 }
4316 mSoundPoolListenerThread = null;
4317 if (status != 0) {
4318 Log.w(TAG,
4319 "onLoadSoundEffects(), Error "+status+ " while loading samples");
4320 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4321 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
4322 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4323 }
4324 }
4325
4326 mSoundPool.release();
4327 mSoundPool = null;
4328 }
4329 }
4330 return (status == 0);
4331 }
4332
4333 /**
4334 * Unloads samples from the sound pool.
4335 * This method can be called to free some memory when
4336 * sound effects are disabled.
4337 */
4338 private void onUnloadSoundEffects() {
4339 synchronized (mSoundEffectsLock) {
4340 if (mSoundPool == null) {
4341 return;
4342 }
4343
4344 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4345 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4346 poolId[fileIdx] = 0;
4347 }
4348
4349 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4350 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
4351 continue;
4352 }
4353 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
4354 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
4355 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4356 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
4357 }
4358 }
4359 mSoundPool.release();
4360 mSoundPool = null;
4361 }
4362 }
4363
4364 private void onPlaySoundEffect(int effectType, int volume) {
4365 synchronized (mSoundEffectsLock) {
4366
4367 onLoadSoundEffects();
4368
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004369 if (mSoundPool == null) {
4370 return;
4371 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004372 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08004373 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004374 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07004375 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004376 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07004377 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004378 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004379
4380 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004381 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
4382 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004383 } else {
4384 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004385 try {
Eric Laurente78fced2013-03-15 16:03:47 -07004386 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
4387 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004388 mediaPlayer.setDataSource(filePath);
4389 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
4390 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08004391 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004392 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
4393 public void onCompletion(MediaPlayer mp) {
4394 cleanupPlayer(mp);
4395 }
4396 });
4397 mediaPlayer.setOnErrorListener(new OnErrorListener() {
4398 public boolean onError(MediaPlayer mp, int what, int extra) {
4399 cleanupPlayer(mp);
4400 return true;
4401 }
4402 });
4403 mediaPlayer.start();
4404 } catch (IOException ex) {
4405 Log.w(TAG, "MediaPlayer IOException: "+ex);
4406 } catch (IllegalArgumentException ex) {
4407 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
4408 } catch (IllegalStateException ex) {
4409 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004410 }
4411 }
4412 }
4413 }
4414
4415 private void cleanupPlayer(MediaPlayer mp) {
4416 if (mp != null) {
4417 try {
4418 mp.stop();
4419 mp.release();
4420 } catch (IllegalStateException ex) {
4421 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
4422 }
4423 }
4424 }
4425
Eric Laurentfa640152011-03-12 15:59:51 -08004426 private void setForceUse(int usage, int config) {
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004427 synchronized (mConnectedDevices) {
4428 setForceUseInt_SyncDevices(usage, config);
4429 }
Eric Laurentfa640152011-03-12 15:59:51 -08004430 }
4431
Eric Laurent05274f32012-11-29 12:48:18 -08004432 private void onPersistSafeVolumeState(int state) {
4433 Settings.Global.putInt(mContentResolver,
4434 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
4435 state);
4436 }
4437
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004438 @Override
4439 public void handleMessage(Message msg) {
Eric Laurentafbb0472011-12-15 09:04:23 -08004440 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004441
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004442 case MSG_SET_DEVICE_VOLUME:
4443 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
4444 break;
4445
4446 case MSG_SET_ALL_VOLUMES:
4447 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004448 break;
4449
4450 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07004451 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004452 break;
4453
Justin Koh57978ed2012-04-03 17:37:58 -07004454 case MSG_PERSIST_MASTER_VOLUME_MUTE:
Eric Laurent83a017b2013-03-19 18:15:31 -07004455 if (mUseFixedVolume) {
4456 return;
4457 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004458 Settings.System.putIntForUser(mContentResolver,
4459 Settings.System.VOLUME_MASTER_MUTE,
4460 msg.arg1,
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004461 msg.arg2);
Justin Koh57978ed2012-04-03 17:37:58 -07004462 break;
4463
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004464 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08004465 // note that the value persisted is the current ringer mode, not the
4466 // value of ringer mode as of the time the request was made to persist
John Spurlock661f2cf2014-11-17 10:29:10 -05004467 persistRingerMode(getRingerModeInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004468 break;
4469
Andy Hunged0ea402015-10-30 14:11:46 -07004470 case MSG_AUDIO_SERVER_DIED:
4471 onAudioServerDied();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004472 break;
4473
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004474 case MSG_UNLOAD_SOUND_EFFECTS:
4475 onUnloadSoundEffects();
4476 break;
4477
Eric Laurent117b7bb2011-01-16 17:07:27 -08004478 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004479 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
4480 // can take several dozens of milliseconds to complete
4481 boolean loaded = onLoadSoundEffects();
4482 if (msg.obj != null) {
4483 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
4484 synchronized (reply) {
4485 reply.mStatus = loaded ? 0 : -1;
4486 reply.notify();
4487 }
4488 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08004489 break;
4490
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004491 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004492 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004493 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004494
4495 case MSG_BTA2DP_DOCK_TIMEOUT:
4496 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004497 synchronized (mConnectedDevices) {
4498 makeA2dpDeviceUnavailableNow( (String) msg.obj );
4499 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004500 break;
Eric Laurentfa640152011-03-12 15:59:51 -08004501
4502 case MSG_SET_FORCE_USE:
Eric Laurentc390bed2012-07-03 12:24:05 -07004503 case MSG_SET_FORCE_BT_A2DP_USE:
Eric Laurentfa640152011-03-12 15:59:51 -08004504 setForceUse(msg.arg1, msg.arg2);
4505 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07004506
Eric Laurentdc03c612011-04-01 10:59:41 -07004507 case MSG_BT_HEADSET_CNCT_FAILED:
4508 resetBluetoothSco();
4509 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004510
4511 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
Paul McLean10804eb2015-01-28 11:16:35 -08004512 { WiredDeviceConnectionState connectState =
4513 (WiredDeviceConnectionState)msg.obj;
4514 onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
John Spurlock90874332015-03-10 16:00:54 -04004515 connectState.mAddress, connectState.mName, connectState.mCaller);
Paul McLean10804eb2015-01-28 11:16:35 -08004516 mAudioEventWakeLock.release();
4517 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004518 break;
4519
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004520 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
4521 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
4522 mAudioEventWakeLock.release();
4523 break;
4524
4525 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
4526 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004527 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004528 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004529
4530 case MSG_REPORT_NEW_ROUTES: {
4531 int N = mRoutesObservers.beginBroadcast();
4532 if (N > 0) {
4533 AudioRoutesInfo routes;
4534 synchronized (mCurAudioRoutes) {
4535 routes = new AudioRoutesInfo(mCurAudioRoutes);
4536 }
4537 while (N > 0) {
4538 N--;
4539 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
4540 try {
4541 obs.dispatchAudioRoutesChanged(routes);
4542 } catch (RemoteException e) {
4543 }
4544 }
4545 }
4546 mRoutesObservers.finishBroadcast();
John Spurlock8a52c442015-03-26 14:23:58 -04004547 observeDevicesForStreams(-1);
Dianne Hackborn632ca412012-06-14 19:34:10 -07004548 break;
4549 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004550
Eric Laurentc34dcc12012-09-10 13:51:52 -07004551 case MSG_CHECK_MUSIC_ACTIVE:
John Spurlock90874332015-03-10 16:00:54 -04004552 onCheckMusicActive((String) msg.obj);
Eric Laurentc34dcc12012-09-10 13:51:52 -07004553 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004554
4555 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
4556 onSendBecomingNoisyIntent();
4557 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07004558
4559 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
4560 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
John Spurlock90874332015-03-10 16:00:54 -04004561 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED),
4562 (String) msg.obj);
Eric Laurentd640bd32012-09-28 18:01:48 -07004563 break;
Eric Laurent05274f32012-11-29 12:48:18 -08004564 case MSG_PERSIST_SAFE_VOLUME_STATE:
4565 onPersistSafeVolumeState(msg.arg1);
4566 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08004567
Eric Laurent2a57ca92013-03-07 17:29:27 -08004568 case MSG_BROADCAST_BT_CONNECTION_STATE:
4569 onBroadcastScoConnectionState(msg.arg1);
4570 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004571
4572 case MSG_SYSTEM_READY:
4573 onSystemReady();
4574 break;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004575
Eric Laurent0867bed2015-05-20 14:49:08 -07004576 case MSG_INDICATE_SYSTEM_READY:
4577 onIndicateSystemReady();
4578 break;
4579
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004580 case MSG_PERSIST_MUSIC_ACTIVE_MS:
4581 final int musicActiveMs = msg.arg1;
4582 Settings.Secure.putIntForUser(mContentResolver,
4583 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
4584 UserHandle.USER_CURRENT);
4585 break;
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004586 case MSG_PERSIST_MICROPHONE_MUTE:
4587 Settings.System.putIntForUser(mContentResolver,
4588 Settings.System.MICROPHONE_MUTE,
4589 msg.arg1,
4590 msg.arg2);
4591 break;
RoboErik5452e252015-02-06 15:33:53 -08004592 case MSG_UNMUTE_STREAM:
4593 onUnmuteStream(msg.arg1, msg.arg2);
4594 break;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07004595 case MSG_DYN_POLICY_MIX_STATE_UPDATE:
4596 onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1);
4597 break;
Andy Hungf04b84d2015-12-18 17:33:27 -08004598
4599 case MSG_PERSIST_MASTER_MONO:
4600 Settings.System.putIntForUser(mContentResolver,
4601 Settings.System.MASTER_MONO,
4602 msg.arg1 /* value */,
4603 msg.arg2 /* userHandle */);
4604 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004605 }
4606 }
4607 }
4608
Jason Parekhb1096152009-03-24 17:48:25 -07004609 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07004610
Jason Parekhb1096152009-03-24 17:48:25 -07004611 SettingsObserver() {
4612 super(new Handler());
4613 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4614 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004615 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4616 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07004617 }
4618
4619 @Override
4620 public void onChange(boolean selfChange) {
4621 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08004622 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
4623 // However there appear to be some missing locks around mRingerModeMutedStreams
4624 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
4625 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07004626 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004627 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07004628 /*
4629 * Ensure all stream types that should be affected by ringer mode
4630 * are in the proper state.
4631 */
John Spurlock661f2cf2014-11-17 10:29:10 -05004632 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurenta553c252009-07-17 12:17:14 -07004633 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004634 readDockAudioSettings(mContentResolver);
Eric Laurenta553c252009-07-17 12:17:14 -07004635 }
Jason Parekhb1096152009-03-24 17:48:25 -07004636 }
Jason Parekhb1096152009-03-24 17:48:25 -07004637 }
Eric Laurenta553c252009-07-17 12:17:14 -07004638
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004639 // must be called synchronized on mConnectedDevices
Paul McLean20eec5b2015-05-09 13:02:18 -07004640 private void makeA2dpDeviceAvailable(String address, String name) {
Eric Laurent78472112012-05-21 08:57:21 -07004641 // enable A2DP before notifying A2DP connection to avoid unecessary processing in
4642 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004643 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4644 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4645 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Eric Laurent78472112012-05-21 08:57:21 -07004646 setBluetoothA2dpOnInt(true);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004647 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004648 AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004649 // Reset A2DP suspend state each time a new sink is connected
4650 AudioSystem.setParameters("A2dpSuspended=false");
Paul McLean394a8e12015-03-03 10:29:19 -07004651 mConnectedDevices.put(
4652 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
Paul McLean20eec5b2015-05-09 13:02:18 -07004653 new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
Paul McLean394a8e12015-03-03 10:29:19 -07004654 address));
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004655 }
4656
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004657 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004658 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07004659 }
4660
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004661 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004662 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004663 synchronized (mA2dpAvrcpLock) {
4664 mAvrcpAbsVolSupported = false;
4665 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004666 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004667 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004668 mConnectedDevices.remove(
4669 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
RoboErik5535ea82014-09-25 14:53:16 -07004670 synchronized (mCurAudioRoutes) {
4671 // Remove A2DP routes as well
John Spurlock61560172015-02-06 19:46:04 -05004672 if (mCurAudioRoutes.bluetoothName != null) {
4673 mCurAudioRoutes.bluetoothName = null;
RoboErik5535ea82014-09-25 14:53:16 -07004674 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4675 SENDMSG_NOOP, 0, 0, null, 0);
4676 }
4677 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004678 }
4679
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004680 // must be called synchronized on mConnectedDevices
Eric Laurentd138e4e2015-05-15 16:41:15 -07004681 private void makeA2dpDeviceUnavailableLater(String address, int delayMs) {
Eric Laurent3b591262010-04-20 07:01:00 -07004682 // prevent any activity on the A2DP audio output to avoid unwanted
4683 // reconnection of the sink.
4684 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004685 // the device will be made unavailable later, so consider it disconnected right away
Paul McLean394a8e12015-03-03 10:29:19 -07004686 mConnectedDevices.remove(
4687 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004688 // send the delayed message to make the device unavailable later
4689 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
Eric Laurentd138e4e2015-05-15 16:41:15 -07004690 mAudioHandler.sendMessageDelayed(msg, delayMs);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004691
4692 }
4693
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004694 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004695 private void makeA2dpSrcAvailable(String address) {
4696 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004697 AudioSystem.DEVICE_STATE_AVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004698 mConnectedDevices.put(
4699 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
Paul McLean20eec5b2015-05-09 13:02:18 -07004700 new DeviceListSpec(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "",
Paul McLean394a8e12015-03-03 10:29:19 -07004701 address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004702 }
4703
4704 // must be called synchronized on mConnectedDevices
4705 private void makeA2dpSrcUnavailable(String address) {
4706 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004707 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004708 mConnectedDevices.remove(
4709 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004710 }
4711
4712 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004713 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004714 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4715 }
4716
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004717 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004718 private boolean hasScheduledA2dpDockTimeout() {
4719 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4720 }
4721
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004722 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004723 {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004724 if (DEBUG_VOL) {
4725 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
4726 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004727 if (btDevice == null) {
4728 return;
4729 }
4730 String address = btDevice.getAddress();
4731 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4732 address = "";
4733 }
John Du5a0cf7a2013-07-19 11:30:34 -07004734
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004735 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004736 String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4737 btDevice.getAddress());
4738 DeviceListSpec deviceSpec = mConnectedDevices.get(key);
4739 boolean isConnected = deviceSpec != null;
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004740
4741 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4742 if (btDevice.isBluetoothDock()) {
4743 if (state == BluetoothProfile.STATE_DISCONNECTED) {
4744 // introduction of a delay for transient disconnections of docks when
4745 // power is rapidly turned off/on, this message will be canceled if
4746 // we reconnect the dock under a preset delay
Eric Laurentd138e4e2015-05-15 16:41:15 -07004747 makeA2dpDeviceUnavailableLater(address, BTA2DP_DOCK_TIMEOUT_MILLIS);
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004748 // the next time isConnected is evaluated, it will be false for the dock
4749 }
4750 } else {
4751 makeA2dpDeviceUnavailableNow(address);
4752 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07004753 synchronized (mCurAudioRoutes) {
John Spurlock61560172015-02-06 19:46:04 -05004754 if (mCurAudioRoutes.bluetoothName != null) {
4755 mCurAudioRoutes.bluetoothName = null;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004756 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4757 SENDMSG_NOOP, 0, 0, null, 0);
4758 }
4759 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004760 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4761 if (btDevice.isBluetoothDock()) {
4762 // this could be a reconnection after a transient disconnection
4763 cancelA2dpDeviceTimeout();
4764 mDockAddress = address;
4765 } else {
4766 // this could be a connection of another A2DP device before the timeout of
4767 // a dock: cancel the dock timeout, and make the dock unavailable now
4768 if(hasScheduledA2dpDockTimeout()) {
4769 cancelA2dpDeviceTimeout();
4770 makeA2dpDeviceUnavailableNow(mDockAddress);
4771 }
4772 }
Paul McLean20eec5b2015-05-09 13:02:18 -07004773 makeA2dpDeviceAvailable(address, btDevice.getName());
Dianne Hackborn632ca412012-06-14 19:34:10 -07004774 synchronized (mCurAudioRoutes) {
4775 String name = btDevice.getAliasName();
John Spurlock61560172015-02-06 19:46:04 -05004776 if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
4777 mCurAudioRoutes.bluetoothName = name;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004778 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4779 SENDMSG_NOOP, 0, 0, null, 0);
4780 }
4781 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004782 }
4783 }
4784 }
4785
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004786 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
4787 {
4788 if (DEBUG_VOL) {
4789 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
4790 }
4791 if (btDevice == null) {
4792 return;
4793 }
4794 String address = btDevice.getAddress();
4795 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4796 address = "";
4797 }
4798
4799 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004800 String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
4801 DeviceListSpec deviceSpec = mConnectedDevices.get(key);
4802 boolean isConnected = deviceSpec != null;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004803
4804 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4805 makeA2dpSrcUnavailable(address);
4806 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4807 makeA2dpSrcAvailable(address);
4808 }
4809 }
4810 }
4811
John Du5a0cf7a2013-07-19 11:30:34 -07004812 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
4813 // address is not used for now, but may be used when multiple a2dp devices are supported
4814 synchronized (mA2dpAvrcpLock) {
4815 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004816 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07004817 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4818 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4819 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4820 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4821 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07004822 }
4823 }
4824
Paul McLean394a8e12015-03-03 10:29:19 -07004825 private boolean handleDeviceConnection(boolean connect, int device, String address,
4826 String deviceName) {
4827 if (DEBUG_DEVICES) {
4828 Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device)
4829 + " address:" + address + " name:" + deviceName + ")");
4830 }
Eric Laurent59f48272012-04-05 19:42:21 -07004831 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004832 String deviceKey = makeDeviceListKey(device, address);
4833 if (DEBUG_DEVICES) {
4834 Slog.i(TAG, "deviceKey:" + deviceKey);
4835 }
4836 DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
4837 boolean isConnected = deviceSpec != null;
4838 if (DEBUG_DEVICES) {
4839 Slog.i(TAG, "deviceSpec:" + deviceSpec + " is(already)Connected:" + isConnected);
4840 }
4841 if (connect && !isConnected) {
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07004842 final int res = AudioSystem.setDeviceConnectionState(device,
4843 AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);
4844 if (res != AudioSystem.AUDIO_STATUS_OK) {
4845 Slog.e(TAG, "not connecting device 0x" + Integer.toHexString(device) +
4846 " due to command error " + res );
4847 return false;
4848 }
Paul McLean394a8e12015-03-03 10:29:19 -07004849 mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
4850 return true;
4851 } else if (!connect && isConnected) {
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07004852 AudioSystem.setDeviceConnectionState(device,
4853 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName);
4854 // always remove even if disconnection failed
Paul McLean394a8e12015-03-03 10:29:19 -07004855 mConnectedDevices.remove(deviceKey);
4856 return true;
Eric Laurent59f48272012-04-05 19:42:21 -07004857 }
4858 }
4859 return false;
4860 }
4861
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004862 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4863 // sent if none of these devices is connected.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004864 // Access synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004865 int mBecomingNoisyIntentDevices =
4866 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07004867 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07004868 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004869 AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004870
4871 // must be called before removing the device from mConnectedDevices
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004872 // Called synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004873 private int checkSendBecomingNoisyIntent(int device, int state) {
4874 int delay = 0;
4875 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4876 int devices = 0;
John Spurlock8c3dc852015-04-23 21:32:37 -04004877 for (int i = 0; i < mConnectedDevices.size(); i++) {
4878 int dev = mConnectedDevices.valueAt(i).mDeviceType;
Paul McLean394a8e12015-03-03 10:29:19 -07004879 if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
4880 && ((dev & mBecomingNoisyIntentDevices) != 0)) {
4881 devices |= dev;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004882 }
4883 }
4884 if (devices == device) {
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004885 sendMsg(mAudioHandler,
4886 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4887 SENDMSG_REPLACE,
4888 0,
4889 0,
4890 null,
4891 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004892 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004893 }
4894 }
4895
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004896 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
4897 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004898 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004899 synchronized (mLastDeviceConnectMsgTime) {
4900 long time = SystemClock.uptimeMillis();
4901 if (mLastDeviceConnectMsgTime > time) {
Matthew Xiec525cf72015-01-22 20:13:17 -08004902 delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004903 }
4904 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004905 }
4906 return delay;
4907 }
4908
Paul McLean394a8e12015-03-03 10:29:19 -07004909 private void sendDeviceConnectionIntent(int device, int state, String address,
4910 String deviceName) {
4911 if (DEBUG_DEVICES) {
4912 Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
4913 " state:0x" + Integer.toHexString(state) + " address:" + address +
4914 " name:" + deviceName + ");");
4915 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004916 Intent intent = new Intent();
4917
Paul McLean10804eb2015-01-28 11:16:35 -08004918 intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
4919 intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
4920 intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
4921
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004922 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4923
Dianne Hackborn632ca412012-06-14 19:34:10 -07004924 int connType = 0;
4925
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004926 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004927 connType = AudioRoutesInfo.MAIN_HEADSET;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004928 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4929 intent.putExtra("microphone", 1);
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004930 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
4931 device == AudioSystem.DEVICE_OUT_LINE) {
4932 /*do apps care about line-out vs headphones?*/
Dianne Hackborn632ca412012-06-14 19:34:10 -07004933 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004934 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4935 intent.putExtra("microphone", 0);
Eric Laurent6fa42452015-01-09 15:09:40 -08004936 } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
4937 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004938 connType = AudioRoutesInfo.MAIN_HDMI;
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004939 configureHdmiPlugIntent(intent, state);
Paul McLean10804eb2015-01-28 11:16:35 -08004940 } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE) {
4941 connType = AudioRoutesInfo.MAIN_USB;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004942 }
4943
Dianne Hackborn632ca412012-06-14 19:34:10 -07004944 synchronized (mCurAudioRoutes) {
4945 if (connType != 0) {
John Spurlock61560172015-02-06 19:46:04 -05004946 int newConn = mCurAudioRoutes.mainType;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004947 if (state != 0) {
4948 newConn |= connType;
4949 } else {
4950 newConn &= ~connType;
4951 }
John Spurlock61560172015-02-06 19:46:04 -05004952 if (newConn != mCurAudioRoutes.mainType) {
4953 mCurAudioRoutes.mainType = newConn;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004954 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4955 SENDMSG_NOOP, 0, 0, null, 0);
4956 }
4957 }
4958 }
4959
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004960 final long ident = Binder.clearCallingIdentity();
4961 try {
4962 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
4963 } finally {
4964 Binder.restoreCallingIdentity(ident);
4965 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004966 }
4967
Paul McLean10804eb2015-01-28 11:16:35 -08004968 private void onSetWiredDeviceConnectionState(int device, int state, String address,
John Spurlock90874332015-03-10 16:00:54 -04004969 String deviceName, String caller) {
Paul McLean394a8e12015-03-03 10:29:19 -07004970 if (DEBUG_DEVICES) {
John Spurlock90874332015-03-10 16:00:54 -04004971 Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
4972 + " state:" + Integer.toHexString(state)
4973 + " address:" + address
4974 + " deviceName:" + deviceName
4975 + " caller: " + caller + ");");
Paul McLean394a8e12015-03-03 10:29:19 -07004976 }
Paul McLean10804eb2015-01-28 11:16:35 -08004977
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004978 synchronized (mConnectedDevices) {
4979 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004980 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4981 (device == AudioSystem.DEVICE_OUT_LINE))) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004982 setBluetoothA2dpOnInt(true);
4983 }
Eric Laurentae4506e2014-05-29 16:04:32 -07004984 boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
4985 (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
4986 ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07004987 if (!handleDeviceConnection(state == 1, device, address, deviceName)) {
4988 // change of connection state failed, bailout
4989 return;
4990 }
Eric Laurentf1a457d2012-09-20 16:27:23 -07004991 if (state != 0) {
4992 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004993 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4994 (device == AudioSystem.DEVICE_OUT_LINE)) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07004995 setBluetoothA2dpOnInt(false);
4996 }
4997 if ((device & mSafeMediaVolumeDevices) != 0) {
4998 sendMsg(mAudioHandler,
4999 MSG_CHECK_MUSIC_ACTIVE,
5000 SENDMSG_REPLACE,
5001 0,
5002 0,
John Spurlock90874332015-03-10 16:00:54 -04005003 caller,
Eric Laurentf1a457d2012-09-20 16:27:23 -07005004 MUSIC_ACTIVE_POLL_PERIOD_MS);
5005 }
Eric Laurent212532b2014-07-21 15:43:18 -07005006 // Television devices without CEC service apply software volume on HDMI output
5007 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
5008 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
5009 checkAllFixedVolumeDevices();
5010 if (mHdmiManager != null) {
5011 synchronized (mHdmiManager) {
5012 if (mHdmiPlaybackClient != null) {
5013 mHdmiCecSink = false;
5014 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
5015 }
5016 }
5017 }
5018 }
5019 } else {
5020 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
5021 if (mHdmiManager != null) {
5022 synchronized (mHdmiManager) {
5023 mHdmiCecSink = false;
5024 }
5025 }
5026 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005027 }
Paul McLean10804eb2015-01-28 11:16:35 -08005028 if (!isUsb && device != AudioSystem.DEVICE_IN_WIRED_HEADSET) {
5029 sendDeviceConnectionIntent(device, state, address, deviceName);
Mike Lockwooddb454842012-09-18 11:16:57 -07005030 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005031 }
5032 }
5033
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005034 private void configureHdmiPlugIntent(Intent intent, int state) {
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005035 intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
5036 intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005037 if (state == 1) {
5038 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
5039 int[] portGeneration = new int[1];
5040 int status = AudioSystem.listAudioPorts(ports, portGeneration);
5041 if (status == AudioManager.SUCCESS) {
5042 for (AudioPort port : ports) {
5043 if (port instanceof AudioDevicePort) {
5044 final AudioDevicePort devicePort = (AudioDevicePort) port;
Eric Laurent6fa42452015-01-09 15:09:40 -08005045 if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
5046 devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005047 // format the list of supported encodings
Eric Laurentcae34662015-05-19 16:46:52 -07005048 int[] formats = AudioFormat.filterPublicFormats(devicePort.formats());
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005049 if (formats.length > 0) {
5050 ArrayList<Integer> encodingList = new ArrayList(1);
5051 for (int format : formats) {
5052 // a format in the list can be 0, skip it
5053 if (format != AudioFormat.ENCODING_INVALID) {
5054 encodingList.add(format);
5055 }
5056 }
5057 int[] encodingArray = new int[encodingList.size()];
5058 for (int i = 0 ; i < encodingArray.length ; i++) {
5059 encodingArray[i] = encodingList.get(i);
5060 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005061 intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005062 }
5063 // find the maximum supported number of channels
5064 int maxChannels = 0;
5065 for (int mask : devicePort.channelMasks()) {
5066 int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
5067 if (channelCount > maxChannels) {
5068 maxChannels = channelCount;
5069 }
5070 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005071 intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005072 }
5073 }
5074 }
5075 }
5076 }
5077 }
5078
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07005079 /* cache of the address of the last dock the device was connected to */
5080 private String mDockAddress;
5081
Eric Laurenta553c252009-07-17 12:17:14 -07005082 /**
5083 * Receiver for misc intent broadcasts the Phone app cares about.
5084 */
5085 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
5086 @Override
5087 public void onReceive(Context context, Intent intent) {
5088 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07005089 int outDevice;
5090 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07005091 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07005092
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08005093 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
5094 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
5095 Intent.EXTRA_DOCK_STATE_UNDOCKED);
5096 int config;
5097 switch (dockState) {
5098 case Intent.EXTRA_DOCK_STATE_DESK:
5099 config = AudioSystem.FORCE_BT_DESK_DOCK;
5100 break;
5101 case Intent.EXTRA_DOCK_STATE_CAR:
5102 config = AudioSystem.FORCE_BT_CAR_DOCK;
5103 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05005104 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08005105 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05005106 break;
5107 case Intent.EXTRA_DOCK_STATE_HE_DESK:
5108 config = AudioSystem.FORCE_DIGITAL_DOCK;
5109 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08005110 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
5111 default:
5112 config = AudioSystem.FORCE_NONE;
5113 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08005114 // Low end docks have a menu to enable or disable audio
5115 // (see mDockAudioMediaEnabled)
5116 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
5117 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
5118 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
5119 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
5120 }
5121 mDockState = dockState;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07005122 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
Eric Laurent59f48272012-04-05 19:42:21 -07005123 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07005124 BluetoothProfile.STATE_DISCONNECTED);
Eric Laurentdca56b92011-09-02 14:20:56 -07005125 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Eric Laurent0867bed2015-05-20 14:49:08 -07005126
Eric Laurent98859b22015-06-12 14:35:59 -07005127 setBtScoDeviceConnectionState(btDevice, state);
Paul McLeandf361462014-04-10 16:02:55 -07005128 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005129 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07005130 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005131 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005132 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07005133 // broadcast intent if the connection was initated by AudioService
5134 if (!mScoClients.isEmpty() &&
5135 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
5136 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
5137 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005138 broadcast = true;
5139 }
5140 switch (btState) {
5141 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07005142 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07005143 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5144 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5145 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005146 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005147 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005148 break;
5149 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07005150 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08005151 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07005152 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08005153 break;
5154 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07005155 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5156 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5157 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005158 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005159 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005160 default:
5161 // do not broadcast CONNECTING or invalid state
5162 broadcast = false;
5163 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005164 }
5165 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005166 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07005167 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07005168 //FIXME: this is to maintain compatibility with deprecated intent
5169 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08005170 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07005171 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005172 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08005173 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005174 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06005175 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005176 RotationHelper.enable();
Jon Eklund318f0fe2014-01-23 17:53:48 -06005177 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005178 AudioSystem.setParameters("screen_state=on");
5179 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06005180 if (mMonitorRotation) {
5181 //reduce wakeups (save current) by only listening when display is on
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005182 RotationHelper.disable();
Jon Eklund318f0fe2014-01-23 17:53:48 -06005183 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005184 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07005185 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005186 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07005187 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Yasuhiro Matsuda4ced7192015-07-10 22:08:44 +09005188 if (mUserSwitchedReceived) {
5189 // attempt to stop music playback for background user except on first user
5190 // switch (i.e. first boot)
5191 sendMsg(mAudioHandler,
5192 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
5193 SENDMSG_REPLACE,
5194 0,
5195 0,
5196 null,
5197 0);
5198 }
5199 mUserSwitchedReceived = true;
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07005200 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005201 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07005202
Eric Laurent5bfaeae2012-09-21 18:44:48 -07005203 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07005204 readAudioSettings(true /*userSwitch*/);
5205 // preserve STREAM_MUSIC volume from one user to the next.
5206 sendMsg(mAudioHandler,
5207 MSG_SET_ALL_VOLUMES,
5208 SENDMSG_QUEUE,
5209 0,
5210 0,
5211 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005212 } else if (action.equals(Intent.ACTION_USER_BACKGROUND)) {
5213 // Disable audio recording for the background user/profile
5214 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
5215 if (userId >= 0) {
5216 // TODO Kill recording streams instead of killing processes holding permission
5217 UserInfo userInfo = UserManagerService.getInstance().getUserInfo(userId);
5218 killBackgroundUserProcessesWithRecordAudioPermission(userInfo);
5219 }
Makoto Onukiac65e1e2015-11-20 15:33:17 -08005220 UserManagerService.getInstance().setUserRestriction(
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005221 UserManager.DISALLOW_RECORD_AUDIO, true, userId);
5222 } else if (action.equals(Intent.ACTION_USER_FOREGROUND)) {
5223 // Enable audio recording for foreground user/profile
5224 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Makoto Onukiac65e1e2015-11-20 15:33:17 -08005225 UserManagerService.getInstance().setUserRestriction(
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005226 UserManager.DISALLOW_RECORD_AUDIO, false, userId);
Eric Laurenta553c252009-07-17 12:17:14 -07005227 }
5228 }
Paul McLeanc837a452014-04-09 09:04:43 -07005229 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005230
Makoto Onukid45a4a22015-11-02 17:17:38 -08005231 private class AudioServiceUserRestrictionsListener implements UserRestrictionsListener {
5232
5233 @Override
5234 public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
5235 Bundle prevRestrictions) {
5236 // Update mic mute state.
5237 {
5238 final boolean wasRestricted =
5239 prevRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
5240 final boolean isRestricted =
5241 newRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
5242 if (wasRestricted != isRestricted) {
5243 setMicrophoneMuteNoCallerCheck(isRestricted, userId);
5244 }
5245 }
5246
5247 // Update speaker mute state.
5248 {
5249 final boolean wasRestricted =
5250 prevRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME);
5251 final boolean isRestricted =
5252 newRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME);
5253 if (wasRestricted != isRestricted) {
5254 setMasterMuteInternalNoCallerCheck(isRestricted, /* flags =*/ 0, userId);
5255 }
5256 }
5257 }
5258 } // end class AudioServiceUserRestrictionsListener
5259
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005260 private void killBackgroundUserProcessesWithRecordAudioPermission(UserInfo oldUser) {
5261 PackageManager pm = mContext.getPackageManager();
5262 // Find the home activity of the user. It should not be killed to avoid expensive restart,
5263 // when the user switches back. For managed profiles, we should kill all recording apps
5264 ComponentName homeActivityName = null;
5265 if (!oldUser.isManagedProfile()) {
5266 homeActivityName = LocalServices.getService(ActivityManagerInternal.class)
5267 .getHomeActivityForUser(oldUser.id);
5268 }
5269 final String[] permissions = { Manifest.permission.RECORD_AUDIO };
5270 List<PackageInfo> packages;
5271 try {
5272 packages = AppGlobals.getPackageManager()
5273 .getPackagesHoldingPermissions(permissions, 0, oldUser.id).getList();
5274 } catch (RemoteException e) {
5275 throw new AndroidRuntimeException(e);
5276 }
5277 for (int j = packages.size() - 1; j >= 0; j--) {
5278 PackageInfo pkg = packages.get(j);
Fyodor Kupolovbcb6c1e2015-05-11 12:05:15 -07005279 // Skip system processes
5280 if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
5281 continue;
5282 }
Amith Yamasanic1cbaab2015-07-21 11:46:14 -07005283 // Skip packages that have permission to interact across users
5284 if (pm.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS, pkg.packageName)
5285 == PackageManager.PERMISSION_GRANTED) {
5286 continue;
5287 }
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005288 if (homeActivityName != null
5289 && pkg.packageName.equals(homeActivityName.getPackageName())
5290 && pkg.applicationInfo.isSystemApp()) {
5291 continue;
5292 }
5293 try {
Svetoslavaa41add2015-08-06 15:03:55 -07005294 final int uid = pkg.applicationInfo.uid;
5295 ActivityManagerNative.getDefault().killUid(UserHandle.getAppId(uid),
5296 UserHandle.getUserId(uid),
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005297 "killBackgroundUserProcessesWithAudioRecordPermission");
5298 } catch (RemoteException e) {
5299 Log.w(TAG, "Error calling killUid", e);
5300 }
5301 }
5302 }
5303
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005304
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005305 //==========================================================================================
5306 // Audio Focus
5307 //==========================================================================================
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005308 public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005309 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005310 IAudioPolicyCallback pcb) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005311 // permission checks
5312 if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
John Spurlock61560172015-02-06 19:46:04 -05005313 if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005314 if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
5315 android.Manifest.permission.MODIFY_PHONE_STATE)) {
5316 Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
5317 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5318 }
5319 } else {
5320 // only a registered audio policy can be used to lock focus
5321 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005322 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
5323 Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005324 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5325 }
5326 }
5327 }
5328 }
5329
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005330 return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
5331 clientId, callingPackageName, flags);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005332 }
5333
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005334 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
5335 return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005336 }
5337
5338 public void unregisterAudioFocusClient(String clientId) {
5339 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005340 }
5341
Jean-Michel Trivi23805662013-07-31 14:19:18 -07005342 public int getCurrentAudioFocus() {
5343 return mMediaFocusControl.getCurrentAudioFocus();
5344 }
5345
John Spurlock5e783732015-02-19 10:28:59 -05005346 private boolean readCameraSoundForced() {
5347 return SystemProperties.getBoolean("audio.camerasound.force", false) ||
5348 mContext.getResources().getBoolean(
5349 com.android.internal.R.bool.config_camera_sound_forced);
5350 }
5351
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005352 //==========================================================================================
5353 // Device orientation
5354 //==========================================================================================
5355 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005356 * Handles device configuration changes that may map to a change in the orientation
5357 * or orientation.
5358 * Monitoring orientation and rotation is optional, and is defined by the definition and value
5359 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005360 */
5361 private void handleConfigurationChanged(Context context) {
5362 try {
5363 // reading new orientation "safely" (i.e. under try catch) in case anything
5364 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07005365 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005366 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07005367 if (mMonitorOrientation) {
5368 int newOrientation = config.orientation;
5369 if (newOrientation != mDeviceOrientation) {
5370 mDeviceOrientation = newOrientation;
5371 setOrientationForAudioSystem();
5372 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005373 }
Eric Laurentd640bd32012-09-28 18:01:48 -07005374 sendMsg(mAudioHandler,
5375 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
5376 SENDMSG_REPLACE,
5377 0,
5378 0,
John Spurlock90874332015-03-10 16:00:54 -04005379 TAG,
Eric Laurentd640bd32012-09-28 18:01:48 -07005380 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07005381
John Spurlock5e783732015-02-19 10:28:59 -05005382 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -07005383 synchronized (mSettingsLock) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005384 boolean cameraSoundForcedChanged = false;
Eric Laurentdd45d012012-10-08 09:04:34 -07005385 synchronized (mCameraSoundForced) {
5386 if (cameraSoundForced != mCameraSoundForced) {
5387 mCameraSoundForced = cameraSoundForced;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005388 cameraSoundForcedChanged = true;
Eric Laurentdd45d012012-10-08 09:04:34 -07005389 }
5390 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005391 if (cameraSoundForcedChanged) {
5392 if (!isPlatformTelevision()) {
5393 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
5394 if (cameraSoundForced) {
5395 s.setAllIndexesToMax();
5396 mRingerModeAffectedStreams &=
5397 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5398 } else {
John Spurlock90874332015-03-10 16:00:54 -04005399 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005400 mRingerModeAffectedStreams |=
5401 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5402 }
5403 // take new state into account for streams muted by ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05005404 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005405 }
5406
5407 sendMsg(mAudioHandler,
5408 MSG_SET_FORCE_USE,
5409 SENDMSG_QUEUE,
5410 AudioSystem.FOR_SYSTEM,
5411 cameraSoundForced ?
5412 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
5413 null,
5414 0);
5415
5416 sendMsg(mAudioHandler,
5417 MSG_SET_ALL_VOLUMES,
5418 SENDMSG_QUEUE,
5419 0,
5420 0,
5421 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
5422 }
Eric Laurentdd45d012012-10-08 09:04:34 -07005423 }
John Spurlock3346a802014-05-20 16:25:37 -04005424 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005425 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005426 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005427 }
5428 }
5429
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005430 //TODO move to an external "orientation helper" class
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005431 private void setOrientationForAudioSystem() {
5432 switch (mDeviceOrientation) {
5433 case Configuration.ORIENTATION_LANDSCAPE:
5434 //Log.i(TAG, "orientation is landscape");
5435 AudioSystem.setParameters("orientation=landscape");
5436 break;
5437 case Configuration.ORIENTATION_PORTRAIT:
5438 //Log.i(TAG, "orientation is portrait");
5439 AudioSystem.setParameters("orientation=portrait");
5440 break;
5441 case Configuration.ORIENTATION_SQUARE:
5442 //Log.i(TAG, "orientation is square");
5443 AudioSystem.setParameters("orientation=square");
5444 break;
5445 case Configuration.ORIENTATION_UNDEFINED:
5446 //Log.i(TAG, "orientation is undefined");
5447 AudioSystem.setParameters("orientation=undefined");
5448 break;
5449 default:
5450 Log.e(TAG, "Unknown orientation");
5451 }
5452 }
5453
Eric Laurent78472112012-05-21 08:57:21 -07005454 // Handles request to override default use of A2DP for media.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005455 // Must be called synchronized on mConnectedDevices
Eric Laurent78472112012-05-21 08:57:21 -07005456 public void setBluetoothA2dpOnInt(boolean on) {
5457 synchronized (mBluetoothA2dpEnabledLock) {
5458 mBluetoothA2dpEnabled = on;
Eric Laurentc390bed2012-07-03 12:24:05 -07005459 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005460 setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
Eric Laurentc390bed2012-07-03 12:24:05 -07005461 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
Eric Laurent78472112012-05-21 08:57:21 -07005462 }
5463 }
5464
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005465 // Must be called synchronized on mConnectedDevices
5466 private void setForceUseInt_SyncDevices(int usage, int config) {
5467 switch (usage) {
5468 case AudioSystem.FOR_MEDIA:
5469 if (config == AudioSystem.FORCE_NO_BT_A2DP) {
5470 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ALL_A2DP;
5471 } else { // config == AudioSystem.FORCE_NONE
5472 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
5473 }
5474 break;
5475 case AudioSystem.FOR_DOCK:
5476 if (config == AudioSystem.FORCE_ANALOG_DOCK) {
5477 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5478 } else { // config == AudioSystem.FORCE_NONE
5479 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5480 }
5481 break;
5482 default:
5483 // usage doesn't affect the broadcast of ACTION_AUDIO_BECOMING_NOISY
5484 }
5485 AudioSystem.setForceUse(usage, config);
5486 }
5487
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005488 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07005489 public void setRingtonePlayer(IRingtonePlayer player) {
5490 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5491 mRingtonePlayer = player;
5492 }
5493
5494 @Override
5495 public IRingtonePlayer getRingtonePlayer() {
5496 return mRingtonePlayer;
5497 }
5498
5499 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07005500 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5501 synchronized (mCurAudioRoutes) {
5502 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5503 mRoutesObservers.register(observer);
5504 return routes;
5505 }
5506 }
5507
Eric Laurentc34dcc12012-09-10 13:51:52 -07005508
5509 //==========================================================================================
5510 // Safe media volume management.
5511 // MUSIC stream volume level is limited when headphones are connected according to safety
5512 // regulation. When the user attempts to raise the volume above the limit, a warning is
5513 // displayed and the user has to acknowlegde before the volume is actually changed.
5514 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
5515 // property. Platforms with a different limit must set this property accordingly in their
5516 // overlay.
5517 //==========================================================================================
5518
Eric Laurentd640bd32012-09-28 18:01:48 -07005519 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
5520 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
5521 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
5522 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
5523 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
5524 // (when user opts out).
John Spurlock35134602014-07-24 18:10:48 -04005525 private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
5526 private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
5527 private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed
5528 private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
Eric Laurentd640bd32012-09-28 18:01:48 -07005529 private Integer mSafeMediaVolumeState;
5530
5531 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005532 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07005533 private int mSafeMediaVolumeIndex;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005534 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
5535 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
5536 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
5537 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
5538 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
5539 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
5540 private int mMusicActiveMs;
5541 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
5542 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07005543 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07005544
John Spurlock90874332015-03-10 16:00:54 -04005545 private void setSafeMediaVolumeEnabled(boolean on, String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005546 synchronized (mSafeMediaVolumeState) {
5547 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
5548 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
5549 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
5550 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
John Spurlock90874332015-03-10 16:00:54 -04005551 enforceSafeMediaVolume(caller);
Eric Laurentd640bd32012-09-28 18:01:48 -07005552 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
5553 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005554 mMusicActiveMs = 1; // nonzero = confirmed
5555 saveMusicActiveMs();
Eric Laurentd640bd32012-09-28 18:01:48 -07005556 sendMsg(mAudioHandler,
5557 MSG_CHECK_MUSIC_ACTIVE,
5558 SENDMSG_REPLACE,
5559 0,
5560 0,
John Spurlock90874332015-03-10 16:00:54 -04005561 caller,
Eric Laurentd640bd32012-09-28 18:01:48 -07005562 MUSIC_ACTIVE_POLL_PERIOD_MS);
5563 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005564 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005565 }
5566 }
5567
John Spurlock90874332015-03-10 16:00:54 -04005568 private void enforceSafeMediaVolume(String caller) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005569 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07005570 int devices = mSafeMediaVolumeDevices;
5571 int i = 0;
5572
5573 while (devices != 0) {
5574 int device = 1 << i++;
5575 if ((device & devices) == 0) {
5576 continue;
5577 }
Eric Laurent42b041e2013-03-29 11:36:03 -07005578 int index = streamState.getIndex(device);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005579 if (index > mSafeMediaVolumeIndex) {
John Spurlock90874332015-03-10 16:00:54 -04005580 streamState.setIndex(mSafeMediaVolumeIndex, device, caller);
Eric Laurent42b041e2013-03-29 11:36:03 -07005581 sendMsg(mAudioHandler,
5582 MSG_SET_DEVICE_VOLUME,
5583 SENDMSG_QUEUE,
5584 device,
5585 0,
5586 streamState,
5587 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005588 }
5589 devices &= ~device;
5590 }
5591 }
5592
5593 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005594 synchronized (mSafeMediaVolumeState) {
5595 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07005596 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
5597 ((device & mSafeMediaVolumeDevices) != 0) &&
5598 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005599 return false;
5600 }
5601 return true;
5602 }
5603 }
5604
John Spurlock3346a802014-05-20 16:25:37 -04005605 @Override
John Spurlock90874332015-03-10 16:00:54 -04005606 public void disableSafeMediaVolume(String callingPackage) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005607 enforceVolumeController("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07005608 synchronized (mSafeMediaVolumeState) {
John Spurlock90874332015-03-10 16:00:54 -04005609 setSafeMediaVolumeEnabled(false, callingPackage);
Eric Laurentfde16d52012-12-03 14:42:39 -08005610 if (mPendingVolumeCommand != null) {
5611 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
5612 mPendingVolumeCommand.mIndex,
5613 mPendingVolumeCommand.mFlags,
John Spurlock90874332015-03-10 16:00:54 -04005614 mPendingVolumeCommand.mDevice,
5615 callingPackage);
Eric Laurentfde16d52012-12-03 14:42:39 -08005616 mPendingVolumeCommand = null;
5617 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005618 }
5619 }
5620
Jungshik Jang41d97462014-06-30 22:26:29 +09005621 //==========================================================================================
5622 // Hdmi Cec system audio mode.
John Spurlockbc82b122015-03-02 16:12:38 -05005623 // If Hdmi Cec's system audio mode is on, audio service should send the volume change
5624 // to HdmiControlService so that the audio receiver can handle it.
Jungshik Jang41d97462014-06-30 22:26:29 +09005625 //==========================================================================================
5626
Eric Laurent212532b2014-07-21 15:43:18 -07005627 private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
5628 public void onComplete(int status) {
5629 if (mHdmiManager != null) {
5630 synchronized (mHdmiManager) {
5631 mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
5632 // Television devices without CEC service apply software volume on HDMI output
5633 if (isPlatformTelevision() && !mHdmiCecSink) {
5634 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5635 }
5636 checkAllFixedVolumeDevices();
5637 }
5638 }
5639 }
5640 };
5641
Jungshik Jang41d97462014-06-30 22:26:29 +09005642 // If HDMI-CEC system audio is supported
5643 private boolean mHdmiSystemAudioSupported = false;
5644 // Set only when device is tv.
5645 private HdmiTvClient mHdmiTvClient;
Eric Laurent0b03f992014-11-18 18:08:02 -08005646 // true if the device has system feature PackageManager.FEATURE_LEANBACK.
Eric Laurent212532b2014-07-21 15:43:18 -07005647 // cached HdmiControlManager interface
5648 private HdmiControlManager mHdmiManager;
5649 // Set only when device is a set-top box.
5650 private HdmiPlaybackClient mHdmiPlaybackClient;
5651 // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5652 private boolean mHdmiCecSink;
5653
5654 private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
Jungshik Jang41d97462014-06-30 22:26:29 +09005655
5656 @Override
Jungshik Jang12307ca2014-07-15 19:27:56 +09005657 public int setHdmiSystemAudioSupported(boolean on) {
Eric Laurent212532b2014-07-21 15:43:18 -07005658 int device = AudioSystem.DEVICE_NONE;
5659 if (mHdmiManager != null) {
5660 synchronized (mHdmiManager) {
5661 if (mHdmiTvClient == null) {
5662 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5663 return device;
5664 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005665
Eric Laurent212532b2014-07-21 15:43:18 -07005666 synchronized (mHdmiTvClient) {
5667 if (mHdmiSystemAudioSupported != on) {
5668 mHdmiSystemAudioSupported = on;
5669 AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5670 on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5671 AudioSystem.FORCE_NONE);
5672 }
John Spurlock8a52c442015-03-26 14:23:58 -04005673 device = getDevicesForStream(AudioSystem.STREAM_MUSIC);
Eric Laurent212532b2014-07-21 15:43:18 -07005674 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005675 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005676 }
Eric Laurent212532b2014-07-21 15:43:18 -07005677 return device;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005678 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005679
Terry Heoe7d6d972014-09-04 21:05:28 +09005680 @Override
5681 public boolean isHdmiSystemAudioSupported() {
5682 return mHdmiSystemAudioSupported;
5683 }
5684
Eric Laurentdd45d012012-10-08 09:04:34 -07005685 //==========================================================================================
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005686 // Accessibility: taking touch exploration into account for selecting the default
5687 // stream override timeout when adjusting volume
5688 //==========================================================================================
5689 private static class StreamOverride
5690 implements AccessibilityManager.TouchExplorationStateChangeListener {
5691
5692 // AudioService.getActiveStreamType() will return:
5693 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
5694 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
5695 // stopped
Jean-Michel Triviccffda82015-05-21 18:23:57 -07005696 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 0;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005697 private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
5698
5699 static int sDelayMs;
5700
5701 static void init(Context ctxt) {
5702 AccessibilityManager accessibilityManager =
5703 (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
5704 updateDefaultStreamOverrideDelay(
5705 accessibilityManager.isTouchExplorationEnabled());
5706 accessibilityManager.addTouchExplorationStateChangeListener(
5707 new StreamOverride());
5708 }
5709
5710 @Override
5711 public void onTouchExplorationStateChanged(boolean enabled) {
5712 updateDefaultStreamOverrideDelay(enabled);
5713 }
5714
5715 private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
5716 if (touchExploreEnabled) {
5717 sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
5718 } else {
5719 sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
5720 }
5721 if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
5722 + " stream override delay is now " + sDelayMs + " ms");
5723 }
5724 }
5725
5726 //==========================================================================================
Eric Laurentdd45d012012-10-08 09:04:34 -07005727 // Camera shutter sound policy.
5728 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5729 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5730 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5731 //==========================================================================================
5732
5733 // cached value of com.android.internal.R.bool.config_camera_sound_forced
5734 private Boolean mCameraSoundForced;
5735
5736 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5737 public boolean isCameraSoundForced() {
5738 synchronized (mCameraSoundForced) {
5739 return mCameraSoundForced;
5740 }
5741 }
5742
5743 private static final String[] RINGER_MODE_NAMES = new String[] {
5744 "SILENT",
5745 "VIBRATE",
5746 "NORMAL"
5747 };
5748
5749 private void dumpRingerMode(PrintWriter pw) {
5750 pw.println("\nRinger mode: ");
John Spurlock661f2cf2014-11-17 10:29:10 -05005751 pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
5752 pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
John Spurlock50ced3f2015-05-11 16:00:09 -04005753 dumpRingerModeStreams(pw, "affected", mRingerModeAffectedStreams);
5754 dumpRingerModeStreams(pw, "muted", mRingerModeMutedStreams);
John Spurlock661f2cf2014-11-17 10:29:10 -05005755 pw.print("- delegate = "); pw.println(mRingerModeDelegate);
Eric Laurentdd45d012012-10-08 09:04:34 -07005756 }
5757
John Spurlock50ced3f2015-05-11 16:00:09 -04005758 private void dumpRingerModeStreams(PrintWriter pw, String type, int streams) {
5759 pw.print("- ringer mode "); pw.print(type); pw.print(" streams = 0x");
5760 pw.print(Integer.toHexString(streams));
5761 if (streams != 0) {
5762 pw.print(" (");
5763 boolean first = true;
5764 for (int i = 0; i < AudioSystem.STREAM_NAMES.length; i++) {
5765 final int stream = (1 << i);
5766 if ((streams & stream) != 0) {
5767 if (!first) pw.print(',');
5768 pw.print(AudioSystem.STREAM_NAMES[i]);
5769 streams &= ~stream;
5770 first = false;
5771 }
5772 }
5773 if (streams != 0) {
5774 if (!first) pw.print(',');
5775 pw.print(streams);
5776 }
5777 pw.print(')');
5778 }
5779 pw.println();
5780 }
5781
Dianne Hackborn632ca412012-06-14 19:34:10 -07005782 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005783 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07005784 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5785
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005786 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07005787 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07005788 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005789 pw.println("\nAudio routes:");
John Spurlock61560172015-02-06 19:46:04 -05005790 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
5791 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
John Spurlock35134602014-07-24 18:10:48 -04005792
5793 pw.println("\nOther state:");
John Spurlock3346a802014-05-20 16:25:37 -04005794 pw.print(" mVolumeController="); pw.println(mVolumeController);
John Spurlock35134602014-07-24 18:10:48 -04005795 pw.print(" mSafeMediaVolumeState=");
5796 pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
5797 pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
5798 pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
5799 pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005800 pw.print(" mMcc="); pw.println(mMcc);
John Spurlock5e783732015-02-19 10:28:59 -05005801 pw.print(" mCameraSoundForced="); pw.println(mCameraSoundForced);
John Spurlock661f2cf2014-11-17 10:29:10 -05005802 pw.print(" mHasVibrator="); pw.println(mHasVibrator);
John Spurlockcdb57ae2015-02-11 19:04:11 -05005803 pw.print(" mControllerService="); pw.println(mControllerService);
John Spurlocka48d7792015-03-03 17:35:57 -05005804 pw.print(" mVolumePolicy="); pw.println(mVolumePolicy);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005805
5806 dumpAudioPolicies(pw);
John Spurlock35134602014-07-24 18:10:48 -04005807 }
5808
5809 private static String safeMediaVolumeStateToString(Integer state) {
5810 switch(state) {
5811 case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
5812 case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
5813 case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
5814 case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
5815 }
5816 return null;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005817 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07005818
5819 // Inform AudioFlinger of our device's low RAM attribute
5820 private static void readAndSetLowRamDevice()
5821 {
5822 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
5823 if (status != 0) {
5824 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
5825 }
5826 }
John Spurlock3346a802014-05-20 16:25:37 -04005827
John Spurlockcdb57ae2015-02-11 19:04:11 -05005828 private void enforceVolumeController(String action) {
5829 if (mControllerService.mUid != 0 && Binder.getCallingUid() == mControllerService.mUid) {
5830 return;
5831 }
John Spurlock3346a802014-05-20 16:25:37 -04005832 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
5833 "Only SystemUI can " + action);
5834 }
5835
5836 @Override
5837 public void setVolumeController(final IVolumeController controller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005838 enforceVolumeController("set the volume controller");
John Spurlock3346a802014-05-20 16:25:37 -04005839
5840 // return early if things are not actually changing
5841 if (mVolumeController.isSameBinder(controller)) {
5842 return;
5843 }
5844
5845 // dismiss the old volume controller
5846 mVolumeController.postDismiss();
5847 if (controller != null) {
5848 // we are about to register a new controller, listen for its death
5849 try {
5850 controller.asBinder().linkToDeath(new DeathRecipient() {
5851 @Override
5852 public void binderDied() {
5853 if (mVolumeController.isSameBinder(controller)) {
5854 Log.w(TAG, "Current remote volume controller died, unregistering");
5855 setVolumeController(null);
5856 }
5857 }
5858 }, 0);
5859 } catch (RemoteException e) {
5860 // noop
5861 }
5862 }
5863 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04005864 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
5865 }
5866
5867 @Override
5868 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005869 enforceVolumeController("notify about volume controller visibility");
John Spurlock33f4e042014-07-11 13:10:58 -04005870
5871 // return early if the controller is not current
5872 if (!mVolumeController.isSameBinder(controller)) {
5873 return;
5874 }
5875
5876 mVolumeController.setVisible(visible);
5877 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04005878 }
RoboErikd09bd0c2014-06-24 17:45:19 -07005879
John Spurlocka48d7792015-03-03 17:35:57 -05005880 @Override
5881 public void setVolumePolicy(VolumePolicy policy) {
5882 enforceVolumeController("set volume policy");
John Spurlockb02c7442015-04-14 09:32:25 -04005883 if (policy != null && !policy.equals(mVolumePolicy)) {
John Spurlocka48d7792015-03-03 17:35:57 -05005884 mVolumePolicy = policy;
John Spurlockb02c7442015-04-14 09:32:25 -04005885 if (DEBUG_VOL) Log.d(TAG, "Volume policy changed: " + mVolumePolicy);
John Spurlocka48d7792015-03-03 17:35:57 -05005886 }
5887 }
5888
RoboErikd09bd0c2014-06-24 17:45:19 -07005889 public static class VolumeController {
5890 private static final String TAG = "VolumeController";
5891
5892 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04005893 private boolean mVisible;
5894 private long mNextLongPress;
5895 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07005896
5897 public void setController(IVolumeController controller) {
5898 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04005899 mVisible = false;
5900 }
5901
5902 public void loadSettings(ContentResolver cr) {
5903 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
5904 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
5905 }
5906
RoboErik4197cb62015-01-21 15:45:32 -08005907 public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
5908 if (isMute) {
5909 return false;
5910 }
John Spurlock33f4e042014-07-11 13:10:58 -04005911 boolean suppress = false;
5912 if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
5913 final long now = SystemClock.uptimeMillis();
5914 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
5915 // ui will become visible
5916 if (mNextLongPress < now) {
5917 mNextLongPress = now + mLongPressTimeout;
5918 }
5919 suppress = true;
5920 } else if (mNextLongPress > 0) { // in a long-press
5921 if (now > mNextLongPress) {
5922 // long press triggered, no more suppression
5923 mNextLongPress = 0;
5924 } else {
5925 // keep suppressing until the long press triggers
5926 suppress = true;
5927 }
5928 }
5929 }
5930 return suppress;
5931 }
5932
5933 public void setVisible(boolean visible) {
5934 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07005935 }
5936
5937 public boolean isSameBinder(IVolumeController controller) {
5938 return Objects.equals(asBinder(), binder(controller));
5939 }
5940
5941 public IBinder asBinder() {
5942 return binder(mController);
5943 }
5944
5945 private static IBinder binder(IVolumeController controller) {
5946 return controller == null ? null : controller.asBinder();
5947 }
5948
5949 @Override
5950 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04005951 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07005952 }
5953
5954 public void postDisplaySafeVolumeWarning(int flags) {
5955 if (mController == null)
5956 return;
5957 try {
5958 mController.displaySafeVolumeWarning(flags);
5959 } catch (RemoteException e) {
5960 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
5961 }
5962 }
5963
5964 public void postVolumeChanged(int streamType, int flags) {
5965 if (mController == null)
5966 return;
5967 try {
5968 mController.volumeChanged(streamType, flags);
5969 } catch (RemoteException e) {
5970 Log.w(TAG, "Error calling volumeChanged", e);
5971 }
5972 }
5973
RoboErikd09bd0c2014-06-24 17:45:19 -07005974 public void postMasterMuteChanged(int flags) {
5975 if (mController == null)
5976 return;
5977 try {
5978 mController.masterMuteChanged(flags);
5979 } catch (RemoteException e) {
5980 Log.w(TAG, "Error calling masterMuteChanged", e);
5981 }
5982 }
5983
5984 public void setLayoutDirection(int layoutDirection) {
5985 if (mController == null)
5986 return;
5987 try {
5988 mController.setLayoutDirection(layoutDirection);
5989 } catch (RemoteException e) {
5990 Log.w(TAG, "Error calling setLayoutDirection", e);
5991 }
5992 }
5993
5994 public void postDismiss() {
5995 if (mController == null)
5996 return;
5997 try {
5998 mController.dismiss();
5999 } catch (RemoteException e) {
6000 Log.w(TAG, "Error calling dismiss", e);
6001 }
6002 }
6003 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006004
RoboErik0dac35a2014-08-12 15:48:49 -07006005 /**
6006 * Interface for system components to get some extra functionality through
6007 * LocalServices.
6008 */
6009 final class AudioServiceInternal extends AudioManagerInternal {
John Spurlock661f2cf2014-11-17 10:29:10 -05006010 @Override
6011 public void setRingerModeDelegate(RingerModeDelegate delegate) {
6012 mRingerModeDelegate = delegate;
6013 if (mRingerModeDelegate != null) {
John Spurlock50ced3f2015-05-11 16:00:09 -04006014 updateRingerModeAffectedStreams();
John Spurlock661f2cf2014-11-17 10:29:10 -05006015 setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
6016 }
6017 }
RoboErik272e1612014-09-05 11:39:29 -07006018
6019 @Override
6020 public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
6021 String callingPackage, int uid) {
6022 // direction and stream type swap here because the public
6023 // adjustSuggested has a different order than the other methods.
John Spurlock90874332015-03-10 16:00:54 -04006024 adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage,
6025 callingPackage, uid);
RoboErik272e1612014-09-05 11:39:29 -07006026 }
6027
RoboErik0dac35a2014-08-12 15:48:49 -07006028 @Override
6029 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
6030 String callingPackage, int uid) {
John Spurlock90874332015-03-10 16:00:54 -04006031 adjustStreamVolume(streamType, direction, flags, callingPackage,
6032 callingPackage, uid);
RoboErik0dac35a2014-08-12 15:48:49 -07006033 }
6034
6035 @Override
6036 public void setStreamVolumeForUid(int streamType, int direction, int flags,
6037 String callingPackage, int uid) {
John Spurlock90874332015-03-10 16:00:54 -04006038 setStreamVolume(streamType, direction, flags, callingPackage, callingPackage, uid);
RoboErik0dac35a2014-08-12 15:48:49 -07006039 }
RoboErik519c7742014-11-18 10:59:09 -08006040
6041 @Override
John Spurlock661f2cf2014-11-17 10:29:10 -05006042 public int getRingerModeInternal() {
6043 return AudioService.this.getRingerModeInternal();
6044 }
6045
6046 @Override
6047 public void setRingerModeInternal(int ringerMode, String caller) {
6048 AudioService.this.setRingerModeInternal(ringerMode, caller);
6049 }
John Spurlockcdb57ae2015-02-11 19:04:11 -05006050
6051 @Override
6052 public int getVolumeControllerUid() {
6053 return mControllerService.mUid;
6054 }
John Spurlock50ced3f2015-05-11 16:00:09 -04006055
6056 @Override
6057 public void updateRingerModeAffectedStreamsInternal() {
6058 synchronized (mSettingsLock) {
6059 if (updateRingerModeAffectedStreams()) {
6060 setRingerModeInt(getRingerModeInternal(), false);
6061 }
6062 }
6063 }
RoboErik0dac35a2014-08-12 15:48:49 -07006064 }
6065
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006066 //==========================================================================================
6067 // Audio policy management
6068 //==========================================================================================
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006069 public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
6070 boolean hasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006071 AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
6072
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006073 if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
6074 + " with config:" + policyConfig);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006075 String regId = null;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006076 // error handling
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006077 boolean hasPermissionForPolicy =
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006078 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006079 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
6080 if (!hasPermissionForPolicy) {
6081 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
6082 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006083 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006084 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006085
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006086 synchronized (mAudioPolicies) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006087 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006088 if (mAudioPolicies.containsKey(pcb.asBinder())) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006089 Slog.e(TAG, "Cannot re-register policy");
6090 return null;
6091 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006092 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
6093 pcb.asBinder().linkToDeath(app, 0/*flags*/);
6094 regId = app.getRegistrationId();
6095 mAudioPolicies.put(pcb.asBinder(), app);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006096 } catch (RemoteException e) {
6097 // audio policy owner has already died!
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006098 Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006099 " binder death", e);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006100 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006101 }
6102 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006103 return regId;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006104 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006105
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006106 public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
6107 if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006108 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006109 AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006110 if (app == null) {
6111 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
6112 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006113 return;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006114 } else {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006115 pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006116 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006117 app.release();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006118 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006119 // TODO implement clearing mix attribute matching info in native audio policy
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006120 }
6121
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006122 public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
6123 if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
6124 + " policy " + pcb.asBinder());
6125 // error handling
6126 boolean hasPermissionForPolicy =
6127 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
6128 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
6129 if (!hasPermissionForPolicy) {
6130 Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
6131 + Binder.getCallingPid() + " / uid "
6132 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
6133 return AudioManager.ERROR;
6134 }
6135
6136 synchronized (mAudioPolicies) {
6137 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
6138 Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
6139 return AudioManager.ERROR;
6140 }
6141 final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
6142 if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6143 // is there already one policy managing ducking?
Eric Laurent0867bed2015-05-20 14:49:08 -07006144 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006145 if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6146 Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
6147 return AudioManager.ERROR;
6148 }
6149 }
6150 }
6151 app.mFocusDuckBehavior = duckingBehavior;
6152 mMediaFocusControl.setDuckingInExtPolicyAvailable(
6153 duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
6154 }
6155 return AudioManager.SUCCESS;
6156 }
6157
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006158 private void dumpAudioPolicies(PrintWriter pw) {
6159 pw.println("\nAudio policies:");
6160 synchronized (mAudioPolicies) {
Eric Laurent0867bed2015-05-20 14:49:08 -07006161 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006162 pw.println(policy.toLogFriendlyString());
6163 }
6164 }
6165 }
6166
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006167 //======================
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006168 // Audio policy callback from AudioSystem
6169 //======================
6170 private final AudioSystem.DynamicPolicyCallback mDynPolicyCallback =
6171 new AudioSystem.DynamicPolicyCallback() {
6172 public void onDynamicPolicyMixStateUpdate(String regId, int state) {
6173 if (!TextUtils.isEmpty(regId)) {
6174 sendMsg(mAudioHandler, MSG_DYN_POLICY_MIX_STATE_UPDATE, SENDMSG_QUEUE,
6175 state /*arg1*/, 0 /*arg2 ignored*/, regId /*obj*/, 0 /*delay*/);
6176 }
6177 }
6178 };
6179
6180 private void onDynPolicyMixStateUpdate(String regId, int state) {
6181 if (DEBUG_AP) Log.d(TAG, "onDynamicPolicyMixStateUpdate("+ regId + ", " + state +")");
6182 synchronized (mAudioPolicies) {
6183 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
6184 for (AudioMix mix : policy.getMixes()) {
6185 if (mix.getRegistration().equals(regId)) {
6186 try {
6187 policy.mPolicyCallback.notifyMixStateUpdate(regId, state);
6188 } catch (RemoteException e) {
6189 Log.e(TAG, "Can't call notifyMixStateUpdate() on IAudioPolicyCallback "
6190 + policy.mPolicyCallback.asBinder(), e);
6191 }
6192 return;
6193 }
6194 }
6195 }
6196 }
6197
6198 }
6199
6200 //======================
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006201 // Audio policy proxy
6202 //======================
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006203 /**
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006204 * This internal class inherits from AudioPolicyConfig, each instance contains all the
6205 * mixes of an AudioPolicy and their configurations.
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006206 */
6207 public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006208 private static final String TAG = "AudioPolicyProxy";
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006209 IAudioPolicyCallback mPolicyCallback;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006210 boolean mHasFocusListener;
6211 /**
6212 * Audio focus ducking behavior for an audio policy.
6213 * This variable reflects the value that was successfully set in
6214 * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
6215 * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
6216 * is handling ducking for audio focus.
6217 */
6218 int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
6219
6220 AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
6221 boolean hasFocusListener) {
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006222 super(config);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006223 setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006224 mPolicyCallback = token;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006225 mHasFocusListener = hasFocusListener;
6226 if (mHasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006227 mMediaFocusControl.addFocusFollower(mPolicyCallback);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006228 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006229 connectMixes();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006230 }
6231
6232 public void binderDied() {
6233 synchronized (mAudioPolicies) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006234 Log.i(TAG, "audio policy " + mPolicyCallback + " died");
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006235 release();
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006236 mAudioPolicies.remove(mPolicyCallback.asBinder());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006237 }
6238 }
6239
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006240 String getRegistrationId() {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006241 return getRegistration();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006242 }
6243
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006244 void release() {
6245 if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6246 mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
6247 }
6248 if (mHasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006249 mMediaFocusControl.removeFocusFollower(mPolicyCallback);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006250 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006251 AudioSystem.registerPolicyMixes(mMixes, false);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006252 }
6253
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006254 void connectMixes() {
6255 AudioSystem.registerPolicyMixes(mMixes, true);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006256 }
6257 };
6258
6259 private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
6260 new HashMap<IBinder, AudioPolicyProxy>();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006261 private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
John Spurlockcdb57ae2015-02-11 19:04:11 -05006262
6263 private class ControllerService extends ContentObserver {
6264 private int mUid;
6265 private ComponentName mComponent;
6266
6267 public ControllerService() {
6268 super(null);
6269 }
6270
6271 @Override
6272 public String toString() {
6273 return String.format("{mUid=%d,mComponent=%s}", mUid, mComponent);
6274 }
6275
6276 public void init() {
6277 onChange(true);
6278 mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
6279 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT), false, this);
6280 }
6281
6282 @Override
6283 public void onChange(boolean selfChange) {
6284 mUid = 0;
6285 mComponent = null;
6286 final String setting = Settings.Secure.getString(mContentResolver,
6287 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
6288 if (setting == null) return;
6289 try {
6290 mComponent = ComponentName.unflattenFromString(setting);
6291 if (mComponent == null) return;
6292 mUid = mContext.getPackageManager()
6293 .getApplicationInfo(mComponent.getPackageName(), 0).uid;
6294 } catch (Exception e) {
6295 Log.w(TAG, "Error loading controller service", e);
6296 }
6297 if (DEBUG_VOL) Log.d(TAG, "Reloaded controller service: " + this);
6298 }
6299 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006300}