blob: 548f563bd6af7ba13dc20a58ee449371bf6e924f [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;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -080061import android.media.AudioRecordConfiguration;
John Spurlock61560172015-02-06 19:46:04 -050062import android.media.AudioRoutesInfo;
John Spurlock61560172015-02-06 19:46:04 -050063import android.media.IAudioFocusDispatcher;
64import android.media.IAudioRoutesObserver;
65import android.media.IAudioService;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -080066import android.media.IRecordingConfigDispatcher;
John Spurlock61560172015-02-06 19:46:04 -050067import android.media.IRingtonePlayer;
68import android.media.IVolumeController;
69import android.media.MediaPlayer;
70import android.media.SoundPool;
John Spurlocka48d7792015-03-03 17:35:57 -050071import android.media.VolumePolicy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.media.MediaPlayer.OnCompletionListener;
73import android.media.MediaPlayer.OnErrorListener;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -070074import android.media.audiopolicy.AudioMix;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -080075import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070076import android.media.audiopolicy.AudioPolicyConfig;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -080077import android.media.audiopolicy.IAudioPolicyCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078import android.os.Binder;
Eric Laurentc18c9132013-04-12 17:24:56 -070079import android.os.Build;
Makoto Onukid45a4a22015-11-02 17:17:38 -080080import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081import android.os.Environment;
82import android.os.Handler;
83import android.os.IBinder;
84import android.os.Looper;
85import android.os.Message;
Jean-Michel Trivic6802222012-04-30 11:15:03 -070086import android.os.PowerManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070087import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088import android.os.RemoteException;
John Spurlock33f4e042014-07-11 13:10:58 -040089import android.os.SystemClock;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070090import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070091import android.os.UserHandle;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070092import android.os.UserManager;
Makoto Onukid45a4a22015-11-02 17:17:38 -080093import android.os.UserManagerInternal;
94import android.os.UserManagerInternal.UserRestrictionsListener;
Eric Laurentbffc3d12012-05-07 17:43:49 -070095import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096import android.provider.Settings;
97import android.provider.Settings.System;
Tyler Gunnef9f6f92014-09-12 22:16:17 -070098import android.telecom.TelecomManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070099import android.text.TextUtils;
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700100import android.util.AndroidRuntimeException;
John Spurlock8c3dc852015-04-23 21:32:37 -0400101import android.util.ArrayMap;
102import android.util.ArraySet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103import android.util.Log;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400104import android.util.MathUtils;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -0700105import android.util.Slog;
John Spurlock2bb02ec2015-03-02 13:13:06 -0500106import android.util.SparseIntArray;
Jean-Michel Trivid327f212010-03-16 21:44:33 -0700107import android.view.KeyEvent;
RoboErik519c7742014-11-18 10:59:09 -0800108import android.view.OrientationEventListener;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700109import android.view.Surface;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700110import android.view.WindowManager;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700111import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112
Eric Laurente78fced2013-03-15 16:03:47 -0700113import com.android.internal.util.XmlUtils;
John Spurlock90874332015-03-10 16:00:54 -0400114import com.android.server.EventLogTags;
RoboErik0dac35a2014-08-12 15:48:49 -0700115import com.android.server.LocalServices;
Makoto Onukie1aef852015-10-15 17:28:35 -0700116import com.android.server.SystemService;
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700117import com.android.server.pm.UserManagerService;
Eric Laurente78fced2013-03-15 16:03:47 -0700118
119import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800121import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122import java.io.IOException;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800123import java.io.PrintWriter;
Eric Laurente78fced2013-03-15 16:03:47 -0700124import java.lang.reflect.Field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125import java.util.ArrayList;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700126import java.util.HashMap;
127import java.util.Iterator;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -0700128import java.util.List;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700129import java.util.NoSuchElementException;
RoboErikd09bd0c2014-06-24 17:45:19 -0700130import java.util.Objects;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131
132/**
133 * The implementation of the volume manager service.
134 * <p>
135 * This implementation focuses on delivering a responsive UI. Most methods are
136 * asynchronous to external calls. For example, the task of setting a volume
137 * will update our internal state, but in a separate thread will set the system
138 * volume and later persist to the database. Similarly, setting the ringer mode
139 * will update the state and broadcast a change and in a separate thread later
140 * persist the ringer mode.
141 *
142 * @hide
143 */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700144public class AudioService extends IAudioService.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145
146 private static final String TAG = "AudioService";
147
Jean-Michel Trivi339567d2014-07-29 09:53:34 -0700148 /** Debug audio mode */
149 protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -0700150
151 /** Debug audio policy feature */
152 protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);
153
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700154 /** Debug volumes */
John Spurlockae641c92014-06-30 18:11:40 -0400155 protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700156
Paul McLean394a8e12015-03-03 10:29:19 -0700157 /** debug calls to devices APIs */
158 protected static final boolean DEBUG_DEVICES = Log.isLoggable(TAG + ".DEVICES", Log.DEBUG);
159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 /** How long to delay before persisting a change in volume/ringer mode. */
RoboErik45edba12012-03-27 17:54:36 -0700161 private static final int PERSIST_DELAY = 500;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162
RoboErik5452e252015-02-06 15:33:53 -0800163 /** How long to delay after a volume down event before unmuting a stream */
164 private static final int UNMUTE_STREAM_DELAY = 350;
165
John Spurlock3346a802014-05-20 16:25:37 -0400166 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400167 * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
168 */
169 private static final int FLAG_ADJUST_VOLUME = 1;
170
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700171 private final Context mContext;
172 private final ContentResolver mContentResolver;
173 private final AppOpsManager mAppOps;
Eric Laurent212532b2014-07-21 15:43:18 -0700174
Eric Laurent212532b2014-07-21 15:43:18 -0700175 // the platform type affects volume and silent mode behavior
176 private final int mPlatformType;
177
178 private boolean isPlatformVoice() {
John Spurlock61560172015-02-06 19:46:04 -0500179 return mPlatformType == AudioSystem.PLATFORM_VOICE;
Eric Laurent212532b2014-07-21 15:43:18 -0700180 }
181
182 private boolean isPlatformTelevision() {
John Spurlock61560172015-02-06 19:46:04 -0500183 return mPlatformType == AudioSystem.PLATFORM_TELEVISION;
Eric Laurent212532b2014-07-21 15:43:18 -0700184 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800185
John Spurlock3346a802014-05-20 16:25:37 -0400186 /** The controller for the volume UI. */
187 private final VolumeController mVolumeController = new VolumeController();
John Spurlockcdb57ae2015-02-11 19:04:11 -0500188 private final ControllerService mControllerService = new ControllerService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189
190 // sendMsg() flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 /** If the msg is already queued, replace it with this one. */
192 private static final int SENDMSG_REPLACE = 0;
193 /** If the msg is already queued, ignore this one and leave the old. */
194 private static final int SENDMSG_NOOP = 1;
195 /** If the msg is already queued, queue this one and leave the old. */
196 private static final int SENDMSG_QUEUE = 2;
197
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700198 // AudioHandler messages
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800199 private static final int MSG_SET_DEVICE_VOLUME = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 private static final int MSG_PERSIST_VOLUME = 1;
201 private static final int MSG_PERSIST_RINGER_MODE = 3;
Andy Hunged0ea402015-10-30 14:11:46 -0700202 private static final int MSG_AUDIO_SERVER_DIED = 4;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700203 private static final int MSG_PLAY_SOUND_EFFECT = 5;
204 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
205 private static final int MSG_LOAD_SOUND_EFFECTS = 7;
206 private static final int MSG_SET_FORCE_USE = 8;
207 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
208 private static final int MSG_SET_ALL_VOLUMES = 10;
209 private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
210 private static final int MSG_REPORT_NEW_ROUTES = 12;
211 private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
212 private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
213 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
214 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
215 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
216 private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
217 private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
218 private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700219 private static final int MSG_SYSTEM_READY = 21;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400220 private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
Julia Reynoldsb53453f2014-08-22 11:42:43 -0400221 private static final int MSG_PERSIST_MICROPHONE_MUTE = 23;
RoboErik5452e252015-02-06 15:33:53 -0800222 private static final int MSG_UNMUTE_STREAM = 24;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -0700223 private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 25;
Eric Laurent0867bed2015-05-20 14:49:08 -0700224 private static final int MSG_INDICATE_SYSTEM_READY = 26;
Andy Hungf04b84d2015-12-18 17:33:27 -0800225 private static final int MSG_PERSIST_MASTER_MONO = 27;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700226 // start of messages handled under wakelock
227 // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
Jean-Michel Trivie12c39b2012-06-06 10:51:58 -0700228 // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700229 private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
Mike Lockwood0a40ec22014-05-21 10:08:50 -0700230 private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
231 private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700232 // end of messages handled under wakelock
Eric Laurentafbb0472011-12-15 09:04:23 -0800233
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -0700234 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
Eric Laurentdc03c612011-04-01 10:59:41 -0700235 // Timeout for connection to bluetooth headset service
236 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
237
Eric Laurent0867bed2015-05-20 14:49:08 -0700238 // retry delay in case of failure to indicate system ready to AudioFlinger
239 private static final int INDICATE_SYSTEM_READY_RETRY_DELAY_MS = 1000;
240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241 /** @see AudioSystemThread */
242 private AudioSystemThread mAudioSystemThread;
243 /** @see AudioHandler */
244 private AudioHandler mAudioHandler;
245 /** @see VolumeStreamState */
246 private VolumeStreamState[] mStreamStates;
Jason Parekhb1096152009-03-24 17:48:25 -0700247 private SettingsObserver mSettingsObserver;
Eric Laurenta553c252009-07-17 12:17:14 -0700248
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700249 private int mMode = AudioSystem.MODE_NORMAL;
Glenn Kastenba195eb2011-12-13 09:30:40 -0800250 // protects mRingerMode
251 private final Object mSettingsLock = new Object();
Eric Laurent45c90ce2012-04-24 18:44:22 -0700252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 private SoundPool mSoundPool;
Glenn Kasten30c918c2011-11-10 17:56:41 -0800254 private final Object mSoundEffectsLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 private static final int NUM_SOUNDPOOL_CHANNELS = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256
257 /* Sound effect file names */
258 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
Eric Laurente78fced2013-03-15 16:03:47 -0700259 private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260
261 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
262 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
263 * uses soundpool (second column) */
Eric Laurente78fced2013-03-15 16:03:47 -0700264 private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265
John Spurlockb6e19e32015-03-10 21:33:44 -0400266 /** Maximum volume index values for audio streams */
Eric Laurent91377de2014-10-10 15:24:04 -0700267 private static int[] MAX_STREAM_VOLUME = new int[] {
Eric Laurent6ee99522009-08-25 06:30:59 -0700268 5, // STREAM_VOICE_CALL
269 7, // STREAM_SYSTEM
270 7, // STREAM_RING
271 15, // STREAM_MUSIC
272 7, // STREAM_ALARM
273 7, // STREAM_NOTIFICATION
274 15, // STREAM_BLUETOOTH_SCO
275 7, // STREAM_SYSTEM_ENFORCED
276 15, // STREAM_DTMF
277 15 // STREAM_TTS
Jared Suttles59820132009-08-13 21:50:52 -0500278 };
Eric Laurent91377de2014-10-10 15:24:04 -0700279
John Spurlockb6e19e32015-03-10 21:33:44 -0400280 /** Minimum volume index values for audio streams */
281 private static int[] MIN_STREAM_VOLUME = new int[] {
282 1, // STREAM_VOICE_CALL
283 0, // STREAM_SYSTEM
284 0, // STREAM_RING
285 0, // STREAM_MUSIC
286 0, // STREAM_ALARM
287 0, // STREAM_NOTIFICATION
Eric Laurente4381ec2015-10-29 17:52:48 -0700288 0, // STREAM_BLUETOOTH_SCO
John Spurlockb6e19e32015-03-10 21:33:44 -0400289 0, // STREAM_SYSTEM_ENFORCED
290 0, // STREAM_DTMF
291 0 // STREAM_TTS
292 };
293
Eric Laurent6d517662012-04-23 18:42:39 -0700294 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
Eric Laurenta553c252009-07-17 12:17:14 -0700295 * of another stream: This avoids multiplying the volume settings for hidden
296 * stream types that follow other stream behavior for volume settings
Eric Laurent6d517662012-04-23 18:42:39 -0700297 * NOTE: do not create loops in aliases!
298 * Some streams alias to different streams according to device category (phone or tablet) or
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700299 * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
Eric Laurent212532b2014-07-21 15:43:18 -0700300 * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
301 * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
302 * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
303 private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700304 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
305 AudioSystem.STREAM_RING, // STREAM_SYSTEM
306 AudioSystem.STREAM_RING, // STREAM_RING
307 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
308 AudioSystem.STREAM_ALARM, // STREAM_ALARM
309 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
310 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
311 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
312 AudioSystem.STREAM_RING, // STREAM_DTMF
313 AudioSystem.STREAM_MUSIC // STREAM_TTS
Eric Laurenta553c252009-07-17 12:17:14 -0700314 };
Eric Laurent212532b2014-07-21 15:43:18 -0700315 private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
316 AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL
317 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
318 AudioSystem.STREAM_MUSIC, // STREAM_RING
319 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
320 AudioSystem.STREAM_MUSIC, // STREAM_ALARM
321 AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
322 AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO
323 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
324 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
325 AudioSystem.STREAM_MUSIC // STREAM_TTS
326 };
327 private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700328 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
John Spurlock4f0f1202014-08-05 13:28:33 -0400329 AudioSystem.STREAM_RING, // STREAM_SYSTEM
Eric Laurent6d517662012-04-23 18:42:39 -0700330 AudioSystem.STREAM_RING, // STREAM_RING
331 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
332 AudioSystem.STREAM_ALARM, // STREAM_ALARM
333 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
334 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
John Spurlock4f0f1202014-08-05 13:28:33 -0400335 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
336 AudioSystem.STREAM_RING, // STREAM_DTMF
Eric Laurent6d517662012-04-23 18:42:39 -0700337 AudioSystem.STREAM_MUSIC // STREAM_TTS
338 };
339 private int[] mStreamVolumeAlias;
Eric Laurenta553c252009-07-17 12:17:14 -0700340
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700341 /**
342 * Map AudioSystem.STREAM_* constants to app ops. This should be used
343 * after mapping through mStreamVolumeAlias.
344 */
John Spurlock59dc9c12015-03-02 11:20:15 -0500345 private static final int[] STREAM_VOLUME_OPS = new int[] {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700346 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL
347 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM
348 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING
349 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC
350 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM
351 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION
352 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO
353 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED
354 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF
355 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS
356 };
357
Eric Laurent83a017b2013-03-19 18:15:31 -0700358 private final boolean mUseFixedVolume;
359
Glenn Kasten30c918c2011-11-10 17:56:41 -0800360 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 public void onError(int error) {
362 switch (error) {
363 case AudioSystem.AUDIO_STATUS_SERVER_DIED:
Andy Hunged0ea402015-10-30 14:11:46 -0700364 sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED,
Eric Laurentdfb881f2013-07-18 14:41:39 -0700365 SENDMSG_NOOP, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 break;
367 default:
368 break;
369 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700370 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 };
372
373 /**
374 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
375 * {@link AudioManager#RINGER_MODE_SILENT}, or
376 * {@link AudioManager#RINGER_MODE_VIBRATE}.
377 */
Glenn Kastenba195eb2011-12-13 09:30:40 -0800378 // protected by mSettingsLock
John Spurlock661f2cf2014-11-17 10:29:10 -0500379 private int mRingerMode; // internal ringer mode, affects muting of underlying streams
380 private int mRingerModeExternal = -1; // reported ringer mode to outside clients (AudioManager)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381
Eric Laurent9bcf4012009-06-12 06:09:28 -0700382 /** @see System#MODE_RINGER_STREAMS_AFFECTED */
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700383 private int mRingerModeAffectedStreams = 0;
Eric Laurent9bcf4012009-06-12 06:09:28 -0700384
Eric Laurent5b4e6542010-03-19 20:02:21 -0700385 // Streams currently muted by ringer mode
386 private int mRingerModeMutedStreams;
387
John Spurlock3ce37252015-02-17 13:20:45 -0500388 /** Streams that can be muted. Do not resolve to aliases when checking.
389 * @see System#MUTE_STREAMS_AFFECTED */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 private int mMuteAffectedStreams;
391
392 /**
Eric Laurentbffc3d12012-05-07 17:43:49 -0700393 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
394 * mVibrateSetting is just maintained during deprecation period but vibration policy is
395 * now only controlled by mHasVibrator and mRingerMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 */
397 private int mVibrateSetting;
398
Eric Laurentbffc3d12012-05-07 17:43:49 -0700399 // Is there a vibrator
400 private final boolean mHasVibrator;
401
Eric Laurenta553c252009-07-17 12:17:14 -0700402 // Broadcast receiver for device connections intent broadcasts
403 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
404
Makoto Onukid45a4a22015-11-02 17:17:38 -0800405 /** Interface for UserManagerService. */
406 private final UserManagerInternal mUserManagerInternal;
407
408 private final UserRestrictionsListener mUserRestrictionsListener =
409 new AudioServiceUserRestrictionsListener();
410
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700411 // Devices currently connected
Paul McLean394a8e12015-03-03 10:29:19 -0700412 // Use makeDeviceListKey() to make a unique key for this list.
413 private class DeviceListSpec {
414 int mDeviceType;
415 String mDeviceName;
416 String mDeviceAddress;
417
418 public DeviceListSpec(int deviceType, String deviceName, String deviceAddress) {
419 mDeviceType = deviceType;
420 mDeviceName = deviceName;
421 mDeviceAddress = deviceAddress;
422 }
423
424 public String toString() {
425 return "[type:0x" + Integer.toHexString(mDeviceType) + " name:" + mDeviceName
426 + " address:" + mDeviceAddress + "]";
427 }
428 }
429
430 // Generate a unique key for the mConnectedDevices List by composing the device "type"
431 // and the "address" associated with a specific instance of that device type
432 private String makeDeviceListKey(int device, String deviceAddress) {
433 return "0x" + Integer.toHexString(device) + ":" + deviceAddress;
434 }
435
John Spurlock8c3dc852015-04-23 21:32:37 -0400436 private final ArrayMap<String, DeviceListSpec> mConnectedDevices = new ArrayMap<>();
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700437
438 // Forced device usage for communications
439 private int mForcedUseForComm;
440
Eric Laurent9272b4b2010-01-23 17:12:59 -0800441 // List of binder death handlers for setMode() client processes.
442 // The last process to have called setMode() is at the top of the list.
Glenn Kasten30c918c2011-11-10 17:56:41 -0800443 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
Eric Laurenteb14a782009-12-17 03:12:59 -0800444
Eric Laurent3def1ee2010-03-17 23:26:26 -0700445 // List of clients having issued a SCO start request
Glenn Kasten30c918c2011-11-10 17:56:41 -0800446 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
Eric Laurent3def1ee2010-03-17 23:26:26 -0700447
448 // BluetoothHeadset API to control SCO connection
449 private BluetoothHeadset mBluetoothHeadset;
450
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700451 // Bluetooth headset device
452 private BluetoothDevice mBluetoothHeadsetDevice;
Eric Laurent3def1ee2010-03-17 23:26:26 -0700453
Eric Laurent62ef7672010-11-24 10:58:32 -0800454 // Indicate if SCO audio connection is currently active and if the initiator is
455 // audio service (internal) or bluetooth headset (external)
456 private int mScoAudioState;
457 // SCO audio state is not active
458 private static final int SCO_STATE_INACTIVE = 0;
Eric Laurentdc03c612011-04-01 10:59:41 -0700459 // SCO audio activation request waiting for headset service to connect
460 private static final int SCO_STATE_ACTIVATE_REQ = 1;
Eric Laurent25fc29b2013-04-05 12:13:54 -0700461 // SCO audio state is active or starting due to a request from AudioManager API
Eric Laurentdc03c612011-04-01 10:59:41 -0700462 private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
463 // SCO audio deactivation request waiting for headset service to connect
464 private static final int SCO_STATE_DEACTIVATE_REQ = 5;
465
Eric Laurent62ef7672010-11-24 10:58:32 -0800466 // SCO audio state is active due to an action in BT handsfree (either voice recognition or
467 // in call audio)
468 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
Eric Laurentdc03c612011-04-01 10:59:41 -0700469 // Deactivation request for all SCO connections (initiated by audio mode change)
470 // waiting for headset service to connect
471 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
472
Eric Laurentc18c9132013-04-12 17:24:56 -0700473 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
474 // originated from an app targeting an API version before JB MR2 and raw audio after that.
475 private int mScoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -0700476 // SCO audio mode is undefined
477 private static final int SCO_MODE_UNDEFINED = -1;
Eric Laurentc18c9132013-04-12 17:24:56 -0700478 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
479 private static final int SCO_MODE_VIRTUAL_CALL = 0;
480 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
481 private static final int SCO_MODE_RAW = 1;
Liejun Taof4e51d82014-07-16 11:18:29 -0700482 // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
483 private static final int SCO_MODE_VR = 2;
484
485 private static final int SCO_MODE_MAX = 2;
Eric Laurentc18c9132013-04-12 17:24:56 -0700486
Eric Laurentdc03c612011-04-01 10:59:41 -0700487 // Current connection state indicated by bluetooth headset
488 private int mScoConnectionState;
Eric Laurent62ef7672010-11-24 10:58:32 -0800489
Eric Laurenta60e2122010-12-28 16:49:07 -0800490 // true if boot sequence has been completed
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700491 private boolean mSystemReady;
Yasuhiro Matsuda4ced7192015-07-10 22:08:44 +0900492 // true if Intent.ACTION_USER_SWITCHED has ever been received
493 private boolean mUserSwitchedReceived;
Eric Laurenta60e2122010-12-28 16:49:07 -0800494 // listener for SoundPool sample load completion indication
495 private SoundPoolCallback mSoundPoolCallBack;
496 // thread for SoundPool listener
497 private SoundPoolListenerThread mSoundPoolListenerThread;
498 // message looper for SoundPool listener
499 private Looper mSoundPoolLooper = null;
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700500 // volume applied to sound played with playSoundEffect()
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700501 private static int sSoundEffectVolumeDb;
Eric Laurent25101b02011-02-02 09:33:30 -0800502 // previous volume adjustment direction received by checkForRingerModeChange()
503 private int mPrevVolDirection = AudioManager.ADJUST_SAME;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700504 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
505 // is controlled by Vol keys.
506 private int mVolumeControlStream = -1;
507 private final Object mForceControlStreamLock = new Object();
508 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
509 // server process so in theory it is not necessary to monitor the client death.
510 // However it is good to be ready for future evolutions.
511 private ForceControlStreamClient mForceControlStreamClient = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700512 // Used to play ringtones outside system_server
513 private volatile IRingtonePlayer mRingtonePlayer;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800514
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700515 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
516
Eric Laurent78472112012-05-21 08:57:21 -0700517 // Request to override default use of A2DP for media.
518 private boolean mBluetoothA2dpEnabled;
519 private final Object mBluetoothA2dpEnabledLock = new Object();
520
Dianne Hackborn632ca412012-06-14 19:34:10 -0700521 // Monitoring of audio routes. Protected by mCurAudioRoutes.
522 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
523 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
524 = new RemoteCallbackList<IAudioRoutesObserver>();
525
Eric Laurent4bbcc652012-09-24 14:26:30 -0700526 // Devices for which the volume is fixed and VolumePanel slider should be disabled
Eric Laurent212532b2014-07-21 15:43:18 -0700527 int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700528 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Eric Laurent212532b2014-07-21 15:43:18 -0700529 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
530 AudioSystem.DEVICE_OUT_HDMI_ARC |
531 AudioSystem.DEVICE_OUT_SPDIF |
532 AudioSystem.DEVICE_OUT_AUX_LINE;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700533 int mFullVolumeDevices = 0;
Eric Laurent4bbcc652012-09-24 14:26:30 -0700534
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700535 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700536 private final boolean mMonitorOrientation;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700537 private final boolean mMonitorRotation;
Eric Laurentd640bd32012-09-28 18:01:48 -0700538
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700539 private boolean mDockAudioMediaEnabled = true;
540
Eric Laurent08ed1b92012-11-05 14:54:12 -0800541 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
542
Eric Laurentfde16d52012-12-03 14:42:39 -0800543 // Used when safe volume warning message display is requested by setStreamVolume(). In this
544 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
545 // and used later when/if disableSafeMediaVolume() is called.
546 private StreamVolumeCommand mPendingVolumeCommand;
547
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700548 private PowerManager.WakeLock mAudioEventWakeLock;
549
550 private final MediaFocusControl mMediaFocusControl;
551
John Du5a0cf7a2013-07-19 11:30:34 -0700552 // Reference to BluetoothA2dp to query for AbsoluteVolume.
553 private BluetoothA2dp mA2dp;
seunghwan.hong4fe77952014-10-29 17:43:20 +0900554 // lock always taken synchronized on mConnectedDevices
John Du5a0cf7a2013-07-19 11:30:34 -0700555 private final Object mA2dpAvrcpLock = new Object();
556 // If absolute volume is supported in AVRCP device
557 private boolean mAvrcpAbsVolSupported = false;
558
Eric Laurentadbe8bf2014-11-03 18:26:32 -0800559 private static Long mLastDeviceConnectMsgTime = new Long(0);
560
John Spurlock661f2cf2014-11-17 10:29:10 -0500561 private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
John Spurlocka48d7792015-03-03 17:35:57 -0500562 private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
John Spurlock07e72432015-03-13 11:46:52 -0400563 private long mLoweredFromNormalToVibrateTime;
John Spurlock661f2cf2014-11-17 10:29:10 -0500564
Paul McLean10804eb2015-01-28 11:16:35 -0800565 // Intent "extra" data keys.
566 public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName";
567 public static final String CONNECT_INTENT_KEY_STATE = "state";
568 public static final String CONNECT_INTENT_KEY_ADDRESS = "address";
569 public static final String CONNECT_INTENT_KEY_HAS_PLAYBACK = "hasPlayback";
570 public static final String CONNECT_INTENT_KEY_HAS_CAPTURE = "hasCapture";
571 public static final String CONNECT_INTENT_KEY_HAS_MIDI = "hasMIDI";
572 public static final String CONNECT_INTENT_KEY_DEVICE_CLASS = "class";
573
574 // Defines the format for the connection "address" for ALSA devices
575 public static String makeAlsaAddressString(int card, int device) {
576 return "card=" + card + ";device=" + device + ";";
577 }
578
Makoto Onukie1aef852015-10-15 17:28:35 -0700579 public static final class Lifecycle extends SystemService {
580 private AudioService mService;
581
582 public Lifecycle(Context context) {
583 super(context);
584 mService = new AudioService(context);
585 }
586
587 @Override
588 public void onStart() {
589 publishBinderService(Context.AUDIO_SERVICE, mService);
590 }
591
592 @Override
593 public void onBootPhase(int phase) {
594 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
595 mService.systemReady();
596 }
597 }
598 }
599
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600 ///////////////////////////////////////////////////////////////////////////
601 // Construction
602 ///////////////////////////////////////////////////////////////////////////
603
604 /** @hide */
605 public AudioService(Context context) {
606 mContext = context;
607 mContentResolver = context.getContentResolver();
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700608 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700609
John Spurlock61560172015-02-06 19:46:04 -0500610 mPlatformType = AudioSystem.getPlatformType(context);
Jared Suttles59820132009-08-13 21:50:52 -0500611
Makoto Onukid45a4a22015-11-02 17:17:38 -0800612 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
613
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700614 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700615 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700616
Eric Laurentbffc3d12012-05-07 17:43:49 -0700617 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
618 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
619
John Spurlockb6e19e32015-03-10 21:33:44 -0400620 // Initialize volume
Eric Laurent91377de2014-10-10 15:24:04 -0700621 int maxVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps",
622 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
623 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
624 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500625 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700626 }
627 maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
628 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
629 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
630 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500631 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700632 }
Jared Suttles59820132009-08-13 21:50:52 -0500633
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700634 sSoundEffectVolumeDb = context.getResources().getInteger(
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700635 com.android.internal.R.integer.config_soundEffectVolumeDb);
Eric Laurent25101b02011-02-02 09:33:30 -0800636
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700637 mForcedUseForComm = AudioSystem.FORCE_NONE;
Eric Laurentdd45d012012-10-08 09:04:34 -0700638
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 createAudioSystemThread();
Eric Laurentdd45d012012-10-08 09:04:34 -0700640
Eric Laurentdfb881f2013-07-18 14:41:39 -0700641 AudioSystem.setErrorCallback(mAudioSystemCallback);
642
John Spurlock5e783732015-02-19 10:28:59 -0500643 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -0700644 mCameraSoundForced = new Boolean(cameraSoundForced);
645 sendMsg(mAudioHandler,
646 MSG_SET_FORCE_USE,
647 SENDMSG_QUEUE,
648 AudioSystem.FOR_SYSTEM,
649 cameraSoundForced ?
650 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
651 null,
652 0);
653
Eric Laurent05274f32012-11-29 12:48:18 -0800654 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
655 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
656 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
657 // The default safe volume index read here will be replaced by the actual value when
658 // the mcc is read by onConfigureSafeVolume()
659 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
660 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
661
Eric Laurent83a017b2013-03-19 18:15:31 -0700662 mUseFixedVolume = mContext.getResources().getBoolean(
663 com.android.internal.R.bool.config_useFixedVolume);
664
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700665 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
666 // array initialized by updateStreamVolumeAlias()
John Spurlock90874332015-03-10 16:00:54 -0400667 updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 readPersistedSettings();
Eric Laurentc1d41662011-07-19 11:21:13 -0700669 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700670 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700671
Jean-Michel Trivid4de20d2015-11-04 14:45:54 -0800672 mMediaFocusControl = new MediaFocusControl(mContext);
John Spurlockb6e19e32015-03-10 21:33:44 -0400673
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700674 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700675
676 // Call setRingerModeInt() to apply correct mute
677 // state on streams affected by ringer mode.
678 mRingerModeMutedStreams = 0;
John Spurlock661f2cf2014-11-17 10:29:10 -0500679 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3891c4c2010-04-20 09:40:57 -0700680
Eric Laurenta553c252009-07-17 12:17:14 -0700681 // Register for device connection intent broadcasts.
682 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700683 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700684 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
685 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700686 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
687 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700688 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700689 intentFilter.addAction(Intent.ACTION_USER_BACKGROUND);
690 intentFilter.addAction(Intent.ACTION_USER_FOREGROUND);
Paul McLeanc837a452014-04-09 09:04:43 -0700691 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Eric Laurentb70b78a2016-01-13 19:16:04 -0800692 intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700693
Eric Laurentd640bd32012-09-28 18:01:48 -0700694 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700695 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700696 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
697 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700698 Log.v(TAG, "monitoring device orientation");
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700699 // initialize orientation in AudioSystem
700 setOrientationForAudioSystem();
701 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700702 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
703 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -0700704 RotationHelper.init(mContext, mAudioHandler);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700705 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700706
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700707 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null);
Jared Suttles59820132009-08-13 21:50:52 -0500708
RoboErik0dac35a2014-08-12 15:48:49 -0700709 LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
Makoto Onukid45a4a22015-11-02 17:17:38 -0800710
711 mUserManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -0800712
713 mRecordMonitor.initMonitor();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 }
715
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700716 public void systemReady() {
717 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
718 0, 0, null, 0);
719 }
720
721 public void onSystemReady() {
722 mSystemReady = true;
723 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
724 0, 0, null, 0);
725
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700726 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
727 resetBluetoothSco();
728 getBluetoothHeadset();
729 //FIXME: this is to maintain compatibility with deprecated intent
730 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
731 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
732 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
733 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
734 sendStickyBroadcastToAll(newIntent);
735
736 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
737 if (adapter != null) {
738 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
739 BluetoothProfile.A2DP);
740 }
741
Eric Laurent212532b2014-07-21 15:43:18 -0700742 mHdmiManager =
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900743 (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700744 if (mHdmiManager != null) {
745 synchronized (mHdmiManager) {
746 mHdmiTvClient = mHdmiManager.getTvClient();
Jungshik Jangc9ff9682014-09-15 17:41:06 +0900747 if (mHdmiTvClient != null) {
748 mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
749 }
Eric Laurent212532b2014-07-21 15:43:18 -0700750 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
751 mHdmiCecSink = false;
752 }
753 }
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900754
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700755 sendMsg(mAudioHandler,
756 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
757 SENDMSG_REPLACE,
758 0,
759 0,
John Spurlock90874332015-03-10 16:00:54 -0400760 TAG,
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700761 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700762
763 StreamOverride.init(mContext);
John Spurlockcdb57ae2015-02-11 19:04:11 -0500764 mControllerService.init();
Eric Laurent0867bed2015-05-20 14:49:08 -0700765 onIndicateSystemReady();
766 }
767
768 void onIndicateSystemReady() {
769 if (AudioSystem.systemReady() == AudioSystem.SUCCESS) {
770 return;
771 }
772 sendMsg(mAudioHandler,
773 MSG_INDICATE_SYSTEM_READY,
774 SENDMSG_REPLACE,
775 0,
776 0,
777 null,
778 INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
779 }
780
Andy Hunged0ea402015-10-30 14:11:46 -0700781 public void onAudioServerDied() {
Eric Laurent0867bed2015-05-20 14:49:08 -0700782 if (!mSystemReady ||
783 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Andy Hunged0ea402015-10-30 14:11:46 -0700784 Log.e(TAG, "Audioserver died.");
785 sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent0867bed2015-05-20 14:49:08 -0700786 null, 500);
787 return;
788 }
Andy Hunged0ea402015-10-30 14:11:46 -0700789 Log.e(TAG, "Audioserver started.");
Eric Laurent0867bed2015-05-20 14:49:08 -0700790
791 // indicate to audio HAL that we start the reconfiguration phase after a media
792 // server crash
793 // Note that we only execute this when the media server
794 // process restarts after a crash, not the first time it is started.
795 AudioSystem.setParameters("restarting=true");
796
797 readAndSetLowRamDevice();
798
799 // Restore device connection states
800 synchronized (mConnectedDevices) {
801 for (int i = 0; i < mConnectedDevices.size(); i++) {
802 DeviceListSpec spec = mConnectedDevices.valueAt(i);
803 AudioSystem.setDeviceConnectionState(
804 spec.mDeviceType,
805 AudioSystem.DEVICE_STATE_AVAILABLE,
806 spec.mDeviceAddress,
807 spec.mDeviceName);
808 }
809 }
810 // Restore call state
811 AudioSystem.setPhoneState(mMode);
812
813 // Restore forced usage for communcations and record
814 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
815 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
816 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
817 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
818
819 // Restore stream volumes
820 int numStreamTypes = AudioSystem.getNumStreamTypes();
821 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
822 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurente4381ec2015-10-29 17:52:48 -0700823 AudioSystem.initStreamVolume(
824 streamType, streamState.mIndexMin / 10, streamState.mIndexMax / 10);
Eric Laurent0867bed2015-05-20 14:49:08 -0700825
826 streamState.applyAllVolumes();
827 }
828
Andy Hungf04b84d2015-12-18 17:33:27 -0800829 // Restore mono mode
830 final boolean masterMono = System.getIntForUser(
831 mContentResolver, System.MASTER_MONO,
832 0 /* default */, UserHandle.USER_CURRENT) == 1;
833 AudioSystem.setMasterMono(masterMono);
834
Eric Laurent0867bed2015-05-20 14:49:08 -0700835 // Restore ringer mode
836 setRingerModeInt(getRingerModeInternal(), false);
837
838 // Reset device orientation (if monitored for this device)
839 if (mMonitorOrientation) {
840 setOrientationForAudioSystem();
841 }
842 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -0700843 RotationHelper.updateOrientation();
Eric Laurent0867bed2015-05-20 14:49:08 -0700844 }
845
846 synchronized (mBluetoothA2dpEnabledLock) {
847 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
848 mBluetoothA2dpEnabled ?
849 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
850 }
851
852 synchronized (mSettingsLock) {
853 AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
854 mDockAudioMediaEnabled ?
855 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
856 }
857 if (mHdmiManager != null) {
858 synchronized (mHdmiManager) {
859 if (mHdmiTvClient != null) {
860 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
861 }
862 }
863 }
864
865 synchronized (mAudioPolicies) {
866 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
867 policy.connectMixes();
868 }
869 }
870
871 onIndicateSystemReady();
872 // indicate the end of reconfiguration phase to audio HAL
873 AudioSystem.setParameters("restarting=false");
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700874 }
875
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 private void createAudioSystemThread() {
877 mAudioSystemThread = new AudioSystemThread();
878 mAudioSystemThread.start();
879 waitForAudioHandlerCreation();
880 }
881
882 /** Waits for the volume handler to be created by the other thread. */
883 private void waitForAudioHandlerCreation() {
884 synchronized(this) {
885 while (mAudioHandler == null) {
886 try {
887 // Wait for mAudioHandler to be set by the other thread
888 wait();
889 } catch (InterruptedException e) {
890 Log.e(TAG, "Interrupted while waiting on volume handler.");
891 }
892 }
893 }
894 }
895
Eric Laurent24482012012-05-10 09:41:17 -0700896 private void checkAllAliasStreamVolumes() {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700897 synchronized (VolumeStreamState.class) {
898 int numStreamTypes = AudioSystem.getNumStreamTypes();
899 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
900 if (streamType != mStreamVolumeAlias[streamType]) {
901 mStreamStates[streamType].
John Spurlock90874332015-03-10 16:00:54 -0400902 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]],
903 TAG);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700904 }
905 // apply stream volume
RoboErik4197cb62015-01-21 15:45:32 -0800906 if (!mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700907 mStreamStates[streamType].applyAllVolumes();
908 }
Eric Laurent24482012012-05-10 09:41:17 -0700909 }
910 }
911 }
912
Eric Laurent212532b2014-07-21 15:43:18 -0700913 private void checkAllFixedVolumeDevices()
914 {
915 int numStreamTypes = AudioSystem.getNumStreamTypes();
916 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
917 mStreamStates[streamType].checkFixedVolumeDevices();
918 }
919 }
920
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700921 private void checkAllFixedVolumeDevices(int streamType) {
922 mStreamStates[streamType].checkFixedVolumeDevices();
923 }
924
John Spurlockb6e19e32015-03-10 21:33:44 -0400925 private void checkMuteAffectedStreams() {
926 // any stream with a min level > 0 is not muteable by definition
927 for (int i = 0; i < mStreamStates.length; i++) {
928 final VolumeStreamState vss = mStreamStates[i];
929 if (vss.mIndexMin > 0) {
930 mMuteAffectedStreams &= ~(1 << vss.mStreamType);
931 }
932 }
933 }
934
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936 int numStreamTypes = AudioSystem.getNumStreamTypes();
937 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
938
939 for (int i = 0; i < numStreamTypes; i++) {
Eric Laurent6d517662012-04-23 18:42:39 -0700940 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -0700941 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942
Eric Laurent212532b2014-07-21 15:43:18 -0700943 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -0700944 checkAllAliasStreamVolumes();
John Spurlockb6e19e32015-03-10 21:33:44 -0400945 checkMuteAffectedStreams();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946 }
947
Eric Laurentbffc3d12012-05-07 17:43:49 -0700948 private void dumpStreamStates(PrintWriter pw) {
949 pw.println("\nStream volumes (device: index)");
950 int numStreamTypes = AudioSystem.getNumStreamTypes();
951 for (int i = 0; i < numStreamTypes; i++) {
John Spurlock61560172015-02-06 19:46:04 -0500952 pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":");
Eric Laurentbffc3d12012-05-07 17:43:49 -0700953 mStreamStates[i].dump(pw);
954 pw.println("");
955 }
Eric Laurentdd45d012012-10-08 09:04:34 -0700956 pw.print("\n- mute affected streams = 0x");
957 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -0700958 }
959
John Spurlock90874332015-03-10 16:00:54 -0400960 private void updateStreamVolumeAlias(boolean updateVolumes, String caller) {
Eric Laurent6d517662012-04-23 18:42:39 -0700961 int dtmfStreamAlias;
Eric Laurent212532b2014-07-21 15:43:18 -0700962
963 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -0500964 case AudioSystem.PLATFORM_VOICE:
Eric Laurent212532b2014-07-21 15:43:18 -0700965 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
Eric Laurent6d517662012-04-23 18:42:39 -0700966 dtmfStreamAlias = AudioSystem.STREAM_RING;
Eric Laurent212532b2014-07-21 15:43:18 -0700967 break;
John Spurlock61560172015-02-06 19:46:04 -0500968 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -0700969 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
970 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
971 break;
972 default:
973 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
Eric Laurent6d517662012-04-23 18:42:39 -0700974 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
975 }
Eric Laurent212532b2014-07-21 15:43:18 -0700976
977 if (isPlatformTelevision()) {
978 mRingerModeAffectedStreams = 0;
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700979 } else {
Eric Laurent212532b2014-07-21 15:43:18 -0700980 if (isInCommunication()) {
981 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
982 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
983 } else {
984 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
985 }
Eric Laurent6d517662012-04-23 18:42:39 -0700986 }
Eric Laurent212532b2014-07-21 15:43:18 -0700987
Eric Laurent6d517662012-04-23 18:42:39 -0700988 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
989 if (updateVolumes) {
John Spurlock90874332015-03-10 16:00:54 -0400990 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
991 caller);
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700992 // apply stream mute states according to new value of mRingerModeAffectedStreams
John Spurlock661f2cf2014-11-17 10:29:10 -0500993 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent6d517662012-04-23 18:42:39 -0700994 sendMsg(mAudioHandler,
995 MSG_SET_ALL_VOLUMES,
996 SENDMSG_QUEUE,
997 0,
998 0,
999 mStreamStates[AudioSystem.STREAM_DTMF], 0);
1000 }
1001 }
1002
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001003 private void readDockAudioSettings(ContentResolver cr)
1004 {
1005 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -07001006 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001007
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001008 sendMsg(mAudioHandler,
1009 MSG_SET_FORCE_USE,
1010 SENDMSG_QUEUE,
1011 AudioSystem.FOR_DOCK,
1012 mDockAudioMediaEnabled ?
1013 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
1014 null,
1015 0);
1016 }
1017
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018 private void readPersistedSettings() {
1019 final ContentResolver cr = mContentResolver;
1020
Eric Laurentbffc3d12012-05-07 17:43:49 -07001021 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07001022 Settings.Global.getInt(
1023 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -07001024 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -07001025 // sanity check in case the settings are restored from a device with incompatible
1026 // ringer modes
John Spurlock97559372014-10-24 16:27:36 -04001027 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001028 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -07001029 }
1030 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1031 ringerMode = AudioManager.RINGER_MODE_SILENT;
1032 }
1033 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07001034 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -08001035 }
Eric Laurent212532b2014-07-21 15:43:18 -07001036 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001037 ringerMode = AudioManager.RINGER_MODE_NORMAL;
1038 }
Glenn Kastenba195eb2011-12-13 09:30:40 -08001039 synchronized(mSettingsLock) {
1040 mRingerMode = ringerMode;
John Spurlock661f2cf2014-11-17 10:29:10 -05001041 if (mRingerModeExternal == -1) {
1042 mRingerModeExternal = mRingerMode;
1043 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001044
Eric Laurentdd45d012012-10-08 09:04:34 -07001045 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
1046 // are still needed while setVibrateSetting() and getVibrateSetting() are being
1047 // deprecated.
John Spurlock61560172015-02-06 19:46:04 -05001048 mVibrateSetting = AudioSystem.getValueForVibrateSetting(0,
Eric Laurentdd45d012012-10-08 09:04:34 -07001049 AudioManager.VIBRATE_TYPE_NOTIFICATION,
1050 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
1051 : AudioManager.VIBRATE_SETTING_OFF);
John Spurlock61560172015-02-06 19:46:04 -05001052 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting,
Eric Laurentdd45d012012-10-08 09:04:34 -07001053 AudioManager.VIBRATE_TYPE_RINGER,
1054 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
1055 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001056
Eric Laurent24e0d9b2013-10-03 18:15:07 -07001057 updateRingerModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001058 readDockAudioSettings(cr);
Eric Laurent402f7f22011-02-04 12:30:32 -08001059 }
Eric Laurentc1d41662011-07-19 11:21:13 -07001060
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001061 mMuteAffectedStreams = System.getIntForUser(cr,
John Spurlock61560172015-02-06 19:46:04 -05001062 System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
John Spurlock24c05182015-02-05 12:30:36 -05001063 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064
Makoto Onukid45a4a22015-11-02 17:17:38 -08001065 final int currentUser = getCurrentUserId();
1066
1067 // In addition to checking the system setting, also check the current user restriction.
1068 // Because of the delay before persisting VOLUME_MASTER_MUTE, there's a window where
1069 // DISALLOW_ADJUST_VOLUME will be ignored when it's set right before switching users.
1070 boolean masterMute = (System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
1071 0, UserHandle.USER_CURRENT) == 1)
1072 || mUserManagerInternal.getUserRestriction(
1073 currentUser, UserManager.DISALLOW_ADJUST_VOLUME);
Eric Laurent83a017b2013-03-19 18:15:31 -07001074 if (mUseFixedVolume) {
1075 masterMute = false;
1076 AudioSystem.setMasterVolume(1.0f);
1077 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08001078 if (DEBUG_VOL) {
1079 Log.d(TAG, String.format("Master mute %s, user=%d", masterMute, currentUser));
1080 }
Jae Seo1b434da2015-11-11 18:58:51 -08001081 setSystemAudioMute(masterMute);
Justin Koh57978ed2012-04-03 17:37:58 -07001082 AudioSystem.setMasterMute(masterMute);
1083 broadcastMasterMuteStatus(masterMute);
1084
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001085 boolean microphoneMute =
Makoto Onukid45a4a22015-11-02 17:17:38 -08001086 (System.getIntForUser(cr, System.MICROPHONE_MUTE, 0, UserHandle.USER_CURRENT) == 1)
1087 || mUserManagerInternal.getUserRestriction(
1088 currentUser, UserManager.DISALLOW_UNMUTE_MICROPHONE);
1089 if (DEBUG_VOL) {
1090 Log.d(TAG, String.format("Mic mute %s, user=%d", microphoneMute, currentUser));
1091 }
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001092 AudioSystem.muteMicrophone(microphoneMute);
1093
Andy Hungf04b84d2015-12-18 17:33:27 -08001094 final boolean masterMono = System.getIntForUser(
1095 cr, System.MASTER_MONO, 0 /* default */, UserHandle.USER_CURRENT) == 1;
1096 if (DEBUG_VOL) {
1097 Log.d(TAG, String.format("Master mono %b, user=%d", masterMono, currentUser));
1098 }
1099 AudioSystem.setMasterMono(masterMono);
1100 broadcastMasterMonoStatus(masterMono);
1101
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001102 // Each stream will read its own persisted settings
1103
John Spurlockbcc10872014-11-28 15:29:21 -05001104 // Broadcast the sticky intents
1105 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
1106 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107
1108 // Broadcast vibrate settings
1109 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
1110 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07001111
John Spurlock33f4e042014-07-11 13:10:58 -04001112 // Load settings for the volume controller
1113 mVolumeController.loadSettings(cr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 }
1115
Eric Laurenta553c252009-07-17 12:17:14 -07001116 private int rescaleIndex(int index, int srcStream, int dstStream) {
1117 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
1118 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001119
1120 ///////////////////////////////////////////////////////////////////////////
1121 // IPC methods
1122 ///////////////////////////////////////////////////////////////////////////
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123 /** @see AudioManager#adjustVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001124 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001125 String callingPackage, String caller) {
RoboErik272e1612014-09-05 11:39:29 -07001126 adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
John Spurlock90874332015-03-10 16:00:54 -04001127 caller, Binder.getCallingUid());
RoboErik272e1612014-09-05 11:39:29 -07001128 }
1129
1130 private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001131 String callingPackage, String caller, int uid) {
1132 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType
1133 + ", flags=" + flags + ", caller=" + caller);
Eric Laurent402f7f22011-02-04 12:30:32 -08001134 int streamType;
RoboErik4197cb62015-01-21 15:45:32 -08001135 boolean isMute = isMuteAdjust(direction);
Eric Laurent45c90ce2012-04-24 18:44:22 -07001136 if (mVolumeControlStream != -1) {
1137 streamType = mVolumeControlStream;
Eric Laurent402f7f22011-02-04 12:30:32 -08001138 } else {
1139 streamType = getActiveStreamType(suggestedStreamType);
1140 }
John Spurlock0a376af2015-03-26 16:24:12 -04001141 ensureValidStreamType(streamType);
John Spurlock33f4e042014-07-11 13:10:58 -04001142 final int resolvedStream = mStreamVolumeAlias[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143
RoboErik2811dd32014-08-12 09:48:13 -07001144 // Play sounds on STREAM_RING only.
1145 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
John Spurlock33f4e042014-07-11 13:10:58 -04001146 resolvedStream != AudioSystem.STREAM_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001147 flags &= ~AudioManager.FLAG_PLAY_SOUND;
1148 }
1149
John Spurlock33f4e042014-07-11 13:10:58 -04001150 // For notifications/ring, show the ui before making any adjustments
RoboErik4197cb62015-01-21 15:45:32 -08001151 // Don't suppress mute/unmute requests
1152 if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
John Spurlock33f4e042014-07-11 13:10:58 -04001153 direction = 0;
1154 flags &= ~AudioManager.FLAG_PLAY_SOUND;
1155 flags &= ~AudioManager.FLAG_VIBRATE;
1156 if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
1157 }
1158
John Spurlock90874332015-03-10 16:00:54 -04001159 adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001160 }
1161
1162 /** @see AudioManager#adjustStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001163 public void adjustStreamVolume(int streamType, int direction, int flags,
1164 String callingPackage) {
John Spurlock90874332015-03-10 16:00:54 -04001165 adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage,
1166 Binder.getCallingUid());
RoboErik0dac35a2014-08-12 15:48:49 -07001167 }
1168
1169 private void adjustStreamVolume(int streamType, int direction, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001170 String callingPackage, String caller, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001171 if (mUseFixedVolume) {
1172 return;
1173 }
John Spurlock90874332015-03-10 16:00:54 -04001174 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream=" + streamType + ", dir=" + direction
1175 + ", flags=" + flags + ", caller=" + caller);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07001176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177 ensureValidDirection(direction);
1178 ensureValidStreamType(streamType);
1179
RoboErik4197cb62015-01-21 15:45:32 -08001180 boolean isMuteAdjust = isMuteAdjust(direction);
1181
John Spurlock3ce37252015-02-17 13:20:45 -05001182 if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
1183 return;
1184 }
1185
Eric Laurent96a33d12011-11-08 10:31:57 -08001186 // use stream type alias here so that streams with same alias have the same behavior,
1187 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
1188 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
Eric Laurent6d517662012-04-23 18:42:39 -07001189 int streamTypeAlias = mStreamVolumeAlias[streamType];
RoboErik4197cb62015-01-21 15:45:32 -08001190
Eric Laurentb024c302011-10-14 17:19:27 -07001191 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001192
1193 final int device = getDeviceForStream(streamTypeAlias);
Eric Laurent3ef75492012-11-28 12:12:23 -08001194
Eric Laurent42b041e2013-03-29 11:36:03 -07001195 int aliasIndex = streamState.getIndex(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 boolean adjustVolume = true;
Eric Laurent3ef75492012-11-28 12:12:23 -08001197 int step;
Eric Laurent24482012012-05-10 09:41:17 -07001198
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001199 // skip a2dp absolute volume control request when the device
1200 // is not an a2dp device
1201 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1202 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1203 return;
1204 }
1205
Kenny Guy70e0c582015-06-30 19:18:28 +01001206 // If we are being called by the system (e.g. hardware keys) check for current user
1207 // so we handle user restrictions correctly.
1208 if (uid == android.os.Process.SYSTEM_UID) {
1209 uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
1210 }
John Spurlock59dc9c12015-03-02 11:20:15 -05001211 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001212 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001213 return;
1214 }
1215
Eric Laurentfde16d52012-12-03 14:42:39 -08001216 // reset any pending volume command
1217 synchronized (mSafeMediaVolumeState) {
1218 mPendingVolumeCommand = null;
1219 }
1220
Eric Laurent3ef75492012-11-28 12:12:23 -08001221 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1222 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1223 ((device & mFixedVolumeDevices) != 0)) {
1224 flags |= AudioManager.FLAG_FIXED_VOLUME;
1225
1226 // Always toggle between max safe volume and 0 for fixed volume devices where safe
1227 // volume is enforced, and max and 0 for the others.
1228 // This is simulated by stepping by the full allowed volume range
1229 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1230 (device & mSafeMediaVolumeDevices) != 0) {
1231 step = mSafeMediaVolumeIndex;
1232 } else {
1233 step = streamState.getMaxIndex();
1234 }
1235 if (aliasIndex != 0) {
1236 aliasIndex = step;
1237 }
1238 } else {
1239 // convert one UI step (+/-1) into a number of internal units on the stream alias
1240 step = rescaleIndex(10, streamType, streamTypeAlias);
1241 }
1242
Eric Laurent42b041e2013-03-29 11:36:03 -07001243 // If either the client forces allowing ringer modes for this adjustment,
1244 // or the stream type is one that is affected by ringer modes
1245 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlockee5ad722015-03-03 16:17:21 -05001246 (streamTypeAlias == getUiSoundsStreamType())) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001247 int ringerMode = getRingerModeInternal();
Eric Laurent42b041e2013-03-29 11:36:03 -07001248 // do not vibrate if already in vibrate mode
1249 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
1250 flags &= ~AudioManager.FLAG_VIBRATE;
Eric Laurent3ef75492012-11-28 12:12:23 -08001251 }
RoboErik5452e252015-02-06 15:33:53 -08001252 // Check if the ringer mode handles this adjustment. If it does we don't
1253 // need to adjust the volume further.
John Spurlock50ced3f2015-05-11 16:00:09 -04001254 final int result = checkForRingerModeChange(aliasIndex, direction, step,
1255 streamState.mIsMuted);
John Spurlocka11b4af2014-06-01 11:52:23 -04001256 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
1257 // If suppressing a volume adjustment in silent mode, display the UI hint
1258 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
1259 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
1260 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001261 // If suppressing a volume down adjustment in vibrate mode, display the UI hint
1262 if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
1263 flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
1264 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001265 }
John Spurlock50ced3f2015-05-11 16:00:09 -04001266 // If the ringermode is suppressing media, prevent changes
1267 if (streamTypeAlias == AudioSystem.STREAM_MUSIC
1268 && (mRingerModeMutedStreams & (1 << AudioSystem.STREAM_MUSIC)) != 0) {
1269 adjustVolume = false;
1270 }
Eric Laurent3ef75492012-11-28 12:12:23 -08001271
Eric Laurent42b041e2013-03-29 11:36:03 -07001272 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001273
Eric Laurent42b041e2013-03-29 11:36:03 -07001274 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
RoboErik5452e252015-02-06 15:33:53 -08001275 mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001276
John Du5a0cf7a2013-07-19 11:30:34 -07001277 // Check if volume update should be send to AVRCP
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001278 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1279 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1280 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1281 synchronized (mA2dpAvrcpLock) {
1282 if (mA2dp != null && mAvrcpAbsVolSupported) {
1283 mA2dp.adjustAvrcpAbsoluteVolume(direction);
1284 }
John Du5a0cf7a2013-07-19 11:30:34 -07001285 }
1286 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001287
RoboErik4197cb62015-01-21 15:45:32 -08001288 if (isMuteAdjust) {
1289 boolean state;
1290 if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
1291 state = !streamState.mIsMuted;
1292 } else {
1293 state = direction == AudioManager.ADJUST_MUTE;
1294 }
1295 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1296 setSystemAudioMute(state);
1297 }
1298 for (int stream = 0; stream < mStreamStates.length; stream++) {
1299 if (streamTypeAlias == mStreamVolumeAlias[stream]) {
Sungmin Choi841ed0a2015-07-26 23:09:49 -07001300 if (!(readCameraSoundForced()
1301 && (mStreamStates[stream].getStreamType()
1302 == AudioSystem.STREAM_SYSTEM_ENFORCED))) {
1303 mStreamStates[stream].mute(state);
1304 }
RoboErik4197cb62015-01-21 15:45:32 -08001305 }
1306 }
1307 } else if ((direction == AudioManager.ADJUST_RAISE) &&
Eric Laurent42b041e2013-03-29 11:36:03 -07001308 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
RoboErik4197cb62015-01-21 15:45:32 -08001309 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -04001310 mVolumeController.postDisplaySafeVolumeWarning(flags);
John Spurlock90874332015-03-10 16:00:54 -04001311 } else if (streamState.adjustIndex(direction * step, device, caller)
1312 || streamState.mIsMuted) {
RoboErik4197cb62015-01-21 15:45:32 -08001313 // Post message to set system volume (it in turn will post a
1314 // message to persist).
1315 if (streamState.mIsMuted) {
1316 // Unmute the stream if it was previously muted
RoboErik5452e252015-02-06 15:33:53 -08001317 if (direction == AudioManager.ADJUST_RAISE) {
1318 // unmute immediately for volume up
1319 streamState.mute(false);
1320 } else if (direction == AudioManager.ADJUST_LOWER) {
John Spurlocka48d7792015-03-03 17:35:57 -05001321 if (mPlatformType == AudioSystem.PLATFORM_TELEVISION) {
1322 sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
1323 streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
1324 }
RoboErik5452e252015-02-06 15:33:53 -08001325 }
RoboErik4197cb62015-01-21 15:45:32 -08001326 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001327 sendMsg(mAudioHandler,
1328 MSG_SET_DEVICE_VOLUME,
1329 SENDMSG_QUEUE,
1330 device,
1331 0,
1332 streamState,
1333 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001334 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001335
RoboErik4197cb62015-01-21 15:45:32 -08001336 // Check if volume update should be sent to Hdmi system audio.
Jungshik Jang41d97462014-06-30 22:26:29 +09001337 int newIndex = mStreamStates[streamType].getIndex(device);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001338 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1339 setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
1340 }
Eric Laurent212532b2014-07-21 15:43:18 -07001341 if (mHdmiManager != null) {
1342 synchronized (mHdmiManager) {
Eric Laurent212532b2014-07-21 15:43:18 -07001343 // mHdmiCecSink true => mHdmiPlaybackClient != null
1344 if (mHdmiCecSink &&
1345 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1346 oldIndex != newIndex) {
1347 synchronized (mHdmiPlaybackClient) {
1348 int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
RoboErik4197cb62015-01-21 15:45:32 -08001349 KeyEvent.KEYCODE_VOLUME_UP;
Eric Laurent212532b2014-07-21 15:43:18 -07001350 mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1351 mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1352 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001353 }
1354 }
1355 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001356 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001357 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001358 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001359 }
1360
RoboErik5452e252015-02-06 15:33:53 -08001361 // Called after a delay when volume down is pressed while muted
1362 private void onUnmuteStream(int stream, int flags) {
1363 VolumeStreamState streamState = mStreamStates[stream];
1364 streamState.mute(false);
1365
1366 final int device = getDeviceForStream(stream);
1367 final int index = mStreamStates[stream].getIndex(device);
1368 sendVolumeUpdate(stream, index, index, flags);
1369 }
1370
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001371 private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
1372 if (mHdmiManager == null
1373 || mHdmiTvClient == null
1374 || oldVolume == newVolume
1375 || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
1376
1377 // Sets the audio volume of AVR when we are in system audio mode. The new volume info
1378 // is tranformed to HDMI-CEC commands and passed through CEC bus.
1379 synchronized (mHdmiManager) {
1380 if (!mHdmiSystemAudioSupported) return;
1381 synchronized (mHdmiTvClient) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001382 final long token = Binder.clearCallingIdentity();
1383 try {
Jinsuk Kim7a9ba422015-02-16 16:47:38 +09001384 mHdmiTvClient.setSystemAudioVolume(oldVolume, newVolume, maxVolume);
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001385 } finally {
1386 Binder.restoreCallingIdentity(token);
1387 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001388 }
1389 }
1390 }
1391
Eric Laurentfde16d52012-12-03 14:42:39 -08001392 // StreamVolumeCommand contains the information needed to defer the process of
1393 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1394 class StreamVolumeCommand {
1395 public final int mStreamType;
1396 public final int mIndex;
1397 public final int mFlags;
1398 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001399
Eric Laurentfde16d52012-12-03 14:42:39 -08001400 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1401 mStreamType = streamType;
1402 mIndex = index;
1403 mFlags = flags;
1404 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001405 }
John Spurlock35134602014-07-24 18:10:48 -04001406
1407 @Override
1408 public String toString() {
1409 return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1410 .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1411 .append(mDevice).append('}').toString();
1412 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001413 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001414
John Spurlock90874332015-03-10 16:00:54 -04001415 private void onSetStreamVolume(int streamType, int index, int flags, int device,
1416 String caller) {
John Spurlock75ae23c2015-06-02 16:26:43 -04001417 final int stream = mStreamVolumeAlias[streamType];
1418 setStreamVolumeInt(stream, index, device, false, caller);
John Spurlockee5ad722015-03-03 16:17:21 -05001419 // setting volume on ui sounds stream type also controls silent mode
Eric Laurent3ef75492012-11-28 12:12:23 -08001420 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlock75ae23c2015-06-02 16:26:43 -04001421 (stream == getUiSoundsStreamType())) {
Eric Laurent3ef75492012-11-28 12:12:23 -08001422 int newRingerMode;
1423 if (index == 0) {
1424 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlocka48d7792015-03-03 17:35:57 -05001425 : mVolumePolicy.volumeDownToEnterSilent ? AudioManager.RINGER_MODE_SILENT
John Spurlock86005342014-05-23 11:58:00 -04001426 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001427 } else {
1428 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1429 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001430 setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/);
Eric Laurent3ef75492012-11-28 12:12:23 -08001431 }
John Spurlock75ae23c2015-06-02 16:26:43 -04001432 // setting non-zero volume for a muted stream unmutes the stream and vice versa
1433 mStreamStates[stream].mute(index == 0);
Eric Laurentfde16d52012-12-03 14:42:39 -08001434 }
1435
1436 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001437 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
John Spurlock90874332015-03-10 16:00:54 -04001438 setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
1439 Binder.getCallingUid());
RoboErik0dac35a2014-08-12 15:48:49 -07001440 }
1441
1442 private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
John Spurlock90874332015-03-10 16:00:54 -04001443 String caller, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001444 if (mUseFixedVolume) {
1445 return;
1446 }
1447
Eric Laurentfde16d52012-12-03 14:42:39 -08001448 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001449 int streamTypeAlias = mStreamVolumeAlias[streamType];
1450 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001451
1452 final int device = getDeviceForStream(streamType);
1453 int oldIndex;
1454
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001455 // skip a2dp absolute volume control request when the device
1456 // is not an a2dp device
1457 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1458 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1459 return;
1460 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001461 // If we are being called by the system (e.g. hardware keys) check for current user
1462 // so we handle user restrictions correctly.
1463 if (uid == android.os.Process.SYSTEM_UID) {
1464 uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
1465 }
John Spurlock59dc9c12015-03-02 11:20:15 -05001466 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001467 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001468 return;
1469 }
1470
Eric Laurentfde16d52012-12-03 14:42:39 -08001471 synchronized (mSafeMediaVolumeState) {
1472 // reset any pending volume command
1473 mPendingVolumeCommand = null;
1474
Eric Laurent42b041e2013-03-29 11:36:03 -07001475 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001476
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001477 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001478
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001479 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1480 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1481 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1482 synchronized (mA2dpAvrcpLock) {
1483 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001484 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001485 }
John Du5a0cf7a2013-07-19 11:30:34 -07001486 }
1487 }
1488
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001489 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1490 setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
Jungshik Jang41d97462014-06-30 22:26:29 +09001491 }
1492
Eric Laurentfde16d52012-12-03 14:42:39 -08001493 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001494 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001495 ((device & mFixedVolumeDevices) != 0)) {
1496 flags |= AudioManager.FLAG_FIXED_VOLUME;
1497
1498 // volume is either 0 or max allowed for fixed volume devices
1499 if (index != 0) {
1500 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1501 (device & mSafeMediaVolumeDevices) != 0) {
1502 index = mSafeMediaVolumeIndex;
1503 } else {
1504 index = streamState.getMaxIndex();
1505 }
1506 }
1507 }
1508
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001509 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001510 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001511 mPendingVolumeCommand = new StreamVolumeCommand(
1512 streamType, index, flags, device);
1513 } else {
John Spurlock90874332015-03-10 16:00:54 -04001514 onSetStreamVolume(streamType, index, flags, device, caller);
Eric Laurent42b041e2013-03-29 11:36:03 -07001515 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001516 }
1517 }
Eric Laurent25101b02011-02-02 09:33:30 -08001518 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001519 }
1520
Eric Laurent45c90ce2012-04-24 18:44:22 -07001521 /** @see AudioManager#forceVolumeControlStream(int) */
1522 public void forceVolumeControlStream(int streamType, IBinder cb) {
1523 synchronized(mForceControlStreamLock) {
1524 mVolumeControlStream = streamType;
1525 if (mVolumeControlStream == -1) {
1526 if (mForceControlStreamClient != null) {
1527 mForceControlStreamClient.release();
1528 mForceControlStreamClient = null;
1529 }
1530 } else {
1531 mForceControlStreamClient = new ForceControlStreamClient(cb);
1532 }
1533 }
1534 }
1535
1536 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1537 private IBinder mCb; // To be notified of client's death
1538
1539 ForceControlStreamClient(IBinder cb) {
1540 if (cb != null) {
1541 try {
1542 cb.linkToDeath(this, 0);
1543 } catch (RemoteException e) {
1544 // Client has died!
1545 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1546 cb = null;
1547 }
1548 }
1549 mCb = cb;
1550 }
1551
1552 public void binderDied() {
1553 synchronized(mForceControlStreamLock) {
1554 Log.w(TAG, "SCO client died");
1555 if (mForceControlStreamClient != this) {
1556 Log.w(TAG, "unregistered control stream client died");
1557 } else {
1558 mForceControlStreamClient = null;
1559 mVolumeControlStream = -1;
1560 }
1561 }
1562 }
1563
1564 public void release() {
1565 if (mCb != null) {
1566 mCb.unlinkToDeath(this, 0);
1567 mCb = null;
1568 }
1569 }
1570 }
1571
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001572 private void sendBroadcastToAll(Intent intent) {
Christopher Tate267603f2015-01-20 14:21:21 -08001573 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
John Spurlock86490862015-02-25 11:22:52 -05001574 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001575 final long ident = Binder.clearCallingIdentity();
1576 try {
1577 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1578 } finally {
1579 Binder.restoreCallingIdentity(ident);
1580 }
1581 }
1582
1583 private void sendStickyBroadcastToAll(Intent intent) {
John Spurlock86490862015-02-25 11:22:52 -05001584 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001585 final long ident = Binder.clearCallingIdentity();
1586 try {
1587 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1588 } finally {
1589 Binder.restoreCallingIdentity(ident);
1590 }
1591 }
1592
Kenny Guy70e0c582015-06-30 19:18:28 +01001593 private int getCurrentUserId() {
1594 final long ident = Binder.clearCallingIdentity();
1595 try {
1596 UserInfo currentUser = ActivityManagerNative.getDefault().getCurrentUser();
1597 return currentUser.id;
1598 } catch (RemoteException e) {
1599 // Activity manager not running, nothing we can do assume user 0.
1600 } finally {
1601 Binder.restoreCallingIdentity(ident);
1602 }
Xiaohui Chen7c696362015-09-16 09:56:14 -07001603 return UserHandle.USER_SYSTEM;
Kenny Guy70e0c582015-06-30 19:18:28 +01001604 }
1605
Eric Laurent25101b02011-02-02 09:33:30 -08001606 // UI update and Broadcast Intent
1607 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
John Spurlock72966d62015-06-18 15:45:07 -04001608 streamType = mStreamVolumeAlias[streamType];
Eric Laurent25101b02011-02-02 09:33:30 -08001609
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001610 if (streamType == AudioSystem.STREAM_MUSIC) {
1611 flags = updateFlagsForSystemAudio(flags);
Jungshik Jang1a6be6e2014-09-16 11:04:54 +09001612 }
John Spurlock3346a802014-05-20 16:25:37 -04001613 mVolumeController.postVolumeChanged(streamType, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001614 }
1615
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001616 // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
1617 // receives volume notification from Audio Receiver.
1618 private int updateFlagsForSystemAudio(int flags) {
1619 if (mHdmiTvClient != null) {
1620 synchronized (mHdmiTvClient) {
1621 if (mHdmiSystemAudioSupported &&
1622 ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
1623 flags &= ~AudioManager.FLAG_SHOW_UI;
1624 }
1625 }
1626 }
1627 return flags;
1628 }
1629
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001630 // UI update and Broadcast Intent
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001631 private void sendMasterMuteUpdate(boolean muted, int flags) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001632 mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
Justin Koh57978ed2012-04-03 17:37:58 -07001633 broadcastMasterMuteStatus(muted);
1634 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001635
Justin Koh57978ed2012-04-03 17:37:58 -07001636 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001637 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1638 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001639 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1640 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001641 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001642 }
1643
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001644 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001645 * Sets the stream state's index, and posts a message to set system volume.
1646 * This will not call out to the UI. Assumes a valid stream type.
1647 *
1648 * @param streamType Type of the stream
1649 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001650 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001651 * @param force If true, set the volume even if the desired volume is same
1652 * as the current volume.
1653 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001654 private void setStreamVolumeInt(int streamType,
1655 int index,
1656 int device,
John Spurlock90874332015-03-10 16:00:54 -04001657 boolean force,
1658 String caller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001659 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07001660
John Spurlock90874332015-03-10 16:00:54 -04001661 if (streamState.setIndex(index, device, caller) || force) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001662 // Post message to set system volume (it in turn will post a message
1663 // to persist).
1664 sendMsg(mAudioHandler,
1665 MSG_SET_DEVICE_VOLUME,
1666 SENDMSG_QUEUE,
1667 device,
1668 0,
1669 streamState,
1670 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 }
1672 }
1673
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001674 private void setSystemAudioMute(boolean state) {
1675 if (mHdmiManager == null || mHdmiTvClient == null) return;
1676 synchronized (mHdmiManager) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001677 if (!mHdmiSystemAudioSupported) return;
1678 synchronized (mHdmiTvClient) {
1679 final long token = Binder.clearCallingIdentity();
1680 try {
1681 mHdmiTvClient.setSystemAudioMute(state);
1682 } finally {
1683 Binder.restoreCallingIdentity(token);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001684 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001685 }
1686 }
1687 }
1688
Eric Laurent25101b02011-02-02 09:33:30 -08001689 /** get stream mute state. */
1690 public boolean isStreamMute(int streamType) {
RoboErik7c82ced2014-12-04 17:39:08 -08001691 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1692 streamType = getActiveStreamType(streamType);
1693 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001694 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08001695 return mStreamStates[streamType].mIsMuted;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001696 }
Eric Laurent25101b02011-02-02 09:33:30 -08001697 }
1698
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07001699 private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
1700 private IBinder mICallback; // To be notified of client's death
1701
1702 RmtSbmxFullVolDeathHandler(IBinder cb) {
1703 mICallback = cb;
1704 try {
1705 cb.linkToDeath(this, 0/*flags*/);
1706 } catch (RemoteException e) {
1707 Log.e(TAG, "can't link to death", e);
1708 }
1709 }
1710
1711 boolean isHandlerFor(IBinder cb) {
1712 return mICallback.equals(cb);
1713 }
1714
1715 void forget() {
1716 try {
1717 mICallback.unlinkToDeath(this, 0/*flags*/);
1718 } catch (NoSuchElementException e) {
1719 Log.e(TAG, "error unlinking to death", e);
1720 }
1721 }
1722
1723 public void binderDied() {
1724 Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
1725 forceRemoteSubmixFullVolume(false, mICallback);
1726 }
1727 }
1728
1729 /**
1730 * call must be synchronized on mRmtSbmxFullVolDeathHandlers
1731 * @return true if there is a registered death handler, false otherwise */
1732 private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1733 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1734 while (it.hasNext()) {
1735 final RmtSbmxFullVolDeathHandler handler = it.next();
1736 if (handler.isHandlerFor(cb)) {
1737 handler.forget();
1738 mRmtSbmxFullVolDeathHandlers.remove(handler);
1739 return true;
1740 }
1741 }
1742 return false;
1743 }
1744
1745 /** call synchronized on mRmtSbmxFullVolDeathHandlers */
1746 private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1747 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1748 while (it.hasNext()) {
1749 if (it.next().isHandlerFor(cb)) {
1750 return true;
1751 }
1752 }
1753 return false;
1754 }
1755
1756 private int mRmtSbmxFullVolRefCount = 0;
1757 private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
1758 new ArrayList<RmtSbmxFullVolDeathHandler>();
1759
1760 public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
1761 if (cb == null) {
1762 return;
1763 }
1764 if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
1765 android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
1766 Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
1767 return;
1768 }
1769 synchronized(mRmtSbmxFullVolDeathHandlers) {
1770 boolean applyRequired = false;
1771 if (startForcing) {
1772 if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
1773 mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
1774 if (mRmtSbmxFullVolRefCount == 0) {
1775 mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1776 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1777 applyRequired = true;
1778 }
1779 mRmtSbmxFullVolRefCount++;
1780 }
1781 } else {
1782 if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
1783 mRmtSbmxFullVolRefCount--;
1784 if (mRmtSbmxFullVolRefCount == 0) {
1785 mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1786 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1787 applyRequired = true;
1788 }
1789 }
1790 }
1791 if (applyRequired) {
1792 // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
1793 checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
1794 mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
1795 }
1796 }
1797 }
1798
Kenny Guy70e0c582015-06-30 19:18:28 +01001799 private void setMasterMuteInternal(boolean mute, int flags, String callingPackage, int uid,
1800 int userId) {
1801 // If we are being called by the system check for user we are going to change
1802 // so we handle user restrictions correctly.
1803 if (uid == android.os.Process.SYSTEM_UID) {
1804 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
1805 }
Makoto Onuki4f160732015-10-27 17:15:38 -07001806 // If OP_AUDIO_MASTER_VOLUME is set, disallow unmuting.
1807 if (!mute && mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
RoboErik7c82ced2014-12-04 17:39:08 -08001808 != AppOpsManager.MODE_ALLOWED) {
Julia Reynolds4a21b252014-06-04 11:11:43 -04001809 return;
1810 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001811 if (userId != UserHandle.getCallingUserId() &&
1812 mContext.checkCallingOrSelfPermission(
1813 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1814 != PackageManager.PERMISSION_GRANTED) {
1815 return;
1816 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08001817 setMasterMuteInternalNoCallerCheck(mute, flags, userId);
1818 }
1819
1820 private void setMasterMuteInternalNoCallerCheck(boolean mute, int flags, int userId) {
1821 if (DEBUG_VOL) {
1822 Log.d(TAG, String.format("Master mute %s, %d, user=%d", mute, flags, userId));
1823 }
1824 if (mUseFixedVolume) {
1825 return; // If using fixed volume, we don't mute.
1826 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001827 if (getCurrentUserId() == userId) {
1828 if (mute != AudioSystem.getMasterMute()) {
1829 setSystemAudioMute(mute);
1830 AudioSystem.setMasterMute(mute);
1831 // Post a persist master volume msg
1832 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, mute ? 1
1833 : 0, userId, null, PERSIST_DELAY);
1834 sendMasterMuteUpdate(mute, flags);
RoboErik7c82ced2014-12-04 17:39:08 -08001835
Kenny Guy70e0c582015-06-30 19:18:28 +01001836 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1837 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute);
1838 sendBroadcastToAll(intent);
1839 }
1840 } else {
1841 // If not the current user just persist the setting which will be loaded
1842 // on user switch.
1843 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, mute ? 1
1844 : 0, userId, null, PERSIST_DELAY);
Jason Simmons1ce5b262012-02-02 13:00:17 -08001845 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08001846 }
1847
1848 /** get master mute state. */
1849 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08001850 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001851 }
1852
Kenny Guy70e0c582015-06-30 19:18:28 +01001853 public void setMasterMute(boolean mute, int flags, String callingPackage, int userId) {
1854 setMasterMuteInternal(mute, flags, callingPackage, Binder.getCallingUid(),
1855 userId);
John Spurlockee5ad722015-03-03 16:17:21 -05001856 }
1857
Andy Hungf04b84d2015-12-18 17:33:27 -08001858 /** @hide */
1859 public boolean isMasterMono() {
1860 return AudioSystem.getMasterMono();
1861 }
1862
1863 /** @hide */
1864 public void setMasterMono(boolean mono, String callingPackage, int userId) {
1865 int callingUid = Binder.getCallingUid();
1866 // If we are being called by the system check for user we are going to change
1867 // so we handle user restrictions correctly.
1868 if (callingUid == android.os.Process.SYSTEM_UID) {
1869 callingUid = UserHandle.getUid(userId, UserHandle.getAppId(callingUid));
1870 }
1871
1872 if (userId != UserHandle.getCallingUserId() &&
1873 mContext.checkCallingOrSelfPermission(
1874 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1875 != PackageManager.PERMISSION_GRANTED) {
1876 return;
1877 }
1878 if (DEBUG_VOL) {
1879 Log.d(TAG, String.format("Master mono %b, user=%d", mono, userId));
1880 }
1881
1882 if (getCurrentUserId() == userId) {
1883 if (mono != AudioSystem.getMasterMono()) {
1884 AudioSystem.setMasterMono(mono);
1885 // Post a persist master mono msg
1886 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_MONO, SENDMSG_REPLACE, mono ? 1
1887 : 0 /* value */, userId, null /* obj */, 0 /* delay */);
1888 // notify apps and settings
1889 broadcastMasterMonoStatus(mono);
1890 }
1891 } else {
1892 // Post a persist master mono msg
1893 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_MONO, SENDMSG_REPLACE, mono ? 1
1894 : 0 /* value */, userId, null /* obj */, 0 /* delay */);
1895 }
1896 }
1897
1898 private void broadcastMasterMonoStatus(boolean mono) {
1899 Intent intent = new Intent(AudioManager.MASTER_MONO_CHANGED_ACTION);
1900 intent.putExtra(AudioManager.EXTRA_MASTER_MONO, mono);
1901 sendBroadcastToAll(intent);
1902 }
1903
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001904 /** @see AudioManager#getStreamVolume(int) */
1905 public int getStreamVolume(int streamType) {
1906 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001907 int device = getDeviceForStream(streamType);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001908 synchronized (VolumeStreamState.class) {
1909 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001910
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001911 // by convention getStreamVolume() returns 0 when a stream is muted.
RoboErik4197cb62015-01-21 15:45:32 -08001912 if (mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001913 index = 0;
1914 }
1915 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
1916 (device & mFixedVolumeDevices) != 0) {
1917 index = mStreamStates[streamType].getMaxIndex();
1918 }
1919 return (index + 5) / 10;
Eric Laurent42b041e2013-03-29 11:36:03 -07001920 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001921 }
1922
1923 /** @see AudioManager#getStreamMaxVolume(int) */
1924 public int getStreamMaxVolume(int streamType) {
1925 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07001926 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001927 }
1928
John Spurlockb6e19e32015-03-10 21:33:44 -04001929 /** @see AudioManager#getStreamMinVolume(int) */
1930 public int getStreamMinVolume(int streamType) {
1931 ensureValidStreamType(streamType);
1932 return (mStreamStates[streamType].getMinIndex() + 5) / 10;
1933 }
1934
Eric Laurent25101b02011-02-02 09:33:30 -08001935 /** Get last audible volume before stream was muted. */
1936 public int getLastAudibleStreamVolume(int streamType) {
1937 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001938 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001939 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08001940 }
1941
John Spurlockee5ad722015-03-03 16:17:21 -05001942 /** @see AudioManager#getUiSoundsStreamType() */
1943 public int getUiSoundsStreamType() {
John Spurlock4f0f1202014-08-05 13:28:33 -04001944 return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
Eric Laurent6d517662012-04-23 18:42:39 -07001945 }
1946
Makoto Onukid45a4a22015-11-02 17:17:38 -08001947 /** @see AudioManager#setMicrophoneMute(boolean) */
1948 @Override
Kenny Guy70e0c582015-06-30 19:18:28 +01001949 public void setMicrophoneMute(boolean on, String callingPackage, int userId) {
1950 // If we are being called by the system check for user we are going to change
1951 // so we handle user restrictions correctly.
1952 int uid = Binder.getCallingUid();
1953 if (uid == android.os.Process.SYSTEM_UID) {
1954 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
1955 }
Makoto Onuki4f160732015-10-27 17:15:38 -07001956 // If OP_MUTE_MICROPHONE is set, disallow unmuting.
1957 if (!on && mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, uid, callingPackage)
Kenny Guy70e0c582015-06-30 19:18:28 +01001958 != AppOpsManager.MODE_ALLOWED) {
Emily Bernier22c921a2014-05-28 11:01:32 -04001959 return;
1960 }
Jean-Michel Trivi4a4fea02014-08-29 18:14:09 -07001961 if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
1962 return;
1963 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001964 if (userId != UserHandle.getCallingUserId() &&
1965 mContext.checkCallingOrSelfPermission(
1966 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1967 != PackageManager.PERMISSION_GRANTED) {
1968 return;
1969 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08001970 setMicrophoneMuteNoCallerCheck(on, userId);
1971 }
Emily Bernier22c921a2014-05-28 11:01:32 -04001972
Makoto Onukid45a4a22015-11-02 17:17:38 -08001973 private void setMicrophoneMuteNoCallerCheck(boolean on, int userId) {
1974 if (DEBUG_VOL) {
1975 Log.d(TAG, String.format("Mic mute %s, user=%d", on, userId));
1976 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001977 // If mute is for current user actually mute, else just persist the setting
1978 // which will be loaded on user switch.
1979 if (getCurrentUserId() == userId) {
1980 AudioSystem.muteMicrophone(on);
1981 }
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001982 // Post a persist microphone msg.
1983 sendMsg(mAudioHandler, MSG_PERSIST_MICROPHONE_MUTE, SENDMSG_REPLACE, on ? 1
Kenny Guy70e0c582015-06-30 19:18:28 +01001984 : 0, userId, null, PERSIST_DELAY);
Emily Bernier22c921a2014-05-28 11:01:32 -04001985 }
1986
John Spurlock661f2cf2014-11-17 10:29:10 -05001987 @Override
1988 public int getRingerModeExternal() {
1989 synchronized(mSettingsLock) {
1990 return mRingerModeExternal;
1991 }
1992 }
1993
1994 @Override
1995 public int getRingerModeInternal() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001996 synchronized(mSettingsLock) {
1997 return mRingerMode;
1998 }
1999 }
2000
2001 private void ensureValidRingerMode(int ringerMode) {
John Spurlock97559372014-10-24 16:27:36 -04002002 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08002003 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
2004 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002005 }
2006
John Spurlock97559372014-10-24 16:27:36 -04002007 /** @see AudioManager#isValidRingerMode(int) */
2008 public boolean isValidRingerMode(int ringerMode) {
2009 return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
2010 }
2011
John Spurlock661f2cf2014-11-17 10:29:10 -05002012 public void setRingerModeExternal(int ringerMode, String caller) {
John Spurlockaf88a192014-12-23 16:14:44 -05002013 setRingerMode(ringerMode, caller, true /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05002014 }
2015
2016 public void setRingerModeInternal(int ringerMode, String caller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05002017 enforceVolumeController("setRingerModeInternal");
John Spurlockaf88a192014-12-23 16:14:44 -05002018 setRingerMode(ringerMode, caller, false /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05002019 }
2020
2021 private void setRingerMode(int ringerMode, String caller, boolean external) {
Eric Laurent212532b2014-07-21 15:43:18 -07002022 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07002023 return;
2024 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002025 if (caller == null || caller.length() == 0) {
2026 throw new IllegalArgumentException("Bad caller: " + caller);
2027 }
John Spurlock97559372014-10-24 16:27:36 -04002028 ensureValidRingerMode(ringerMode);
Eric Laurent24482012012-05-10 09:41:17 -07002029 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
2030 ringerMode = AudioManager.RINGER_MODE_SILENT;
2031 }
John Spurlockaf88a192014-12-23 16:14:44 -05002032 final long identity = Binder.clearCallingIdentity();
2033 try {
2034 synchronized (mSettingsLock) {
2035 final int ringerModeInternal = getRingerModeInternal();
2036 final int ringerModeExternal = getRingerModeExternal();
2037 if (external) {
2038 setRingerModeExt(ringerMode);
2039 if (mRingerModeDelegate != null) {
2040 ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
John Spurlocka48d7792015-03-03 17:35:57 -05002041 ringerMode, caller, ringerModeInternal, mVolumePolicy);
John Spurlockaf88a192014-12-23 16:14:44 -05002042 }
2043 if (ringerMode != ringerModeInternal) {
2044 setRingerModeInt(ringerMode, true /*persist*/);
2045 }
2046 } else /*internal*/ {
2047 if (ringerMode != ringerModeInternal) {
2048 setRingerModeInt(ringerMode, true /*persist*/);
2049 }
2050 if (mRingerModeDelegate != null) {
2051 ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
John Spurlocka48d7792015-03-03 17:35:57 -05002052 ringerMode, caller, ringerModeExternal, mVolumePolicy);
John Spurlockaf88a192014-12-23 16:14:44 -05002053 }
2054 setRingerModeExt(ringerMode);
John Spurlock57627792014-12-11 11:29:54 -05002055 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002056 }
John Spurlockaf88a192014-12-23 16:14:44 -05002057 } finally {
2058 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002059 }
2060 }
2061
John Spurlock661f2cf2014-11-17 10:29:10 -05002062 private void setRingerModeExt(int ringerMode) {
2063 synchronized(mSettingsLock) {
2064 if (ringerMode == mRingerModeExternal) return;
2065 mRingerModeExternal = ringerMode;
John Spurlocke5b42d92014-10-15 12:03:48 -04002066 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002067 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05002068 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
John Spurlocke5b42d92014-10-15 12:03:48 -04002069 }
2070
John Spurlock50ced3f2015-05-11 16:00:09 -04002071 private void muteRingerModeStreams() {
Eric Laurent5b4e6542010-03-19 20:02:21 -07002072 // Mute stream if not previously muted by ringer mode and ringer mode
2073 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
2074 // Unmute stream if previously muted by ringer mode and ringer mode
2075 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07002076 int numStreamTypes = AudioSystem.getNumStreamTypes();
John Spurlock50ced3f2015-05-11 16:00:09 -04002077 final boolean ringerModeMute = mRingerMode == AudioManager.RINGER_MODE_VIBRATE
2078 || mRingerMode == AudioManager.RINGER_MODE_SILENT;
Eric Laurent5b4e6542010-03-19 20:02:21 -07002079 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002080 final boolean isMuted = isStreamMutedByRingerMode(streamType);
2081 final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
2082 if (isMuted == shouldMute) continue;
2083 if (!shouldMute) {
2084 // unmute
2085 // ring and notifications volume should never be 0 when not silenced
John Spurlockd9c75db2015-04-28 11:19:13 -04002086 if (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002087 synchronized (VolumeStreamState.class) {
John Spurlocka48d7792015-03-03 17:35:57 -05002088 final VolumeStreamState vss = mStreamStates[streamType];
2089 for (int i = 0; i < vss.mIndexMap.size(); i++) {
2090 int device = vss.mIndexMap.keyAt(i);
2091 int value = vss.mIndexMap.valueAt(i);
John Spurlock2bb02ec2015-03-02 13:13:06 -05002092 if (value == 0) {
John Spurlocka48d7792015-03-03 17:35:57 -05002093 vss.setIndex(10, device, TAG);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002094 }
2095 }
Eric Laurent9e0d25f2015-02-12 17:28:53 -08002096 // Persist volume for stream ring when it is changed here
2097 final int device = getDeviceForStream(streamType);
2098 sendMsg(mAudioHandler,
2099 MSG_PERSIST_VOLUME,
2100 SENDMSG_QUEUE,
2101 device,
2102 0,
2103 mStreamStates[streamType],
2104 PERSIST_DELAY);
Eric Laurentb024c302011-10-14 17:19:27 -07002105 }
Eric Laurent9bcf4012009-06-12 06:09:28 -07002106 }
RoboErik4197cb62015-01-21 15:45:32 -08002107 mStreamStates[streamType].mute(false);
John Spurlock661f2cf2014-11-17 10:29:10 -05002108 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent5b4e6542010-03-19 20:02:21 -07002109 } else {
John Spurlock661f2cf2014-11-17 10:29:10 -05002110 // mute
RoboErik4197cb62015-01-21 15:45:32 -08002111 mStreamStates[streamType].mute(true);
John Spurlock661f2cf2014-11-17 10:29:10 -05002112 mRingerModeMutedStreams |= (1 << streamType);
Jason Parekhb1096152009-03-24 17:48:25 -07002113 }
2114 }
John Spurlock50ced3f2015-05-11 16:00:09 -04002115 }
2116
2117 private void setRingerModeInt(int ringerMode, boolean persist) {
2118 final boolean change;
2119 synchronized(mSettingsLock) {
2120 change = mRingerMode != ringerMode;
2121 mRingerMode = ringerMode;
2122 }
2123
2124 muteRingerModeStreams();
Eric Laurenta553c252009-07-17 12:17:14 -07002125
Jason Parekhb1096152009-03-24 17:48:25 -07002126 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07002127 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002128 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07002129 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
2130 }
John Spurlockbcc10872014-11-28 15:29:21 -05002131 if (change) {
2132 // Send sticky broadcast
2133 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
2134 }
Jason Parekhb1096152009-03-24 17:48:25 -07002135 }
2136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002137 /** @see AudioManager#shouldVibrate(int) */
2138 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002139 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002140
2141 switch (getVibrateSetting(vibrateType)) {
2142
2143 case AudioManager.VIBRATE_SETTING_ON:
John Spurlock57627792014-12-11 11:29:54 -05002144 return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002145
2146 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
John Spurlock57627792014-12-11 11:29:54 -05002147 return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002148
2149 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04002150 // return false, even for incoming calls
2151 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002152
2153 default:
2154 return false;
2155 }
2156 }
2157
2158 /** @see AudioManager#getVibrateSetting(int) */
2159 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002160 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002161 return (mVibrateSetting >> (vibrateType * 2)) & 3;
2162 }
2163
2164 /** @see AudioManager#setVibrateSetting(int, int) */
2165 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
2166
Eric Laurentbffc3d12012-05-07 17:43:49 -07002167 if (!mHasVibrator) return;
2168
John Spurlock61560172015-02-06 19:46:04 -05002169 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
2170 vibrateSetting);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002171
2172 // Broadcast change
2173 broadcastVibrateSetting(vibrateType);
2174
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002175 }
2176
Eric Laurent9272b4b2010-01-23 17:12:59 -08002177 private class SetModeDeathHandler implements IBinder.DeathRecipient {
2178 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002179 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002180 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
2181
Eric Laurent9f103de2011-09-08 15:04:23 -07002182 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08002183 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07002184 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002185 }
2186
2187 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07002188 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002189 synchronized(mSetModeDeathHandlers) {
2190 Log.w(TAG, "setMode() client died");
2191 int index = mSetModeDeathHandlers.indexOf(this);
2192 if (index < 0) {
2193 Log.w(TAG, "unregistered setMode() client died");
2194 } else {
John Spurlock90874332015-03-10 16:00:54 -04002195 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid, TAG);
Eric Laurent9272b4b2010-01-23 17:12:59 -08002196 }
2197 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002198 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2199 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002200 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07002201 final long ident = Binder.clearCallingIdentity();
2202 disconnectBluetoothSco(newModeOwnerPid);
2203 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07002204 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08002205 }
2206
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002207 public int getPid() {
2208 return mPid;
2209 }
2210
Eric Laurent9272b4b2010-01-23 17:12:59 -08002211 public void setMode(int mode) {
2212 mMode = mode;
2213 }
2214
2215 public int getMode() {
2216 return mMode;
2217 }
2218
2219 public IBinder getBinder() {
2220 return mCb;
2221 }
2222 }
2223
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002224 /** @see AudioManager#setMode(int) */
John Spurlock90874332015-03-10 16:00:54 -04002225 public void setMode(int mode, IBinder cb, String callingPackage) {
2226 if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ", callingPackage=" + callingPackage + ")"); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002227 if (!checkAudioSettingsPermission("setMode()")) {
2228 return;
2229 }
Eric Laurenta553c252009-07-17 12:17:14 -07002230
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07002231 if ( (mode == AudioSystem.MODE_IN_CALL) &&
2232 (mContext.checkCallingOrSelfPermission(
2233 android.Manifest.permission.MODIFY_PHONE_STATE)
2234 != PackageManager.PERMISSION_GRANTED)) {
2235 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
2236 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
2237 return;
2238 }
2239
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08002240 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07002241 return;
2242 }
2243
Eric Laurentd7454be2011-09-14 08:45:58 -07002244 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002245 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07002246 if (mode == AudioSystem.MODE_CURRENT) {
2247 mode = mMode;
2248 }
John Spurlock90874332015-03-10 16:00:54 -04002249 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid(), callingPackage);
Eric Laurent9f103de2011-09-08 15:04:23 -07002250 }
2251 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2252 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002253 if (newModeOwnerPid != 0) {
2254 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07002255 }
2256 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002257
Eric Laurent9f103de2011-09-08 15:04:23 -07002258 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07002259 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07002260 // any mode other than NORMAL.
John Spurlock90874332015-03-10 16:00:54 -04002261 private int setModeInt(int mode, IBinder cb, int pid, String caller) {
2262 if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ", caller="
2263 + caller + ")"); }
Eric Laurentd7454be2011-09-14 08:45:58 -07002264 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002265 if (cb == null) {
2266 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07002267 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07002268 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002269
Eric Laurent9f103de2011-09-08 15:04:23 -07002270 SetModeDeathHandler hdlr = null;
2271 Iterator iter = mSetModeDeathHandlers.iterator();
2272 while (iter.hasNext()) {
2273 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
2274 if (h.getPid() == pid) {
2275 hdlr = h;
2276 // Remove from client list so that it is re-inserted at top of list
2277 iter.remove();
2278 hdlr.getBinder().unlinkToDeath(hdlr, 0);
2279 break;
2280 }
2281 }
2282 int status = AudioSystem.AUDIO_STATUS_OK;
2283 do {
2284 if (mode == AudioSystem.MODE_NORMAL) {
2285 // get new mode from client at top the list if any
2286 if (!mSetModeDeathHandlers.isEmpty()) {
2287 hdlr = mSetModeDeathHandlers.get(0);
2288 cb = hdlr.getBinder();
2289 mode = hdlr.getMode();
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002290 if (DEBUG_MODE) {
2291 Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
2292 + hdlr.mPid);
2293 }
Eric Laurentb9c9d262009-05-06 08:13:20 -07002294 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002295 } else {
2296 if (hdlr == null) {
2297 hdlr = new SetModeDeathHandler(cb, pid);
2298 }
2299 // Register for client death notification
2300 try {
2301 cb.linkToDeath(hdlr, 0);
2302 } catch (RemoteException e) {
2303 // Client has died!
2304 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
2305 }
2306
2307 // Last client to call setMode() is always at top of client list
2308 // as required by SetModeDeathHandler.binderDied()
2309 mSetModeDeathHandlers.add(0, hdlr);
2310 hdlr.setMode(mode);
2311 }
2312
2313 if (mode != mMode) {
2314 status = AudioSystem.setPhoneState(mode);
2315 if (status == AudioSystem.AUDIO_STATUS_OK) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002316 if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002317 mMode = mode;
2318 } else {
2319 if (hdlr != null) {
2320 mSetModeDeathHandlers.remove(hdlr);
2321 cb.unlinkToDeath(hdlr, 0);
2322 }
2323 // force reading new top of mSetModeDeathHandlers stack
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002324 if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002325 mode = AudioSystem.MODE_NORMAL;
2326 }
2327 } else {
2328 status = AudioSystem.AUDIO_STATUS_OK;
2329 }
2330 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
2331
2332 if (status == AudioSystem.AUDIO_STATUS_OK) {
2333 if (mode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002334 if (mSetModeDeathHandlers.isEmpty()) {
2335 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
2336 } else {
2337 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2338 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002339 }
2340 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002341 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07002342 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
John Spurlock90874332015-03-10 16:00:54 -04002343 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, caller);
Eric Laurent6d517662012-04-23 18:42:39 -07002344
John Spurlock90874332015-03-10 16:00:54 -04002345 updateStreamVolumeAlias(true /*updateVolumes*/, caller);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002346 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002347 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002348 }
2349
2350 /** @see AudioManager#getMode() */
2351 public int getMode() {
2352 return mMode;
2353 }
2354
Eric Laurente78fced2013-03-15 16:03:47 -07002355 //==========================================================================================
2356 // Sound Effects
2357 //==========================================================================================
2358
2359 private static final String TAG_AUDIO_ASSETS = "audio_assets";
2360 private static final String ATTR_VERSION = "version";
2361 private static final String TAG_GROUP = "group";
2362 private static final String ATTR_GROUP_NAME = "name";
2363 private static final String TAG_ASSET = "asset";
2364 private static final String ATTR_ASSET_ID = "id";
2365 private static final String ATTR_ASSET_FILE = "file";
2366
2367 private static final String ASSET_FILE_VERSION = "1.0";
2368 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
2369
Glenn Kasten167d1a22013-07-23 16:24:41 -07002370 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002371
2372 class LoadSoundEffectReply {
2373 public int mStatus = 1;
2374 };
2375
Eric Laurente78fced2013-03-15 16:03:47 -07002376 private void loadTouchSoundAssetDefaults() {
2377 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
2378 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
2379 SOUND_EFFECT_FILES_MAP[i][0] = 0;
2380 SOUND_EFFECT_FILES_MAP[i][1] = -1;
2381 }
2382 }
2383
2384 private void loadTouchSoundAssets() {
2385 XmlResourceParser parser = null;
2386
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002387 // only load assets once.
2388 if (!SOUND_EFFECT_FILES.isEmpty()) {
2389 return;
2390 }
2391
Eric Laurente78fced2013-03-15 16:03:47 -07002392 loadTouchSoundAssetDefaults();
2393
2394 try {
2395 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
2396
2397 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
2398 String version = parser.getAttributeValue(null, ATTR_VERSION);
2399 boolean inTouchSoundsGroup = false;
2400
2401 if (ASSET_FILE_VERSION.equals(version)) {
2402 while (true) {
2403 XmlUtils.nextElement(parser);
2404 String element = parser.getName();
2405 if (element == null) {
2406 break;
2407 }
2408 if (element.equals(TAG_GROUP)) {
2409 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
2410 if (GROUP_TOUCH_SOUNDS.equals(name)) {
2411 inTouchSoundsGroup = true;
2412 break;
2413 }
2414 }
2415 }
2416 while (inTouchSoundsGroup) {
2417 XmlUtils.nextElement(parser);
2418 String element = parser.getName();
2419 if (element == null) {
2420 break;
2421 }
2422 if (element.equals(TAG_ASSET)) {
2423 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
2424 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
2425 int fx;
2426
2427 try {
2428 Field field = AudioManager.class.getField(id);
2429 fx = field.getInt(null);
2430 } catch (Exception e) {
2431 Log.w(TAG, "Invalid touch sound ID: "+id);
2432 continue;
2433 }
2434
2435 int i = SOUND_EFFECT_FILES.indexOf(file);
2436 if (i == -1) {
2437 i = SOUND_EFFECT_FILES.size();
2438 SOUND_EFFECT_FILES.add(file);
2439 }
2440 SOUND_EFFECT_FILES_MAP[fx][0] = i;
2441 } else {
2442 break;
2443 }
2444 }
2445 }
2446 } catch (Resources.NotFoundException e) {
2447 Log.w(TAG, "audio assets file not found", e);
2448 } catch (XmlPullParserException e) {
2449 Log.w(TAG, "XML parser exception reading touch sound assets", e);
2450 } catch (IOException e) {
2451 Log.w(TAG, "I/O exception reading touch sound assets", e);
2452 } finally {
2453 if (parser != null) {
2454 parser.close();
2455 }
2456 }
2457 }
2458
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002459 /** @see AudioManager#playSoundEffect(int) */
2460 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002461 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002462 }
2463
2464 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002465 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07002466 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
2467 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
2468 return;
2469 }
2470
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002471 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002472 effectType, (int) (volume * 1000), null, 0);
2473 }
2474
2475 /**
2476 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08002477 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002478 */
2479 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002480 int attempts = 3;
2481 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08002482
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002483 synchronized (reply) {
2484 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
2485 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08002486 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07002487 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002488 } catch (InterruptedException e) {
2489 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08002490 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002491 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002492 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002493 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002494 }
2495
2496 /**
2497 * Unloads samples from the sound pool.
2498 * This method can be called to free some memory when
2499 * sound effects are disabled.
2500 */
2501 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002502 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002503 }
2504
Eric Laurenta60e2122010-12-28 16:49:07 -08002505 class SoundPoolListenerThread extends Thread {
2506 public SoundPoolListenerThread() {
2507 super("SoundPoolListenerThread");
2508 }
2509
2510 @Override
2511 public void run() {
2512
2513 Looper.prepare();
2514 mSoundPoolLooper = Looper.myLooper();
2515
2516 synchronized (mSoundEffectsLock) {
2517 if (mSoundPool != null) {
2518 mSoundPoolCallBack = new SoundPoolCallback();
2519 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2520 }
2521 mSoundEffectsLock.notify();
2522 }
2523 Looper.loop();
2524 }
2525 }
2526
2527 private final class SoundPoolCallback implements
2528 android.media.SoundPool.OnLoadCompleteListener {
2529
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002530 int mStatus = 1; // 1 means neither error nor last sample loaded yet
2531 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08002532
2533 public int status() {
2534 return mStatus;
2535 }
2536
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002537 public void setSamples(int[] samples) {
2538 for (int i = 0; i < samples.length; i++) {
2539 // do not wait ack for samples rejected upfront by SoundPool
2540 if (samples[i] > 0) {
2541 mSamples.add(samples[i]);
2542 }
2543 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002544 }
2545
2546 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2547 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002548 int i = mSamples.indexOf(sampleId);
2549 if (i >= 0) {
2550 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08002551 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002552 if ((status != 0) || mSamples. isEmpty()) {
2553 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08002554 mSoundEffectsLock.notify();
2555 }
2556 }
2557 }
2558 }
2559
Eric Laurent4050c932009-07-08 02:52:14 -07002560 /** @see AudioManager#reloadAudioSettings() */
2561 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002562 readAudioSettings(false /*userSwitch*/);
2563 }
2564
2565 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07002566 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2567 readPersistedSettings();
2568
2569 // restore volume settings
2570 int numStreamTypes = AudioSystem.getNumStreamTypes();
2571 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2572 VolumeStreamState streamState = mStreamStates[streamType];
2573
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002574 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2575 continue;
2576 }
2577
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002578 streamState.readSettings();
2579 synchronized (VolumeStreamState.class) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002580 // unmute stream that was muted but is not affect by mute anymore
RoboErik4197cb62015-01-21 15:45:32 -08002581 if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07002582 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
RoboErik4197cb62015-01-21 15:45:32 -08002583 streamState.mIsMuted = false;
Eric Laurent4050c932009-07-08 02:52:14 -07002584 }
Eric Laurent4050c932009-07-08 02:52:14 -07002585 }
2586 }
2587
Eric Laurent33902db2012-10-07 16:15:07 -07002588 // apply new ringer mode before checking volume for alias streams so that streams
2589 // muted by ringer mode have the correct volume
John Spurlock661f2cf2014-11-17 10:29:10 -05002590 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent33902db2012-10-07 16:15:07 -07002591
Eric Laurent212532b2014-07-21 15:43:18 -07002592 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07002593 checkAllAliasStreamVolumes();
John Spurlockb6e19e32015-03-10 21:33:44 -04002594 checkMuteAffectedStreams();
Eric Laurent24482012012-05-10 09:41:17 -07002595
Eric Laurentd640bd32012-09-28 18:01:48 -07002596 synchronized (mSafeMediaVolumeState) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002597 mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2598 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2599 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
Eric Laurentd640bd32012-09-28 18:01:48 -07002600 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
John Spurlock90874332015-03-10 16:00:54 -04002601 enforceSafeMediaVolume(TAG);
Eric Laurentf1a457d2012-09-20 16:27:23 -07002602 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07002603 }
Eric Laurent4050c932009-07-08 02:52:14 -07002604 }
2605
Dianne Hackborn961cae92013-03-20 14:59:43 -07002606 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002607 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002608 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2609 return;
2610 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002611
2612 if (on) {
2613 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2614 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2615 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
2616 }
2617 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2618 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2619 mForcedUseForComm = AudioSystem.FORCE_NONE;
2620 }
Eric Laurentfa640152011-03-12 15:59:51 -08002621
Eric Laurentafbb0472011-12-15 09:04:23 -08002622 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002623 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002624 }
2625
2626 /** @see AudioManager#isSpeakerphoneOn() */
2627 public boolean isSpeakerphoneOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002628 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002629 }
2630
Dianne Hackborn961cae92013-03-20 14:59:43 -07002631 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurent48221252015-09-24 18:41:48 -07002632 public void setBluetoothScoOn(boolean on) {
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002633 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2634 return;
2635 }
Eric Laurent48221252015-09-24 18:41:48 -07002636 setBluetoothScoOnInt(on);
2637 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002638
Eric Laurent48221252015-09-24 18:41:48 -07002639 public void setBluetoothScoOnInt(boolean on) {
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002640 if (on) {
2641 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2642 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2643 mForcedUseForComm = AudioSystem.FORCE_NONE;
2644 }
Eric Laurentfa640152011-03-12 15:59:51 -08002645
Eric Laurentafbb0472011-12-15 09:04:23 -08002646 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002647 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08002648 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002649 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002650 }
2651
2652 /** @see AudioManager#isBluetoothScoOn() */
2653 public boolean isBluetoothScoOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002654 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002655 }
2656
Dianne Hackborn961cae92013-03-20 14:59:43 -07002657 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07002658 public void setBluetoothA2dpOn(boolean on) {
Eric Laurentc390bed2012-07-03 12:24:05 -07002659 synchronized (mBluetoothA2dpEnabledLock) {
2660 mBluetoothA2dpEnabled = on;
2661 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2662 AudioSystem.FOR_MEDIA,
2663 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2664 null, 0);
2665 }
Eric Laurent78472112012-05-21 08:57:21 -07002666 }
2667
2668 /** @see AudioManager#isBluetoothA2dpOn() */
2669 public boolean isBluetoothA2dpOn() {
2670 synchronized (mBluetoothA2dpEnabledLock) {
2671 return mBluetoothA2dpEnabled;
2672 }
2673 }
2674
Eric Laurent3def1ee2010-03-17 23:26:26 -07002675 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07002676 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
2677 int scoAudioMode =
2678 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
Liejun Taof4e51d82014-07-16 11:18:29 -07002679 SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
Eric Laurent83900752014-05-15 15:14:22 -07002680 startBluetoothScoInt(cb, scoAudioMode);
2681 }
2682
2683 /** @see AudioManager#startBluetoothScoVirtualCall() */
2684 public void startBluetoothScoVirtualCall(IBinder cb) {
2685 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
2686 }
2687
2688 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07002689 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002690 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002691 return;
2692 }
Eric Laurent854938a2011-02-22 12:05:20 -08002693 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002694 // The calling identity must be cleared before calling ScoClient.incCount().
2695 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2696 // and this must be done on behalf of system server to make sure permissions are granted.
2697 // The caller identity must be cleared after getScoClient() because it is needed if a new
2698 // client is created.
2699 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07002700 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08002701 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002702 }
2703
2704 /** @see AudioManager#stopBluetoothSco() */
2705 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07002706 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002707 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002708 return;
2709 }
Eric Laurent854938a2011-02-22 12:05:20 -08002710 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002711 // The calling identity must be cleared before calling ScoClient.decCount().
2712 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2713 // and this must be done on behalf of system server to make sure permissions are granted.
2714 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08002715 if (client != null) {
2716 client.decCount();
2717 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08002718 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002719 }
2720
Eric Laurent78472112012-05-21 08:57:21 -07002721
Eric Laurent3def1ee2010-03-17 23:26:26 -07002722 private class ScoClient implements IBinder.DeathRecipient {
2723 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002724 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002725 private int mStartcount; // number of SCO connections started by this client
2726
2727 ScoClient(IBinder cb) {
2728 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002729 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002730 mStartcount = 0;
2731 }
2732
2733 public void binderDied() {
2734 synchronized(mScoClients) {
2735 Log.w(TAG, "SCO client died");
2736 int index = mScoClients.indexOf(this);
2737 if (index < 0) {
2738 Log.w(TAG, "unregistered SCO client died");
2739 } else {
2740 clearCount(true);
2741 mScoClients.remove(this);
2742 }
2743 }
2744 }
2745
Eric Laurent83900752014-05-15 15:14:22 -07002746 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002747 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07002748 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002749 if (mStartcount == 0) {
2750 try {
2751 mCb.linkToDeath(this, 0);
2752 } catch (RemoteException e) {
2753 // client has already died!
2754 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
2755 }
2756 }
2757 mStartcount++;
2758 }
2759 }
2760
2761 public void decCount() {
2762 synchronized(mScoClients) {
2763 if (mStartcount == 0) {
2764 Log.w(TAG, "ScoClient.decCount() already 0");
2765 } else {
2766 mStartcount--;
2767 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002768 try {
2769 mCb.unlinkToDeath(this, 0);
2770 } catch (NoSuchElementException e) {
2771 Log.w(TAG, "decCount() going to 0 but not registered to binder");
2772 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002773 }
Eric Laurentc18c9132013-04-12 17:24:56 -07002774 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002775 }
2776 }
2777 }
2778
2779 public void clearCount(boolean stopSco) {
2780 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002781 if (mStartcount != 0) {
2782 try {
2783 mCb.unlinkToDeath(this, 0);
2784 } catch (NoSuchElementException e) {
2785 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2786 }
2787 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002788 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002789 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002790 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002791 }
2792 }
2793 }
2794
2795 public int getCount() {
2796 return mStartcount;
2797 }
2798
2799 public IBinder getBinder() {
2800 return mCb;
2801 }
2802
Eric Laurentd7454be2011-09-14 08:45:58 -07002803 public int getPid() {
2804 return mCreatorPid;
2805 }
2806
Eric Laurent3def1ee2010-03-17 23:26:26 -07002807 public int totalCount() {
2808 synchronized(mScoClients) {
2809 int count = 0;
2810 int size = mScoClients.size();
2811 for (int i = 0; i < size; i++) {
2812 count += mScoClients.get(i).getCount();
2813 }
2814 return count;
2815 }
2816 }
2817
Eric Laurent83900752014-05-15 15:14:22 -07002818 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08002819 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07002820 if (totalCount() == 0) {
2821 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2822 // Make sure that the state transitions to CONNECTING even if we cannot initiate
2823 // the connection.
2824 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2825 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002826 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07002827 synchronized(mSetModeDeathHandlers) {
2828 if ((mSetModeDeathHandlers.isEmpty() ||
2829 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2830 (mScoAudioState == SCO_STATE_INACTIVE ||
2831 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2832 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07002833 mScoAudioMode = scoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -07002834 if (scoAudioMode == SCO_MODE_UNDEFINED) {
Andre Eisenbach570cc532014-10-28 17:03:18 -07002835 if (mBluetoothHeadsetDevice != null) {
2836 mScoAudioMode = new Integer(Settings.Global.getInt(
2837 mContentResolver,
2838 "bluetooth_sco_channel_"+
2839 mBluetoothHeadsetDevice.getAddress(),
2840 SCO_MODE_VIRTUAL_CALL));
2841 if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2842 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2843 }
2844 } else {
2845 mScoAudioMode = SCO_MODE_RAW;
Liejun Taof4e51d82014-07-16 11:18:29 -07002846 }
2847 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002848 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002849 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002850 if (mScoAudioMode == SCO_MODE_RAW) {
2851 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002852 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002853 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2854 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002855 } else if (mScoAudioMode == SCO_MODE_VR) {
2856 status = mBluetoothHeadset.startVoiceRecognition(
2857 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002858 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002859
Eric Laurentc18c9132013-04-12 17:24:56 -07002860 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07002861 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2862 } else {
2863 broadcastScoConnectionState(
2864 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2865 }
2866 } else if (getBluetoothHeadset()) {
2867 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07002868 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002869 } else {
2870 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2871 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002872 }
2873 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07002874 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002875 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002876 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002877 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002878 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2879 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2880 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07002881 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002882 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002883 if (mScoAudioMode == SCO_MODE_RAW) {
2884 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002885 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002886 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2887 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002888 } else if (mScoAudioMode == SCO_MODE_VR) {
2889 status = mBluetoothHeadset.stopVoiceRecognition(
2890 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002891 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002892
Eric Laurentc18c9132013-04-12 17:24:56 -07002893 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002894 mScoAudioState = SCO_STATE_INACTIVE;
2895 broadcastScoConnectionState(
2896 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2897 }
2898 } else if (getBluetoothHeadset()) {
2899 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2900 }
2901 } else {
2902 mScoAudioState = SCO_STATE_INACTIVE;
2903 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2904 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002905 }
2906 }
2907 }
2908 }
2909
Eric Laurent62ef7672010-11-24 10:58:32 -08002910 private void checkScoAudioState() {
2911 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002912 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08002913 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2914 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2915 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2916 }
2917 }
2918
Eric Laurent854938a2011-02-22 12:05:20 -08002919 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002920 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002921 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002922 int size = mScoClients.size();
2923 for (int i = 0; i < size; i++) {
2924 client = mScoClients.get(i);
2925 if (client.getBinder() == cb)
2926 return client;
2927 }
Eric Laurent854938a2011-02-22 12:05:20 -08002928 if (create) {
2929 client = new ScoClient(cb);
2930 mScoClients.add(client);
2931 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002932 return client;
2933 }
2934 }
2935
Eric Laurentd7454be2011-09-14 08:45:58 -07002936 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002937 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002938 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002939 int size = mScoClients.size();
2940 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08002941 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07002942 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08002943 cl.clearCount(stopSco);
2944 } else {
2945 savedClient = cl;
2946 }
2947 }
2948 mScoClients.clear();
2949 if (savedClient != null) {
2950 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002951 }
2952 }
2953 }
2954
Eric Laurentdc03c612011-04-01 10:59:41 -07002955 private boolean getBluetoothHeadset() {
2956 boolean result = false;
2957 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2958 if (adapter != null) {
2959 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2960 BluetoothProfile.HEADSET);
2961 }
2962 // If we could not get a bluetooth headset proxy, send a failure message
2963 // without delay to reset the SCO audio state and clear SCO clients.
2964 // If we could get a proxy, send a delayed failure message that will reset our state
2965 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08002966 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002967 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2968 return result;
2969 }
2970
Eric Laurentd7454be2011-09-14 08:45:58 -07002971 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002972 synchronized(mScoClients) {
2973 checkScoAudioState();
2974 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2975 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2976 if (mBluetoothHeadsetDevice != null) {
2977 if (mBluetoothHeadset != null) {
2978 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07002979 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002980 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002981 SENDMSG_REPLACE, 0, 0, null, 0);
2982 }
2983 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2984 getBluetoothHeadset()) {
2985 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2986 }
2987 }
2988 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07002989 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07002990 }
2991 }
2992 }
2993
2994 private void resetBluetoothSco() {
2995 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002996 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07002997 mScoAudioState = SCO_STATE_INACTIVE;
2998 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2999 }
Eric Laurent48221252015-09-24 18:41:48 -07003000 AudioSystem.setParameters("A2dpSuspended=false");
3001 setBluetoothScoOnInt(false);
Eric Laurentdc03c612011-04-01 10:59:41 -07003002 }
3003
3004 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08003005 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
3006 SENDMSG_QUEUE, state, 0, null, 0);
3007 }
3008
3009 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07003010 if (state != mScoConnectionState) {
3011 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
3012 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
3013 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
3014 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003015 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07003016 mScoConnectionState = state;
3017 }
3018 }
3019
Eric Laurent98859b22015-06-12 14:35:59 -07003020 void setBtScoDeviceConnectionState(BluetoothDevice btDevice, int state) {
3021 if (btDevice == null) {
3022 return;
3023 }
3024
3025 String address = btDevice.getAddress();
3026 BluetoothClass btClass = btDevice.getBluetoothClass();
3027 int outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
3028 int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
3029 if (btClass != null) {
3030 switch (btClass.getDeviceClass()) {
3031 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
3032 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
3033 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
3034 break;
3035 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
3036 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
3037 break;
3038 }
3039 }
3040
3041 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
3042 address = "";
3043 }
3044
3045 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
3046
3047 String btDeviceName = btDevice.getName();
3048 boolean success =
3049 handleDeviceConnection(connected, outDevice, address, btDeviceName) &&
3050 handleDeviceConnection(connected, inDevice, address, btDeviceName);
3051 if (success) {
3052 synchronized (mScoClients) {
3053 if (connected) {
3054 mBluetoothHeadsetDevice = btDevice;
3055 } else {
3056 mBluetoothHeadsetDevice = null;
3057 resetBluetoothSco();
3058 }
3059 }
3060 }
3061 }
3062
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07003063 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
3064 new BluetoothProfile.ServiceListener() {
3065 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003066 BluetoothDevice btDevice;
3067 List<BluetoothDevice> deviceList;
3068 switch(profile) {
3069 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09003070 synchronized (mConnectedDevices) {
3071 synchronized (mA2dpAvrcpLock) {
3072 mA2dp = (BluetoothA2dp) proxy;
3073 deviceList = mA2dp.getConnectedDevices();
3074 if (deviceList.size() > 0) {
3075 btDevice = deviceList.get(0);
John Du5a0cf7a2013-07-19 11:30:34 -07003076 int state = mA2dp.getConnectionState(btDevice);
3077 int delay = checkSendBecomingNoisyIntent(
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003078 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3079 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
John Du5a0cf7a2013-07-19 11:30:34 -07003080 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003081 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07003082 state,
3083 0,
3084 btDevice,
3085 delay);
3086 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003087 }
Eric Laurent62ef7672010-11-24 10:58:32 -08003088 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003089 break;
3090
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003091 case BluetoothProfile.A2DP_SINK:
3092 deviceList = proxy.getConnectedDevices();
3093 if (deviceList.size() > 0) {
3094 btDevice = deviceList.get(0);
3095 synchronized (mConnectedDevices) {
3096 int state = proxy.getConnectionState(btDevice);
3097 queueMsgUnderWakeLock(mAudioHandler,
3098 MSG_SET_A2DP_SRC_CONNECTION_STATE,
3099 state,
3100 0,
3101 btDevice,
3102 0 /* delay */);
3103 }
3104 }
3105 break;
3106
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003107 case BluetoothProfile.HEADSET:
3108 synchronized (mScoClients) {
3109 // Discard timeout message
3110 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
3111 mBluetoothHeadset = (BluetoothHeadset) proxy;
3112 deviceList = mBluetoothHeadset.getConnectedDevices();
3113 if (deviceList.size() > 0) {
3114 mBluetoothHeadsetDevice = deviceList.get(0);
3115 } else {
3116 mBluetoothHeadsetDevice = null;
3117 }
3118 // Refresh SCO audio state
3119 checkScoAudioState();
3120 // Continue pending action if any
3121 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
3122 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
3123 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
3124 boolean status = false;
3125 if (mBluetoothHeadsetDevice != null) {
3126 switch (mScoAudioState) {
3127 case SCO_STATE_ACTIVATE_REQ:
3128 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07003129 if (mScoAudioMode == SCO_MODE_RAW) {
3130 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003131 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003132 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
3133 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003134 } else if (mScoAudioMode == SCO_MODE_VR) {
3135 status = mBluetoothHeadset.startVoiceRecognition(
3136 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003137 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003138 break;
3139 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07003140 if (mScoAudioMode == SCO_MODE_RAW) {
3141 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003142 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003143 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
3144 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003145 } else if (mScoAudioMode == SCO_MODE_VR) {
3146 status = mBluetoothHeadset.stopVoiceRecognition(
3147 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003148 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003149 break;
3150 case SCO_STATE_DEACTIVATE_EXT_REQ:
3151 status = mBluetoothHeadset.stopVoiceRecognition(
3152 mBluetoothHeadsetDevice);
3153 }
3154 }
3155 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08003156 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003157 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07003158 }
3159 }
Eric Laurentdc03c612011-04-01 10:59:41 -07003160 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003161 break;
3162
3163 default:
3164 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003165 }
3166 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07003167 public void onServiceDisconnected(int profile) {
Eric Laurentb70b78a2016-01-13 19:16:04 -08003168
Paul McLean394a8e12015-03-03 10:29:19 -07003169 switch (profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003170 case BluetoothProfile.A2DP:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003171 disconnectA2dp();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003172 break;
3173
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003174 case BluetoothProfile.A2DP_SINK:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003175 disconnectA2dpSink();
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003176 break;
3177
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003178 case BluetoothProfile.HEADSET:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003179 disconnectHeadset();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003180 break;
3181
3182 default:
3183 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003184 }
3185 }
3186 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003187
Eric Laurentb70b78a2016-01-13 19:16:04 -08003188 void disconnectAllBluetoothProfiles() {
3189 disconnectA2dp();
3190 disconnectA2dpSink();
3191 disconnectHeadset();
3192 }
3193
3194 void disconnectA2dp() {
3195 synchronized (mConnectedDevices) {
3196 synchronized (mA2dpAvrcpLock) {
3197 ArraySet<String> toRemove = null;
3198 // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
3199 for (int i = 0; i < mConnectedDevices.size(); i++) {
3200 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
3201 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
3202 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
3203 toRemove.add(deviceSpec.mDeviceAddress);
3204 }
3205 }
3206 if (toRemove != null) {
3207 int delay = checkSendBecomingNoisyIntent(
3208 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3209 0);
3210 for (int i = 0; i < toRemove.size(); i++) {
3211 makeA2dpDeviceUnavailableLater(toRemove.valueAt(i), delay);
3212 }
3213 }
3214 }
3215 }
3216 }
3217
3218 void disconnectA2dpSink() {
3219 synchronized (mConnectedDevices) {
3220 ArraySet<String> toRemove = null;
3221 // Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
3222 for(int i = 0; i < mConnectedDevices.size(); i++) {
3223 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
3224 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) {
3225 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
3226 toRemove.add(deviceSpec.mDeviceAddress);
3227 }
3228 }
3229 if (toRemove != null) {
3230 for (int i = 0; i < toRemove.size(); i++) {
3231 makeA2dpSrcUnavailable(toRemove.valueAt(i));
3232 }
3233 }
3234 }
3235 }
3236
3237 void disconnectHeadset() {
3238 synchronized (mScoClients) {
3239 if (mBluetoothHeadsetDevice != null) {
3240 setBtScoDeviceConnectionState(mBluetoothHeadsetDevice,
3241 BluetoothProfile.STATE_DISCONNECTED);
3242 }
3243 mBluetoothHeadset = null;
3244 }
3245 }
3246
John Spurlock90874332015-03-10 16:00:54 -04003247 private void onCheckMusicActive(String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07003248 synchronized (mSafeMediaVolumeState) {
3249 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07003250 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
3251
3252 if ((device & mSafeMediaVolumeDevices) != 0) {
3253 sendMsg(mAudioHandler,
3254 MSG_CHECK_MUSIC_ACTIVE,
3255 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07003256 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07003257 0,
John Spurlock90874332015-03-10 16:00:54 -04003258 caller,
Eric Laurentc34dcc12012-09-10 13:51:52 -07003259 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07003260 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07003261 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
3262 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07003263 // Approximate cumulative active music time
3264 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
3265 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
John Spurlock90874332015-03-10 16:00:54 -04003266 setSafeMediaVolumeEnabled(true, caller);
Eric Laurentc34dcc12012-09-10 13:51:52 -07003267 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07003268 }
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003269 saveMusicActiveMs();
Eric Laurentc34dcc12012-09-10 13:51:52 -07003270 }
3271 }
3272 }
3273 }
3274 }
3275
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003276 private void saveMusicActiveMs() {
3277 mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
3278 }
3279
John Spurlock90874332015-03-10 16:00:54 -04003280 private void onConfigureSafeVolume(boolean force, String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07003281 synchronized (mSafeMediaVolumeState) {
3282 int mcc = mContext.getResources().getConfiguration().mcc;
3283 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
3284 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
3285 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
John Spurlock35134602014-07-24 18:10:48 -04003286 boolean safeMediaVolumeEnabled =
3287 SystemProperties.getBoolean("audio.safemedia.force", false)
3288 || mContext.getResources().getBoolean(
3289 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08003290
Ricardo Garcia3a30a762015-06-23 15:54:45 -07003291 boolean safeMediaVolumeBypass =
3292 SystemProperties.getBoolean("audio.safemedia.bypass", false);
3293
Eric Laurent05274f32012-11-29 12:48:18 -08003294 // The persisted state is either "disabled" or "active": this is the state applied
3295 // next time we boot and cannot be "inactive"
3296 int persistedState;
Ricardo Garcia3a30a762015-06-23 15:54:45 -07003297 if (safeMediaVolumeEnabled && !safeMediaVolumeBypass) {
Eric Laurent05274f32012-11-29 12:48:18 -08003298 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
3299 // The state can already be "inactive" here if the user has forced it before
3300 // the 30 seconds timeout for forced configuration. In this case we don't reset
3301 // it to "active".
3302 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003303 if (mMusicActiveMs == 0) {
3304 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
John Spurlock90874332015-03-10 16:00:54 -04003305 enforceSafeMediaVolume(caller);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003306 } else {
3307 // We have existing playback time recorded, already confirmed.
3308 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
3309 }
Eric Laurent05274f32012-11-29 12:48:18 -08003310 }
Eric Laurentd640bd32012-09-28 18:01:48 -07003311 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08003312 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07003313 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
3314 }
3315 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08003316 sendMsg(mAudioHandler,
3317 MSG_PERSIST_SAFE_VOLUME_STATE,
3318 SENDMSG_QUEUE,
3319 persistedState,
3320 0,
3321 null,
3322 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07003323 }
3324 }
3325 }
3326
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003327 ///////////////////////////////////////////////////////////////////////////
3328 // Internal methods
3329 ///////////////////////////////////////////////////////////////////////////
3330
3331 /**
3332 * Checks if the adjustment should change ringer mode instead of just
3333 * adjusting volume. If so, this will set the proper ringer mode and volume
3334 * indices on the stream states.
3335 */
John Spurlocka48d7792015-03-03 17:35:57 -05003336 private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted) {
3337 final boolean isTv = mPlatformType == AudioSystem.PLATFORM_TELEVISION;
John Spurlocka11b4af2014-06-01 11:52:23 -04003338 int result = FLAG_ADJUST_VOLUME;
John Spurlock661f2cf2014-11-17 10:29:10 -05003339 int ringerMode = getRingerModeInternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003340
Eric Laurentbffc3d12012-05-07 17:43:49 -07003341 switch (ringerMode) {
3342 case RINGER_MODE_NORMAL:
3343 if (direction == AudioManager.ADJUST_LOWER) {
3344 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07003345 // "step" is the delta in internal index units corresponding to a
3346 // change of 1 in UI index units.
3347 // Because of rounding when rescaling from one stream index range to its alias
3348 // index range, we cannot simply test oldIndex == step:
3349 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
3350 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003351 ringerMode = RINGER_MODE_VIBRATE;
John Spurlock07e72432015-03-13 11:46:52 -04003352 mLoweredFromNormalToVibrateTime = SystemClock.uptimeMillis();
Eric Laurentbffc3d12012-05-07 17:43:49 -07003353 }
3354 } else {
John Spurlockd9c75db2015-04-28 11:19:13 -04003355 if (oldIndex == step && mVolumePolicy.volumeDownToEnterSilent) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003356 ringerMode = RINGER_MODE_SILENT;
3357 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07003358 }
John Spurlocka48d7792015-03-03 17:35:57 -05003359 } else if (isTv && (direction == AudioManager.ADJUST_TOGGLE_MUTE
3360 || direction == AudioManager.ADJUST_MUTE)) {
RoboErik5452e252015-02-06 15:33:53 -08003361 if (mHasVibrator) {
3362 ringerMode = RINGER_MODE_VIBRATE;
3363 } else {
3364 ringerMode = RINGER_MODE_SILENT;
3365 }
3366 // Setting the ringer mode will toggle mute
3367 result &= ~FLAG_ADJUST_VOLUME;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003368 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003369 break;
3370 case RINGER_MODE_VIBRATE:
3371 if (!mHasVibrator) {
3372 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
3373 "but no vibrator is present");
3374 break;
3375 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003376 if ((direction == AudioManager.ADJUST_LOWER)) {
RoboErik5452e252015-02-06 15:33:53 -08003377 // This is the case we were muted with the volume turned up
John Spurlocka48d7792015-03-03 17:35:57 -05003378 if (isTv && oldIndex >= 2 * step && isMuted) {
RoboErik5452e252015-02-06 15:33:53 -08003379 ringerMode = RINGER_MODE_NORMAL;
3380 } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
John Spurlocka48d7792015-03-03 17:35:57 -05003381 if (mVolumePolicy.volumeDownToEnterSilent) {
John Spurlock07e72432015-03-13 11:46:52 -04003382 final long diff = SystemClock.uptimeMillis()
3383 - mLoweredFromNormalToVibrateTime;
John Spurlockd9c75db2015-04-28 11:19:13 -04003384 if (diff > mVolumePolicy.vibrateToSilentDebounce
3385 && mRingerModeDelegate.canVolumeDownEnterSilent()) {
John Spurlock07e72432015-03-13 11:46:52 -04003386 ringerMode = RINGER_MODE_SILENT;
3387 }
John Spurlock795a5142014-12-08 14:09:35 -05003388 } else {
3389 result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
3390 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003391 }
RoboErik5452e252015-02-06 15:33:53 -08003392 } else if (direction == AudioManager.ADJUST_RAISE
3393 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3394 || direction == AudioManager.ADJUST_UNMUTE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003395 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07003396 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003397 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003398 break;
3399 case RINGER_MODE_SILENT:
John Spurlocka48d7792015-03-03 17:35:57 -05003400 if (isTv && direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
RoboErik5452e252015-02-06 15:33:53 -08003401 // This is the case we were muted with the volume turned up
3402 ringerMode = RINGER_MODE_NORMAL;
3403 } else if (direction == AudioManager.ADJUST_RAISE
3404 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3405 || direction == AudioManager.ADJUST_UNMUTE) {
John Spurlocka48d7792015-03-03 17:35:57 -05003406 if (!mVolumePolicy.volumeUpToExitSilent) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003407 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003408 } else {
RoboErik5452e252015-02-06 15:33:53 -08003409 if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003410 ringerMode = RINGER_MODE_VIBRATE;
3411 } else {
RoboErik5452e252015-02-06 15:33:53 -08003412 // If we don't have a vibrator or they were toggling mute
3413 // go straight back to normal.
John Spurlocka11b4af2014-06-01 11:52:23 -04003414 ringerMode = RINGER_MODE_NORMAL;
3415 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003416 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05003417 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003418 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003419 break;
3420 default:
3421 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
3422 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003423 }
3424
John Spurlock661f2cf2014-11-17 10:29:10 -05003425 setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003426
Eric Laurent25101b02011-02-02 09:33:30 -08003427 mPrevVolDirection = direction;
3428
John Spurlocka11b4af2014-06-01 11:52:23 -04003429 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003430 }
3431
John Spurlock3346a802014-05-20 16:25:37 -04003432 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003433 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07003434 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003435 }
3436
Eric Laurent5b4e6542010-03-19 20:02:21 -07003437 private boolean isStreamMutedByRingerMode(int streamType) {
3438 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
3439 }
3440
John Spurlock50ced3f2015-05-11 16:00:09 -04003441 private boolean updateRingerModeAffectedStreams() {
3442 int ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003443 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3444 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
3445 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
3446 UserHandle.USER_CURRENT);
3447
John Spurlock50ced3f2015-05-11 16:00:09 -04003448 if (mPlatformType == AudioSystem.PLATFORM_TELEVISION) {
3449 ringerModeAffectedStreams = 0;
3450 } else if (mRingerModeDelegate != null) {
3451 ringerModeAffectedStreams = mRingerModeDelegate
3452 .getRingerModeAffectedStreams(ringerModeAffectedStreams);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003453 }
3454 synchronized (mCameraSoundForced) {
3455 if (mCameraSoundForced) {
3456 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3457 } else {
3458 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3459 }
3460 }
3461 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
3462 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
3463 } else {
3464 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
3465 }
3466
3467 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3468 Settings.System.putIntForUser(mContentResolver,
3469 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3470 ringerModeAffectedStreams,
3471 UserHandle.USER_CURRENT);
3472 mRingerModeAffectedStreams = ringerModeAffectedStreams;
3473 return true;
3474 }
3475 return false;
3476 }
3477
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05003478 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003479 public boolean isStreamAffectedByMute(int streamType) {
3480 return (mMuteAffectedStreams & (1 << streamType)) != 0;
3481 }
3482
3483 private void ensureValidDirection(int direction) {
RoboErik4197cb62015-01-21 15:45:32 -08003484 switch (direction) {
3485 case AudioManager.ADJUST_LOWER:
3486 case AudioManager.ADJUST_RAISE:
3487 case AudioManager.ADJUST_SAME:
3488 case AudioManager.ADJUST_MUTE:
3489 case AudioManager.ADJUST_UNMUTE:
3490 case AudioManager.ADJUST_TOGGLE_MUTE:
3491 break;
3492 default:
3493 throw new IllegalArgumentException("Bad direction " + direction);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003494 }
3495 }
3496
3497 private void ensureValidStreamType(int streamType) {
3498 if (streamType < 0 || streamType >= mStreamStates.length) {
3499 throw new IllegalArgumentException("Bad stream type " + streamType);
3500 }
3501 }
3502
RoboErik4197cb62015-01-21 15:45:32 -08003503 private boolean isMuteAdjust(int adjust) {
3504 return adjust == AudioManager.ADJUST_MUTE || adjust == AudioManager.ADJUST_UNMUTE
3505 || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
3506 }
3507
Eric Laurent6d517662012-04-23 18:42:39 -07003508 private boolean isInCommunication() {
Nancy Chen0eb1e402014-08-21 22:52:29 -07003509 boolean IsInCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003510
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003511 TelecomManager telecomManager =
3512 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
Eric Laurent38edfda2014-12-18 17:38:04 -08003513
3514 final long ident = Binder.clearCallingIdentity();
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003515 IsInCall = telecomManager.isInCall();
Eric Laurent38edfda2014-12-18 17:38:04 -08003516 Binder.restoreCallingIdentity(ident);
Santos Cordon9eb45932014-06-27 12:28:43 -07003517
Nancy Chen0eb1e402014-08-21 22:52:29 -07003518 return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
Eric Laurent6d517662012-04-23 18:42:39 -07003519 }
Eric Laurent25101b02011-02-02 09:33:30 -08003520
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003521 /**
3522 * For code clarity for getActiveStreamType(int)
3523 * @param delay_ms max time since last STREAM_MUSIC activity to consider
3524 * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
3525 * in the last "delay_ms" ms.
3526 */
3527 private boolean isAfMusicActiveRecently(int delay_ms) {
3528 return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
3529 || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
3530 }
3531
Eric Laurent6d517662012-04-23 18:42:39 -07003532 private int getActiveStreamType(int suggestedStreamType) {
Eric Laurent212532b2014-07-21 15:43:18 -07003533 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003534 case AudioSystem.PLATFORM_VOICE:
Eric Laurent6d517662012-04-23 18:42:39 -07003535 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003536 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3537 == AudioSystem.FORCE_BT_SCO) {
3538 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
3539 return AudioSystem.STREAM_BLUETOOTH_SCO;
3540 } else {
3541 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
3542 return AudioSystem.STREAM_VOICE_CALL;
3543 }
Eric Laurent25101b02011-02-02 09:33:30 -08003544 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003545 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003546 if (DEBUG_VOL)
3547 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3548 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003549 } else {
3550 if (DEBUG_VOL)
3551 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
3552 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003553 }
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003554 } else if (isAfMusicActiveRecently(0)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003555 if (DEBUG_VOL)
3556 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3557 return AudioSystem.STREAM_MUSIC;
Eric Laurent25101b02011-02-02 09:33:30 -08003558 }
Eric Laurent212532b2014-07-21 15:43:18 -07003559 break;
John Spurlock61560172015-02-06 19:46:04 -05003560 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -07003561 if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
RoboErik2811dd32014-08-12 09:48:13 -07003562 // TV always defaults to STREAM_MUSIC
Eric Laurent212532b2014-07-21 15:43:18 -07003563 return AudioSystem.STREAM_MUSIC;
Eric Laurent212532b2014-07-21 15:43:18 -07003564 }
3565 break;
3566 default:
Eric Laurent6d517662012-04-23 18:42:39 -07003567 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003568 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3569 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003570 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08003571 return AudioSystem.STREAM_BLUETOOTH_SCO;
3572 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003573 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08003574 return AudioSystem.STREAM_VOICE_CALL;
3575 }
3576 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003577 StreamOverride.sDelayMs) ||
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003578 AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003579 StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003580 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08003581 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003582 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003583 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003584 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
3585 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003586 } else {
John Spurlockeb1d88d2014-07-19 14:49:19 -04003587 if (DEBUG_VOL) Log.v(TAG,
3588 "getActiveStreamType: using STREAM_NOTIFICATION as default");
3589 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003590 }
Joe Onoratoc7fcba42011-01-05 16:53:11 -08003591 }
Eric Laurent212532b2014-07-21 15:43:18 -07003592 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003593 }
Eric Laurent212532b2014-07-21 15:43:18 -07003594 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
3595 + suggestedStreamType);
3596 return suggestedStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003597 }
3598
John Spurlockbcc10872014-11-28 15:29:21 -05003599 private void broadcastRingerMode(String action, int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003600 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05003601 Intent broadcast = new Intent(action);
Glenn Kastenba195eb2011-12-13 09:30:40 -08003602 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003603 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
3604 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003605 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003606 }
3607
3608 private void broadcastVibrateSetting(int vibrateType) {
3609 // Send broadcast
3610 if (ActivityManagerNative.isSystemReady()) {
3611 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
3612 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
3613 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003614 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003615 }
3616 }
3617
3618 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003619 /**
3620 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
3621 * Note that the wake lock needs to be released after the message has been handled.
3622 */
3623 private void queueMsgUnderWakeLock(Handler handler, int msg,
3624 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003625 final long ident = Binder.clearCallingIdentity();
3626 // Always acquire the wake lock as AudioService because it is released by the
3627 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003628 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003629 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003630 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
3631 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003632
Eric Laurentafbb0472011-12-15 09:04:23 -08003633 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003634 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003635
3636 if (existingMsgPolicy == SENDMSG_REPLACE) {
3637 handler.removeMessages(msg);
3638 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
3639 return;
3640 }
Eric Laurentadbe8bf2014-11-03 18:26:32 -08003641 synchronized (mLastDeviceConnectMsgTime) {
3642 long time = SystemClock.uptimeMillis() + delay;
3643 handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
3644 if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
3645 msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
3646 msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
3647 mLastDeviceConnectMsgTime = time;
3648 }
3649 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003650 }
3651
3652 boolean checkAudioSettingsPermission(String method) {
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07003653 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003654 == PackageManager.PERMISSION_GRANTED) {
3655 return true;
3656 }
3657 String msg = "Audio Settings Permission Denial: " + method + " from pid="
3658 + Binder.getCallingPid()
3659 + ", uid=" + Binder.getCallingUid();
3660 Log.w(TAG, msg);
3661 return false;
3662 }
3663
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003664 private int getDeviceForStream(int stream) {
John Spurlock8a52c442015-03-26 14:23:58 -04003665 int device = getDevicesForStream(stream);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003666 if ((device & (device - 1)) != 0) {
3667 // Multiple device selection is either:
3668 // - speaker + one other device: give priority to speaker in this case.
3669 // - one A2DP device + another device: happens with duplicated output. In this case
3670 // retain the device on the A2DP output as the other must not correspond to an active
3671 // selection if not the speaker.
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003672 // - HDMI-CEC system audio mode only output: give priority to available item in order.
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003673 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
3674 device = AudioSystem.DEVICE_OUT_SPEAKER;
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003675 } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
3676 device = AudioSystem.DEVICE_OUT_HDMI_ARC;
3677 } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
3678 device = AudioSystem.DEVICE_OUT_SPDIF;
3679 } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
3680 device = AudioSystem.DEVICE_OUT_AUX_LINE;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003681 } else {
3682 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
3683 }
3684 }
3685 return device;
3686 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003687
John Spurlock8a52c442015-03-26 14:23:58 -04003688 private int getDevicesForStream(int stream) {
3689 return getDevicesForStream(stream, true /*checkOthers*/);
3690 }
3691
3692 private int getDevicesForStream(int stream, boolean checkOthers) {
3693 ensureValidStreamType(stream);
3694 synchronized (VolumeStreamState.class) {
3695 return mStreamStates[stream].observeDevicesForStream_syncVSS(checkOthers);
3696 }
3697 }
3698
3699 private void observeDevicesForStreams(int skipStream) {
3700 synchronized (VolumeStreamState.class) {
3701 for (int stream = 0; stream < mStreamStates.length; stream++) {
3702 if (stream != skipStream) {
3703 mStreamStates[stream].observeDevicesForStream_syncVSS(false /*checkOthers*/);
3704 }
3705 }
3706 }
3707 }
3708
Paul McLean10804eb2015-01-28 11:16:35 -08003709 /*
3710 * A class just for packaging up a set of connection parameters.
3711 */
3712 private class WiredDeviceConnectionState {
John Spurlock90874332015-03-10 16:00:54 -04003713 public final int mType;
3714 public final int mState;
3715 public final String mAddress;
3716 public final String mName;
3717 public final String mCaller;
Paul McLean10804eb2015-01-28 11:16:35 -08003718
John Spurlock90874332015-03-10 16:00:54 -04003719 public WiredDeviceConnectionState(int type, int state, String address, String name,
3720 String caller) {
Paul McLean10804eb2015-01-28 11:16:35 -08003721 mType = type;
3722 mState = state;
3723 mAddress = address;
3724 mName = name;
John Spurlock90874332015-03-10 16:00:54 -04003725 mCaller = caller;
Paul McLean10804eb2015-01-28 11:16:35 -08003726 }
3727 }
3728
John Spurlock90874332015-03-10 16:00:54 -04003729 public void setWiredDeviceConnectionState(int type, int state, String address, String name,
3730 String caller) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003731 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07003732 if (DEBUG_DEVICES) {
3733 Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
3734 + address + ")");
3735 }
Paul McLean10804eb2015-01-28 11:16:35 -08003736 int delay = checkSendBecomingNoisyIntent(type, state);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003737 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003738 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Paul McLean10804eb2015-01-28 11:16:35 -08003739 0,
3740 0,
John Spurlock90874332015-03-10 16:00:54 -04003741 new WiredDeviceConnectionState(type, state, address, name, caller),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003742 delay);
3743 }
3744 }
3745
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003746 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003747 {
3748 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003749 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
3750 throw new IllegalArgumentException("invalid profile " + profile);
3751 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003752 synchronized (mConnectedDevices) {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003753 if (profile == BluetoothProfile.A2DP) {
3754 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3755 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
3756 } else {
3757 delay = 0;
3758 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003759 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003760 (profile == BluetoothProfile.A2DP ?
3761 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003762 state,
3763 0,
3764 device,
3765 delay);
3766 }
3767 return delay;
3768 }
3769
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003770 ///////////////////////////////////////////////////////////////////////////
3771 // Inner classes
3772 ///////////////////////////////////////////////////////////////////////////
3773
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003774 // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
3775 // 1 mScoclient OR mSafeMediaVolumeState
3776 // 2 mSetModeDeathHandlers
3777 // 3 mSettingsLock
3778 // 4 VolumeStreamState.class
3779 // 5 mCameraSoundForced
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003780 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003781 private final int mStreamType;
John Spurlockb6e19e32015-03-10 21:33:44 -04003782 private final int mIndexMin;
3783 private final int mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003784
RoboErik4197cb62015-01-21 15:45:32 -08003785 private boolean mIsMuted;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003786 private String mVolumeIndexSettingName;
John Spurlock8a52c442015-03-26 14:23:58 -04003787 private int mObservedDevices;
John Spurlockb6e19e32015-03-10 21:33:44 -04003788
John Spurlock2bb02ec2015-03-02 13:13:06 -05003789 private final SparseIntArray mIndexMap = new SparseIntArray(8);
John Spurlockf63860c2015-02-19 09:46:27 -05003790 private final Intent mVolumeChanged;
John Spurlock8a52c442015-03-26 14:23:58 -04003791 private final Intent mStreamDevicesChanged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003792
Eric Laurenta553c252009-07-17 12:17:14 -07003793 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003794
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003795 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003796
3797 mStreamType = streamType;
John Spurlockb6e19e32015-03-10 21:33:44 -04003798 mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;
3799 mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;
3800 AudioSystem.initStreamVolume(streamType, mIndexMin / 10, mIndexMax / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003801
Eric Laurent33902db2012-10-07 16:15:07 -07003802 readSettings();
John Spurlockf63860c2015-02-19 09:46:27 -05003803 mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
3804 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
John Spurlock8a52c442015-03-26 14:23:58 -04003805 mStreamDevicesChanged = new Intent(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
3806 mStreamDevicesChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
3807 }
3808
3809 public int observeDevicesForStream_syncVSS(boolean checkOthers) {
3810 final int devices = AudioSystem.getDevicesForStream(mStreamType);
3811 if (devices == mObservedDevices) {
3812 return devices;
3813 }
3814 final int prevDevices = mObservedDevices;
3815 mObservedDevices = devices;
3816 if (checkOthers) {
3817 // one stream's devices have changed, check the others
3818 observeDevicesForStreams(mStreamType);
3819 }
3820 // log base stream changes to the event log
3821 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
3822 EventLogTags.writeStreamDevicesChanged(mStreamType, prevDevices, devices);
3823 }
3824 sendBroadcastToAll(mStreamDevicesChanged
3825 .putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, prevDevices)
3826 .putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, devices));
3827 return devices;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003828 }
3829
Eric Laurent42b041e2013-03-29 11:36:03 -07003830 public String getSettingNameForDevice(int device) {
3831 String name = mVolumeIndexSettingName;
Eric Laurent948d3272014-05-16 15:18:45 -07003832 String suffix = AudioSystem.getOutputDeviceName(device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003833 if (suffix.isEmpty()) {
3834 return name;
3835 }
3836 return name + "_" + suffix;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003837 }
3838
Eric Laurentfdbee862014-05-12 15:26:12 -07003839 public void readSettings() {
3840 synchronized (VolumeStreamState.class) {
John Spurlockee5ad722015-03-03 16:17:21 -05003841 // force maximum volume on all streams if fixed volume property is set
3842 if (mUseFixedVolume) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003843 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07003844 return;
3845 }
3846 // do not read system stream volume from settings: this stream is always aliased
3847 // to another stream type and its volume is never persisted. Values in settings can
3848 // only be stale values
3849 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3850 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
John Spurlock61560172015-02-06 19:46:04 -05003851 int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
Eric Laurentfdbee862014-05-12 15:26:12 -07003852 synchronized (mCameraSoundForced) {
3853 if (mCameraSoundForced) {
3854 index = mIndexMax;
3855 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003856 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003857 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003858 return;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003859 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003860
Eric Laurentfdbee862014-05-12 15:26:12 -07003861 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
3862
3863 for (int i = 0; remainingDevices != 0; i++) {
3864 int device = (1 << i);
3865 if ((device & remainingDevices) == 0) {
3866 continue;
3867 }
3868 remainingDevices &= ~device;
3869
3870 // retrieve current volume for device
3871 String name = getSettingNameForDevice(device);
3872 // if no volume stored for current stream and device, use default volume if default
3873 // device, continue otherwise
3874 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
John Spurlock61560172015-02-06 19:46:04 -05003875 AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
Eric Laurentfdbee862014-05-12 15:26:12 -07003876 int index = Settings.System.getIntForUser(
3877 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3878 if (index == -1) {
3879 continue;
3880 }
3881
John Spurlock2bb02ec2015-03-02 13:13:06 -05003882 mIndexMap.put(device, getValidIndex(10 * index));
Eric Laurentdd45d012012-10-08 09:04:34 -07003883 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003884 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003885 }
3886
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003887 // must be called while synchronized VolumeStreamState.class
3888 public void applyDeviceVolume_syncVSS(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003889 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003890 if (mIsMuted) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003891 index = 0;
Liejun Tao4565a472016-01-20 17:52:20 -06003892 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) {
3893 /* Special handling for Bluetooth Absolute Volume scenario
3894 * If we send full audio gain, some accessories are too loud even at its lowest
3895 * volume. We are not able to enumerate all such accessories, so here is the
3896 * workaround from phone side.
3897 * For the lowest volume steps 1 and 2, restrict audio gain to 50% and 75%.
3898 * For volume step 0, set audio gain to 0 as some accessories won't mute on their end.
3899 */
3900 int i = (getIndex(device) + 5)/10;
3901 if (i == 0) {
3902 // 0% for volume 0
3903 index = 0;
3904 } else if (i == 1) {
3905 // 50% for volume 1
3906 index = (int)(mIndexMax * 0.5) /10;
3907 } else if (i == 2) {
3908 // 75% for volume 2
3909 index = (int)(mIndexMax * 0.75) /10;
3910 } else {
3911 // otherwise, full gain
3912 index = (mIndexMax + 5)/10;
3913 }
3914 } else if ((device & mFullVolumeDevices) != 0) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003915 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07003916 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07003917 index = (getIndex(device) + 5)/10;
3918 }
3919 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003920 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003921
Eric Laurentfdbee862014-05-12 15:26:12 -07003922 public void applyAllVolumes() {
3923 synchronized (VolumeStreamState.class) {
3924 // apply default volume first: by convention this will reset all
3925 // devices volumes in audio policy manager to the supplied value
3926 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003927 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003928 index = 0;
3929 } else {
3930 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3931 }
3932 AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3933 // then apply device specific volumes
John Spurlock2bb02ec2015-03-02 13:13:06 -05003934 for (int i = 0; i < mIndexMap.size(); i++) {
3935 int device = mIndexMap.keyAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07003936 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
RoboErik4197cb62015-01-21 15:45:32 -08003937 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003938 index = 0;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003939 } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3940 mAvrcpAbsVolSupported)
3941 || ((device & mFullVolumeDevices) != 0))
3942 {
Eric Laurentfdbee862014-05-12 15:26:12 -07003943 index = (mIndexMax + 5)/10;
3944 } else {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003945 index = (mIndexMap.valueAt(i) + 5)/10;
Eric Laurentfdbee862014-05-12 15:26:12 -07003946 }
3947 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07003948 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003949 }
3950 }
3951 }
3952
John Spurlock90874332015-03-10 16:00:54 -04003953 public boolean adjustIndex(int deltaIndex, int device, String caller) {
3954 return setIndex(getIndex(device) + deltaIndex, device, caller);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003955 }
3956
John Spurlock90874332015-03-10 16:00:54 -04003957 public boolean setIndex(int index, int device, String caller) {
John Spurlockf63860c2015-02-19 09:46:27 -05003958 boolean changed = false;
3959 int oldIndex;
Eric Laurentfdbee862014-05-12 15:26:12 -07003960 synchronized (VolumeStreamState.class) {
John Spurlockf63860c2015-02-19 09:46:27 -05003961 oldIndex = getIndex(device);
Eric Laurentfdbee862014-05-12 15:26:12 -07003962 index = getValidIndex(index);
3963 synchronized (mCameraSoundForced) {
3964 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3965 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07003966 }
3967 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003968 mIndexMap.put(device, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003969
John Spurlockf63860c2015-02-19 09:46:27 -05003970 changed = oldIndex != index;
3971 if (changed) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003972 // Apply change to all streams using this one as alias
3973 // if changing volume of current device, also change volume of current
3974 // device on aliased stream
3975 boolean currentDevice = (device == getDeviceForStream(mStreamType));
3976 int numStreamTypes = AudioSystem.getNumStreamTypes();
3977 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3978 if (streamType != mStreamType &&
3979 mStreamVolumeAlias[streamType] == mStreamType) {
3980 int scaledIndex = rescaleIndex(index, mStreamType, streamType);
John Spurlock90874332015-03-10 16:00:54 -04003981 mStreamStates[streamType].setIndex(scaledIndex, device, caller);
Eric Laurentfdbee862014-05-12 15:26:12 -07003982 if (currentDevice) {
3983 mStreamStates[streamType].setIndex(scaledIndex,
John Spurlock90874332015-03-10 16:00:54 -04003984 getDeviceForStream(streamType), caller);
Eric Laurentfdbee862014-05-12 15:26:12 -07003985 }
3986 }
3987 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003988 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003989 }
John Spurlockf63860c2015-02-19 09:46:27 -05003990 if (changed) {
3991 oldIndex = (oldIndex + 5) / 10;
3992 index = (index + 5) / 10;
John Spurlock90874332015-03-10 16:00:54 -04003993 // log base stream changes to the event log
3994 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
3995 if (caller == null) {
3996 Log.w(TAG, "No caller for volume_changed event", new Throwable());
3997 }
3998 EventLogTags.writeVolumeChanged(mStreamType, oldIndex, index, mIndexMax / 10,
3999 caller);
4000 }
4001 // fire changed intents for all streams
John Spurlockf63860c2015-02-19 09:46:27 -05004002 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
4003 mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
Jean-Michel Trivi560877d2015-06-25 17:38:35 -07004004 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
4005 mStreamVolumeAlias[mStreamType]);
John Spurlockf63860c2015-02-19 09:46:27 -05004006 sendBroadcastToAll(mVolumeChanged);
4007 }
4008 return changed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004009 }
4010
Eric Laurentfdbee862014-05-12 15:26:12 -07004011 public int getIndex(int device) {
4012 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004013 int index = mIndexMap.get(device, -1);
4014 if (index == -1) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004015 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
John Spurlock2bb02ec2015-03-02 13:13:06 -05004016 index = mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurentfdbee862014-05-12 15:26:12 -07004017 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05004018 return index;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004019 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07004020 }
4021
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004022 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07004023 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004024 }
4025
John Spurlockb6e19e32015-03-10 21:33:44 -04004026 public int getMinIndex() {
4027 return mIndexMin;
4028 }
4029
John Spurlock90874332015-03-10 16:00:54 -04004030 public void setAllIndexes(VolumeStreamState srcStream, String caller) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004031 synchronized (VolumeStreamState.class) {
4032 int srcStreamType = srcStream.getStreamType();
4033 // apply default device volume from source stream to all devices first in case
4034 // some devices are present in this stream state but not in source stream state
4035 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004036 index = rescaleIndex(index, srcStreamType, mStreamType);
John Spurlock2bb02ec2015-03-02 13:13:06 -05004037 for (int i = 0; i < mIndexMap.size(); i++) {
4038 mIndexMap.put(mIndexMap.keyAt(i), index);
Eric Laurentfdbee862014-05-12 15:26:12 -07004039 }
4040 // Now apply actual volume for devices in source stream state
John Spurlock2bb02ec2015-03-02 13:13:06 -05004041 SparseIntArray srcMap = srcStream.mIndexMap;
4042 for (int i = 0; i < srcMap.size(); i++) {
4043 int device = srcMap.keyAt(i);
4044 index = srcMap.valueAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07004045 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07004046
John Spurlock90874332015-03-10 16:00:54 -04004047 setIndex(index, device, caller);
Eric Laurentfdbee862014-05-12 15:26:12 -07004048 }
Eric Laurent6d517662012-04-23 18:42:39 -07004049 }
4050 }
4051
Eric Laurentfdbee862014-05-12 15:26:12 -07004052 public void setAllIndexesToMax() {
4053 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004054 for (int i = 0; i < mIndexMap.size(); i++) {
4055 mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07004056 }
Eric Laurentdd45d012012-10-08 09:04:34 -07004057 }
Eric Laurentdd45d012012-10-08 09:04:34 -07004058 }
4059
RoboErik4197cb62015-01-21 15:45:32 -08004060 public void mute(boolean state) {
John Spurlock22b9ee12015-02-18 22:51:44 -05004061 boolean changed = false;
Eric Laurentfdbee862014-05-12 15:26:12 -07004062 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08004063 if (state != mIsMuted) {
John Spurlock22b9ee12015-02-18 22:51:44 -05004064 changed = true;
RoboErik4197cb62015-01-21 15:45:32 -08004065 mIsMuted = state;
John Spurlock22b9ee12015-02-18 22:51:44 -05004066
RoboErik4197cb62015-01-21 15:45:32 -08004067 // Set the new mute volume. This propagates the values to
4068 // the audio system, otherwise the volume won't be changed
4069 // at the lower level.
4070 sendMsg(mAudioHandler,
4071 MSG_SET_ALL_VOLUMES,
4072 SENDMSG_QUEUE,
4073 0,
4074 0,
4075 this, 0);
Eric Laurentfdbee862014-05-12 15:26:12 -07004076 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004077 }
John Spurlock22b9ee12015-02-18 22:51:44 -05004078 if (changed) {
4079 // Stream mute changed, fire the intent.
4080 Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
4081 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
4082 intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
4083 sendBroadcastToAll(intent);
4084 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004085 }
4086
Eric Laurent6d517662012-04-23 18:42:39 -07004087 public int getStreamType() {
4088 return mStreamType;
4089 }
4090
Eric Laurent212532b2014-07-21 15:43:18 -07004091 public void checkFixedVolumeDevices() {
4092 synchronized (VolumeStreamState.class) {
4093 // ignore settings for fixed volume devices: volume should always be at max or 0
4094 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004095 for (int i = 0; i < mIndexMap.size(); i++) {
4096 int device = mIndexMap.keyAt(i);
4097 int index = mIndexMap.valueAt(i);
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07004098 if (((device & mFullVolumeDevices) != 0)
4099 || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004100 mIndexMap.put(device, mIndexMax);
Eric Laurent212532b2014-07-21 15:43:18 -07004101 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004102 applyDeviceVolume_syncVSS(device);
Eric Laurent212532b2014-07-21 15:43:18 -07004103 }
4104 }
4105 }
4106 }
4107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004108 private int getValidIndex(int index) {
John Spurlockb6e19e32015-03-10 21:33:44 -04004109 if (index < mIndexMin) {
4110 return mIndexMin;
John Spurlockee5ad722015-03-03 16:17:21 -05004111 } else if (mUseFixedVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07004112 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004113 }
4114
4115 return index;
4116 }
4117
Eric Laurentbffc3d12012-05-07 17:43:49 -07004118 private void dump(PrintWriter pw) {
RoboErik4197cb62015-01-21 15:45:32 -08004119 pw.print(" Muted: ");
4120 pw.println(mIsMuted);
John Spurlockb6e19e32015-03-10 21:33:44 -04004121 pw.print(" Min: ");
4122 pw.println((mIndexMin + 5) / 10);
John Spurlock2b29bc42014-08-26 16:40:35 -04004123 pw.print(" Max: ");
4124 pw.println((mIndexMax + 5) / 10);
Eric Laurentbffc3d12012-05-07 17:43:49 -07004125 pw.print(" Current: ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05004126 for (int i = 0; i < mIndexMap.size(); i++) {
4127 if (i > 0) {
4128 pw.print(", ");
4129 }
4130 final int device = mIndexMap.keyAt(i);
John Spurlock2b29bc42014-08-26 16:40:35 -04004131 pw.print(Integer.toHexString(device));
4132 final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
4133 : AudioSystem.getOutputDeviceName(device);
4134 if (!deviceName.isEmpty()) {
4135 pw.print(" (");
4136 pw.print(deviceName);
4137 pw.print(")");
4138 }
4139 pw.print(": ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05004140 final int index = (mIndexMap.valueAt(i) + 5) / 10;
John Spurlock2b29bc42014-08-26 16:40:35 -04004141 pw.print(index);
Eric Laurentbffc3d12012-05-07 17:43:49 -07004142 }
John Spurlockb32fc972015-03-05 13:58:00 -05004143 pw.println();
4144 pw.print(" Devices: ");
John Spurlock8a52c442015-03-26 14:23:58 -04004145 final int devices = getDevicesForStream(mStreamType);
John Spurlockb32fc972015-03-05 13:58:00 -05004146 int device, i = 0, n = 0;
John Spurlock1ff1e6e2015-03-09 14:21:20 -04004147 // iterate all devices from 1 to DEVICE_OUT_DEFAULT exclusive
4148 // (the default device is not returned by getDevicesForStream)
4149 while ((device = 1 << i) != AudioSystem.DEVICE_OUT_DEFAULT) {
John Spurlockb32fc972015-03-05 13:58:00 -05004150 if ((devices & device) != 0) {
4151 if (n++ > 0) {
4152 pw.print(", ");
4153 }
4154 pw.print(AudioSystem.getOutputDeviceName(device));
4155 }
4156 i++;
4157 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07004158 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004159 }
4160
4161 /** Thread that handles native AudioSystem control. */
4162 private class AudioSystemThread extends Thread {
4163 AudioSystemThread() {
4164 super("AudioService");
4165 }
4166
4167 @Override
4168 public void run() {
4169 // Set this thread up so the handler will work on it
4170 Looper.prepare();
4171
4172 synchronized(AudioService.this) {
4173 mAudioHandler = new AudioHandler();
4174
4175 // Notify that the handler has been created
4176 AudioService.this.notify();
4177 }
4178
4179 // Listen for volume change requests that are set by VolumePanel
4180 Looper.loop();
4181 }
4182 }
4183
4184 /** Handles internal volume messages in separate volume thread. */
4185 private class AudioHandler extends Handler {
4186
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004187 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004188
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004189 synchronized (VolumeStreamState.class) {
4190 // Apply volume
4191 streamState.applyDeviceVolume_syncVSS(device);
Eric Laurenta553c252009-07-17 12:17:14 -07004192
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004193 // Apply change to all streams using this one as alias
4194 int numStreamTypes = AudioSystem.getNumStreamTypes();
4195 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4196 if (streamType != streamState.mStreamType &&
4197 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
4198 // Make sure volume is also maxed out on A2DP device for aliased stream
4199 // that may have a different device selected
4200 int streamDevice = getDeviceForStream(streamType);
4201 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
4202 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
4203 mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
4204 }
4205 mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
Eric Laurentcd772d02013-10-30 18:31:07 -07004206 }
Eric Laurenta553c252009-07-17 12:17:14 -07004207 }
4208 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004209 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08004210 sendMsg(mAudioHandler,
4211 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08004212 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004213 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07004214 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08004215 streamState,
4216 PERSIST_DELAY);
4217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004218 }
4219
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004220 private void setAllVolumes(VolumeStreamState streamState) {
4221
4222 // Apply volume
4223 streamState.applyAllVolumes();
4224
4225 // Apply change to all streams using this one as alias
4226 int numStreamTypes = AudioSystem.getNumStreamTypes();
4227 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4228 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07004229 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004230 mStreamStates[streamType].applyAllVolumes();
4231 }
4232 }
4233 }
4234
Eric Laurent42b041e2013-03-29 11:36:03 -07004235 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07004236 if (mUseFixedVolume) {
4237 return;
4238 }
Eric Laurent212532b2014-07-21 15:43:18 -07004239 if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
4240 return;
4241 }
Eric Laurent42b041e2013-03-29 11:36:03 -07004242 System.putIntForUser(mContentResolver,
4243 streamState.getSettingNameForDevice(device),
4244 (streamState.getIndex(device) + 5)/ 10,
4245 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004246 }
4247
Glenn Kastenba195eb2011-12-13 09:30:40 -08004248 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07004249 if (mUseFixedVolume) {
4250 return;
4251 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07004252 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004253 }
4254
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004255 private boolean onLoadSoundEffects() {
4256 int status;
4257
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004258 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004259 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004260 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
4261 return false;
4262 }
4263
4264 if (mSoundPool != null) {
4265 return true;
4266 }
4267
4268 loadTouchSoundAssets();
4269
Jean-Michel Trivi55a30c42014-07-20 17:56:11 -07004270 mSoundPool = new SoundPool.Builder()
4271 .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
4272 .setAudioAttributes(new AudioAttributes.Builder()
4273 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
4274 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
4275 .build())
4276 .build();
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004277 mSoundPoolCallBack = null;
4278 mSoundPoolListenerThread = new SoundPoolListenerThread();
4279 mSoundPoolListenerThread.start();
4280 int attempts = 3;
4281 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
4282 try {
4283 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07004284 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004285 } catch (InterruptedException e) {
4286 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
4287 }
4288 }
4289
4290 if (mSoundPoolCallBack == null) {
4291 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
4292 if (mSoundPoolLooper != null) {
4293 mSoundPoolLooper.quit();
4294 mSoundPoolLooper = null;
4295 }
4296 mSoundPoolListenerThread = null;
4297 mSoundPool.release();
4298 mSoundPool = null;
4299 return false;
4300 }
4301 /*
4302 * poolId table: The value -1 in this table indicates that corresponding
4303 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
4304 * Once loaded, the value in poolId is the sample ID and the same
4305 * sample can be reused for another effect using the same file.
4306 */
4307 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4308 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4309 poolId[fileIdx] = -1;
4310 }
4311 /*
4312 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
4313 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
4314 * this indicates we have a valid sample loaded for this effect.
4315 */
4316
4317 int numSamples = 0;
4318 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4319 // Do not load sample if this effect uses the MediaPlayer
4320 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
4321 continue;
4322 }
4323 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
4324 String filePath = Environment.getRootDirectory()
4325 + SOUND_EFFECTS_PATH
4326 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
4327 int sampleId = mSoundPool.load(filePath, 0);
4328 if (sampleId <= 0) {
4329 Log.w(TAG, "Soundpool could not load file: "+filePath);
4330 } else {
4331 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
4332 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
4333 numSamples++;
4334 }
4335 } else {
4336 SOUND_EFFECT_FILES_MAP[effect][1] =
4337 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
4338 }
4339 }
4340 // wait for all samples to be loaded
4341 if (numSamples > 0) {
4342 mSoundPoolCallBack.setSamples(poolId);
4343
4344 attempts = 3;
4345 status = 1;
4346 while ((status == 1) && (attempts-- > 0)) {
4347 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07004348 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004349 status = mSoundPoolCallBack.status();
4350 } catch (InterruptedException e) {
4351 Log.w(TAG, "Interrupted while waiting sound pool callback.");
4352 }
4353 }
4354 } else {
4355 status = -1;
4356 }
4357
4358 if (mSoundPoolLooper != null) {
4359 mSoundPoolLooper.quit();
4360 mSoundPoolLooper = null;
4361 }
4362 mSoundPoolListenerThread = null;
4363 if (status != 0) {
4364 Log.w(TAG,
4365 "onLoadSoundEffects(), Error "+status+ " while loading samples");
4366 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4367 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
4368 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4369 }
4370 }
4371
4372 mSoundPool.release();
4373 mSoundPool = null;
4374 }
4375 }
4376 return (status == 0);
4377 }
4378
4379 /**
4380 * Unloads samples from the sound pool.
4381 * This method can be called to free some memory when
4382 * sound effects are disabled.
4383 */
4384 private void onUnloadSoundEffects() {
4385 synchronized (mSoundEffectsLock) {
4386 if (mSoundPool == null) {
4387 return;
4388 }
4389
4390 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4391 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4392 poolId[fileIdx] = 0;
4393 }
4394
4395 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4396 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
4397 continue;
4398 }
4399 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
4400 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
4401 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4402 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
4403 }
4404 }
4405 mSoundPool.release();
4406 mSoundPool = null;
4407 }
4408 }
4409
4410 private void onPlaySoundEffect(int effectType, int volume) {
4411 synchronized (mSoundEffectsLock) {
4412
4413 onLoadSoundEffects();
4414
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004415 if (mSoundPool == null) {
4416 return;
4417 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004418 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08004419 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004420 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07004421 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004422 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07004423 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004424 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004425
4426 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004427 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
4428 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004429 } else {
4430 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004431 try {
Eric Laurente78fced2013-03-15 16:03:47 -07004432 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
4433 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004434 mediaPlayer.setDataSource(filePath);
4435 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
4436 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08004437 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004438 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
4439 public void onCompletion(MediaPlayer mp) {
4440 cleanupPlayer(mp);
4441 }
4442 });
4443 mediaPlayer.setOnErrorListener(new OnErrorListener() {
4444 public boolean onError(MediaPlayer mp, int what, int extra) {
4445 cleanupPlayer(mp);
4446 return true;
4447 }
4448 });
4449 mediaPlayer.start();
4450 } catch (IOException ex) {
4451 Log.w(TAG, "MediaPlayer IOException: "+ex);
4452 } catch (IllegalArgumentException ex) {
4453 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
4454 } catch (IllegalStateException ex) {
4455 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004456 }
4457 }
4458 }
4459 }
4460
4461 private void cleanupPlayer(MediaPlayer mp) {
4462 if (mp != null) {
4463 try {
4464 mp.stop();
4465 mp.release();
4466 } catch (IllegalStateException ex) {
4467 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
4468 }
4469 }
4470 }
4471
Eric Laurentfa640152011-03-12 15:59:51 -08004472 private void setForceUse(int usage, int config) {
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004473 synchronized (mConnectedDevices) {
4474 setForceUseInt_SyncDevices(usage, config);
4475 }
Eric Laurentfa640152011-03-12 15:59:51 -08004476 }
4477
Eric Laurent05274f32012-11-29 12:48:18 -08004478 private void onPersistSafeVolumeState(int state) {
4479 Settings.Global.putInt(mContentResolver,
4480 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
4481 state);
4482 }
4483
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004484 @Override
4485 public void handleMessage(Message msg) {
Eric Laurentafbb0472011-12-15 09:04:23 -08004486 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004487
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004488 case MSG_SET_DEVICE_VOLUME:
4489 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
4490 break;
4491
4492 case MSG_SET_ALL_VOLUMES:
4493 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004494 break;
4495
4496 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07004497 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004498 break;
4499
Justin Koh57978ed2012-04-03 17:37:58 -07004500 case MSG_PERSIST_MASTER_VOLUME_MUTE:
Eric Laurent83a017b2013-03-19 18:15:31 -07004501 if (mUseFixedVolume) {
4502 return;
4503 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004504 Settings.System.putIntForUser(mContentResolver,
4505 Settings.System.VOLUME_MASTER_MUTE,
4506 msg.arg1,
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004507 msg.arg2);
Justin Koh57978ed2012-04-03 17:37:58 -07004508 break;
4509
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004510 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08004511 // note that the value persisted is the current ringer mode, not the
4512 // value of ringer mode as of the time the request was made to persist
John Spurlock661f2cf2014-11-17 10:29:10 -05004513 persistRingerMode(getRingerModeInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004514 break;
4515
Andy Hunged0ea402015-10-30 14:11:46 -07004516 case MSG_AUDIO_SERVER_DIED:
4517 onAudioServerDied();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004518 break;
4519
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004520 case MSG_UNLOAD_SOUND_EFFECTS:
4521 onUnloadSoundEffects();
4522 break;
4523
Eric Laurent117b7bb2011-01-16 17:07:27 -08004524 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004525 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
4526 // can take several dozens of milliseconds to complete
4527 boolean loaded = onLoadSoundEffects();
4528 if (msg.obj != null) {
4529 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
4530 synchronized (reply) {
4531 reply.mStatus = loaded ? 0 : -1;
4532 reply.notify();
4533 }
4534 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08004535 break;
4536
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004537 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004538 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004539 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004540
4541 case MSG_BTA2DP_DOCK_TIMEOUT:
4542 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004543 synchronized (mConnectedDevices) {
4544 makeA2dpDeviceUnavailableNow( (String) msg.obj );
4545 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004546 break;
Eric Laurentfa640152011-03-12 15:59:51 -08004547
4548 case MSG_SET_FORCE_USE:
Eric Laurentc390bed2012-07-03 12:24:05 -07004549 case MSG_SET_FORCE_BT_A2DP_USE:
Eric Laurentfa640152011-03-12 15:59:51 -08004550 setForceUse(msg.arg1, msg.arg2);
4551 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07004552
Eric Laurentdc03c612011-04-01 10:59:41 -07004553 case MSG_BT_HEADSET_CNCT_FAILED:
4554 resetBluetoothSco();
4555 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004556
4557 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
Paul McLean10804eb2015-01-28 11:16:35 -08004558 { WiredDeviceConnectionState connectState =
4559 (WiredDeviceConnectionState)msg.obj;
4560 onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
John Spurlock90874332015-03-10 16:00:54 -04004561 connectState.mAddress, connectState.mName, connectState.mCaller);
Paul McLean10804eb2015-01-28 11:16:35 -08004562 mAudioEventWakeLock.release();
4563 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004564 break;
4565
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004566 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
4567 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
4568 mAudioEventWakeLock.release();
4569 break;
4570
4571 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
4572 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004573 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004574 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004575
4576 case MSG_REPORT_NEW_ROUTES: {
4577 int N = mRoutesObservers.beginBroadcast();
4578 if (N > 0) {
4579 AudioRoutesInfo routes;
4580 synchronized (mCurAudioRoutes) {
4581 routes = new AudioRoutesInfo(mCurAudioRoutes);
4582 }
4583 while (N > 0) {
4584 N--;
4585 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
4586 try {
4587 obs.dispatchAudioRoutesChanged(routes);
4588 } catch (RemoteException e) {
4589 }
4590 }
4591 }
4592 mRoutesObservers.finishBroadcast();
John Spurlock8a52c442015-03-26 14:23:58 -04004593 observeDevicesForStreams(-1);
Dianne Hackborn632ca412012-06-14 19:34:10 -07004594 break;
4595 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004596
Eric Laurentc34dcc12012-09-10 13:51:52 -07004597 case MSG_CHECK_MUSIC_ACTIVE:
John Spurlock90874332015-03-10 16:00:54 -04004598 onCheckMusicActive((String) msg.obj);
Eric Laurentc34dcc12012-09-10 13:51:52 -07004599 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004600
4601 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
4602 onSendBecomingNoisyIntent();
4603 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07004604
4605 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
4606 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
John Spurlock90874332015-03-10 16:00:54 -04004607 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED),
4608 (String) msg.obj);
Eric Laurentd640bd32012-09-28 18:01:48 -07004609 break;
Eric Laurent05274f32012-11-29 12:48:18 -08004610 case MSG_PERSIST_SAFE_VOLUME_STATE:
4611 onPersistSafeVolumeState(msg.arg1);
4612 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08004613
Eric Laurent2a57ca92013-03-07 17:29:27 -08004614 case MSG_BROADCAST_BT_CONNECTION_STATE:
4615 onBroadcastScoConnectionState(msg.arg1);
4616 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004617
4618 case MSG_SYSTEM_READY:
4619 onSystemReady();
4620 break;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004621
Eric Laurent0867bed2015-05-20 14:49:08 -07004622 case MSG_INDICATE_SYSTEM_READY:
4623 onIndicateSystemReady();
4624 break;
4625
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004626 case MSG_PERSIST_MUSIC_ACTIVE_MS:
4627 final int musicActiveMs = msg.arg1;
4628 Settings.Secure.putIntForUser(mContentResolver,
4629 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
4630 UserHandle.USER_CURRENT);
4631 break;
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004632 case MSG_PERSIST_MICROPHONE_MUTE:
4633 Settings.System.putIntForUser(mContentResolver,
4634 Settings.System.MICROPHONE_MUTE,
4635 msg.arg1,
4636 msg.arg2);
4637 break;
RoboErik5452e252015-02-06 15:33:53 -08004638 case MSG_UNMUTE_STREAM:
4639 onUnmuteStream(msg.arg1, msg.arg2);
4640 break;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07004641 case MSG_DYN_POLICY_MIX_STATE_UPDATE:
4642 onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1);
4643 break;
Andy Hungf04b84d2015-12-18 17:33:27 -08004644
4645 case MSG_PERSIST_MASTER_MONO:
4646 Settings.System.putIntForUser(mContentResolver,
4647 Settings.System.MASTER_MONO,
4648 msg.arg1 /* value */,
4649 msg.arg2 /* userHandle */);
4650 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004651 }
4652 }
4653 }
4654
Jason Parekhb1096152009-03-24 17:48:25 -07004655 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07004656
Jason Parekhb1096152009-03-24 17:48:25 -07004657 SettingsObserver() {
4658 super(new Handler());
4659 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4660 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004661 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4662 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07004663 }
4664
4665 @Override
4666 public void onChange(boolean selfChange) {
4667 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08004668 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
4669 // However there appear to be some missing locks around mRingerModeMutedStreams
4670 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
4671 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07004672 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004673 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07004674 /*
4675 * Ensure all stream types that should be affected by ringer mode
4676 * are in the proper state.
4677 */
John Spurlock661f2cf2014-11-17 10:29:10 -05004678 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurenta553c252009-07-17 12:17:14 -07004679 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004680 readDockAudioSettings(mContentResolver);
Eric Laurenta553c252009-07-17 12:17:14 -07004681 }
Jason Parekhb1096152009-03-24 17:48:25 -07004682 }
Jason Parekhb1096152009-03-24 17:48:25 -07004683 }
Eric Laurenta553c252009-07-17 12:17:14 -07004684
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004685 // must be called synchronized on mConnectedDevices
Paul McLean20eec5b2015-05-09 13:02:18 -07004686 private void makeA2dpDeviceAvailable(String address, String name) {
Eric Laurent78472112012-05-21 08:57:21 -07004687 // enable A2DP before notifying A2DP connection to avoid unecessary processing in
4688 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004689 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4690 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4691 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Eric Laurent78472112012-05-21 08:57:21 -07004692 setBluetoothA2dpOnInt(true);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004693 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004694 AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004695 // Reset A2DP suspend state each time a new sink is connected
4696 AudioSystem.setParameters("A2dpSuspended=false");
Paul McLean394a8e12015-03-03 10:29:19 -07004697 mConnectedDevices.put(
4698 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
Paul McLean20eec5b2015-05-09 13:02:18 -07004699 new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
Paul McLean394a8e12015-03-03 10:29:19 -07004700 address));
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004701 }
4702
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004703 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004704 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07004705 }
4706
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004707 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004708 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004709 synchronized (mA2dpAvrcpLock) {
4710 mAvrcpAbsVolSupported = false;
4711 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004712 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004713 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004714 mConnectedDevices.remove(
4715 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
RoboErik5535ea82014-09-25 14:53:16 -07004716 synchronized (mCurAudioRoutes) {
4717 // Remove A2DP routes as well
John Spurlock61560172015-02-06 19:46:04 -05004718 if (mCurAudioRoutes.bluetoothName != null) {
4719 mCurAudioRoutes.bluetoothName = null;
RoboErik5535ea82014-09-25 14:53:16 -07004720 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4721 SENDMSG_NOOP, 0, 0, null, 0);
4722 }
4723 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004724 }
4725
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004726 // must be called synchronized on mConnectedDevices
Eric Laurentd138e4e2015-05-15 16:41:15 -07004727 private void makeA2dpDeviceUnavailableLater(String address, int delayMs) {
Eric Laurent3b591262010-04-20 07:01:00 -07004728 // prevent any activity on the A2DP audio output to avoid unwanted
4729 // reconnection of the sink.
4730 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004731 // the device will be made unavailable later, so consider it disconnected right away
Paul McLean394a8e12015-03-03 10:29:19 -07004732 mConnectedDevices.remove(
4733 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004734 // send the delayed message to make the device unavailable later
4735 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
Eric Laurentd138e4e2015-05-15 16:41:15 -07004736 mAudioHandler.sendMessageDelayed(msg, delayMs);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004737
4738 }
4739
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004740 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004741 private void makeA2dpSrcAvailable(String address) {
4742 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004743 AudioSystem.DEVICE_STATE_AVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004744 mConnectedDevices.put(
4745 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
Paul McLean20eec5b2015-05-09 13:02:18 -07004746 new DeviceListSpec(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "",
Paul McLean394a8e12015-03-03 10:29:19 -07004747 address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004748 }
4749
4750 // must be called synchronized on mConnectedDevices
4751 private void makeA2dpSrcUnavailable(String address) {
4752 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004753 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004754 mConnectedDevices.remove(
4755 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004756 }
4757
4758 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004759 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004760 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4761 }
4762
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004763 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004764 private boolean hasScheduledA2dpDockTimeout() {
4765 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4766 }
4767
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004768 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004769 {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004770 if (DEBUG_VOL) {
4771 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
4772 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004773 if (btDevice == null) {
4774 return;
4775 }
4776 String address = btDevice.getAddress();
4777 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4778 address = "";
4779 }
John Du5a0cf7a2013-07-19 11:30:34 -07004780
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004781 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004782 String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4783 btDevice.getAddress());
4784 DeviceListSpec deviceSpec = mConnectedDevices.get(key);
4785 boolean isConnected = deviceSpec != null;
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004786
4787 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4788 if (btDevice.isBluetoothDock()) {
4789 if (state == BluetoothProfile.STATE_DISCONNECTED) {
4790 // introduction of a delay for transient disconnections of docks when
4791 // power is rapidly turned off/on, this message will be canceled if
4792 // we reconnect the dock under a preset delay
Eric Laurentd138e4e2015-05-15 16:41:15 -07004793 makeA2dpDeviceUnavailableLater(address, BTA2DP_DOCK_TIMEOUT_MILLIS);
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004794 // the next time isConnected is evaluated, it will be false for the dock
4795 }
4796 } else {
4797 makeA2dpDeviceUnavailableNow(address);
4798 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07004799 synchronized (mCurAudioRoutes) {
John Spurlock61560172015-02-06 19:46:04 -05004800 if (mCurAudioRoutes.bluetoothName != null) {
4801 mCurAudioRoutes.bluetoothName = null;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004802 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4803 SENDMSG_NOOP, 0, 0, null, 0);
4804 }
4805 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004806 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4807 if (btDevice.isBluetoothDock()) {
4808 // this could be a reconnection after a transient disconnection
4809 cancelA2dpDeviceTimeout();
4810 mDockAddress = address;
4811 } else {
4812 // this could be a connection of another A2DP device before the timeout of
4813 // a dock: cancel the dock timeout, and make the dock unavailable now
4814 if(hasScheduledA2dpDockTimeout()) {
4815 cancelA2dpDeviceTimeout();
4816 makeA2dpDeviceUnavailableNow(mDockAddress);
4817 }
4818 }
Paul McLean20eec5b2015-05-09 13:02:18 -07004819 makeA2dpDeviceAvailable(address, btDevice.getName());
Dianne Hackborn632ca412012-06-14 19:34:10 -07004820 synchronized (mCurAudioRoutes) {
4821 String name = btDevice.getAliasName();
John Spurlock61560172015-02-06 19:46:04 -05004822 if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
4823 mCurAudioRoutes.bluetoothName = name;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004824 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4825 SENDMSG_NOOP, 0, 0, null, 0);
4826 }
4827 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004828 }
4829 }
4830 }
4831
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004832 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
4833 {
4834 if (DEBUG_VOL) {
4835 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
4836 }
4837 if (btDevice == null) {
4838 return;
4839 }
4840 String address = btDevice.getAddress();
4841 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4842 address = "";
4843 }
4844
4845 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004846 String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
4847 DeviceListSpec deviceSpec = mConnectedDevices.get(key);
4848 boolean isConnected = deviceSpec != null;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004849
4850 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4851 makeA2dpSrcUnavailable(address);
4852 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4853 makeA2dpSrcAvailable(address);
4854 }
4855 }
4856 }
4857
John Du5a0cf7a2013-07-19 11:30:34 -07004858 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
4859 // address is not used for now, but may be used when multiple a2dp devices are supported
4860 synchronized (mA2dpAvrcpLock) {
4861 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004862 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07004863 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4864 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4865 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4866 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4867 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07004868 }
4869 }
4870
Paul McLean394a8e12015-03-03 10:29:19 -07004871 private boolean handleDeviceConnection(boolean connect, int device, String address,
4872 String deviceName) {
4873 if (DEBUG_DEVICES) {
4874 Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device)
4875 + " address:" + address + " name:" + deviceName + ")");
4876 }
Eric Laurent59f48272012-04-05 19:42:21 -07004877 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004878 String deviceKey = makeDeviceListKey(device, address);
4879 if (DEBUG_DEVICES) {
4880 Slog.i(TAG, "deviceKey:" + deviceKey);
4881 }
4882 DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
4883 boolean isConnected = deviceSpec != null;
4884 if (DEBUG_DEVICES) {
4885 Slog.i(TAG, "deviceSpec:" + deviceSpec + " is(already)Connected:" + isConnected);
4886 }
4887 if (connect && !isConnected) {
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07004888 final int res = AudioSystem.setDeviceConnectionState(device,
4889 AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);
4890 if (res != AudioSystem.AUDIO_STATUS_OK) {
4891 Slog.e(TAG, "not connecting device 0x" + Integer.toHexString(device) +
4892 " due to command error " + res );
4893 return false;
4894 }
Paul McLean394a8e12015-03-03 10:29:19 -07004895 mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
4896 return true;
4897 } else if (!connect && isConnected) {
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07004898 AudioSystem.setDeviceConnectionState(device,
4899 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName);
4900 // always remove even if disconnection failed
Paul McLean394a8e12015-03-03 10:29:19 -07004901 mConnectedDevices.remove(deviceKey);
4902 return true;
Eric Laurent59f48272012-04-05 19:42:21 -07004903 }
4904 }
4905 return false;
4906 }
4907
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004908 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4909 // sent if none of these devices is connected.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004910 // Access synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004911 int mBecomingNoisyIntentDevices =
4912 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07004913 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07004914 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004915 AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004916
4917 // must be called before removing the device from mConnectedDevices
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004918 // Called synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004919 private int checkSendBecomingNoisyIntent(int device, int state) {
4920 int delay = 0;
4921 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4922 int devices = 0;
John Spurlock8c3dc852015-04-23 21:32:37 -04004923 for (int i = 0; i < mConnectedDevices.size(); i++) {
4924 int dev = mConnectedDevices.valueAt(i).mDeviceType;
Paul McLean394a8e12015-03-03 10:29:19 -07004925 if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
4926 && ((dev & mBecomingNoisyIntentDevices) != 0)) {
4927 devices |= dev;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004928 }
4929 }
4930 if (devices == device) {
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004931 sendMsg(mAudioHandler,
4932 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4933 SENDMSG_REPLACE,
4934 0,
4935 0,
4936 null,
4937 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004938 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004939 }
4940 }
4941
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004942 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
4943 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004944 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004945 synchronized (mLastDeviceConnectMsgTime) {
4946 long time = SystemClock.uptimeMillis();
4947 if (mLastDeviceConnectMsgTime > time) {
Matthew Xiec525cf72015-01-22 20:13:17 -08004948 delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004949 }
4950 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004951 }
4952 return delay;
4953 }
4954
Paul McLean394a8e12015-03-03 10:29:19 -07004955 private void sendDeviceConnectionIntent(int device, int state, String address,
4956 String deviceName) {
4957 if (DEBUG_DEVICES) {
4958 Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
4959 " state:0x" + Integer.toHexString(state) + " address:" + address +
4960 " name:" + deviceName + ");");
4961 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004962 Intent intent = new Intent();
4963
Paul McLean10804eb2015-01-28 11:16:35 -08004964 intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
4965 intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
4966 intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
4967
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004968 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4969
Dianne Hackborn632ca412012-06-14 19:34:10 -07004970 int connType = 0;
4971
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004972 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004973 connType = AudioRoutesInfo.MAIN_HEADSET;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004974 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4975 intent.putExtra("microphone", 1);
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004976 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
4977 device == AudioSystem.DEVICE_OUT_LINE) {
4978 /*do apps care about line-out vs headphones?*/
Dianne Hackborn632ca412012-06-14 19:34:10 -07004979 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004980 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4981 intent.putExtra("microphone", 0);
Eric Laurent6fa42452015-01-09 15:09:40 -08004982 } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
4983 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004984 connType = AudioRoutesInfo.MAIN_HDMI;
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004985 configureHdmiPlugIntent(intent, state);
Paul McLean10804eb2015-01-28 11:16:35 -08004986 } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE) {
4987 connType = AudioRoutesInfo.MAIN_USB;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004988 }
4989
Dianne Hackborn632ca412012-06-14 19:34:10 -07004990 synchronized (mCurAudioRoutes) {
4991 if (connType != 0) {
John Spurlock61560172015-02-06 19:46:04 -05004992 int newConn = mCurAudioRoutes.mainType;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004993 if (state != 0) {
4994 newConn |= connType;
4995 } else {
4996 newConn &= ~connType;
4997 }
John Spurlock61560172015-02-06 19:46:04 -05004998 if (newConn != mCurAudioRoutes.mainType) {
4999 mCurAudioRoutes.mainType = newConn;
Dianne Hackborn632ca412012-06-14 19:34:10 -07005000 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
5001 SENDMSG_NOOP, 0, 0, null, 0);
5002 }
5003 }
5004 }
5005
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005006 final long ident = Binder.clearCallingIdentity();
5007 try {
5008 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
5009 } finally {
5010 Binder.restoreCallingIdentity(ident);
5011 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005012 }
5013
Paul McLean10804eb2015-01-28 11:16:35 -08005014 private void onSetWiredDeviceConnectionState(int device, int state, String address,
John Spurlock90874332015-03-10 16:00:54 -04005015 String deviceName, String caller) {
Paul McLean394a8e12015-03-03 10:29:19 -07005016 if (DEBUG_DEVICES) {
John Spurlock90874332015-03-10 16:00:54 -04005017 Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
5018 + " state:" + Integer.toHexString(state)
5019 + " address:" + address
5020 + " deviceName:" + deviceName
5021 + " caller: " + caller + ");");
Paul McLean394a8e12015-03-03 10:29:19 -07005022 }
Paul McLean10804eb2015-01-28 11:16:35 -08005023
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005024 synchronized (mConnectedDevices) {
5025 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05005026 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
5027 (device == AudioSystem.DEVICE_OUT_LINE))) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005028 setBluetoothA2dpOnInt(true);
5029 }
Eric Laurentae4506e2014-05-29 16:04:32 -07005030 boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
5031 (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
5032 ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07005033 if (!handleDeviceConnection(state == 1, device, address, deviceName)) {
5034 // change of connection state failed, bailout
5035 return;
5036 }
Eric Laurentf1a457d2012-09-20 16:27:23 -07005037 if (state != 0) {
5038 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05005039 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
5040 (device == AudioSystem.DEVICE_OUT_LINE)) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07005041 setBluetoothA2dpOnInt(false);
5042 }
5043 if ((device & mSafeMediaVolumeDevices) != 0) {
5044 sendMsg(mAudioHandler,
5045 MSG_CHECK_MUSIC_ACTIVE,
5046 SENDMSG_REPLACE,
5047 0,
5048 0,
John Spurlock90874332015-03-10 16:00:54 -04005049 caller,
Eric Laurentf1a457d2012-09-20 16:27:23 -07005050 MUSIC_ACTIVE_POLL_PERIOD_MS);
5051 }
Eric Laurent212532b2014-07-21 15:43:18 -07005052 // Television devices without CEC service apply software volume on HDMI output
5053 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
5054 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
5055 checkAllFixedVolumeDevices();
5056 if (mHdmiManager != null) {
5057 synchronized (mHdmiManager) {
5058 if (mHdmiPlaybackClient != null) {
5059 mHdmiCecSink = false;
5060 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
5061 }
5062 }
5063 }
5064 }
5065 } else {
5066 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
5067 if (mHdmiManager != null) {
5068 synchronized (mHdmiManager) {
5069 mHdmiCecSink = false;
5070 }
5071 }
5072 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005073 }
Paul McLean10804eb2015-01-28 11:16:35 -08005074 if (!isUsb && device != AudioSystem.DEVICE_IN_WIRED_HEADSET) {
5075 sendDeviceConnectionIntent(device, state, address, deviceName);
Mike Lockwooddb454842012-09-18 11:16:57 -07005076 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005077 }
5078 }
5079
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005080 private void configureHdmiPlugIntent(Intent intent, int state) {
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005081 intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
5082 intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005083 if (state == 1) {
5084 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
5085 int[] portGeneration = new int[1];
5086 int status = AudioSystem.listAudioPorts(ports, portGeneration);
5087 if (status == AudioManager.SUCCESS) {
5088 for (AudioPort port : ports) {
5089 if (port instanceof AudioDevicePort) {
5090 final AudioDevicePort devicePort = (AudioDevicePort) port;
Eric Laurent6fa42452015-01-09 15:09:40 -08005091 if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
5092 devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005093 // format the list of supported encodings
Eric Laurentcae34662015-05-19 16:46:52 -07005094 int[] formats = AudioFormat.filterPublicFormats(devicePort.formats());
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005095 if (formats.length > 0) {
5096 ArrayList<Integer> encodingList = new ArrayList(1);
5097 for (int format : formats) {
5098 // a format in the list can be 0, skip it
5099 if (format != AudioFormat.ENCODING_INVALID) {
5100 encodingList.add(format);
5101 }
5102 }
5103 int[] encodingArray = new int[encodingList.size()];
5104 for (int i = 0 ; i < encodingArray.length ; i++) {
5105 encodingArray[i] = encodingList.get(i);
5106 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005107 intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005108 }
5109 // find the maximum supported number of channels
5110 int maxChannels = 0;
5111 for (int mask : devicePort.channelMasks()) {
5112 int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
5113 if (channelCount > maxChannels) {
5114 maxChannels = channelCount;
5115 }
5116 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005117 intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005118 }
5119 }
5120 }
5121 }
5122 }
5123 }
5124
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07005125 /* cache of the address of the last dock the device was connected to */
5126 private String mDockAddress;
5127
Eric Laurenta553c252009-07-17 12:17:14 -07005128 /**
5129 * Receiver for misc intent broadcasts the Phone app cares about.
5130 */
5131 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
5132 @Override
5133 public void onReceive(Context context, Intent intent) {
5134 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07005135 int outDevice;
5136 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07005137 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07005138
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08005139 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
5140 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
5141 Intent.EXTRA_DOCK_STATE_UNDOCKED);
5142 int config;
5143 switch (dockState) {
5144 case Intent.EXTRA_DOCK_STATE_DESK:
5145 config = AudioSystem.FORCE_BT_DESK_DOCK;
5146 break;
5147 case Intent.EXTRA_DOCK_STATE_CAR:
5148 config = AudioSystem.FORCE_BT_CAR_DOCK;
5149 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05005150 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08005151 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05005152 break;
5153 case Intent.EXTRA_DOCK_STATE_HE_DESK:
5154 config = AudioSystem.FORCE_DIGITAL_DOCK;
5155 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08005156 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
5157 default:
5158 config = AudioSystem.FORCE_NONE;
5159 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08005160 // Low end docks have a menu to enable or disable audio
5161 // (see mDockAudioMediaEnabled)
5162 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
5163 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
5164 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
5165 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
5166 }
5167 mDockState = dockState;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07005168 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
Eric Laurent59f48272012-04-05 19:42:21 -07005169 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07005170 BluetoothProfile.STATE_DISCONNECTED);
Eric Laurentdca56b92011-09-02 14:20:56 -07005171 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Eric Laurent0867bed2015-05-20 14:49:08 -07005172
Eric Laurent98859b22015-06-12 14:35:59 -07005173 setBtScoDeviceConnectionState(btDevice, state);
Paul McLeandf361462014-04-10 16:02:55 -07005174 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005175 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07005176 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005177 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005178 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07005179 // broadcast intent if the connection was initated by AudioService
5180 if (!mScoClients.isEmpty() &&
5181 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
5182 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
5183 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005184 broadcast = true;
5185 }
5186 switch (btState) {
5187 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07005188 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07005189 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5190 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5191 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005192 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005193 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005194 break;
5195 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07005196 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08005197 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07005198 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08005199 break;
5200 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07005201 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5202 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5203 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005204 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005205 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005206 default:
5207 // do not broadcast CONNECTING or invalid state
5208 broadcast = false;
5209 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005210 }
5211 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005212 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07005213 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07005214 //FIXME: this is to maintain compatibility with deprecated intent
5215 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08005216 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07005217 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005218 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08005219 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005220 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06005221 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005222 RotationHelper.enable();
Jon Eklund318f0fe2014-01-23 17:53:48 -06005223 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005224 AudioSystem.setParameters("screen_state=on");
5225 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06005226 if (mMonitorRotation) {
5227 //reduce wakeups (save current) by only listening when display is on
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005228 RotationHelper.disable();
Jon Eklund318f0fe2014-01-23 17:53:48 -06005229 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005230 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07005231 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005232 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07005233 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Yasuhiro Matsuda4ced7192015-07-10 22:08:44 +09005234 if (mUserSwitchedReceived) {
5235 // attempt to stop music playback for background user except on first user
5236 // switch (i.e. first boot)
5237 sendMsg(mAudioHandler,
5238 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
5239 SENDMSG_REPLACE,
5240 0,
5241 0,
5242 null,
5243 0);
5244 }
5245 mUserSwitchedReceived = true;
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07005246 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005247 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07005248
Eric Laurent5bfaeae2012-09-21 18:44:48 -07005249 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07005250 readAudioSettings(true /*userSwitch*/);
5251 // preserve STREAM_MUSIC volume from one user to the next.
5252 sendMsg(mAudioHandler,
5253 MSG_SET_ALL_VOLUMES,
5254 SENDMSG_QUEUE,
5255 0,
5256 0,
5257 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005258 } else if (action.equals(Intent.ACTION_USER_BACKGROUND)) {
5259 // Disable audio recording for the background user/profile
5260 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
5261 if (userId >= 0) {
5262 // TODO Kill recording streams instead of killing processes holding permission
5263 UserInfo userInfo = UserManagerService.getInstance().getUserInfo(userId);
5264 killBackgroundUserProcessesWithRecordAudioPermission(userInfo);
5265 }
Makoto Onukiac65e1e2015-11-20 15:33:17 -08005266 UserManagerService.getInstance().setUserRestriction(
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005267 UserManager.DISALLOW_RECORD_AUDIO, true, userId);
5268 } else if (action.equals(Intent.ACTION_USER_FOREGROUND)) {
5269 // Enable audio recording for foreground user/profile
5270 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Makoto Onukiac65e1e2015-11-20 15:33:17 -08005271 UserManagerService.getInstance().setUserRestriction(
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005272 UserManager.DISALLOW_RECORD_AUDIO, false, userId);
Eric Laurentb70b78a2016-01-13 19:16:04 -08005273 } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
5274 state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
5275 if (state == BluetoothAdapter.STATE_OFF ||
5276 state == BluetoothAdapter.STATE_TURNING_OFF) {
5277 disconnectAllBluetoothProfiles();
5278 }
Eric Laurenta553c252009-07-17 12:17:14 -07005279 }
5280 }
Paul McLeanc837a452014-04-09 09:04:43 -07005281 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005282
Makoto Onukid45a4a22015-11-02 17:17:38 -08005283 private class AudioServiceUserRestrictionsListener implements UserRestrictionsListener {
5284
5285 @Override
5286 public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
5287 Bundle prevRestrictions) {
5288 // Update mic mute state.
5289 {
5290 final boolean wasRestricted =
5291 prevRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
5292 final boolean isRestricted =
5293 newRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
5294 if (wasRestricted != isRestricted) {
5295 setMicrophoneMuteNoCallerCheck(isRestricted, userId);
5296 }
5297 }
5298
5299 // Update speaker mute state.
5300 {
5301 final boolean wasRestricted =
5302 prevRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME);
5303 final boolean isRestricted =
5304 newRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME);
5305 if (wasRestricted != isRestricted) {
5306 setMasterMuteInternalNoCallerCheck(isRestricted, /* flags =*/ 0, userId);
5307 }
5308 }
5309 }
5310 } // end class AudioServiceUserRestrictionsListener
5311
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005312 private void killBackgroundUserProcessesWithRecordAudioPermission(UserInfo oldUser) {
5313 PackageManager pm = mContext.getPackageManager();
5314 // Find the home activity of the user. It should not be killed to avoid expensive restart,
5315 // when the user switches back. For managed profiles, we should kill all recording apps
5316 ComponentName homeActivityName = null;
5317 if (!oldUser.isManagedProfile()) {
5318 homeActivityName = LocalServices.getService(ActivityManagerInternal.class)
5319 .getHomeActivityForUser(oldUser.id);
5320 }
5321 final String[] permissions = { Manifest.permission.RECORD_AUDIO };
5322 List<PackageInfo> packages;
5323 try {
5324 packages = AppGlobals.getPackageManager()
5325 .getPackagesHoldingPermissions(permissions, 0, oldUser.id).getList();
5326 } catch (RemoteException e) {
5327 throw new AndroidRuntimeException(e);
5328 }
5329 for (int j = packages.size() - 1; j >= 0; j--) {
5330 PackageInfo pkg = packages.get(j);
Fyodor Kupolovbcb6c1e2015-05-11 12:05:15 -07005331 // Skip system processes
5332 if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
5333 continue;
5334 }
Amith Yamasanic1cbaab2015-07-21 11:46:14 -07005335 // Skip packages that have permission to interact across users
5336 if (pm.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS, pkg.packageName)
5337 == PackageManager.PERMISSION_GRANTED) {
5338 continue;
5339 }
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005340 if (homeActivityName != null
5341 && pkg.packageName.equals(homeActivityName.getPackageName())
5342 && pkg.applicationInfo.isSystemApp()) {
5343 continue;
5344 }
5345 try {
Svetoslavaa41add2015-08-06 15:03:55 -07005346 final int uid = pkg.applicationInfo.uid;
5347 ActivityManagerNative.getDefault().killUid(UserHandle.getAppId(uid),
5348 UserHandle.getUserId(uid),
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005349 "killBackgroundUserProcessesWithAudioRecordPermission");
5350 } catch (RemoteException e) {
5351 Log.w(TAG, "Error calling killUid", e);
5352 }
5353 }
5354 }
5355
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005356
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005357 //==========================================================================================
5358 // Audio Focus
5359 //==========================================================================================
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005360 public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005361 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005362 IAudioPolicyCallback pcb) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005363 // permission checks
5364 if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
John Spurlock61560172015-02-06 19:46:04 -05005365 if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005366 if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
5367 android.Manifest.permission.MODIFY_PHONE_STATE)) {
5368 Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
5369 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5370 }
5371 } else {
5372 // only a registered audio policy can be used to lock focus
5373 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005374 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
5375 Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005376 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5377 }
5378 }
5379 }
5380 }
5381
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005382 return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
5383 clientId, callingPackageName, flags);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005384 }
5385
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005386 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
5387 return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005388 }
5389
5390 public void unregisterAudioFocusClient(String clientId) {
5391 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005392 }
5393
Jean-Michel Trivi23805662013-07-31 14:19:18 -07005394 public int getCurrentAudioFocus() {
5395 return mMediaFocusControl.getCurrentAudioFocus();
5396 }
5397
John Spurlock5e783732015-02-19 10:28:59 -05005398 private boolean readCameraSoundForced() {
5399 return SystemProperties.getBoolean("audio.camerasound.force", false) ||
5400 mContext.getResources().getBoolean(
5401 com.android.internal.R.bool.config_camera_sound_forced);
5402 }
5403
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005404 //==========================================================================================
5405 // Device orientation
5406 //==========================================================================================
5407 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005408 * Handles device configuration changes that may map to a change in the orientation
5409 * or orientation.
5410 * Monitoring orientation and rotation is optional, and is defined by the definition and value
5411 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005412 */
5413 private void handleConfigurationChanged(Context context) {
5414 try {
5415 // reading new orientation "safely" (i.e. under try catch) in case anything
5416 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07005417 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005418 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07005419 if (mMonitorOrientation) {
5420 int newOrientation = config.orientation;
5421 if (newOrientation != mDeviceOrientation) {
5422 mDeviceOrientation = newOrientation;
5423 setOrientationForAudioSystem();
5424 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005425 }
Eric Laurentd640bd32012-09-28 18:01:48 -07005426 sendMsg(mAudioHandler,
5427 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
5428 SENDMSG_REPLACE,
5429 0,
5430 0,
John Spurlock90874332015-03-10 16:00:54 -04005431 TAG,
Eric Laurentd640bd32012-09-28 18:01:48 -07005432 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07005433
John Spurlock5e783732015-02-19 10:28:59 -05005434 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -07005435 synchronized (mSettingsLock) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005436 boolean cameraSoundForcedChanged = false;
Eric Laurentdd45d012012-10-08 09:04:34 -07005437 synchronized (mCameraSoundForced) {
5438 if (cameraSoundForced != mCameraSoundForced) {
5439 mCameraSoundForced = cameraSoundForced;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005440 cameraSoundForcedChanged = true;
Eric Laurentdd45d012012-10-08 09:04:34 -07005441 }
5442 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005443 if (cameraSoundForcedChanged) {
5444 if (!isPlatformTelevision()) {
5445 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
5446 if (cameraSoundForced) {
5447 s.setAllIndexesToMax();
5448 mRingerModeAffectedStreams &=
5449 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5450 } else {
John Spurlock90874332015-03-10 16:00:54 -04005451 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005452 mRingerModeAffectedStreams |=
5453 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5454 }
5455 // take new state into account for streams muted by ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05005456 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005457 }
5458
5459 sendMsg(mAudioHandler,
5460 MSG_SET_FORCE_USE,
5461 SENDMSG_QUEUE,
5462 AudioSystem.FOR_SYSTEM,
5463 cameraSoundForced ?
5464 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
5465 null,
5466 0);
5467
5468 sendMsg(mAudioHandler,
5469 MSG_SET_ALL_VOLUMES,
5470 SENDMSG_QUEUE,
5471 0,
5472 0,
5473 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
5474 }
Eric Laurentdd45d012012-10-08 09:04:34 -07005475 }
John Spurlock3346a802014-05-20 16:25:37 -04005476 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005477 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005478 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005479 }
5480 }
5481
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005482 //TODO move to an external "orientation helper" class
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005483 private void setOrientationForAudioSystem() {
5484 switch (mDeviceOrientation) {
5485 case Configuration.ORIENTATION_LANDSCAPE:
5486 //Log.i(TAG, "orientation is landscape");
5487 AudioSystem.setParameters("orientation=landscape");
5488 break;
5489 case Configuration.ORIENTATION_PORTRAIT:
5490 //Log.i(TAG, "orientation is portrait");
5491 AudioSystem.setParameters("orientation=portrait");
5492 break;
5493 case Configuration.ORIENTATION_SQUARE:
5494 //Log.i(TAG, "orientation is square");
5495 AudioSystem.setParameters("orientation=square");
5496 break;
5497 case Configuration.ORIENTATION_UNDEFINED:
5498 //Log.i(TAG, "orientation is undefined");
5499 AudioSystem.setParameters("orientation=undefined");
5500 break;
5501 default:
5502 Log.e(TAG, "Unknown orientation");
5503 }
5504 }
5505
Eric Laurent78472112012-05-21 08:57:21 -07005506 // Handles request to override default use of A2DP for media.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005507 // Must be called synchronized on mConnectedDevices
Eric Laurent78472112012-05-21 08:57:21 -07005508 public void setBluetoothA2dpOnInt(boolean on) {
5509 synchronized (mBluetoothA2dpEnabledLock) {
5510 mBluetoothA2dpEnabled = on;
Eric Laurentc390bed2012-07-03 12:24:05 -07005511 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005512 setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
Eric Laurentc390bed2012-07-03 12:24:05 -07005513 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
Eric Laurent78472112012-05-21 08:57:21 -07005514 }
5515 }
5516
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005517 // Must be called synchronized on mConnectedDevices
5518 private void setForceUseInt_SyncDevices(int usage, int config) {
5519 switch (usage) {
5520 case AudioSystem.FOR_MEDIA:
5521 if (config == AudioSystem.FORCE_NO_BT_A2DP) {
5522 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ALL_A2DP;
5523 } else { // config == AudioSystem.FORCE_NONE
5524 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
5525 }
5526 break;
5527 case AudioSystem.FOR_DOCK:
5528 if (config == AudioSystem.FORCE_ANALOG_DOCK) {
5529 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5530 } else { // config == AudioSystem.FORCE_NONE
5531 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5532 }
5533 break;
5534 default:
5535 // usage doesn't affect the broadcast of ACTION_AUDIO_BECOMING_NOISY
5536 }
5537 AudioSystem.setForceUse(usage, config);
5538 }
5539
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005540 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07005541 public void setRingtonePlayer(IRingtonePlayer player) {
5542 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5543 mRingtonePlayer = player;
5544 }
5545
5546 @Override
5547 public IRingtonePlayer getRingtonePlayer() {
5548 return mRingtonePlayer;
5549 }
5550
5551 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07005552 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5553 synchronized (mCurAudioRoutes) {
5554 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5555 mRoutesObservers.register(observer);
5556 return routes;
5557 }
5558 }
5559
Eric Laurentc34dcc12012-09-10 13:51:52 -07005560
5561 //==========================================================================================
5562 // Safe media volume management.
5563 // MUSIC stream volume level is limited when headphones are connected according to safety
5564 // regulation. When the user attempts to raise the volume above the limit, a warning is
5565 // displayed and the user has to acknowlegde before the volume is actually changed.
5566 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
5567 // property. Platforms with a different limit must set this property accordingly in their
5568 // overlay.
5569 //==========================================================================================
5570
Eric Laurentd640bd32012-09-28 18:01:48 -07005571 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
5572 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
5573 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
5574 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
5575 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
5576 // (when user opts out).
John Spurlock35134602014-07-24 18:10:48 -04005577 private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
5578 private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
5579 private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed
5580 private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
Eric Laurentd640bd32012-09-28 18:01:48 -07005581 private Integer mSafeMediaVolumeState;
5582
5583 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005584 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07005585 private int mSafeMediaVolumeIndex;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005586 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
5587 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
5588 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
5589 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
5590 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
5591 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
5592 private int mMusicActiveMs;
5593 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
5594 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07005595 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07005596
John Spurlock90874332015-03-10 16:00:54 -04005597 private void setSafeMediaVolumeEnabled(boolean on, String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005598 synchronized (mSafeMediaVolumeState) {
5599 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
5600 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
5601 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
5602 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
John Spurlock90874332015-03-10 16:00:54 -04005603 enforceSafeMediaVolume(caller);
Eric Laurentd640bd32012-09-28 18:01:48 -07005604 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
5605 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005606 mMusicActiveMs = 1; // nonzero = confirmed
5607 saveMusicActiveMs();
Eric Laurentd640bd32012-09-28 18:01:48 -07005608 sendMsg(mAudioHandler,
5609 MSG_CHECK_MUSIC_ACTIVE,
5610 SENDMSG_REPLACE,
5611 0,
5612 0,
John Spurlock90874332015-03-10 16:00:54 -04005613 caller,
Eric Laurentd640bd32012-09-28 18:01:48 -07005614 MUSIC_ACTIVE_POLL_PERIOD_MS);
5615 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005616 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005617 }
5618 }
5619
John Spurlock90874332015-03-10 16:00:54 -04005620 private void enforceSafeMediaVolume(String caller) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005621 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07005622 int devices = mSafeMediaVolumeDevices;
5623 int i = 0;
5624
5625 while (devices != 0) {
5626 int device = 1 << i++;
5627 if ((device & devices) == 0) {
5628 continue;
5629 }
Eric Laurent42b041e2013-03-29 11:36:03 -07005630 int index = streamState.getIndex(device);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005631 if (index > mSafeMediaVolumeIndex) {
John Spurlock90874332015-03-10 16:00:54 -04005632 streamState.setIndex(mSafeMediaVolumeIndex, device, caller);
Eric Laurent42b041e2013-03-29 11:36:03 -07005633 sendMsg(mAudioHandler,
5634 MSG_SET_DEVICE_VOLUME,
5635 SENDMSG_QUEUE,
5636 device,
5637 0,
5638 streamState,
5639 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005640 }
5641 devices &= ~device;
5642 }
5643 }
5644
5645 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005646 synchronized (mSafeMediaVolumeState) {
5647 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07005648 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
5649 ((device & mSafeMediaVolumeDevices) != 0) &&
5650 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005651 return false;
5652 }
5653 return true;
5654 }
5655 }
5656
John Spurlock3346a802014-05-20 16:25:37 -04005657 @Override
John Spurlock90874332015-03-10 16:00:54 -04005658 public void disableSafeMediaVolume(String callingPackage) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005659 enforceVolumeController("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07005660 synchronized (mSafeMediaVolumeState) {
John Spurlock90874332015-03-10 16:00:54 -04005661 setSafeMediaVolumeEnabled(false, callingPackage);
Eric Laurentfde16d52012-12-03 14:42:39 -08005662 if (mPendingVolumeCommand != null) {
5663 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
5664 mPendingVolumeCommand.mIndex,
5665 mPendingVolumeCommand.mFlags,
John Spurlock90874332015-03-10 16:00:54 -04005666 mPendingVolumeCommand.mDevice,
5667 callingPackage);
Eric Laurentfde16d52012-12-03 14:42:39 -08005668 mPendingVolumeCommand = null;
5669 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005670 }
5671 }
5672
Jungshik Jang41d97462014-06-30 22:26:29 +09005673 //==========================================================================================
5674 // Hdmi Cec system audio mode.
John Spurlockbc82b122015-03-02 16:12:38 -05005675 // If Hdmi Cec's system audio mode is on, audio service should send the volume change
5676 // to HdmiControlService so that the audio receiver can handle it.
Jungshik Jang41d97462014-06-30 22:26:29 +09005677 //==========================================================================================
5678
Eric Laurent212532b2014-07-21 15:43:18 -07005679 private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
5680 public void onComplete(int status) {
5681 if (mHdmiManager != null) {
5682 synchronized (mHdmiManager) {
5683 mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
5684 // Television devices without CEC service apply software volume on HDMI output
5685 if (isPlatformTelevision() && !mHdmiCecSink) {
5686 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5687 }
5688 checkAllFixedVolumeDevices();
5689 }
5690 }
5691 }
5692 };
5693
Jungshik Jang41d97462014-06-30 22:26:29 +09005694 // If HDMI-CEC system audio is supported
5695 private boolean mHdmiSystemAudioSupported = false;
5696 // Set only when device is tv.
5697 private HdmiTvClient mHdmiTvClient;
Eric Laurent0b03f992014-11-18 18:08:02 -08005698 // true if the device has system feature PackageManager.FEATURE_LEANBACK.
Eric Laurent212532b2014-07-21 15:43:18 -07005699 // cached HdmiControlManager interface
5700 private HdmiControlManager mHdmiManager;
5701 // Set only when device is a set-top box.
5702 private HdmiPlaybackClient mHdmiPlaybackClient;
5703 // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5704 private boolean mHdmiCecSink;
5705
5706 private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
Jungshik Jang41d97462014-06-30 22:26:29 +09005707
5708 @Override
Jungshik Jang12307ca2014-07-15 19:27:56 +09005709 public int setHdmiSystemAudioSupported(boolean on) {
Eric Laurent212532b2014-07-21 15:43:18 -07005710 int device = AudioSystem.DEVICE_NONE;
5711 if (mHdmiManager != null) {
5712 synchronized (mHdmiManager) {
5713 if (mHdmiTvClient == null) {
5714 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5715 return device;
5716 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005717
Eric Laurent212532b2014-07-21 15:43:18 -07005718 synchronized (mHdmiTvClient) {
5719 if (mHdmiSystemAudioSupported != on) {
5720 mHdmiSystemAudioSupported = on;
5721 AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5722 on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5723 AudioSystem.FORCE_NONE);
5724 }
John Spurlock8a52c442015-03-26 14:23:58 -04005725 device = getDevicesForStream(AudioSystem.STREAM_MUSIC);
Eric Laurent212532b2014-07-21 15:43:18 -07005726 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005727 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005728 }
Eric Laurent212532b2014-07-21 15:43:18 -07005729 return device;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005730 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005731
Terry Heoe7d6d972014-09-04 21:05:28 +09005732 @Override
5733 public boolean isHdmiSystemAudioSupported() {
5734 return mHdmiSystemAudioSupported;
5735 }
5736
Eric Laurentdd45d012012-10-08 09:04:34 -07005737 //==========================================================================================
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005738 // Accessibility: taking touch exploration into account for selecting the default
5739 // stream override timeout when adjusting volume
5740 //==========================================================================================
5741 private static class StreamOverride
5742 implements AccessibilityManager.TouchExplorationStateChangeListener {
5743
5744 // AudioService.getActiveStreamType() will return:
5745 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
5746 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
5747 // stopped
Jean-Michel Triviccffda82015-05-21 18:23:57 -07005748 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 0;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005749 private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
5750
5751 static int sDelayMs;
5752
5753 static void init(Context ctxt) {
5754 AccessibilityManager accessibilityManager =
5755 (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
5756 updateDefaultStreamOverrideDelay(
5757 accessibilityManager.isTouchExplorationEnabled());
5758 accessibilityManager.addTouchExplorationStateChangeListener(
5759 new StreamOverride());
5760 }
5761
5762 @Override
5763 public void onTouchExplorationStateChanged(boolean enabled) {
5764 updateDefaultStreamOverrideDelay(enabled);
5765 }
5766
5767 private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
5768 if (touchExploreEnabled) {
5769 sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
5770 } else {
5771 sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
5772 }
5773 if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
5774 + " stream override delay is now " + sDelayMs + " ms");
5775 }
5776 }
5777
5778 //==========================================================================================
Eric Laurentdd45d012012-10-08 09:04:34 -07005779 // Camera shutter sound policy.
5780 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5781 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5782 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5783 //==========================================================================================
5784
5785 // cached value of com.android.internal.R.bool.config_camera_sound_forced
5786 private Boolean mCameraSoundForced;
5787
5788 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5789 public boolean isCameraSoundForced() {
5790 synchronized (mCameraSoundForced) {
5791 return mCameraSoundForced;
5792 }
5793 }
5794
5795 private static final String[] RINGER_MODE_NAMES = new String[] {
5796 "SILENT",
5797 "VIBRATE",
5798 "NORMAL"
5799 };
5800
5801 private void dumpRingerMode(PrintWriter pw) {
5802 pw.println("\nRinger mode: ");
John Spurlock661f2cf2014-11-17 10:29:10 -05005803 pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
5804 pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
John Spurlock50ced3f2015-05-11 16:00:09 -04005805 dumpRingerModeStreams(pw, "affected", mRingerModeAffectedStreams);
5806 dumpRingerModeStreams(pw, "muted", mRingerModeMutedStreams);
John Spurlock661f2cf2014-11-17 10:29:10 -05005807 pw.print("- delegate = "); pw.println(mRingerModeDelegate);
Eric Laurentdd45d012012-10-08 09:04:34 -07005808 }
5809
John Spurlock50ced3f2015-05-11 16:00:09 -04005810 private void dumpRingerModeStreams(PrintWriter pw, String type, int streams) {
5811 pw.print("- ringer mode "); pw.print(type); pw.print(" streams = 0x");
5812 pw.print(Integer.toHexString(streams));
5813 if (streams != 0) {
5814 pw.print(" (");
5815 boolean first = true;
5816 for (int i = 0; i < AudioSystem.STREAM_NAMES.length; i++) {
5817 final int stream = (1 << i);
5818 if ((streams & stream) != 0) {
5819 if (!first) pw.print(',');
5820 pw.print(AudioSystem.STREAM_NAMES[i]);
5821 streams &= ~stream;
5822 first = false;
5823 }
5824 }
5825 if (streams != 0) {
5826 if (!first) pw.print(',');
5827 pw.print(streams);
5828 }
5829 pw.print(')');
5830 }
5831 pw.println();
5832 }
5833
Dianne Hackborn632ca412012-06-14 19:34:10 -07005834 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005835 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07005836 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5837
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005838 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07005839 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07005840 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005841 pw.println("\nAudio routes:");
John Spurlock61560172015-02-06 19:46:04 -05005842 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
5843 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
John Spurlock35134602014-07-24 18:10:48 -04005844
5845 pw.println("\nOther state:");
John Spurlock3346a802014-05-20 16:25:37 -04005846 pw.print(" mVolumeController="); pw.println(mVolumeController);
John Spurlock35134602014-07-24 18:10:48 -04005847 pw.print(" mSafeMediaVolumeState=");
5848 pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
5849 pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
5850 pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
5851 pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005852 pw.print(" mMcc="); pw.println(mMcc);
John Spurlock5e783732015-02-19 10:28:59 -05005853 pw.print(" mCameraSoundForced="); pw.println(mCameraSoundForced);
John Spurlock661f2cf2014-11-17 10:29:10 -05005854 pw.print(" mHasVibrator="); pw.println(mHasVibrator);
John Spurlockcdb57ae2015-02-11 19:04:11 -05005855 pw.print(" mControllerService="); pw.println(mControllerService);
John Spurlocka48d7792015-03-03 17:35:57 -05005856 pw.print(" mVolumePolicy="); pw.println(mVolumePolicy);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005857
5858 dumpAudioPolicies(pw);
John Spurlock35134602014-07-24 18:10:48 -04005859 }
5860
5861 private static String safeMediaVolumeStateToString(Integer state) {
5862 switch(state) {
5863 case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
5864 case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
5865 case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
5866 case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
5867 }
5868 return null;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005869 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07005870
5871 // Inform AudioFlinger of our device's low RAM attribute
5872 private static void readAndSetLowRamDevice()
5873 {
5874 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
5875 if (status != 0) {
5876 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
5877 }
5878 }
John Spurlock3346a802014-05-20 16:25:37 -04005879
John Spurlockcdb57ae2015-02-11 19:04:11 -05005880 private void enforceVolumeController(String action) {
5881 if (mControllerService.mUid != 0 && Binder.getCallingUid() == mControllerService.mUid) {
5882 return;
5883 }
John Spurlock3346a802014-05-20 16:25:37 -04005884 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
5885 "Only SystemUI can " + action);
5886 }
5887
5888 @Override
5889 public void setVolumeController(final IVolumeController controller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005890 enforceVolumeController("set the volume controller");
John Spurlock3346a802014-05-20 16:25:37 -04005891
5892 // return early if things are not actually changing
5893 if (mVolumeController.isSameBinder(controller)) {
5894 return;
5895 }
5896
5897 // dismiss the old volume controller
5898 mVolumeController.postDismiss();
5899 if (controller != null) {
5900 // we are about to register a new controller, listen for its death
5901 try {
5902 controller.asBinder().linkToDeath(new DeathRecipient() {
5903 @Override
5904 public void binderDied() {
5905 if (mVolumeController.isSameBinder(controller)) {
5906 Log.w(TAG, "Current remote volume controller died, unregistering");
5907 setVolumeController(null);
5908 }
5909 }
5910 }, 0);
5911 } catch (RemoteException e) {
5912 // noop
5913 }
5914 }
5915 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04005916 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
5917 }
5918
5919 @Override
5920 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005921 enforceVolumeController("notify about volume controller visibility");
John Spurlock33f4e042014-07-11 13:10:58 -04005922
5923 // return early if the controller is not current
5924 if (!mVolumeController.isSameBinder(controller)) {
5925 return;
5926 }
5927
5928 mVolumeController.setVisible(visible);
5929 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04005930 }
RoboErikd09bd0c2014-06-24 17:45:19 -07005931
John Spurlocka48d7792015-03-03 17:35:57 -05005932 @Override
5933 public void setVolumePolicy(VolumePolicy policy) {
5934 enforceVolumeController("set volume policy");
John Spurlockb02c7442015-04-14 09:32:25 -04005935 if (policy != null && !policy.equals(mVolumePolicy)) {
John Spurlocka48d7792015-03-03 17:35:57 -05005936 mVolumePolicy = policy;
John Spurlockb02c7442015-04-14 09:32:25 -04005937 if (DEBUG_VOL) Log.d(TAG, "Volume policy changed: " + mVolumePolicy);
John Spurlocka48d7792015-03-03 17:35:57 -05005938 }
5939 }
5940
RoboErikd09bd0c2014-06-24 17:45:19 -07005941 public static class VolumeController {
5942 private static final String TAG = "VolumeController";
5943
5944 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04005945 private boolean mVisible;
5946 private long mNextLongPress;
5947 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07005948
5949 public void setController(IVolumeController controller) {
5950 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04005951 mVisible = false;
5952 }
5953
5954 public void loadSettings(ContentResolver cr) {
5955 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
5956 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
5957 }
5958
RoboErik4197cb62015-01-21 15:45:32 -08005959 public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
5960 if (isMute) {
5961 return false;
5962 }
John Spurlock33f4e042014-07-11 13:10:58 -04005963 boolean suppress = false;
5964 if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
5965 final long now = SystemClock.uptimeMillis();
5966 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
5967 // ui will become visible
5968 if (mNextLongPress < now) {
5969 mNextLongPress = now + mLongPressTimeout;
5970 }
5971 suppress = true;
5972 } else if (mNextLongPress > 0) { // in a long-press
5973 if (now > mNextLongPress) {
5974 // long press triggered, no more suppression
5975 mNextLongPress = 0;
5976 } else {
5977 // keep suppressing until the long press triggers
5978 suppress = true;
5979 }
5980 }
5981 }
5982 return suppress;
5983 }
5984
5985 public void setVisible(boolean visible) {
5986 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07005987 }
5988
5989 public boolean isSameBinder(IVolumeController controller) {
5990 return Objects.equals(asBinder(), binder(controller));
5991 }
5992
5993 public IBinder asBinder() {
5994 return binder(mController);
5995 }
5996
5997 private static IBinder binder(IVolumeController controller) {
5998 return controller == null ? null : controller.asBinder();
5999 }
6000
6001 @Override
6002 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04006003 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07006004 }
6005
6006 public void postDisplaySafeVolumeWarning(int flags) {
6007 if (mController == null)
6008 return;
6009 try {
6010 mController.displaySafeVolumeWarning(flags);
6011 } catch (RemoteException e) {
6012 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
6013 }
6014 }
6015
6016 public void postVolumeChanged(int streamType, int flags) {
6017 if (mController == null)
6018 return;
6019 try {
6020 mController.volumeChanged(streamType, flags);
6021 } catch (RemoteException e) {
6022 Log.w(TAG, "Error calling volumeChanged", e);
6023 }
6024 }
6025
RoboErikd09bd0c2014-06-24 17:45:19 -07006026 public void postMasterMuteChanged(int flags) {
6027 if (mController == null)
6028 return;
6029 try {
6030 mController.masterMuteChanged(flags);
6031 } catch (RemoteException e) {
6032 Log.w(TAG, "Error calling masterMuteChanged", e);
6033 }
6034 }
6035
6036 public void setLayoutDirection(int layoutDirection) {
6037 if (mController == null)
6038 return;
6039 try {
6040 mController.setLayoutDirection(layoutDirection);
6041 } catch (RemoteException e) {
6042 Log.w(TAG, "Error calling setLayoutDirection", e);
6043 }
6044 }
6045
6046 public void postDismiss() {
6047 if (mController == null)
6048 return;
6049 try {
6050 mController.dismiss();
6051 } catch (RemoteException e) {
6052 Log.w(TAG, "Error calling dismiss", e);
6053 }
6054 }
6055 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006056
RoboErik0dac35a2014-08-12 15:48:49 -07006057 /**
6058 * Interface for system components to get some extra functionality through
6059 * LocalServices.
6060 */
6061 final class AudioServiceInternal extends AudioManagerInternal {
John Spurlock661f2cf2014-11-17 10:29:10 -05006062 @Override
6063 public void setRingerModeDelegate(RingerModeDelegate delegate) {
6064 mRingerModeDelegate = delegate;
6065 if (mRingerModeDelegate != null) {
John Spurlock50ced3f2015-05-11 16:00:09 -04006066 updateRingerModeAffectedStreams();
John Spurlock661f2cf2014-11-17 10:29:10 -05006067 setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
6068 }
6069 }
RoboErik272e1612014-09-05 11:39:29 -07006070
6071 @Override
6072 public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
6073 String callingPackage, int uid) {
6074 // direction and stream type swap here because the public
6075 // adjustSuggested has a different order than the other methods.
John Spurlock90874332015-03-10 16:00:54 -04006076 adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage,
6077 callingPackage, uid);
RoboErik272e1612014-09-05 11:39:29 -07006078 }
6079
RoboErik0dac35a2014-08-12 15:48:49 -07006080 @Override
6081 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
6082 String callingPackage, int uid) {
John Spurlock90874332015-03-10 16:00:54 -04006083 adjustStreamVolume(streamType, direction, flags, callingPackage,
6084 callingPackage, uid);
RoboErik0dac35a2014-08-12 15:48:49 -07006085 }
6086
6087 @Override
6088 public void setStreamVolumeForUid(int streamType, int direction, int flags,
6089 String callingPackage, int uid) {
John Spurlock90874332015-03-10 16:00:54 -04006090 setStreamVolume(streamType, direction, flags, callingPackage, callingPackage, uid);
RoboErik0dac35a2014-08-12 15:48:49 -07006091 }
RoboErik519c7742014-11-18 10:59:09 -08006092
6093 @Override
John Spurlock661f2cf2014-11-17 10:29:10 -05006094 public int getRingerModeInternal() {
6095 return AudioService.this.getRingerModeInternal();
6096 }
6097
6098 @Override
6099 public void setRingerModeInternal(int ringerMode, String caller) {
6100 AudioService.this.setRingerModeInternal(ringerMode, caller);
6101 }
John Spurlockcdb57ae2015-02-11 19:04:11 -05006102
6103 @Override
6104 public int getVolumeControllerUid() {
6105 return mControllerService.mUid;
6106 }
John Spurlock50ced3f2015-05-11 16:00:09 -04006107
6108 @Override
6109 public void updateRingerModeAffectedStreamsInternal() {
6110 synchronized (mSettingsLock) {
6111 if (updateRingerModeAffectedStreams()) {
6112 setRingerModeInt(getRingerModeInternal(), false);
6113 }
6114 }
6115 }
RoboErik0dac35a2014-08-12 15:48:49 -07006116 }
6117
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006118 //==========================================================================================
6119 // Audio policy management
6120 //==========================================================================================
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006121 public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
6122 boolean hasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006123 AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
6124
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006125 if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
6126 + " with config:" + policyConfig);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006127 String regId = null;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006128 // error handling
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006129 boolean hasPermissionForPolicy =
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006130 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006131 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
6132 if (!hasPermissionForPolicy) {
6133 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
6134 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006135 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006136 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006137
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006138 synchronized (mAudioPolicies) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006139 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006140 if (mAudioPolicies.containsKey(pcb.asBinder())) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006141 Slog.e(TAG, "Cannot re-register policy");
6142 return null;
6143 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006144 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
6145 pcb.asBinder().linkToDeath(app, 0/*flags*/);
6146 regId = app.getRegistrationId();
6147 mAudioPolicies.put(pcb.asBinder(), app);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006148 } catch (RemoteException e) {
6149 // audio policy owner has already died!
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006150 Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006151 " binder death", e);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006152 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006153 }
6154 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006155 return regId;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006156 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006157
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006158 public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
6159 if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006160 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006161 AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006162 if (app == null) {
6163 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
6164 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006165 return;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006166 } else {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006167 pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006168 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006169 app.release();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006170 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006171 // TODO implement clearing mix attribute matching info in native audio policy
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006172 }
6173
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006174 public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
6175 if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
6176 + " policy " + pcb.asBinder());
6177 // error handling
6178 boolean hasPermissionForPolicy =
6179 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
6180 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
6181 if (!hasPermissionForPolicy) {
6182 Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
6183 + Binder.getCallingPid() + " / uid "
6184 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
6185 return AudioManager.ERROR;
6186 }
6187
6188 synchronized (mAudioPolicies) {
6189 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
6190 Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
6191 return AudioManager.ERROR;
6192 }
6193 final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
6194 if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6195 // is there already one policy managing ducking?
Eric Laurent0867bed2015-05-20 14:49:08 -07006196 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006197 if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6198 Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
6199 return AudioManager.ERROR;
6200 }
6201 }
6202 }
6203 app.mFocusDuckBehavior = duckingBehavior;
6204 mMediaFocusControl.setDuckingInExtPolicyAvailable(
6205 duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
6206 }
6207 return AudioManager.SUCCESS;
6208 }
6209
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006210 private void dumpAudioPolicies(PrintWriter pw) {
6211 pw.println("\nAudio policies:");
6212 synchronized (mAudioPolicies) {
Eric Laurent0867bed2015-05-20 14:49:08 -07006213 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006214 pw.println(policy.toLogFriendlyString());
6215 }
6216 }
6217 }
6218
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006219 //======================
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08006220 // Audio policy callbacks from AudioSystem for dynamic policies
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006221 //======================
6222 private final AudioSystem.DynamicPolicyCallback mDynPolicyCallback =
6223 new AudioSystem.DynamicPolicyCallback() {
6224 public void onDynamicPolicyMixStateUpdate(String regId, int state) {
6225 if (!TextUtils.isEmpty(regId)) {
6226 sendMsg(mAudioHandler, MSG_DYN_POLICY_MIX_STATE_UPDATE, SENDMSG_QUEUE,
6227 state /*arg1*/, 0 /*arg2 ignored*/, regId /*obj*/, 0 /*delay*/);
6228 }
6229 }
6230 };
6231
6232 private void onDynPolicyMixStateUpdate(String regId, int state) {
6233 if (DEBUG_AP) Log.d(TAG, "onDynamicPolicyMixStateUpdate("+ regId + ", " + state +")");
6234 synchronized (mAudioPolicies) {
6235 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
6236 for (AudioMix mix : policy.getMixes()) {
6237 if (mix.getRegistration().equals(regId)) {
6238 try {
6239 policy.mPolicyCallback.notifyMixStateUpdate(regId, state);
6240 } catch (RemoteException e) {
6241 Log.e(TAG, "Can't call notifyMixStateUpdate() on IAudioPolicyCallback "
6242 + policy.mPolicyCallback.asBinder(), e);
6243 }
6244 return;
6245 }
6246 }
6247 }
6248 }
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08006249 }
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006250
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08006251 //======================
6252 // Audio policy callbacks from AudioSystem for recording configuration updates
6253 //======================
6254 private final RecordingActivityMonitor mRecordMonitor = new RecordingActivityMonitor();
6255
6256 public void registerRecordingCallback(IRecordingConfigDispatcher rcdb) {
6257 mRecordMonitor.registerRecordingCallback(rcdb);
6258 }
6259
6260 public void unregisterRecordingCallback(IRecordingConfigDispatcher rcdb) {
6261 mRecordMonitor.unregisterRecordingCallback(rcdb);
6262 }
6263
6264 public AudioRecordConfiguration[] getActiveRecordConfigurations() {
6265 return mRecordMonitor.getActiveRecordConfigurations();
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006266 }
6267
6268 //======================
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006269 // Audio policy proxy
6270 //======================
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006271 /**
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006272 * This internal class inherits from AudioPolicyConfig, each instance contains all the
6273 * mixes of an AudioPolicy and their configurations.
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006274 */
6275 public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006276 private static final String TAG = "AudioPolicyProxy";
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006277 IAudioPolicyCallback mPolicyCallback;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006278 boolean mHasFocusListener;
6279 /**
6280 * Audio focus ducking behavior for an audio policy.
6281 * This variable reflects the value that was successfully set in
6282 * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
6283 * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
6284 * is handling ducking for audio focus.
6285 */
6286 int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
6287
6288 AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
6289 boolean hasFocusListener) {
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006290 super(config);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006291 setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006292 mPolicyCallback = token;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006293 mHasFocusListener = hasFocusListener;
6294 if (mHasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006295 mMediaFocusControl.addFocusFollower(mPolicyCallback);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006296 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006297 connectMixes();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006298 }
6299
6300 public void binderDied() {
6301 synchronized (mAudioPolicies) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006302 Log.i(TAG, "audio policy " + mPolicyCallback + " died");
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006303 release();
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006304 mAudioPolicies.remove(mPolicyCallback.asBinder());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006305 }
6306 }
6307
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006308 String getRegistrationId() {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006309 return getRegistration();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006310 }
6311
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006312 void release() {
6313 if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6314 mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
6315 }
6316 if (mHasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006317 mMediaFocusControl.removeFocusFollower(mPolicyCallback);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006318 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006319 AudioSystem.registerPolicyMixes(mMixes, false);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006320 }
6321
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006322 void connectMixes() {
6323 AudioSystem.registerPolicyMixes(mMixes, true);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006324 }
6325 };
6326
6327 private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
6328 new HashMap<IBinder, AudioPolicyProxy>();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006329 private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
John Spurlockcdb57ae2015-02-11 19:04:11 -05006330
6331 private class ControllerService extends ContentObserver {
6332 private int mUid;
6333 private ComponentName mComponent;
6334
6335 public ControllerService() {
6336 super(null);
6337 }
6338
6339 @Override
6340 public String toString() {
6341 return String.format("{mUid=%d,mComponent=%s}", mUid, mComponent);
6342 }
6343
6344 public void init() {
6345 onChange(true);
6346 mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
6347 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT), false, this);
6348 }
6349
6350 @Override
6351 public void onChange(boolean selfChange) {
6352 mUid = 0;
6353 mComponent = null;
6354 final String setting = Settings.Secure.getString(mContentResolver,
6355 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
6356 if (setting == null) return;
6357 try {
6358 mComponent = ComponentName.unflattenFromString(setting);
6359 if (mComponent == null) return;
6360 mUid = mContext.getPackageManager()
6361 .getApplicationInfo(mComponent.getPackageName(), 0).uid;
6362 } catch (Exception e) {
6363 Log.w(TAG, "Error loading controller service", e);
6364 }
6365 if (DEBUG_VOL) Log.d(TAG, "Reloaded controller service: " + this);
6366 }
6367 }
Eric Laurentb70b78a2016-01-13 19:16:04 -08006368}