blob: 0f3f9ce6bfb4c128725348678dd7fd67256a90d0 [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;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070028import android.app.AppGlobals;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -070029import android.app.AppOpsManager;
Julia Reynolds48034f82016-03-09 10:15:16 -050030import android.app.NotificationManager;
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;
Julia Reynolds48034f82016-03-09 10:15:16 -050043import android.content.pm.ApplicationInfo;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070044import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.content.pm.PackageManager;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070046import android.content.pm.UserInfo;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -070047import android.content.res.Configuration;
Eric Laurente78fced2013-03-15 16:03:47 -070048import android.content.res.Resources;
49import android.content.res.XmlResourceParser;
Jason Parekhb1096152009-03-24 17:48:25 -070050import android.database.ContentObserver;
Jungshik Jang41d97462014-06-30 22:26:29 +090051import android.hardware.hdmi.HdmiControlManager;
Eric Laurent212532b2014-07-21 15:43:18 -070052import android.hardware.hdmi.HdmiPlaybackClient;
Jungshik Jang41d97462014-06-30 22:26:29 +090053import android.hardware.hdmi.HdmiTvClient;
Paul McLeanc837a452014-04-09 09:04:43 -070054import android.hardware.usb.UsbManager;
John Spurlock61560172015-02-06 19:46:04 -050055import android.media.AudioAttributes;
56import android.media.AudioDevicePort;
57import android.media.AudioSystem;
58import android.media.AudioFormat;
59import android.media.AudioManager;
60import android.media.AudioManagerInternal;
61import android.media.AudioPort;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080062import android.media.AudioPlaybackConfiguration;
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -080063import android.media.AudioRecordingConfiguration;
John Spurlock61560172015-02-06 19:46:04 -050064import android.media.AudioRoutesInfo;
John Spurlock61560172015-02-06 19:46:04 -050065import android.media.IAudioFocusDispatcher;
66import android.media.IAudioRoutesObserver;
67import android.media.IAudioService;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080068import android.media.IPlaybackConfigDispatcher;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -080069import android.media.IRecordingConfigDispatcher;
John Spurlock61560172015-02-06 19:46:04 -050070import android.media.IRingtonePlayer;
71import android.media.IVolumeController;
72import android.media.MediaPlayer;
73import android.media.SoundPool;
John Spurlocka48d7792015-03-03 17:35:57 -050074import android.media.VolumePolicy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075import android.media.MediaPlayer.OnCompletionListener;
76import android.media.MediaPlayer.OnErrorListener;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080077import android.media.PlayerBase;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -070078import android.media.audiopolicy.AudioMix;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -080079import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070080import android.media.audiopolicy.AudioPolicyConfig;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -080081import android.media.audiopolicy.IAudioPolicyCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082import android.os.Binder;
Eric Laurentc18c9132013-04-12 17:24:56 -070083import android.os.Build;
Makoto Onukid45a4a22015-11-02 17:17:38 -080084import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.os.Environment;
86import android.os.Handler;
87import android.os.IBinder;
88import android.os.Looper;
89import android.os.Message;
Jean-Michel Trivic6802222012-04-30 11:15:03 -070090import android.os.PowerManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070091import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092import android.os.RemoteException;
John Spurlock33f4e042014-07-11 13:10:58 -040093import android.os.SystemClock;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070094import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070095import android.os.UserHandle;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070096import android.os.UserManager;
Makoto Onukid45a4a22015-11-02 17:17:38 -080097import android.os.UserManagerInternal;
98import android.os.UserManagerInternal.UserRestrictionsListener;
Eric Laurentbffc3d12012-05-07 17:43:49 -070099import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100import android.provider.Settings;
101import android.provider.Settings.System;
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700102import android.telecom.TelecomManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -0700103import android.text.TextUtils;
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700104import android.util.AndroidRuntimeException;
John Spurlock8c3dc852015-04-23 21:32:37 -0400105import android.util.ArrayMap;
106import android.util.ArraySet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107import android.util.Log;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400108import android.util.MathUtils;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -0700109import android.util.Slog;
John Spurlock2bb02ec2015-03-02 13:13:06 -0500110import android.util.SparseIntArray;
Jean-Michel Trivid327f212010-03-16 21:44:33 -0700111import android.view.KeyEvent;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700112import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113
Eric Laurente78fced2013-03-15 16:03:47 -0700114import com.android.internal.util.XmlUtils;
John Spurlock90874332015-03-10 16:00:54 -0400115import com.android.server.EventLogTags;
RoboErik0dac35a2014-08-12 15:48:49 -0700116import com.android.server.LocalServices;
Makoto Onukie1aef852015-10-15 17:28:35 -0700117import com.android.server.SystemService;
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700118import com.android.server.pm.UserManagerService;
Eric Laurente78fced2013-03-15 16:03:47 -0700119
120import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800122import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123import java.io.IOException;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800124import java.io.PrintWriter;
Eric Laurente78fced2013-03-15 16:03:47 -0700125import java.lang.reflect.Field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126import java.util.ArrayList;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700127import java.util.HashMap;
128import java.util.Iterator;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -0700129import java.util.List;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700130import java.util.NoSuchElementException;
RoboErikd09bd0c2014-06-24 17:45:19 -0700131import java.util.Objects;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132
133/**
134 * The implementation of the volume manager service.
135 * <p>
136 * This implementation focuses on delivering a responsive UI. Most methods are
137 * asynchronous to external calls. For example, the task of setting a volume
138 * will update our internal state, but in a separate thread will set the system
139 * volume and later persist to the database. Similarly, setting the ringer mode
140 * will update the state and broadcast a change and in a separate thread later
141 * persist the ringer mode.
142 *
143 * @hide
144 */
Jean-Michel Triviac487672016-11-11 10:05:18 -0800145public class AudioService extends IAudioService.Stub
146 implements AccessibilityManager.TouchExplorationStateChangeListener,
147 AccessibilityManager.AccessibilityStateChangeListener{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148
149 private static final String TAG = "AudioService";
150
Jean-Michel Trivi339567d2014-07-29 09:53:34 -0700151 /** Debug audio mode */
152 protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -0700153
154 /** Debug audio policy feature */
155 protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);
156
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700157 /** Debug volumes */
John Spurlockae641c92014-06-30 18:11:40 -0400158 protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700159
Paul McLean394a8e12015-03-03 10:29:19 -0700160 /** debug calls to devices APIs */
161 protected static final boolean DEBUG_DEVICES = Log.isLoggable(TAG + ".DEVICES", Log.DEBUG);
162
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 /** How long to delay before persisting a change in volume/ringer mode. */
RoboErik45edba12012-03-27 17:54:36 -0700164 private static final int PERSIST_DELAY = 500;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165
RoboErik5452e252015-02-06 15:33:53 -0800166 /** How long to delay after a volume down event before unmuting a stream */
167 private static final int UNMUTE_STREAM_DELAY = 350;
168
John Spurlock3346a802014-05-20 16:25:37 -0400169 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400170 * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
171 */
172 private static final int FLAG_ADJUST_VOLUME = 1;
173
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700174 private final Context mContext;
175 private final ContentResolver mContentResolver;
176 private final AppOpsManager mAppOps;
Eric Laurent212532b2014-07-21 15:43:18 -0700177
Eric Laurent212532b2014-07-21 15:43:18 -0700178 // the platform type affects volume and silent mode behavior
179 private final int mPlatformType;
180
Muyuan Li1ed6df62016-06-18 11:16:52 -0700181 // indicates whether the system maps all streams to a single stream.
182 private final boolean mIsSingleVolume;
183
Eric Laurent212532b2014-07-21 15:43:18 -0700184 private boolean isPlatformVoice() {
John Spurlock61560172015-02-06 19:46:04 -0500185 return mPlatformType == AudioSystem.PLATFORM_VOICE;
Eric Laurent212532b2014-07-21 15:43:18 -0700186 }
187
188 private boolean isPlatformTelevision() {
John Spurlock61560172015-02-06 19:46:04 -0500189 return mPlatformType == AudioSystem.PLATFORM_TELEVISION;
Eric Laurent212532b2014-07-21 15:43:18 -0700190 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800191
John Spurlock3346a802014-05-20 16:25:37 -0400192 /** The controller for the volume UI. */
193 private final VolumeController mVolumeController = new VolumeController();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194
195 // sendMsg() flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 /** If the msg is already queued, replace it with this one. */
197 private static final int SENDMSG_REPLACE = 0;
198 /** If the msg is already queued, ignore this one and leave the old. */
199 private static final int SENDMSG_NOOP = 1;
200 /** If the msg is already queued, queue this one and leave the old. */
201 private static final int SENDMSG_QUEUE = 2;
202
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700203 // AudioHandler messages
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800204 private static final int MSG_SET_DEVICE_VOLUME = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205 private static final int MSG_PERSIST_VOLUME = 1;
206 private static final int MSG_PERSIST_RINGER_MODE = 3;
Andy Hunged0ea402015-10-30 14:11:46 -0700207 private static final int MSG_AUDIO_SERVER_DIED = 4;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700208 private static final int MSG_PLAY_SOUND_EFFECT = 5;
209 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
210 private static final int MSG_LOAD_SOUND_EFFECTS = 7;
211 private static final int MSG_SET_FORCE_USE = 8;
212 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
213 private static final int MSG_SET_ALL_VOLUMES = 10;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700214 private static final int MSG_REPORT_NEW_ROUTES = 12;
Sungsoocf09fe62016-09-28 16:21:48 +0900215 private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700216 private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
217 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
218 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
219 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
220 private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
221 private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
222 private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700223 private static final int MSG_SYSTEM_READY = 21;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400224 private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
RoboErik5452e252015-02-06 15:33:53 -0800225 private static final int MSG_UNMUTE_STREAM = 24;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -0700226 private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 25;
Eric Laurent0867bed2015-05-20 14:49:08 -0700227 private static final int MSG_INDICATE_SYSTEM_READY = 26;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700228 // start of messages handled under wakelock
229 // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
Jean-Michel Trivie12c39b2012-06-06 10:51:58 -0700230 // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700231 private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
Mike Lockwood0a40ec22014-05-21 10:08:50 -0700232 private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
233 private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800234 private static final int MSG_A2DP_DEVICE_CONFIG_CHANGE = 103;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700235 // end of messages handled under wakelock
Eric Laurentafbb0472011-12-15 09:04:23 -0800236
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -0700237 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
Eric Laurentdc03c612011-04-01 10:59:41 -0700238 // Timeout for connection to bluetooth headset service
239 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
240
Eric Laurent0867bed2015-05-20 14:49:08 -0700241 // retry delay in case of failure to indicate system ready to AudioFlinger
242 private static final int INDICATE_SYSTEM_READY_RETRY_DELAY_MS = 1000;
243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 /** @see AudioSystemThread */
245 private AudioSystemThread mAudioSystemThread;
246 /** @see AudioHandler */
247 private AudioHandler mAudioHandler;
248 /** @see VolumeStreamState */
249 private VolumeStreamState[] mStreamStates;
Jason Parekhb1096152009-03-24 17:48:25 -0700250 private SettingsObserver mSettingsObserver;
Eric Laurenta553c252009-07-17 12:17:14 -0700251
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700252 private int mMode = AudioSystem.MODE_NORMAL;
Glenn Kastenba195eb2011-12-13 09:30:40 -0800253 // protects mRingerMode
254 private final Object mSettingsLock = new Object();
Eric Laurent45c90ce2012-04-24 18:44:22 -0700255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256 private SoundPool mSoundPool;
Glenn Kasten30c918c2011-11-10 17:56:41 -0800257 private final Object mSoundEffectsLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 private static final int NUM_SOUNDPOOL_CHANNELS = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259
260 /* Sound effect file names */
261 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
Eric Laurente78fced2013-03-15 16:03:47 -0700262 private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263
264 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
265 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
266 * uses soundpool (second column) */
Eric Laurente78fced2013-03-15 16:03:47 -0700267 private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268
John Spurlockb6e19e32015-03-10 21:33:44 -0400269 /** Maximum volume index values for audio streams */
Eric Laurent91377de2014-10-10 15:24:04 -0700270 private static int[] MAX_STREAM_VOLUME = new int[] {
Eric Laurent6ee99522009-08-25 06:30:59 -0700271 5, // STREAM_VOICE_CALL
272 7, // STREAM_SYSTEM
273 7, // STREAM_RING
274 15, // STREAM_MUSIC
275 7, // STREAM_ALARM
276 7, // STREAM_NOTIFICATION
277 15, // STREAM_BLUETOOTH_SCO
278 7, // STREAM_SYSTEM_ENFORCED
279 15, // STREAM_DTMF
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800280 15, // STREAM_TTS
281 15 // STREAM_ACCESSIBILITY
Jared Suttles59820132009-08-13 21:50:52 -0500282 };
Eric Laurent91377de2014-10-10 15:24:04 -0700283
John Spurlockb6e19e32015-03-10 21:33:44 -0400284 /** Minimum volume index values for audio streams */
285 private static int[] MIN_STREAM_VOLUME = new int[] {
286 1, // STREAM_VOICE_CALL
287 0, // STREAM_SYSTEM
288 0, // STREAM_RING
289 0, // STREAM_MUSIC
290 0, // STREAM_ALARM
291 0, // STREAM_NOTIFICATION
Eric Laurente4381ec2015-10-29 17:52:48 -0700292 0, // STREAM_BLUETOOTH_SCO
John Spurlockb6e19e32015-03-10 21:33:44 -0400293 0, // STREAM_SYSTEM_ENFORCED
294 0, // STREAM_DTMF
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800295 0, // STREAM_TTS
296 0 // STREAM_ACCESSIBILITY
John Spurlockb6e19e32015-03-10 21:33:44 -0400297 };
298
Eric Laurent6d517662012-04-23 18:42:39 -0700299 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
Eric Laurenta553c252009-07-17 12:17:14 -0700300 * of another stream: This avoids multiplying the volume settings for hidden
301 * stream types that follow other stream behavior for volume settings
Eric Laurent6d517662012-04-23 18:42:39 -0700302 * NOTE: do not create loops in aliases!
303 * Some streams alias to different streams according to device category (phone or tablet) or
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700304 * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
Eric Laurent212532b2014-07-21 15:43:18 -0700305 * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
306 * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
307 * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
308 private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700309 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
310 AudioSystem.STREAM_RING, // STREAM_SYSTEM
311 AudioSystem.STREAM_RING, // STREAM_RING
312 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
313 AudioSystem.STREAM_ALARM, // STREAM_ALARM
314 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
315 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
316 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
317 AudioSystem.STREAM_RING, // STREAM_DTMF
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800318 AudioSystem.STREAM_MUSIC, // STREAM_TTS
319 AudioSystem.STREAM_MUSIC // STREAM_ACCESSIBILITY
Eric Laurenta553c252009-07-17 12:17:14 -0700320 };
Eric Laurent212532b2014-07-21 15:43:18 -0700321 private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
322 AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL
323 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
324 AudioSystem.STREAM_MUSIC, // STREAM_RING
325 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
326 AudioSystem.STREAM_MUSIC, // STREAM_ALARM
327 AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
328 AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO
329 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
330 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800331 AudioSystem.STREAM_MUSIC, // STREAM_TTS
332 AudioSystem.STREAM_MUSIC // STREAM_ACCESSIBILITY
Eric Laurent212532b2014-07-21 15:43:18 -0700333 };
334 private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700335 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
John Spurlock4f0f1202014-08-05 13:28:33 -0400336 AudioSystem.STREAM_RING, // STREAM_SYSTEM
Eric Laurent6d517662012-04-23 18:42:39 -0700337 AudioSystem.STREAM_RING, // STREAM_RING
338 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
339 AudioSystem.STREAM_ALARM, // STREAM_ALARM
340 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
341 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
John Spurlock4f0f1202014-08-05 13:28:33 -0400342 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
343 AudioSystem.STREAM_RING, // STREAM_DTMF
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800344 AudioSystem.STREAM_MUSIC, // STREAM_TTS
345 AudioSystem.STREAM_MUSIC // STREAM_ACCESSIBILITY
Eric Laurent6d517662012-04-23 18:42:39 -0700346 };
347 private int[] mStreamVolumeAlias;
Eric Laurenta553c252009-07-17 12:17:14 -0700348
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700349 /**
350 * Map AudioSystem.STREAM_* constants to app ops. This should be used
351 * after mapping through mStreamVolumeAlias.
352 */
John Spurlock59dc9c12015-03-02 11:20:15 -0500353 private static final int[] STREAM_VOLUME_OPS = new int[] {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700354 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL
355 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM
356 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING
357 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC
358 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM
359 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION
360 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO
361 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED
362 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF
363 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800364 AppOpsManager.OP_AUDIO_ACCESSIBILITY_VOLUME, // STREAM_ACCESSIBILITY
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700365 };
366
Eric Laurent83a017b2013-03-19 18:15:31 -0700367 private final boolean mUseFixedVolume;
368
Glenn Kasten30c918c2011-11-10 17:56:41 -0800369 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 public void onError(int error) {
371 switch (error) {
372 case AudioSystem.AUDIO_STATUS_SERVER_DIED:
Andy Hunged0ea402015-10-30 14:11:46 -0700373 sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED,
Eric Laurentdfb881f2013-07-18 14:41:39 -0700374 SENDMSG_NOOP, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 break;
376 default:
377 break;
378 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700379 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 };
381
382 /**
383 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
384 * {@link AudioManager#RINGER_MODE_SILENT}, or
385 * {@link AudioManager#RINGER_MODE_VIBRATE}.
386 */
Glenn Kastenba195eb2011-12-13 09:30:40 -0800387 // protected by mSettingsLock
John Spurlock661f2cf2014-11-17 10:29:10 -0500388 private int mRingerMode; // internal ringer mode, affects muting of underlying streams
389 private int mRingerModeExternal = -1; // reported ringer mode to outside clients (AudioManager)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390
Eric Laurent9bcf4012009-06-12 06:09:28 -0700391 /** @see System#MODE_RINGER_STREAMS_AFFECTED */
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700392 private int mRingerModeAffectedStreams = 0;
Eric Laurent9bcf4012009-06-12 06:09:28 -0700393
Eric Laurent5b4e6542010-03-19 20:02:21 -0700394 // Streams currently muted by ringer mode
395 private int mRingerModeMutedStreams;
396
John Spurlock3ce37252015-02-17 13:20:45 -0500397 /** Streams that can be muted. Do not resolve to aliases when checking.
398 * @see System#MUTE_STREAMS_AFFECTED */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 private int mMuteAffectedStreams;
400
401 /**
Eric Laurentbffc3d12012-05-07 17:43:49 -0700402 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
403 * mVibrateSetting is just maintained during deprecation period but vibration policy is
404 * now only controlled by mHasVibrator and mRingerMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800405 */
406 private int mVibrateSetting;
407
Eric Laurentbffc3d12012-05-07 17:43:49 -0700408 // Is there a vibrator
409 private final boolean mHasVibrator;
410
Eric Laurenta553c252009-07-17 12:17:14 -0700411 // Broadcast receiver for device connections intent broadcasts
412 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
413
Makoto Onukid45a4a22015-11-02 17:17:38 -0800414 /** Interface for UserManagerService. */
415 private final UserManagerInternal mUserManagerInternal;
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700416 private final ActivityManagerInternal mActivityManagerInternal;
Makoto Onukid45a4a22015-11-02 17:17:38 -0800417
418 private final UserRestrictionsListener mUserRestrictionsListener =
419 new AudioServiceUserRestrictionsListener();
420
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700421 // Devices currently connected
Paul McLean394a8e12015-03-03 10:29:19 -0700422 // Use makeDeviceListKey() to make a unique key for this list.
423 private class DeviceListSpec {
424 int mDeviceType;
425 String mDeviceName;
426 String mDeviceAddress;
427
428 public DeviceListSpec(int deviceType, String deviceName, String deviceAddress) {
429 mDeviceType = deviceType;
430 mDeviceName = deviceName;
431 mDeviceAddress = deviceAddress;
432 }
433
434 public String toString() {
435 return "[type:0x" + Integer.toHexString(mDeviceType) + " name:" + mDeviceName
436 + " address:" + mDeviceAddress + "]";
437 }
438 }
439
440 // Generate a unique key for the mConnectedDevices List by composing the device "type"
441 // and the "address" associated with a specific instance of that device type
442 private String makeDeviceListKey(int device, String deviceAddress) {
443 return "0x" + Integer.toHexString(device) + ":" + deviceAddress;
444 }
445
John Spurlock8c3dc852015-04-23 21:32:37 -0400446 private final ArrayMap<String, DeviceListSpec> mConnectedDevices = new ArrayMap<>();
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700447
448 // Forced device usage for communications
449 private int mForcedUseForComm;
450
Eric Laurent9272b4b2010-01-23 17:12:59 -0800451 // List of binder death handlers for setMode() client processes.
452 // The last process to have called setMode() is at the top of the list.
Glenn Kasten30c918c2011-11-10 17:56:41 -0800453 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
Eric Laurenteb14a782009-12-17 03:12:59 -0800454
Eric Laurent3def1ee2010-03-17 23:26:26 -0700455 // List of clients having issued a SCO start request
Glenn Kasten30c918c2011-11-10 17:56:41 -0800456 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
Eric Laurent3def1ee2010-03-17 23:26:26 -0700457
458 // BluetoothHeadset API to control SCO connection
459 private BluetoothHeadset mBluetoothHeadset;
460
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700461 // Bluetooth headset device
462 private BluetoothDevice mBluetoothHeadsetDevice;
Eric Laurent3def1ee2010-03-17 23:26:26 -0700463
Eric Laurent62ef7672010-11-24 10:58:32 -0800464 // Indicate if SCO audio connection is currently active and if the initiator is
465 // audio service (internal) or bluetooth headset (external)
466 private int mScoAudioState;
467 // SCO audio state is not active
468 private static final int SCO_STATE_INACTIVE = 0;
Eric Laurentdc03c612011-04-01 10:59:41 -0700469 // SCO audio activation request waiting for headset service to connect
470 private static final int SCO_STATE_ACTIVATE_REQ = 1;
Eric Laurent25fc29b2013-04-05 12:13:54 -0700471 // SCO audio state is active or starting due to a request from AudioManager API
Eric Laurentdc03c612011-04-01 10:59:41 -0700472 private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
473 // SCO audio deactivation request waiting for headset service to connect
474 private static final int SCO_STATE_DEACTIVATE_REQ = 5;
475
Eric Laurent62ef7672010-11-24 10:58:32 -0800476 // SCO audio state is active due to an action in BT handsfree (either voice recognition or
477 // in call audio)
478 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
Eric Laurentdc03c612011-04-01 10:59:41 -0700479 // Deactivation request for all SCO connections (initiated by audio mode change)
480 // waiting for headset service to connect
481 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
482
Eric Laurentc18c9132013-04-12 17:24:56 -0700483 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
484 // originated from an app targeting an API version before JB MR2 and raw audio after that.
485 private int mScoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -0700486 // SCO audio mode is undefined
487 private static final int SCO_MODE_UNDEFINED = -1;
Eric Laurentc18c9132013-04-12 17:24:56 -0700488 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
489 private static final int SCO_MODE_VIRTUAL_CALL = 0;
490 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
491 private static final int SCO_MODE_RAW = 1;
Liejun Taof4e51d82014-07-16 11:18:29 -0700492 // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
493 private static final int SCO_MODE_VR = 2;
494
495 private static final int SCO_MODE_MAX = 2;
Eric Laurentc18c9132013-04-12 17:24:56 -0700496
Eric Laurentdc03c612011-04-01 10:59:41 -0700497 // Current connection state indicated by bluetooth headset
498 private int mScoConnectionState;
Eric Laurent62ef7672010-11-24 10:58:32 -0800499
Eric Laurenta60e2122010-12-28 16:49:07 -0800500 // true if boot sequence has been completed
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700501 private boolean mSystemReady;
Yasuhiro Matsuda4ced7192015-07-10 22:08:44 +0900502 // true if Intent.ACTION_USER_SWITCHED has ever been received
503 private boolean mUserSwitchedReceived;
Eric Laurenta60e2122010-12-28 16:49:07 -0800504 // listener for SoundPool sample load completion indication
505 private SoundPoolCallback mSoundPoolCallBack;
506 // thread for SoundPool listener
507 private SoundPoolListenerThread mSoundPoolListenerThread;
508 // message looper for SoundPool listener
509 private Looper mSoundPoolLooper = null;
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700510 // volume applied to sound played with playSoundEffect()
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700511 private static int sSoundEffectVolumeDb;
Eric Laurent25101b02011-02-02 09:33:30 -0800512 // previous volume adjustment direction received by checkForRingerModeChange()
513 private int mPrevVolDirection = AudioManager.ADJUST_SAME;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700514 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
515 // is controlled by Vol keys.
516 private int mVolumeControlStream = -1;
517 private final Object mForceControlStreamLock = new Object();
518 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
519 // server process so in theory it is not necessary to monitor the client death.
520 // However it is good to be ready for future evolutions.
521 private ForceControlStreamClient mForceControlStreamClient = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700522 // Used to play ringtones outside system_server
523 private volatile IRingtonePlayer mRingtonePlayer;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800524
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700525 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
526
Eric Laurent78472112012-05-21 08:57:21 -0700527 // Request to override default use of A2DP for media.
Sungsoo486f7d32016-09-28 16:20:52 +0900528 private boolean mBluetoothA2dpEnabled;
Eric Laurent78472112012-05-21 08:57:21 -0700529 private final Object mBluetoothA2dpEnabledLock = new Object();
530
Dianne Hackborn632ca412012-06-14 19:34:10 -0700531 // Monitoring of audio routes. Protected by mCurAudioRoutes.
532 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
533 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
534 = new RemoteCallbackList<IAudioRoutesObserver>();
535
Eric Laurent4bbcc652012-09-24 14:26:30 -0700536 // Devices for which the volume is fixed and VolumePanel slider should be disabled
Eric Laurent212532b2014-07-21 15:43:18 -0700537 int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700538 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Eric Laurent212532b2014-07-21 15:43:18 -0700539 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
540 AudioSystem.DEVICE_OUT_HDMI_ARC |
541 AudioSystem.DEVICE_OUT_SPDIF |
542 AudioSystem.DEVICE_OUT_AUX_LINE;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700543 int mFullVolumeDevices = 0;
Eric Laurent4bbcc652012-09-24 14:26:30 -0700544
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700545 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700546 private final boolean mMonitorOrientation;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700547 private final boolean mMonitorRotation;
Eric Laurentd640bd32012-09-28 18:01:48 -0700548
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700549 private boolean mDockAudioMediaEnabled = true;
550
Eric Laurent08ed1b92012-11-05 14:54:12 -0800551 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
552
Eric Laurentfde16d52012-12-03 14:42:39 -0800553 // Used when safe volume warning message display is requested by setStreamVolume(). In this
554 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
555 // and used later when/if disableSafeMediaVolume() is called.
556 private StreamVolumeCommand mPendingVolumeCommand;
557
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700558 private PowerManager.WakeLock mAudioEventWakeLock;
559
560 private final MediaFocusControl mMediaFocusControl;
561
John Du5a0cf7a2013-07-19 11:30:34 -0700562 // Reference to BluetoothA2dp to query for AbsoluteVolume.
563 private BluetoothA2dp mA2dp;
seunghwan.hong4fe77952014-10-29 17:43:20 +0900564 // lock always taken synchronized on mConnectedDevices
John Du5a0cf7a2013-07-19 11:30:34 -0700565 private final Object mA2dpAvrcpLock = new Object();
566 // If absolute volume is supported in AVRCP device
567 private boolean mAvrcpAbsVolSupported = false;
568
Eric Laurentadbe8bf2014-11-03 18:26:32 -0800569 private static Long mLastDeviceConnectMsgTime = new Long(0);
570
Julia Reynolds48034f82016-03-09 10:15:16 -0500571 private NotificationManager mNm;
John Spurlock661f2cf2014-11-17 10:29:10 -0500572 private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
John Spurlocka48d7792015-03-03 17:35:57 -0500573 private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
John Spurlock07e72432015-03-13 11:46:52 -0400574 private long mLoweredFromNormalToVibrateTime;
John Spurlock661f2cf2014-11-17 10:29:10 -0500575
Paul McLean10804eb2015-01-28 11:16:35 -0800576 // Intent "extra" data keys.
577 public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName";
578 public static final String CONNECT_INTENT_KEY_STATE = "state";
579 public static final String CONNECT_INTENT_KEY_ADDRESS = "address";
580 public static final String CONNECT_INTENT_KEY_HAS_PLAYBACK = "hasPlayback";
581 public static final String CONNECT_INTENT_KEY_HAS_CAPTURE = "hasCapture";
582 public static final String CONNECT_INTENT_KEY_HAS_MIDI = "hasMIDI";
583 public static final String CONNECT_INTENT_KEY_DEVICE_CLASS = "class";
584
585 // Defines the format for the connection "address" for ALSA devices
586 public static String makeAlsaAddressString(int card, int device) {
587 return "card=" + card + ";device=" + device + ";";
588 }
589
Makoto Onukie1aef852015-10-15 17:28:35 -0700590 public static final class Lifecycle extends SystemService {
591 private AudioService mService;
592
593 public Lifecycle(Context context) {
594 super(context);
595 mService = new AudioService(context);
596 }
597
598 @Override
599 public void onStart() {
600 publishBinderService(Context.AUDIO_SERVICE, mService);
601 }
602
603 @Override
604 public void onBootPhase(int phase) {
605 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
606 mService.systemReady();
607 }
608 }
609 }
610
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 ///////////////////////////////////////////////////////////////////////////
612 // Construction
613 ///////////////////////////////////////////////////////////////////////////
614
615 /** @hide */
616 public AudioService(Context context) {
617 mContext = context;
618 mContentResolver = context.getContentResolver();
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700619 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700620
John Spurlock61560172015-02-06 19:46:04 -0500621 mPlatformType = AudioSystem.getPlatformType(context);
Jared Suttles59820132009-08-13 21:50:52 -0500622
Muyuan Li1ed6df62016-06-18 11:16:52 -0700623 mIsSingleVolume = AudioSystem.isSingleVolume(context);
624
Makoto Onukid45a4a22015-11-02 17:17:38 -0800625 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700626 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
Makoto Onukid45a4a22015-11-02 17:17:38 -0800627
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700628 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700629 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700630
Eric Laurentbffc3d12012-05-07 17:43:49 -0700631 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
632 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
633
John Spurlockb6e19e32015-03-10 21:33:44 -0400634 // Initialize volume
Eric Laurent91377de2014-10-10 15:24:04 -0700635 int maxVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps",
636 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
637 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
638 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500639 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700640 }
641 maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
642 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
643 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
644 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
Hank Freund45926dc2015-12-11 10:50:45 -0800645 if (isPlatformTelevision()) {
646 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume / 4;
647 } else {
648 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
649 }
Eric Laurent91377de2014-10-10 15:24:04 -0700650 }
Jared Suttles59820132009-08-13 21:50:52 -0500651
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700652 sSoundEffectVolumeDb = context.getResources().getInteger(
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700653 com.android.internal.R.integer.config_soundEffectVolumeDb);
Eric Laurent25101b02011-02-02 09:33:30 -0800654
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700655 mForcedUseForComm = AudioSystem.FORCE_NONE;
Eric Laurentdd45d012012-10-08 09:04:34 -0700656
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800657 createAudioSystemThread();
Eric Laurentdd45d012012-10-08 09:04:34 -0700658
Eric Laurentdfb881f2013-07-18 14:41:39 -0700659 AudioSystem.setErrorCallback(mAudioSystemCallback);
660
John Spurlock5e783732015-02-19 10:28:59 -0500661 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -0700662 mCameraSoundForced = new Boolean(cameraSoundForced);
663 sendMsg(mAudioHandler,
664 MSG_SET_FORCE_USE,
665 SENDMSG_QUEUE,
666 AudioSystem.FOR_SYSTEM,
667 cameraSoundForced ?
668 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
669 null,
670 0);
671
Eric Laurent05274f32012-11-29 12:48:18 -0800672 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
673 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
674 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
675 // The default safe volume index read here will be replaced by the actual value when
676 // the mcc is read by onConfigureSafeVolume()
677 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
678 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
679
Eric Laurent83a017b2013-03-19 18:15:31 -0700680 mUseFixedVolume = mContext.getResources().getBoolean(
681 com.android.internal.R.bool.config_useFixedVolume);
682
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700683 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
684 // array initialized by updateStreamVolumeAlias()
John Spurlock90874332015-03-10 16:00:54 -0400685 updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 readPersistedSettings();
Eric Laurentc0232482016-03-15 18:19:23 -0700687 readUserRestrictions();
Eric Laurentc1d41662011-07-19 11:21:13 -0700688 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700689 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700690
Jean-Michel Trivid4de20d2015-11-04 14:45:54 -0800691 mMediaFocusControl = new MediaFocusControl(mContext);
John Spurlockb6e19e32015-03-10 21:33:44 -0400692
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700693 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700694
695 // Call setRingerModeInt() to apply correct mute
696 // state on streams affected by ringer mode.
697 mRingerModeMutedStreams = 0;
John Spurlock661f2cf2014-11-17 10:29:10 -0500698 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3891c4c2010-04-20 09:40:57 -0700699
Eric Laurenta553c252009-07-17 12:17:14 -0700700 // Register for device connection intent broadcasts.
701 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700702 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700703 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
704 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700705 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
706 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700707 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700708 intentFilter.addAction(Intent.ACTION_USER_BACKGROUND);
709 intentFilter.addAction(Intent.ACTION_USER_FOREGROUND);
Paul McLeanc837a452014-04-09 09:04:43 -0700710 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Eric Laurentb70b78a2016-01-13 19:16:04 -0800711 intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700712
Eric Laurentd640bd32012-09-28 18:01:48 -0700713 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700714 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700715 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
716 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700717 Log.v(TAG, "monitoring device orientation");
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700718 // initialize orientation in AudioSystem
719 setOrientationForAudioSystem();
720 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700721 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
722 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -0700723 RotationHelper.init(mContext, mAudioHandler);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700724 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700725
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700726 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null);
Jared Suttles59820132009-08-13 21:50:52 -0500727
RoboErik0dac35a2014-08-12 15:48:49 -0700728 LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
Makoto Onukid45a4a22015-11-02 17:17:38 -0800729
730 mUserManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -0800731
732 mRecordMonitor.initMonitor();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800733 }
734
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700735 public void systemReady() {
736 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
737 0, 0, null, 0);
738 }
739
740 public void onSystemReady() {
741 mSystemReady = true;
742 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
743 0, 0, null, 0);
744
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700745 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
746 resetBluetoothSco();
747 getBluetoothHeadset();
748 //FIXME: this is to maintain compatibility with deprecated intent
749 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
750 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
751 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
752 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
753 sendStickyBroadcastToAll(newIntent);
754
755 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
756 if (adapter != null) {
757 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
758 BluetoothProfile.A2DP);
759 }
760
Jeff Sharkey73ea0ae2016-08-10 17:30:38 -0600761 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_HDMI_CEC)) {
762 mHdmiManager = mContext.getSystemService(HdmiControlManager.class);
Eric Laurent212532b2014-07-21 15:43:18 -0700763 synchronized (mHdmiManager) {
764 mHdmiTvClient = mHdmiManager.getTvClient();
Jungshik Jangc9ff9682014-09-15 17:41:06 +0900765 if (mHdmiTvClient != null) {
766 mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
767 }
Eric Laurent212532b2014-07-21 15:43:18 -0700768 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
769 mHdmiCecSink = false;
770 }
771 }
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900772
Julia Reynolds48034f82016-03-09 10:15:16 -0500773 mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
774
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700775 sendMsg(mAudioHandler,
776 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
777 SENDMSG_REPLACE,
778 0,
779 0,
John Spurlock90874332015-03-10 16:00:54 -0400780 TAG,
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700781 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700782
Jean-Michel Triviac487672016-11-11 10:05:18 -0800783 initA11yMonitoring(mContext);
Eric Laurent0867bed2015-05-20 14:49:08 -0700784 onIndicateSystemReady();
785 }
786
787 void onIndicateSystemReady() {
788 if (AudioSystem.systemReady() == AudioSystem.SUCCESS) {
789 return;
790 }
791 sendMsg(mAudioHandler,
792 MSG_INDICATE_SYSTEM_READY,
793 SENDMSG_REPLACE,
794 0,
795 0,
796 null,
797 INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
798 }
799
Andy Hunged0ea402015-10-30 14:11:46 -0700800 public void onAudioServerDied() {
Eric Laurent0867bed2015-05-20 14:49:08 -0700801 if (!mSystemReady ||
802 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Andy Hunged0ea402015-10-30 14:11:46 -0700803 Log.e(TAG, "Audioserver died.");
804 sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent0867bed2015-05-20 14:49:08 -0700805 null, 500);
806 return;
807 }
Andy Hunged0ea402015-10-30 14:11:46 -0700808 Log.e(TAG, "Audioserver started.");
Eric Laurent0867bed2015-05-20 14:49:08 -0700809
810 // indicate to audio HAL that we start the reconfiguration phase after a media
811 // server crash
812 // Note that we only execute this when the media server
813 // process restarts after a crash, not the first time it is started.
814 AudioSystem.setParameters("restarting=true");
815
816 readAndSetLowRamDevice();
817
818 // Restore device connection states
819 synchronized (mConnectedDevices) {
820 for (int i = 0; i < mConnectedDevices.size(); i++) {
821 DeviceListSpec spec = mConnectedDevices.valueAt(i);
822 AudioSystem.setDeviceConnectionState(
823 spec.mDeviceType,
824 AudioSystem.DEVICE_STATE_AVAILABLE,
825 spec.mDeviceAddress,
826 spec.mDeviceName);
827 }
828 }
829 // Restore call state
830 AudioSystem.setPhoneState(mMode);
831
832 // Restore forced usage for communcations and record
833 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
834 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
835 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
836 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
837
838 // Restore stream volumes
839 int numStreamTypes = AudioSystem.getNumStreamTypes();
840 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
841 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurente4381ec2015-10-29 17:52:48 -0700842 AudioSystem.initStreamVolume(
843 streamType, streamState.mIndexMin / 10, streamState.mIndexMax / 10);
Eric Laurent0867bed2015-05-20 14:49:08 -0700844
845 streamState.applyAllVolumes();
846 }
847
Andy Hungf04b84d2015-12-18 17:33:27 -0800848 // Restore mono mode
Andy Hung7b98e9a2016-02-25 18:34:50 -0800849 updateMasterMono(mContentResolver);
Andy Hungf04b84d2015-12-18 17:33:27 -0800850
Eric Laurent0867bed2015-05-20 14:49:08 -0700851 // Restore ringer mode
852 setRingerModeInt(getRingerModeInternal(), false);
853
854 // Reset device orientation (if monitored for this device)
855 if (mMonitorOrientation) {
856 setOrientationForAudioSystem();
857 }
858 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -0700859 RotationHelper.updateOrientation();
Eric Laurent0867bed2015-05-20 14:49:08 -0700860 }
861
Sungsoocf09fe62016-09-28 16:21:48 +0900862 synchronized (mBluetoothA2dpEnabledLock) {
863 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
864 mBluetoothA2dpEnabled ?
865 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
866 }
867
Eric Laurent0867bed2015-05-20 14:49:08 -0700868 synchronized (mSettingsLock) {
869 AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
870 mDockAudioMediaEnabled ?
871 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
Phil Burked43bf52016-03-01 17:01:35 -0800872 sendEncodedSurroundMode(mContentResolver);
Eric Laurent0867bed2015-05-20 14:49:08 -0700873 }
874 if (mHdmiManager != null) {
875 synchronized (mHdmiManager) {
876 if (mHdmiTvClient != null) {
877 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
878 }
879 }
880 }
881
882 synchronized (mAudioPolicies) {
883 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
884 policy.connectMixes();
885 }
886 }
887
888 onIndicateSystemReady();
889 // indicate the end of reconfiguration phase to audio HAL
890 AudioSystem.setParameters("restarting=false");
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700891 }
892
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800893 private void createAudioSystemThread() {
894 mAudioSystemThread = new AudioSystemThread();
895 mAudioSystemThread.start();
896 waitForAudioHandlerCreation();
897 }
898
899 /** Waits for the volume handler to be created by the other thread. */
900 private void waitForAudioHandlerCreation() {
901 synchronized(this) {
902 while (mAudioHandler == null) {
903 try {
904 // Wait for mAudioHandler to be set by the other thread
905 wait();
906 } catch (InterruptedException e) {
907 Log.e(TAG, "Interrupted while waiting on volume handler.");
908 }
909 }
910 }
911 }
912
Eric Laurent24482012012-05-10 09:41:17 -0700913 private void checkAllAliasStreamVolumes() {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700914 synchronized (VolumeStreamState.class) {
915 int numStreamTypes = AudioSystem.getNumStreamTypes();
916 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
917 if (streamType != mStreamVolumeAlias[streamType]) {
918 mStreamStates[streamType].
John Spurlock90874332015-03-10 16:00:54 -0400919 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]],
920 TAG);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700921 }
922 // apply stream volume
RoboErik4197cb62015-01-21 15:45:32 -0800923 if (!mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700924 mStreamStates[streamType].applyAllVolumes();
925 }
Eric Laurent24482012012-05-10 09:41:17 -0700926 }
927 }
928 }
929
Eric Laurent212532b2014-07-21 15:43:18 -0700930 private void checkAllFixedVolumeDevices()
931 {
932 int numStreamTypes = AudioSystem.getNumStreamTypes();
933 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
934 mStreamStates[streamType].checkFixedVolumeDevices();
935 }
936 }
937
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700938 private void checkAllFixedVolumeDevices(int streamType) {
939 mStreamStates[streamType].checkFixedVolumeDevices();
940 }
941
John Spurlockb6e19e32015-03-10 21:33:44 -0400942 private void checkMuteAffectedStreams() {
943 // any stream with a min level > 0 is not muteable by definition
944 for (int i = 0; i < mStreamStates.length; i++) {
945 final VolumeStreamState vss = mStreamStates[i];
946 if (vss.mIndexMin > 0) {
947 mMuteAffectedStreams &= ~(1 << vss.mStreamType);
948 }
949 }
950 }
951
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 int numStreamTypes = AudioSystem.getNumStreamTypes();
954 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
955
956 for (int i = 0; i < numStreamTypes; i++) {
Eric Laurent6d517662012-04-23 18:42:39 -0700957 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -0700958 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800959
Eric Laurent212532b2014-07-21 15:43:18 -0700960 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -0700961 checkAllAliasStreamVolumes();
John Spurlockb6e19e32015-03-10 21:33:44 -0400962 checkMuteAffectedStreams();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 }
964
Eric Laurentbffc3d12012-05-07 17:43:49 -0700965 private void dumpStreamStates(PrintWriter pw) {
966 pw.println("\nStream volumes (device: index)");
967 int numStreamTypes = AudioSystem.getNumStreamTypes();
968 for (int i = 0; i < numStreamTypes; i++) {
John Spurlock61560172015-02-06 19:46:04 -0500969 pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":");
Eric Laurentbffc3d12012-05-07 17:43:49 -0700970 mStreamStates[i].dump(pw);
971 pw.println("");
972 }
Eric Laurentdd45d012012-10-08 09:04:34 -0700973 pw.print("\n- mute affected streams = 0x");
974 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -0700975 }
976
John Spurlock90874332015-03-10 16:00:54 -0400977 private void updateStreamVolumeAlias(boolean updateVolumes, String caller) {
Eric Laurent6d517662012-04-23 18:42:39 -0700978 int dtmfStreamAlias;
Jean-Michel Triviac487672016-11-11 10:05:18 -0800979 final int a11yStreamAlias = sIndependentA11yVolume ?
980 AudioSystem.STREAM_ACCESSIBILITY : AudioSystem.STREAM_MUSIC;
Eric Laurent212532b2014-07-21 15:43:18 -0700981
Muyuan Li1ed6df62016-06-18 11:16:52 -0700982 if (mIsSingleVolume) {
Eric Laurent212532b2014-07-21 15:43:18 -0700983 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
984 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
Muyuan Li1ed6df62016-06-18 11:16:52 -0700985 } else {
986 switch (mPlatformType) {
987 case AudioSystem.PLATFORM_VOICE:
988 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
989 dtmfStreamAlias = AudioSystem.STREAM_RING;
990 break;
991 default:
992 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
993 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
994 }
Eric Laurent6d517662012-04-23 18:42:39 -0700995 }
Eric Laurent212532b2014-07-21 15:43:18 -0700996
Muyuan Li1ed6df62016-06-18 11:16:52 -0700997 if (mIsSingleVolume) {
Eric Laurent212532b2014-07-21 15:43:18 -0700998 mRingerModeAffectedStreams = 0;
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700999 } else {
Eric Laurent212532b2014-07-21 15:43:18 -07001000 if (isInCommunication()) {
1001 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
1002 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
1003 } else {
1004 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
1005 }
Eric Laurent6d517662012-04-23 18:42:39 -07001006 }
Eric Laurent212532b2014-07-21 15:43:18 -07001007
Eric Laurent6d517662012-04-23 18:42:39 -07001008 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
Jean-Michel Triviac487672016-11-11 10:05:18 -08001009 mStreamVolumeAlias[AudioSystem.STREAM_ACCESSIBILITY] = a11yStreamAlias;
1010
Eric Laurent6d517662012-04-23 18:42:39 -07001011 if (updateVolumes) {
John Spurlock90874332015-03-10 16:00:54 -04001012 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
1013 caller);
Jean-Michel Triviac487672016-11-11 10:05:18 -08001014 mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setAllIndexes(
1015 mStreamStates[a11yStreamAlias], caller);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07001016 // apply stream mute states according to new value of mRingerModeAffectedStreams
John Spurlock661f2cf2014-11-17 10:29:10 -05001017 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent6d517662012-04-23 18:42:39 -07001018 sendMsg(mAudioHandler,
1019 MSG_SET_ALL_VOLUMES,
1020 SENDMSG_QUEUE,
1021 0,
1022 0,
1023 mStreamStates[AudioSystem.STREAM_DTMF], 0);
Jean-Michel Triviac487672016-11-11 10:05:18 -08001024 sendMsg(mAudioHandler,
1025 MSG_SET_ALL_VOLUMES,
1026 SENDMSG_QUEUE,
1027 0,
1028 0,
1029 mStreamStates[AudioSystem.STREAM_ACCESSIBILITY], 0);
Eric Laurent6d517662012-04-23 18:42:39 -07001030 }
1031 }
1032
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001033 private void readDockAudioSettings(ContentResolver cr)
1034 {
1035 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -07001036 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001037
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001038 sendMsg(mAudioHandler,
1039 MSG_SET_FORCE_USE,
1040 SENDMSG_QUEUE,
1041 AudioSystem.FOR_DOCK,
1042 mDockAudioMediaEnabled ?
1043 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
1044 null,
1045 0);
1046 }
1047
Phil Burkac0f7042016-02-24 12:19:08 -08001048
Andy Hung7b98e9a2016-02-25 18:34:50 -08001049 private void updateMasterMono(ContentResolver cr)
1050 {
1051 final boolean masterMono = System.getIntForUser(
1052 cr, System.MASTER_MONO, 0 /* default */, UserHandle.USER_CURRENT) == 1;
1053 if (DEBUG_VOL) {
1054 Log.d(TAG, String.format("Master mono %b", masterMono));
1055 }
1056 AudioSystem.setMasterMono(masterMono);
1057 }
1058
Phil Burked43bf52016-03-01 17:01:35 -08001059 private void sendEncodedSurroundMode(ContentResolver cr)
Phil Burkac0f7042016-02-24 12:19:08 -08001060 {
1061 int encodedSurroundMode = Settings.Global.getInt(
1062 cr, Settings.Global.ENCODED_SURROUND_OUTPUT,
1063 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
1064 sendEncodedSurroundMode(encodedSurroundMode);
1065 }
1066
1067 private void sendEncodedSurroundMode(int encodedSurroundMode)
1068 {
1069 // initialize to guaranteed bad value
1070 int forceSetting = AudioSystem.NUM_FORCE_CONFIG;
1071 switch (encodedSurroundMode) {
1072 case Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO:
1073 forceSetting = AudioSystem.FORCE_NONE;
1074 break;
1075 case Settings.Global.ENCODED_SURROUND_OUTPUT_NEVER:
1076 forceSetting = AudioSystem.FORCE_ENCODED_SURROUND_NEVER;
1077 break;
1078 case Settings.Global.ENCODED_SURROUND_OUTPUT_ALWAYS:
1079 forceSetting = AudioSystem.FORCE_ENCODED_SURROUND_ALWAYS;
1080 break;
1081 default:
1082 Log.e(TAG, "updateSurroundSoundSettings: illegal value "
1083 + encodedSurroundMode);
1084 break;
1085 }
1086 if (forceSetting != AudioSystem.NUM_FORCE_CONFIG) {
1087 sendMsg(mAudioHandler,
1088 MSG_SET_FORCE_USE,
1089 SENDMSG_QUEUE,
1090 AudioSystem.FOR_ENCODED_SURROUND,
1091 forceSetting,
1092 null,
1093 0);
1094 }
1095 }
1096
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097 private void readPersistedSettings() {
1098 final ContentResolver cr = mContentResolver;
1099
Eric Laurentbffc3d12012-05-07 17:43:49 -07001100 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07001101 Settings.Global.getInt(
1102 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -07001103 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -07001104 // sanity check in case the settings are restored from a device with incompatible
1105 // ringer modes
John Spurlock97559372014-10-24 16:27:36 -04001106 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001107 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -07001108 }
1109 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1110 ringerMode = AudioManager.RINGER_MODE_SILENT;
1111 }
1112 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07001113 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -08001114 }
Muyuan Li1ed6df62016-06-18 11:16:52 -07001115 if (mUseFixedVolume || mIsSingleVolume) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001116 ringerMode = AudioManager.RINGER_MODE_NORMAL;
1117 }
Glenn Kastenba195eb2011-12-13 09:30:40 -08001118 synchronized(mSettingsLock) {
1119 mRingerMode = ringerMode;
John Spurlock661f2cf2014-11-17 10:29:10 -05001120 if (mRingerModeExternal == -1) {
1121 mRingerModeExternal = mRingerMode;
1122 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123
Eric Laurentdd45d012012-10-08 09:04:34 -07001124 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
1125 // are still needed while setVibrateSetting() and getVibrateSetting() are being
1126 // deprecated.
John Spurlock61560172015-02-06 19:46:04 -05001127 mVibrateSetting = AudioSystem.getValueForVibrateSetting(0,
Eric Laurentdd45d012012-10-08 09:04:34 -07001128 AudioManager.VIBRATE_TYPE_NOTIFICATION,
1129 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
1130 : AudioManager.VIBRATE_SETTING_OFF);
John Spurlock61560172015-02-06 19:46:04 -05001131 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting,
Eric Laurentdd45d012012-10-08 09:04:34 -07001132 AudioManager.VIBRATE_TYPE_RINGER,
1133 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
1134 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001135
Eric Laurent24e0d9b2013-10-03 18:15:07 -07001136 updateRingerModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001137 readDockAudioSettings(cr);
Phil Burked43bf52016-03-01 17:01:35 -08001138 sendEncodedSurroundMode(cr);
Eric Laurent402f7f22011-02-04 12:30:32 -08001139 }
Eric Laurentc1d41662011-07-19 11:21:13 -07001140
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001141 mMuteAffectedStreams = System.getIntForUser(cr,
John Spurlock61560172015-02-06 19:46:04 -05001142 System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
John Spurlock24c05182015-02-05 12:30:36 -05001143 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144
Andy Hung7b98e9a2016-02-25 18:34:50 -08001145 updateMasterMono(cr);
Andy Hungf04b84d2015-12-18 17:33:27 -08001146
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001147 // Each stream will read its own persisted settings
1148
John Spurlockbcc10872014-11-28 15:29:21 -05001149 // Broadcast the sticky intents
1150 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
1151 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001152
1153 // Broadcast vibrate settings
1154 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
1155 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07001156
John Spurlock33f4e042014-07-11 13:10:58 -04001157 // Load settings for the volume controller
1158 mVolumeController.loadSettings(cr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001159 }
1160
Eric Laurentc0232482016-03-15 18:19:23 -07001161 private void readUserRestrictions() {
1162 final int currentUser = getCurrentUserId();
1163
1164 // Check the current user restriction.
Tony Makc1205112016-07-22 16:02:59 +01001165 boolean masterMute =
1166 mUserManagerInternal.getUserRestriction(currentUser,
1167 UserManager.DISALLLOW_UNMUTE_DEVICE)
1168 || mUserManagerInternal.getUserRestriction(currentUser,
1169 UserManager.DISALLOW_ADJUST_VOLUME);
Eric Laurentc0232482016-03-15 18:19:23 -07001170 if (mUseFixedVolume) {
1171 masterMute = false;
1172 AudioSystem.setMasterVolume(1.0f);
1173 }
1174 if (DEBUG_VOL) {
1175 Log.d(TAG, String.format("Master mute %s, user=%d", masterMute, currentUser));
1176 }
1177 setSystemAudioMute(masterMute);
1178 AudioSystem.setMasterMute(masterMute);
1179 broadcastMasterMuteStatus(masterMute);
1180
1181 boolean microphoneMute = mUserManagerInternal.getUserRestriction(
1182 currentUser, UserManager.DISALLOW_UNMUTE_MICROPHONE);
1183 if (DEBUG_VOL) {
1184 Log.d(TAG, String.format("Mic mute %s, user=%d", microphoneMute, currentUser));
1185 }
1186 AudioSystem.muteMicrophone(microphoneMute);
1187 }
1188
Eric Laurenta553c252009-07-17 12:17:14 -07001189 private int rescaleIndex(int index, int srcStream, int dstStream) {
1190 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
1191 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001192
1193 ///////////////////////////////////////////////////////////////////////////
1194 // IPC methods
1195 ///////////////////////////////////////////////////////////////////////////
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 /** @see AudioManager#adjustVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001197 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001198 String callingPackage, String caller) {
RoboErik272e1612014-09-05 11:39:29 -07001199 adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
John Spurlock90874332015-03-10 16:00:54 -04001200 caller, Binder.getCallingUid());
RoboErik272e1612014-09-05 11:39:29 -07001201 }
1202
1203 private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001204 String callingPackage, String caller, int uid) {
1205 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType
1206 + ", flags=" + flags + ", caller=" + caller);
Eric Laurent402f7f22011-02-04 12:30:32 -08001207 int streamType;
RoboErik4197cb62015-01-21 15:45:32 -08001208 boolean isMute = isMuteAdjust(direction);
Eric Laurent45c90ce2012-04-24 18:44:22 -07001209 if (mVolumeControlStream != -1) {
1210 streamType = mVolumeControlStream;
Eric Laurent402f7f22011-02-04 12:30:32 -08001211 } else {
1212 streamType = getActiveStreamType(suggestedStreamType);
1213 }
John Spurlock0a376af2015-03-26 16:24:12 -04001214 ensureValidStreamType(streamType);
John Spurlock33f4e042014-07-11 13:10:58 -04001215 final int resolvedStream = mStreamVolumeAlias[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001216
RoboErik2811dd32014-08-12 09:48:13 -07001217 // Play sounds on STREAM_RING only.
1218 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
John Spurlock33f4e042014-07-11 13:10:58 -04001219 resolvedStream != AudioSystem.STREAM_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001220 flags &= ~AudioManager.FLAG_PLAY_SOUND;
1221 }
1222
John Spurlock33f4e042014-07-11 13:10:58 -04001223 // For notifications/ring, show the ui before making any adjustments
RoboErik4197cb62015-01-21 15:45:32 -08001224 // Don't suppress mute/unmute requests
1225 if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
John Spurlock33f4e042014-07-11 13:10:58 -04001226 direction = 0;
1227 flags &= ~AudioManager.FLAG_PLAY_SOUND;
1228 flags &= ~AudioManager.FLAG_VIBRATE;
1229 if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
1230 }
1231
John Spurlock90874332015-03-10 16:00:54 -04001232 adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001233 }
1234
1235 /** @see AudioManager#adjustStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001236 public void adjustStreamVolume(int streamType, int direction, int flags,
1237 String callingPackage) {
John Spurlock90874332015-03-10 16:00:54 -04001238 adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage,
1239 Binder.getCallingUid());
RoboErik0dac35a2014-08-12 15:48:49 -07001240 }
1241
1242 private void adjustStreamVolume(int streamType, int direction, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001243 String callingPackage, String caller, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001244 if (mUseFixedVolume) {
1245 return;
1246 }
John Spurlock90874332015-03-10 16:00:54 -04001247 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream=" + streamType + ", dir=" + direction
1248 + ", flags=" + flags + ", caller=" + caller);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07001249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001250 ensureValidDirection(direction);
1251 ensureValidStreamType(streamType);
1252
RoboErik4197cb62015-01-21 15:45:32 -08001253 boolean isMuteAdjust = isMuteAdjust(direction);
1254
John Spurlock3ce37252015-02-17 13:20:45 -05001255 if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
1256 return;
1257 }
1258
Eric Laurent96a33d12011-11-08 10:31:57 -08001259 // use stream type alias here so that streams with same alias have the same behavior,
1260 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
1261 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
Eric Laurent6d517662012-04-23 18:42:39 -07001262 int streamTypeAlias = mStreamVolumeAlias[streamType];
RoboErik4197cb62015-01-21 15:45:32 -08001263
Eric Laurentb024c302011-10-14 17:19:27 -07001264 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001265
1266 final int device = getDeviceForStream(streamTypeAlias);
Eric Laurent3ef75492012-11-28 12:12:23 -08001267
Eric Laurent42b041e2013-03-29 11:36:03 -07001268 int aliasIndex = streamState.getIndex(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269 boolean adjustVolume = true;
Eric Laurent3ef75492012-11-28 12:12:23 -08001270 int step;
Eric Laurent24482012012-05-10 09:41:17 -07001271
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001272 // skip a2dp absolute volume control request when the device
1273 // is not an a2dp device
1274 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1275 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1276 return;
1277 }
1278
Kenny Guy70e0c582015-06-30 19:18:28 +01001279 // If we are being called by the system (e.g. hardware keys) check for current user
1280 // so we handle user restrictions correctly.
1281 if (uid == android.os.Process.SYSTEM_UID) {
1282 uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
1283 }
John Spurlock59dc9c12015-03-02 11:20:15 -05001284 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001285 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001286 return;
1287 }
1288
Eric Laurentfde16d52012-12-03 14:42:39 -08001289 // reset any pending volume command
1290 synchronized (mSafeMediaVolumeState) {
1291 mPendingVolumeCommand = null;
1292 }
1293
Eric Laurent3ef75492012-11-28 12:12:23 -08001294 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1295 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1296 ((device & mFixedVolumeDevices) != 0)) {
1297 flags |= AudioManager.FLAG_FIXED_VOLUME;
1298
1299 // Always toggle between max safe volume and 0 for fixed volume devices where safe
1300 // volume is enforced, and max and 0 for the others.
1301 // This is simulated by stepping by the full allowed volume range
1302 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1303 (device & mSafeMediaVolumeDevices) != 0) {
1304 step = mSafeMediaVolumeIndex;
1305 } else {
1306 step = streamState.getMaxIndex();
1307 }
1308 if (aliasIndex != 0) {
1309 aliasIndex = step;
1310 }
1311 } else {
1312 // convert one UI step (+/-1) into a number of internal units on the stream alias
1313 step = rescaleIndex(10, streamType, streamTypeAlias);
1314 }
1315
Eric Laurent42b041e2013-03-29 11:36:03 -07001316 // If either the client forces allowing ringer modes for this adjustment,
1317 // or the stream type is one that is affected by ringer modes
1318 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlockee5ad722015-03-03 16:17:21 -05001319 (streamTypeAlias == getUiSoundsStreamType())) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001320 int ringerMode = getRingerModeInternal();
Eric Laurent42b041e2013-03-29 11:36:03 -07001321 // do not vibrate if already in vibrate mode
1322 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
1323 flags &= ~AudioManager.FLAG_VIBRATE;
Eric Laurent3ef75492012-11-28 12:12:23 -08001324 }
RoboErik5452e252015-02-06 15:33:53 -08001325 // Check if the ringer mode handles this adjustment. If it does we don't
1326 // need to adjust the volume further.
John Spurlock50ced3f2015-05-11 16:00:09 -04001327 final int result = checkForRingerModeChange(aliasIndex, direction, step,
Julia Reynoldsed783792016-04-08 15:27:35 -04001328 streamState.mIsMuted, callingPackage, flags);
John Spurlocka11b4af2014-06-01 11:52:23 -04001329 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
1330 // If suppressing a volume adjustment in silent mode, display the UI hint
1331 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
1332 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
1333 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001334 // If suppressing a volume down adjustment in vibrate mode, display the UI hint
1335 if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
1336 flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
1337 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001338 }
John Spurlock50ced3f2015-05-11 16:00:09 -04001339 // If the ringermode is suppressing media, prevent changes
Julia Reynoldsed783792016-04-08 15:27:35 -04001340 if (!volumeAdjustmentAllowedByDnd(streamTypeAlias, flags)) {
John Spurlock50ced3f2015-05-11 16:00:09 -04001341 adjustVolume = false;
1342 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001343 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001344
Eric Laurent42b041e2013-03-29 11:36:03 -07001345 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
RoboErik5452e252015-02-06 15:33:53 -08001346 mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001347
John Du5a0cf7a2013-07-19 11:30:34 -07001348 // Check if volume update should be send to AVRCP
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001349 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1350 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1351 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1352 synchronized (mA2dpAvrcpLock) {
1353 if (mA2dp != null && mAvrcpAbsVolSupported) {
1354 mA2dp.adjustAvrcpAbsoluteVolume(direction);
1355 }
John Du5a0cf7a2013-07-19 11:30:34 -07001356 }
1357 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001358
RoboErik4197cb62015-01-21 15:45:32 -08001359 if (isMuteAdjust) {
1360 boolean state;
1361 if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
1362 state = !streamState.mIsMuted;
1363 } else {
1364 state = direction == AudioManager.ADJUST_MUTE;
1365 }
1366 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1367 setSystemAudioMute(state);
1368 }
1369 for (int stream = 0; stream < mStreamStates.length; stream++) {
1370 if (streamTypeAlias == mStreamVolumeAlias[stream]) {
Sungmin Choi841ed0a2015-07-26 23:09:49 -07001371 if (!(readCameraSoundForced()
1372 && (mStreamStates[stream].getStreamType()
1373 == AudioSystem.STREAM_SYSTEM_ENFORCED))) {
1374 mStreamStates[stream].mute(state);
1375 }
RoboErik4197cb62015-01-21 15:45:32 -08001376 }
1377 }
1378 } else if ((direction == AudioManager.ADJUST_RAISE) &&
Eric Laurent42b041e2013-03-29 11:36:03 -07001379 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
RoboErik4197cb62015-01-21 15:45:32 -08001380 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -04001381 mVolumeController.postDisplaySafeVolumeWarning(flags);
John Spurlock90874332015-03-10 16:00:54 -04001382 } else if (streamState.adjustIndex(direction * step, device, caller)
1383 || streamState.mIsMuted) {
RoboErik4197cb62015-01-21 15:45:32 -08001384 // Post message to set system volume (it in turn will post a
1385 // message to persist).
1386 if (streamState.mIsMuted) {
1387 // Unmute the stream if it was previously muted
RoboErik5452e252015-02-06 15:33:53 -08001388 if (direction == AudioManager.ADJUST_RAISE) {
1389 // unmute immediately for volume up
1390 streamState.mute(false);
1391 } else if (direction == AudioManager.ADJUST_LOWER) {
Muyuan Li1ed6df62016-06-18 11:16:52 -07001392 if (mIsSingleVolume) {
John Spurlocka48d7792015-03-03 17:35:57 -05001393 sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
1394 streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
1395 }
RoboErik5452e252015-02-06 15:33:53 -08001396 }
RoboErik4197cb62015-01-21 15:45:32 -08001397 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001398 sendMsg(mAudioHandler,
1399 MSG_SET_DEVICE_VOLUME,
1400 SENDMSG_QUEUE,
1401 device,
1402 0,
1403 streamState,
1404 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001405 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001406
RoboErik4197cb62015-01-21 15:45:32 -08001407 // Check if volume update should be sent to Hdmi system audio.
Jungshik Jang41d97462014-06-30 22:26:29 +09001408 int newIndex = mStreamStates[streamType].getIndex(device);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001409 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1410 setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
1411 }
Eric Laurent212532b2014-07-21 15:43:18 -07001412 if (mHdmiManager != null) {
1413 synchronized (mHdmiManager) {
Eric Laurent212532b2014-07-21 15:43:18 -07001414 // mHdmiCecSink true => mHdmiPlaybackClient != null
1415 if (mHdmiCecSink &&
1416 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1417 oldIndex != newIndex) {
1418 synchronized (mHdmiPlaybackClient) {
1419 int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
RoboErik4197cb62015-01-21 15:45:32 -08001420 KeyEvent.KEYCODE_VOLUME_UP;
Donghyun Cho5f6d404e2016-03-17 20:39:25 +09001421 final long ident = Binder.clearCallingIdentity();
1422 try {
1423 mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1424 mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1425 } finally {
1426 Binder.restoreCallingIdentity(ident);
1427 }
Eric Laurent212532b2014-07-21 15:43:18 -07001428 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001429 }
1430 }
1431 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001432 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001433 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001434 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001435 }
1436
RoboErik5452e252015-02-06 15:33:53 -08001437 // Called after a delay when volume down is pressed while muted
1438 private void onUnmuteStream(int stream, int flags) {
1439 VolumeStreamState streamState = mStreamStates[stream];
1440 streamState.mute(false);
1441
1442 final int device = getDeviceForStream(stream);
1443 final int index = mStreamStates[stream].getIndex(device);
1444 sendVolumeUpdate(stream, index, index, flags);
1445 }
1446
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001447 private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
1448 if (mHdmiManager == null
1449 || mHdmiTvClient == null
1450 || oldVolume == newVolume
1451 || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
1452
1453 // Sets the audio volume of AVR when we are in system audio mode. The new volume info
1454 // is tranformed to HDMI-CEC commands and passed through CEC bus.
1455 synchronized (mHdmiManager) {
1456 if (!mHdmiSystemAudioSupported) return;
1457 synchronized (mHdmiTvClient) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001458 final long token = Binder.clearCallingIdentity();
1459 try {
Jinsuk Kim7a9ba422015-02-16 16:47:38 +09001460 mHdmiTvClient.setSystemAudioVolume(oldVolume, newVolume, maxVolume);
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001461 } finally {
1462 Binder.restoreCallingIdentity(token);
1463 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001464 }
1465 }
1466 }
1467
Eric Laurentfde16d52012-12-03 14:42:39 -08001468 // StreamVolumeCommand contains the information needed to defer the process of
1469 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1470 class StreamVolumeCommand {
1471 public final int mStreamType;
1472 public final int mIndex;
1473 public final int mFlags;
1474 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001475
Eric Laurentfde16d52012-12-03 14:42:39 -08001476 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1477 mStreamType = streamType;
1478 mIndex = index;
1479 mFlags = flags;
1480 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001481 }
John Spurlock35134602014-07-24 18:10:48 -04001482
1483 @Override
1484 public String toString() {
1485 return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1486 .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1487 .append(mDevice).append('}').toString();
1488 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001489 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001490
Julia Reynolds48034f82016-03-09 10:15:16 -05001491 private int getNewRingerMode(int stream, int index, int flags) {
John Spurlockee5ad722015-03-03 16:17:21 -05001492 // setting volume on ui sounds stream type also controls silent mode
Eric Laurent3ef75492012-11-28 12:12:23 -08001493 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlock75ae23c2015-06-02 16:26:43 -04001494 (stream == getUiSoundsStreamType())) {
Eric Laurent3ef75492012-11-28 12:12:23 -08001495 int newRingerMode;
1496 if (index == 0) {
1497 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlocka48d7792015-03-03 17:35:57 -05001498 : mVolumePolicy.volumeDownToEnterSilent ? AudioManager.RINGER_MODE_SILENT
Julia Reynolds48034f82016-03-09 10:15:16 -05001499 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001500 } else {
1501 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1502 }
Julia Reynolds48034f82016-03-09 10:15:16 -05001503 return newRingerMode;
1504 }
1505 return getRingerModeExternal();
1506 }
1507
1508 private boolean isAndroidNPlus(String caller) {
1509 try {
1510 final ApplicationInfo applicationInfo =
1511 mContext.getPackageManager().getApplicationInfoAsUser(
1512 caller, 0, UserHandle.getUserId(Binder.getCallingUid()));
1513 if (applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
1514 return true;
1515 }
1516 return false;
1517 } catch (PackageManager.NameNotFoundException e) {
1518 return true;
1519 }
1520 }
1521
1522 private boolean wouldToggleZenMode(int newMode) {
1523 if (getRingerModeExternal() == AudioManager.RINGER_MODE_SILENT
1524 && newMode != AudioManager.RINGER_MODE_SILENT) {
1525 return true;
1526 } else if (getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT
1527 && newMode == AudioManager.RINGER_MODE_SILENT) {
1528 return true;
1529 }
1530 return false;
1531 }
1532
1533 private void onSetStreamVolume(int streamType, int index, int flags, int device,
1534 String caller) {
1535 final int stream = mStreamVolumeAlias[streamType];
1536 setStreamVolumeInt(stream, index, device, false, caller);
1537 // setting volume on ui sounds stream type also controls silent mode
1538 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1539 (stream == getUiSoundsStreamType())) {
1540 setRingerMode(getNewRingerMode(stream, index, flags),
1541 TAG + ".onSetStreamVolume", false /*external*/);
Eric Laurent3ef75492012-11-28 12:12:23 -08001542 }
John Spurlock75ae23c2015-06-02 16:26:43 -04001543 // setting non-zero volume for a muted stream unmutes the stream and vice versa
1544 mStreamStates[stream].mute(index == 0);
Eric Laurentfde16d52012-12-03 14:42:39 -08001545 }
1546
1547 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001548 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
John Spurlock90874332015-03-10 16:00:54 -04001549 setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
1550 Binder.getCallingUid());
RoboErik0dac35a2014-08-12 15:48:49 -07001551 }
1552
1553 private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
John Spurlock90874332015-03-10 16:00:54 -04001554 String caller, int uid) {
Jean-Michel Triviac487672016-11-11 10:05:18 -08001555 if (DEBUG_VOL) {
1556 Log.d(TAG, "setStreamVolume(stream=" + streamType+", index=" + index
1557 + ", calling=" + callingPackage + ")");
1558 }
Eric Laurent83a017b2013-03-19 18:15:31 -07001559 if (mUseFixedVolume) {
1560 return;
1561 }
1562
Eric Laurentfde16d52012-12-03 14:42:39 -08001563 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001564 int streamTypeAlias = mStreamVolumeAlias[streamType];
1565 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001566
1567 final int device = getDeviceForStream(streamType);
1568 int oldIndex;
1569
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001570 // skip a2dp absolute volume control request when the device
1571 // is not an a2dp device
1572 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1573 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1574 return;
1575 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001576 // If we are being called by the system (e.g. hardware keys) check for current user
1577 // so we handle user restrictions correctly.
1578 if (uid == android.os.Process.SYSTEM_UID) {
1579 uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
1580 }
John Spurlock59dc9c12015-03-02 11:20:15 -05001581 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001582 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001583 return;
1584 }
1585
Julia Reynolds48034f82016-03-09 10:15:16 -05001586 if (isAndroidNPlus(callingPackage)
1587 && wouldToggleZenMode(getNewRingerMode(streamTypeAlias, index, flags))
1588 && !mNm.isNotificationPolicyAccessGrantedForPackage(callingPackage)) {
1589 throw new SecurityException("Not allowed to change Do Not Disturb state");
1590 }
1591
Julia Reynoldsed783792016-04-08 15:27:35 -04001592 if (!volumeAdjustmentAllowedByDnd(streamTypeAlias, flags)) {
1593 return;
1594 }
1595
Eric Laurentfde16d52012-12-03 14:42:39 -08001596 synchronized (mSafeMediaVolumeState) {
1597 // reset any pending volume command
1598 mPendingVolumeCommand = null;
1599
Eric Laurent42b041e2013-03-29 11:36:03 -07001600 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001601
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001602 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001603
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001604 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1605 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1606 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1607 synchronized (mA2dpAvrcpLock) {
1608 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001609 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001610 }
John Du5a0cf7a2013-07-19 11:30:34 -07001611 }
1612 }
1613
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001614 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1615 setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
Jungshik Jang41d97462014-06-30 22:26:29 +09001616 }
1617
Eric Laurentfde16d52012-12-03 14:42:39 -08001618 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001619 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001620 ((device & mFixedVolumeDevices) != 0)) {
1621 flags |= AudioManager.FLAG_FIXED_VOLUME;
1622
1623 // volume is either 0 or max allowed for fixed volume devices
1624 if (index != 0) {
1625 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1626 (device & mSafeMediaVolumeDevices) != 0) {
1627 index = mSafeMediaVolumeIndex;
1628 } else {
1629 index = streamState.getMaxIndex();
1630 }
1631 }
1632 }
1633
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001634 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001635 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001636 mPendingVolumeCommand = new StreamVolumeCommand(
1637 streamType, index, flags, device);
1638 } else {
John Spurlock90874332015-03-10 16:00:54 -04001639 onSetStreamVolume(streamType, index, flags, device, caller);
Eric Laurent42b041e2013-03-29 11:36:03 -07001640 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001641 }
1642 }
Eric Laurent25101b02011-02-02 09:33:30 -08001643 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001644 }
1645
Julia Reynoldsed783792016-04-08 15:27:35 -04001646 // No ringer affected streams can be changed in total silence mode except those that
1647 // will cause the device to exit total silence mode.
1648 private boolean volumeAdjustmentAllowedByDnd(int streamTypeAlias, int flags) {
1649 if (mNm.getZenMode() == Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
1650 && isStreamMutedByRingerMode(streamTypeAlias)) {
1651 if (!(((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1652 (streamTypeAlias == getUiSoundsStreamType()))) {
1653 return false;
1654 }
1655 }
1656 return true;
1657 }
1658
Eric Laurent45c90ce2012-04-24 18:44:22 -07001659 /** @see AudioManager#forceVolumeControlStream(int) */
1660 public void forceVolumeControlStream(int streamType, IBinder cb) {
1661 synchronized(mForceControlStreamLock) {
1662 mVolumeControlStream = streamType;
1663 if (mVolumeControlStream == -1) {
1664 if (mForceControlStreamClient != null) {
1665 mForceControlStreamClient.release();
1666 mForceControlStreamClient = null;
1667 }
1668 } else {
1669 mForceControlStreamClient = new ForceControlStreamClient(cb);
1670 }
1671 }
1672 }
1673
1674 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1675 private IBinder mCb; // To be notified of client's death
1676
1677 ForceControlStreamClient(IBinder cb) {
1678 if (cb != null) {
1679 try {
1680 cb.linkToDeath(this, 0);
1681 } catch (RemoteException e) {
1682 // Client has died!
1683 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1684 cb = null;
1685 }
1686 }
1687 mCb = cb;
1688 }
1689
1690 public void binderDied() {
1691 synchronized(mForceControlStreamLock) {
1692 Log.w(TAG, "SCO client died");
1693 if (mForceControlStreamClient != this) {
1694 Log.w(TAG, "unregistered control stream client died");
1695 } else {
1696 mForceControlStreamClient = null;
1697 mVolumeControlStream = -1;
1698 }
1699 }
1700 }
1701
1702 public void release() {
1703 if (mCb != null) {
1704 mCb.unlinkToDeath(this, 0);
1705 mCb = null;
1706 }
1707 }
1708 }
1709
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001710 private void sendBroadcastToAll(Intent intent) {
Christopher Tate267603f2015-01-20 14:21:21 -08001711 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
John Spurlock86490862015-02-25 11:22:52 -05001712 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001713 final long ident = Binder.clearCallingIdentity();
1714 try {
1715 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1716 } finally {
1717 Binder.restoreCallingIdentity(ident);
1718 }
1719 }
1720
1721 private void sendStickyBroadcastToAll(Intent intent) {
John Spurlock86490862015-02-25 11:22:52 -05001722 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001723 final long ident = Binder.clearCallingIdentity();
1724 try {
1725 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1726 } finally {
1727 Binder.restoreCallingIdentity(ident);
1728 }
1729 }
1730
Kenny Guy70e0c582015-06-30 19:18:28 +01001731 private int getCurrentUserId() {
1732 final long ident = Binder.clearCallingIdentity();
1733 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001734 UserInfo currentUser = ActivityManager.getService().getCurrentUser();
Kenny Guy70e0c582015-06-30 19:18:28 +01001735 return currentUser.id;
1736 } catch (RemoteException e) {
1737 // Activity manager not running, nothing we can do assume user 0.
1738 } finally {
1739 Binder.restoreCallingIdentity(ident);
1740 }
Xiaohui Chen7c696362015-09-16 09:56:14 -07001741 return UserHandle.USER_SYSTEM;
Kenny Guy70e0c582015-06-30 19:18:28 +01001742 }
1743
Eric Laurent25101b02011-02-02 09:33:30 -08001744 // UI update and Broadcast Intent
1745 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
John Spurlock72966d62015-06-18 15:45:07 -04001746 streamType = mStreamVolumeAlias[streamType];
Eric Laurent25101b02011-02-02 09:33:30 -08001747
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001748 if (streamType == AudioSystem.STREAM_MUSIC) {
1749 flags = updateFlagsForSystemAudio(flags);
Jungshik Jang1a6be6e2014-09-16 11:04:54 +09001750 }
John Spurlock3346a802014-05-20 16:25:37 -04001751 mVolumeController.postVolumeChanged(streamType, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001752 }
1753
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001754 // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
1755 // receives volume notification from Audio Receiver.
1756 private int updateFlagsForSystemAudio(int flags) {
1757 if (mHdmiTvClient != null) {
1758 synchronized (mHdmiTvClient) {
1759 if (mHdmiSystemAudioSupported &&
1760 ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
1761 flags &= ~AudioManager.FLAG_SHOW_UI;
1762 }
1763 }
1764 }
1765 return flags;
1766 }
1767
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001768 // UI update and Broadcast Intent
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001769 private void sendMasterMuteUpdate(boolean muted, int flags) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001770 mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
Justin Koh57978ed2012-04-03 17:37:58 -07001771 broadcastMasterMuteStatus(muted);
1772 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001773
Justin Koh57978ed2012-04-03 17:37:58 -07001774 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001775 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1776 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001777 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1778 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001779 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001780 }
1781
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001782 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001783 * Sets the stream state's index, and posts a message to set system volume.
1784 * This will not call out to the UI. Assumes a valid stream type.
1785 *
1786 * @param streamType Type of the stream
1787 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001788 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001789 * @param force If true, set the volume even if the desired volume is same
1790 * as the current volume.
1791 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001792 private void setStreamVolumeInt(int streamType,
1793 int index,
1794 int device,
John Spurlock90874332015-03-10 16:00:54 -04001795 boolean force,
1796 String caller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001797 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07001798
John Spurlock90874332015-03-10 16:00:54 -04001799 if (streamState.setIndex(index, device, caller) || force) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001800 // Post message to set system volume (it in turn will post a message
1801 // to persist).
1802 sendMsg(mAudioHandler,
1803 MSG_SET_DEVICE_VOLUME,
1804 SENDMSG_QUEUE,
1805 device,
1806 0,
1807 streamState,
1808 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001809 }
1810 }
1811
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001812 private void setSystemAudioMute(boolean state) {
1813 if (mHdmiManager == null || mHdmiTvClient == null) return;
1814 synchronized (mHdmiManager) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001815 if (!mHdmiSystemAudioSupported) return;
1816 synchronized (mHdmiTvClient) {
1817 final long token = Binder.clearCallingIdentity();
1818 try {
1819 mHdmiTvClient.setSystemAudioMute(state);
1820 } finally {
1821 Binder.restoreCallingIdentity(token);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001822 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001823 }
1824 }
1825 }
1826
Eric Laurent25101b02011-02-02 09:33:30 -08001827 /** get stream mute state. */
1828 public boolean isStreamMute(int streamType) {
RoboErik7c82ced2014-12-04 17:39:08 -08001829 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1830 streamType = getActiveStreamType(streamType);
1831 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001832 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08001833 return mStreamStates[streamType].mIsMuted;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001834 }
Eric Laurent25101b02011-02-02 09:33:30 -08001835 }
1836
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07001837 private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
1838 private IBinder mICallback; // To be notified of client's death
1839
1840 RmtSbmxFullVolDeathHandler(IBinder cb) {
1841 mICallback = cb;
1842 try {
1843 cb.linkToDeath(this, 0/*flags*/);
1844 } catch (RemoteException e) {
1845 Log.e(TAG, "can't link to death", e);
1846 }
1847 }
1848
1849 boolean isHandlerFor(IBinder cb) {
1850 return mICallback.equals(cb);
1851 }
1852
1853 void forget() {
1854 try {
1855 mICallback.unlinkToDeath(this, 0/*flags*/);
1856 } catch (NoSuchElementException e) {
1857 Log.e(TAG, "error unlinking to death", e);
1858 }
1859 }
1860
1861 public void binderDied() {
1862 Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
1863 forceRemoteSubmixFullVolume(false, mICallback);
1864 }
1865 }
1866
1867 /**
1868 * call must be synchronized on mRmtSbmxFullVolDeathHandlers
1869 * @return true if there is a registered death handler, false otherwise */
1870 private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1871 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1872 while (it.hasNext()) {
1873 final RmtSbmxFullVolDeathHandler handler = it.next();
1874 if (handler.isHandlerFor(cb)) {
1875 handler.forget();
1876 mRmtSbmxFullVolDeathHandlers.remove(handler);
1877 return true;
1878 }
1879 }
1880 return false;
1881 }
1882
1883 /** call synchronized on mRmtSbmxFullVolDeathHandlers */
1884 private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1885 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1886 while (it.hasNext()) {
1887 if (it.next().isHandlerFor(cb)) {
1888 return true;
1889 }
1890 }
1891 return false;
1892 }
1893
1894 private int mRmtSbmxFullVolRefCount = 0;
1895 private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
1896 new ArrayList<RmtSbmxFullVolDeathHandler>();
1897
1898 public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
1899 if (cb == null) {
1900 return;
1901 }
1902 if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
1903 android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
1904 Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
1905 return;
1906 }
1907 synchronized(mRmtSbmxFullVolDeathHandlers) {
1908 boolean applyRequired = false;
1909 if (startForcing) {
1910 if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
1911 mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
1912 if (mRmtSbmxFullVolRefCount == 0) {
1913 mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1914 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1915 applyRequired = true;
1916 }
1917 mRmtSbmxFullVolRefCount++;
1918 }
1919 } else {
1920 if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
1921 mRmtSbmxFullVolRefCount--;
1922 if (mRmtSbmxFullVolRefCount == 0) {
1923 mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1924 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1925 applyRequired = true;
1926 }
1927 }
1928 }
1929 if (applyRequired) {
1930 // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
1931 checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
1932 mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
1933 }
1934 }
1935 }
1936
Kenny Guy70e0c582015-06-30 19:18:28 +01001937 private void setMasterMuteInternal(boolean mute, int flags, String callingPackage, int uid,
1938 int userId) {
1939 // If we are being called by the system check for user we are going to change
1940 // so we handle user restrictions correctly.
1941 if (uid == android.os.Process.SYSTEM_UID) {
1942 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
1943 }
Makoto Onuki4f160732015-10-27 17:15:38 -07001944 // If OP_AUDIO_MASTER_VOLUME is set, disallow unmuting.
1945 if (!mute && mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
RoboErik7c82ced2014-12-04 17:39:08 -08001946 != AppOpsManager.MODE_ALLOWED) {
Julia Reynolds4a21b252014-06-04 11:11:43 -04001947 return;
1948 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001949 if (userId != UserHandle.getCallingUserId() &&
1950 mContext.checkCallingOrSelfPermission(
1951 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1952 != PackageManager.PERMISSION_GRANTED) {
1953 return;
1954 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08001955 setMasterMuteInternalNoCallerCheck(mute, flags, userId);
1956 }
1957
1958 private void setMasterMuteInternalNoCallerCheck(boolean mute, int flags, int userId) {
1959 if (DEBUG_VOL) {
1960 Log.d(TAG, String.format("Master mute %s, %d, user=%d", mute, flags, userId));
1961 }
1962 if (mUseFixedVolume) {
1963 return; // If using fixed volume, we don't mute.
1964 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001965 if (getCurrentUserId() == userId) {
1966 if (mute != AudioSystem.getMasterMute()) {
1967 setSystemAudioMute(mute);
1968 AudioSystem.setMasterMute(mute);
Kenny Guy70e0c582015-06-30 19:18:28 +01001969 sendMasterMuteUpdate(mute, flags);
RoboErik7c82ced2014-12-04 17:39:08 -08001970
Kenny Guy70e0c582015-06-30 19:18:28 +01001971 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1972 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute);
1973 sendBroadcastToAll(intent);
1974 }
Jason Simmons1ce5b262012-02-02 13:00:17 -08001975 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08001976 }
1977
1978 /** get master mute state. */
1979 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08001980 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001981 }
1982
Kenny Guy70e0c582015-06-30 19:18:28 +01001983 public void setMasterMute(boolean mute, int flags, String callingPackage, int userId) {
1984 setMasterMuteInternal(mute, flags, callingPackage, Binder.getCallingUid(),
1985 userId);
John Spurlockee5ad722015-03-03 16:17:21 -05001986 }
1987
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001988 /** @see AudioManager#getStreamVolume(int) */
1989 public int getStreamVolume(int streamType) {
1990 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001991 int device = getDeviceForStream(streamType);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001992 synchronized (VolumeStreamState.class) {
1993 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001994
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001995 // by convention getStreamVolume() returns 0 when a stream is muted.
RoboErik4197cb62015-01-21 15:45:32 -08001996 if (mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001997 index = 0;
1998 }
1999 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
2000 (device & mFixedVolumeDevices) != 0) {
2001 index = mStreamStates[streamType].getMaxIndex();
2002 }
2003 return (index + 5) / 10;
Eric Laurent42b041e2013-03-29 11:36:03 -07002004 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002005 }
2006
2007 /** @see AudioManager#getStreamMaxVolume(int) */
2008 public int getStreamMaxVolume(int streamType) {
2009 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07002010 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002011 }
2012
John Spurlockb6e19e32015-03-10 21:33:44 -04002013 /** @see AudioManager#getStreamMinVolume(int) */
2014 public int getStreamMinVolume(int streamType) {
2015 ensureValidStreamType(streamType);
2016 return (mStreamStates[streamType].getMinIndex() + 5) / 10;
2017 }
2018
Eric Laurent25101b02011-02-02 09:33:30 -08002019 /** Get last audible volume before stream was muted. */
2020 public int getLastAudibleStreamVolume(int streamType) {
2021 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002022 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07002023 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08002024 }
2025
John Spurlockee5ad722015-03-03 16:17:21 -05002026 /** @see AudioManager#getUiSoundsStreamType() */
2027 public int getUiSoundsStreamType() {
John Spurlock4f0f1202014-08-05 13:28:33 -04002028 return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
Eric Laurent6d517662012-04-23 18:42:39 -07002029 }
2030
Makoto Onukid45a4a22015-11-02 17:17:38 -08002031 /** @see AudioManager#setMicrophoneMute(boolean) */
2032 @Override
Kenny Guy70e0c582015-06-30 19:18:28 +01002033 public void setMicrophoneMute(boolean on, String callingPackage, int userId) {
2034 // If we are being called by the system check for user we are going to change
2035 // so we handle user restrictions correctly.
2036 int uid = Binder.getCallingUid();
2037 if (uid == android.os.Process.SYSTEM_UID) {
2038 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
2039 }
Makoto Onuki4f160732015-10-27 17:15:38 -07002040 // If OP_MUTE_MICROPHONE is set, disallow unmuting.
2041 if (!on && mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, uid, callingPackage)
Kenny Guy70e0c582015-06-30 19:18:28 +01002042 != AppOpsManager.MODE_ALLOWED) {
Emily Bernier22c921a2014-05-28 11:01:32 -04002043 return;
2044 }
Jean-Michel Trivi4a4fea02014-08-29 18:14:09 -07002045 if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
2046 return;
2047 }
Kenny Guy70e0c582015-06-30 19:18:28 +01002048 if (userId != UserHandle.getCallingUserId() &&
2049 mContext.checkCallingOrSelfPermission(
2050 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
2051 != PackageManager.PERMISSION_GRANTED) {
2052 return;
2053 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08002054 setMicrophoneMuteNoCallerCheck(on, userId);
2055 }
Emily Bernier22c921a2014-05-28 11:01:32 -04002056
Makoto Onukid45a4a22015-11-02 17:17:38 -08002057 private void setMicrophoneMuteNoCallerCheck(boolean on, int userId) {
2058 if (DEBUG_VOL) {
2059 Log.d(TAG, String.format("Mic mute %s, user=%d", on, userId));
2060 }
Kenny Guy70e0c582015-06-30 19:18:28 +01002061 // If mute is for current user actually mute, else just persist the setting
2062 // which will be loaded on user switch.
2063 if (getCurrentUserId() == userId) {
2064 AudioSystem.muteMicrophone(on);
2065 }
Julia Reynoldsb53453f2014-08-22 11:42:43 -04002066 // Post a persist microphone msg.
Emily Bernier22c921a2014-05-28 11:01:32 -04002067 }
2068
John Spurlock661f2cf2014-11-17 10:29:10 -05002069 @Override
2070 public int getRingerModeExternal() {
2071 synchronized(mSettingsLock) {
2072 return mRingerModeExternal;
2073 }
2074 }
2075
2076 @Override
2077 public int getRingerModeInternal() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08002078 synchronized(mSettingsLock) {
2079 return mRingerMode;
2080 }
2081 }
2082
2083 private void ensureValidRingerMode(int ringerMode) {
John Spurlock97559372014-10-24 16:27:36 -04002084 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08002085 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
2086 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002087 }
2088
John Spurlock97559372014-10-24 16:27:36 -04002089 /** @see AudioManager#isValidRingerMode(int) */
2090 public boolean isValidRingerMode(int ringerMode) {
2091 return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
2092 }
2093
John Spurlock661f2cf2014-11-17 10:29:10 -05002094 public void setRingerModeExternal(int ringerMode, String caller) {
Julia Reynolds48034f82016-03-09 10:15:16 -05002095 if (isAndroidNPlus(caller) && wouldToggleZenMode(ringerMode)
2096 && !mNm.isNotificationPolicyAccessGrantedForPackage(caller)) {
2097 throw new SecurityException("Not allowed to change Do Not Disturb state");
2098 }
2099
John Spurlockaf88a192014-12-23 16:14:44 -05002100 setRingerMode(ringerMode, caller, true /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05002101 }
2102
2103 public void setRingerModeInternal(int ringerMode, String caller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05002104 enforceVolumeController("setRingerModeInternal");
John Spurlockaf88a192014-12-23 16:14:44 -05002105 setRingerMode(ringerMode, caller, false /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05002106 }
2107
2108 private void setRingerMode(int ringerMode, String caller, boolean external) {
Muyuan Li1ed6df62016-06-18 11:16:52 -07002109 if (mUseFixedVolume || mIsSingleVolume) {
Eric Laurent83a017b2013-03-19 18:15:31 -07002110 return;
2111 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002112 if (caller == null || caller.length() == 0) {
2113 throw new IllegalArgumentException("Bad caller: " + caller);
2114 }
John Spurlock97559372014-10-24 16:27:36 -04002115 ensureValidRingerMode(ringerMode);
Eric Laurent24482012012-05-10 09:41:17 -07002116 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
2117 ringerMode = AudioManager.RINGER_MODE_SILENT;
2118 }
John Spurlockaf88a192014-12-23 16:14:44 -05002119 final long identity = Binder.clearCallingIdentity();
2120 try {
2121 synchronized (mSettingsLock) {
2122 final int ringerModeInternal = getRingerModeInternal();
2123 final int ringerModeExternal = getRingerModeExternal();
2124 if (external) {
2125 setRingerModeExt(ringerMode);
2126 if (mRingerModeDelegate != null) {
2127 ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
John Spurlocka48d7792015-03-03 17:35:57 -05002128 ringerMode, caller, ringerModeInternal, mVolumePolicy);
John Spurlockaf88a192014-12-23 16:14:44 -05002129 }
2130 if (ringerMode != ringerModeInternal) {
2131 setRingerModeInt(ringerMode, true /*persist*/);
2132 }
2133 } else /*internal*/ {
2134 if (ringerMode != ringerModeInternal) {
2135 setRingerModeInt(ringerMode, true /*persist*/);
2136 }
2137 if (mRingerModeDelegate != null) {
2138 ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
John Spurlocka48d7792015-03-03 17:35:57 -05002139 ringerMode, caller, ringerModeExternal, mVolumePolicy);
John Spurlockaf88a192014-12-23 16:14:44 -05002140 }
2141 setRingerModeExt(ringerMode);
John Spurlock57627792014-12-11 11:29:54 -05002142 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002143 }
John Spurlockaf88a192014-12-23 16:14:44 -05002144 } finally {
2145 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002146 }
2147 }
2148
John Spurlock661f2cf2014-11-17 10:29:10 -05002149 private void setRingerModeExt(int ringerMode) {
2150 synchronized(mSettingsLock) {
2151 if (ringerMode == mRingerModeExternal) return;
2152 mRingerModeExternal = ringerMode;
John Spurlocke5b42d92014-10-15 12:03:48 -04002153 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002154 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05002155 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
John Spurlocke5b42d92014-10-15 12:03:48 -04002156 }
2157
John Spurlock50ced3f2015-05-11 16:00:09 -04002158 private void muteRingerModeStreams() {
Eric Laurent5b4e6542010-03-19 20:02:21 -07002159 // Mute stream if not previously muted by ringer mode and ringer mode
2160 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
2161 // Unmute stream if previously muted by ringer mode and ringer mode
2162 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07002163 int numStreamTypes = AudioSystem.getNumStreamTypes();
John Spurlock50ced3f2015-05-11 16:00:09 -04002164 final boolean ringerModeMute = mRingerMode == AudioManager.RINGER_MODE_VIBRATE
2165 || mRingerMode == AudioManager.RINGER_MODE_SILENT;
Eric Laurent5b4e6542010-03-19 20:02:21 -07002166 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002167 final boolean isMuted = isStreamMutedByRingerMode(streamType);
2168 final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
2169 if (isMuted == shouldMute) continue;
2170 if (!shouldMute) {
2171 // unmute
2172 // ring and notifications volume should never be 0 when not silenced
John Spurlockd9c75db2015-04-28 11:19:13 -04002173 if (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002174 synchronized (VolumeStreamState.class) {
John Spurlocka48d7792015-03-03 17:35:57 -05002175 final VolumeStreamState vss = mStreamStates[streamType];
2176 for (int i = 0; i < vss.mIndexMap.size(); i++) {
2177 int device = vss.mIndexMap.keyAt(i);
2178 int value = vss.mIndexMap.valueAt(i);
John Spurlock2bb02ec2015-03-02 13:13:06 -05002179 if (value == 0) {
John Spurlocka48d7792015-03-03 17:35:57 -05002180 vss.setIndex(10, device, TAG);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002181 }
2182 }
Eric Laurent9e0d25f2015-02-12 17:28:53 -08002183 // Persist volume for stream ring when it is changed here
2184 final int device = getDeviceForStream(streamType);
2185 sendMsg(mAudioHandler,
2186 MSG_PERSIST_VOLUME,
2187 SENDMSG_QUEUE,
2188 device,
2189 0,
2190 mStreamStates[streamType],
2191 PERSIST_DELAY);
Eric Laurentb024c302011-10-14 17:19:27 -07002192 }
Eric Laurent9bcf4012009-06-12 06:09:28 -07002193 }
RoboErik4197cb62015-01-21 15:45:32 -08002194 mStreamStates[streamType].mute(false);
John Spurlock661f2cf2014-11-17 10:29:10 -05002195 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent5b4e6542010-03-19 20:02:21 -07002196 } else {
John Spurlock661f2cf2014-11-17 10:29:10 -05002197 // mute
RoboErik4197cb62015-01-21 15:45:32 -08002198 mStreamStates[streamType].mute(true);
John Spurlock661f2cf2014-11-17 10:29:10 -05002199 mRingerModeMutedStreams |= (1 << streamType);
Jason Parekhb1096152009-03-24 17:48:25 -07002200 }
2201 }
John Spurlock50ced3f2015-05-11 16:00:09 -04002202 }
2203
2204 private void setRingerModeInt(int ringerMode, boolean persist) {
2205 final boolean change;
2206 synchronized(mSettingsLock) {
2207 change = mRingerMode != ringerMode;
2208 mRingerMode = ringerMode;
2209 }
2210
2211 muteRingerModeStreams();
Eric Laurenta553c252009-07-17 12:17:14 -07002212
Jason Parekhb1096152009-03-24 17:48:25 -07002213 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07002214 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002215 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07002216 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
2217 }
John Spurlockbcc10872014-11-28 15:29:21 -05002218 if (change) {
2219 // Send sticky broadcast
2220 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
2221 }
Jason Parekhb1096152009-03-24 17:48:25 -07002222 }
2223
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002224 /** @see AudioManager#shouldVibrate(int) */
2225 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002226 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002227
2228 switch (getVibrateSetting(vibrateType)) {
2229
2230 case AudioManager.VIBRATE_SETTING_ON:
John Spurlock57627792014-12-11 11:29:54 -05002231 return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002232
2233 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
John Spurlock57627792014-12-11 11:29:54 -05002234 return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002235
2236 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04002237 // return false, even for incoming calls
2238 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002239
2240 default:
2241 return false;
2242 }
2243 }
2244
2245 /** @see AudioManager#getVibrateSetting(int) */
2246 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002247 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002248 return (mVibrateSetting >> (vibrateType * 2)) & 3;
2249 }
2250
2251 /** @see AudioManager#setVibrateSetting(int, int) */
2252 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
2253
Eric Laurentbffc3d12012-05-07 17:43:49 -07002254 if (!mHasVibrator) return;
2255
John Spurlock61560172015-02-06 19:46:04 -05002256 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
2257 vibrateSetting);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002258
2259 // Broadcast change
2260 broadcastVibrateSetting(vibrateType);
2261
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002262 }
2263
Eric Laurent9272b4b2010-01-23 17:12:59 -08002264 private class SetModeDeathHandler implements IBinder.DeathRecipient {
2265 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002266 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002267 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
2268
Eric Laurent9f103de2011-09-08 15:04:23 -07002269 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08002270 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07002271 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002272 }
2273
2274 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07002275 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002276 synchronized(mSetModeDeathHandlers) {
2277 Log.w(TAG, "setMode() client died");
2278 int index = mSetModeDeathHandlers.indexOf(this);
2279 if (index < 0) {
2280 Log.w(TAG, "unregistered setMode() client died");
2281 } else {
John Spurlock90874332015-03-10 16:00:54 -04002282 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid, TAG);
Eric Laurent9272b4b2010-01-23 17:12:59 -08002283 }
2284 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002285 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2286 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002287 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07002288 final long ident = Binder.clearCallingIdentity();
2289 disconnectBluetoothSco(newModeOwnerPid);
2290 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07002291 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08002292 }
2293
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002294 public int getPid() {
2295 return mPid;
2296 }
2297
Eric Laurent9272b4b2010-01-23 17:12:59 -08002298 public void setMode(int mode) {
2299 mMode = mode;
2300 }
2301
2302 public int getMode() {
2303 return mMode;
2304 }
2305
2306 public IBinder getBinder() {
2307 return mCb;
2308 }
2309 }
2310
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002311 /** @see AudioManager#setMode(int) */
John Spurlock90874332015-03-10 16:00:54 -04002312 public void setMode(int mode, IBinder cb, String callingPackage) {
2313 if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ", callingPackage=" + callingPackage + ")"); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002314 if (!checkAudioSettingsPermission("setMode()")) {
2315 return;
2316 }
Eric Laurenta553c252009-07-17 12:17:14 -07002317
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07002318 if ( (mode == AudioSystem.MODE_IN_CALL) &&
2319 (mContext.checkCallingOrSelfPermission(
2320 android.Manifest.permission.MODIFY_PHONE_STATE)
2321 != PackageManager.PERMISSION_GRANTED)) {
2322 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
2323 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
2324 return;
2325 }
2326
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08002327 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07002328 return;
2329 }
2330
Eric Laurentd7454be2011-09-14 08:45:58 -07002331 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002332 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07002333 if (mode == AudioSystem.MODE_CURRENT) {
2334 mode = mMode;
2335 }
John Spurlock90874332015-03-10 16:00:54 -04002336 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid(), callingPackage);
Eric Laurent9f103de2011-09-08 15:04:23 -07002337 }
2338 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2339 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002340 if (newModeOwnerPid != 0) {
2341 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07002342 }
2343 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002344
Eric Laurent9f103de2011-09-08 15:04:23 -07002345 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07002346 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07002347 // any mode other than NORMAL.
John Spurlock90874332015-03-10 16:00:54 -04002348 private int setModeInt(int mode, IBinder cb, int pid, String caller) {
2349 if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ", caller="
2350 + caller + ")"); }
Eric Laurentd7454be2011-09-14 08:45:58 -07002351 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002352 if (cb == null) {
2353 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07002354 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07002355 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002356
Eric Laurent9f103de2011-09-08 15:04:23 -07002357 SetModeDeathHandler hdlr = null;
2358 Iterator iter = mSetModeDeathHandlers.iterator();
2359 while (iter.hasNext()) {
2360 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
2361 if (h.getPid() == pid) {
2362 hdlr = h;
2363 // Remove from client list so that it is re-inserted at top of list
2364 iter.remove();
2365 hdlr.getBinder().unlinkToDeath(hdlr, 0);
2366 break;
2367 }
2368 }
2369 int status = AudioSystem.AUDIO_STATUS_OK;
2370 do {
2371 if (mode == AudioSystem.MODE_NORMAL) {
2372 // get new mode from client at top the list if any
2373 if (!mSetModeDeathHandlers.isEmpty()) {
2374 hdlr = mSetModeDeathHandlers.get(0);
2375 cb = hdlr.getBinder();
2376 mode = hdlr.getMode();
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002377 if (DEBUG_MODE) {
2378 Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
2379 + hdlr.mPid);
2380 }
Eric Laurentb9c9d262009-05-06 08:13:20 -07002381 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002382 } else {
2383 if (hdlr == null) {
2384 hdlr = new SetModeDeathHandler(cb, pid);
2385 }
2386 // Register for client death notification
2387 try {
2388 cb.linkToDeath(hdlr, 0);
2389 } catch (RemoteException e) {
2390 // Client has died!
2391 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
2392 }
2393
2394 // Last client to call setMode() is always at top of client list
2395 // as required by SetModeDeathHandler.binderDied()
2396 mSetModeDeathHandlers.add(0, hdlr);
2397 hdlr.setMode(mode);
2398 }
2399
2400 if (mode != mMode) {
2401 status = AudioSystem.setPhoneState(mode);
2402 if (status == AudioSystem.AUDIO_STATUS_OK) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002403 if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002404 mMode = mode;
2405 } else {
2406 if (hdlr != null) {
2407 mSetModeDeathHandlers.remove(hdlr);
2408 cb.unlinkToDeath(hdlr, 0);
2409 }
2410 // force reading new top of mSetModeDeathHandlers stack
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002411 if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002412 mode = AudioSystem.MODE_NORMAL;
2413 }
2414 } else {
2415 status = AudioSystem.AUDIO_STATUS_OK;
2416 }
2417 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
2418
2419 if (status == AudioSystem.AUDIO_STATUS_OK) {
2420 if (mode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002421 if (mSetModeDeathHandlers.isEmpty()) {
2422 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
2423 } else {
2424 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2425 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002426 }
2427 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002428 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07002429 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
John Spurlock90874332015-03-10 16:00:54 -04002430 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, caller);
Eric Laurent6d517662012-04-23 18:42:39 -07002431
John Spurlock90874332015-03-10 16:00:54 -04002432 updateStreamVolumeAlias(true /*updateVolumes*/, caller);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002433 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002434 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002435 }
2436
2437 /** @see AudioManager#getMode() */
2438 public int getMode() {
2439 return mMode;
2440 }
2441
Eric Laurente78fced2013-03-15 16:03:47 -07002442 //==========================================================================================
2443 // Sound Effects
2444 //==========================================================================================
2445
2446 private static final String TAG_AUDIO_ASSETS = "audio_assets";
2447 private static final String ATTR_VERSION = "version";
2448 private static final String TAG_GROUP = "group";
2449 private static final String ATTR_GROUP_NAME = "name";
2450 private static final String TAG_ASSET = "asset";
2451 private static final String ATTR_ASSET_ID = "id";
2452 private static final String ATTR_ASSET_FILE = "file";
2453
2454 private static final String ASSET_FILE_VERSION = "1.0";
2455 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
2456
Glenn Kasten167d1a22013-07-23 16:24:41 -07002457 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002458
2459 class LoadSoundEffectReply {
2460 public int mStatus = 1;
2461 };
2462
Eric Laurente78fced2013-03-15 16:03:47 -07002463 private void loadTouchSoundAssetDefaults() {
2464 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
2465 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
2466 SOUND_EFFECT_FILES_MAP[i][0] = 0;
2467 SOUND_EFFECT_FILES_MAP[i][1] = -1;
2468 }
2469 }
2470
2471 private void loadTouchSoundAssets() {
2472 XmlResourceParser parser = null;
2473
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002474 // only load assets once.
2475 if (!SOUND_EFFECT_FILES.isEmpty()) {
2476 return;
2477 }
2478
Eric Laurente78fced2013-03-15 16:03:47 -07002479 loadTouchSoundAssetDefaults();
2480
2481 try {
2482 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
2483
2484 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
2485 String version = parser.getAttributeValue(null, ATTR_VERSION);
2486 boolean inTouchSoundsGroup = false;
2487
2488 if (ASSET_FILE_VERSION.equals(version)) {
2489 while (true) {
2490 XmlUtils.nextElement(parser);
2491 String element = parser.getName();
2492 if (element == null) {
2493 break;
2494 }
2495 if (element.equals(TAG_GROUP)) {
2496 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
2497 if (GROUP_TOUCH_SOUNDS.equals(name)) {
2498 inTouchSoundsGroup = true;
2499 break;
2500 }
2501 }
2502 }
2503 while (inTouchSoundsGroup) {
2504 XmlUtils.nextElement(parser);
2505 String element = parser.getName();
2506 if (element == null) {
2507 break;
2508 }
2509 if (element.equals(TAG_ASSET)) {
2510 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
2511 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
2512 int fx;
2513
2514 try {
2515 Field field = AudioManager.class.getField(id);
2516 fx = field.getInt(null);
2517 } catch (Exception e) {
2518 Log.w(TAG, "Invalid touch sound ID: "+id);
2519 continue;
2520 }
2521
2522 int i = SOUND_EFFECT_FILES.indexOf(file);
2523 if (i == -1) {
2524 i = SOUND_EFFECT_FILES.size();
2525 SOUND_EFFECT_FILES.add(file);
2526 }
2527 SOUND_EFFECT_FILES_MAP[fx][0] = i;
2528 } else {
2529 break;
2530 }
2531 }
2532 }
2533 } catch (Resources.NotFoundException e) {
2534 Log.w(TAG, "audio assets file not found", e);
2535 } catch (XmlPullParserException e) {
2536 Log.w(TAG, "XML parser exception reading touch sound assets", e);
2537 } catch (IOException e) {
2538 Log.w(TAG, "I/O exception reading touch sound assets", e);
2539 } finally {
2540 if (parser != null) {
2541 parser.close();
2542 }
2543 }
2544 }
2545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002546 /** @see AudioManager#playSoundEffect(int) */
2547 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002548 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002549 }
2550
2551 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002552 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07002553 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
2554 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
2555 return;
2556 }
2557
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002558 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002559 effectType, (int) (volume * 1000), null, 0);
2560 }
2561
2562 /**
2563 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08002564 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002565 */
2566 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002567 int attempts = 3;
2568 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08002569
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002570 synchronized (reply) {
2571 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
2572 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08002573 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07002574 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002575 } catch (InterruptedException e) {
2576 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08002577 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002578 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002579 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002580 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002581 }
2582
2583 /**
2584 * Unloads samples from the sound pool.
2585 * This method can be called to free some memory when
2586 * sound effects are disabled.
2587 */
2588 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002589 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002590 }
2591
Eric Laurenta60e2122010-12-28 16:49:07 -08002592 class SoundPoolListenerThread extends Thread {
2593 public SoundPoolListenerThread() {
2594 super("SoundPoolListenerThread");
2595 }
2596
2597 @Override
2598 public void run() {
2599
2600 Looper.prepare();
2601 mSoundPoolLooper = Looper.myLooper();
2602
2603 synchronized (mSoundEffectsLock) {
2604 if (mSoundPool != null) {
2605 mSoundPoolCallBack = new SoundPoolCallback();
2606 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2607 }
2608 mSoundEffectsLock.notify();
2609 }
2610 Looper.loop();
2611 }
2612 }
2613
2614 private final class SoundPoolCallback implements
2615 android.media.SoundPool.OnLoadCompleteListener {
2616
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002617 int mStatus = 1; // 1 means neither error nor last sample loaded yet
2618 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08002619
2620 public int status() {
2621 return mStatus;
2622 }
2623
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002624 public void setSamples(int[] samples) {
2625 for (int i = 0; i < samples.length; i++) {
2626 // do not wait ack for samples rejected upfront by SoundPool
2627 if (samples[i] > 0) {
2628 mSamples.add(samples[i]);
2629 }
2630 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002631 }
2632
2633 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2634 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002635 int i = mSamples.indexOf(sampleId);
2636 if (i >= 0) {
2637 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08002638 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002639 if ((status != 0) || mSamples. isEmpty()) {
2640 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08002641 mSoundEffectsLock.notify();
2642 }
2643 }
2644 }
2645 }
2646
Eric Laurent4050c932009-07-08 02:52:14 -07002647 /** @see AudioManager#reloadAudioSettings() */
2648 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002649 readAudioSettings(false /*userSwitch*/);
2650 }
2651
2652 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07002653 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2654 readPersistedSettings();
Eric Laurentc0232482016-03-15 18:19:23 -07002655 readUserRestrictions();
Eric Laurent4050c932009-07-08 02:52:14 -07002656
2657 // restore volume settings
2658 int numStreamTypes = AudioSystem.getNumStreamTypes();
2659 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2660 VolumeStreamState streamState = mStreamStates[streamType];
2661
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002662 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2663 continue;
2664 }
2665
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002666 streamState.readSettings();
2667 synchronized (VolumeStreamState.class) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002668 // unmute stream that was muted but is not affect by mute anymore
RoboErik4197cb62015-01-21 15:45:32 -08002669 if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07002670 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
RoboErik4197cb62015-01-21 15:45:32 -08002671 streamState.mIsMuted = false;
Eric Laurent4050c932009-07-08 02:52:14 -07002672 }
Eric Laurent4050c932009-07-08 02:52:14 -07002673 }
2674 }
2675
Eric Laurent33902db2012-10-07 16:15:07 -07002676 // apply new ringer mode before checking volume for alias streams so that streams
2677 // muted by ringer mode have the correct volume
John Spurlock661f2cf2014-11-17 10:29:10 -05002678 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent33902db2012-10-07 16:15:07 -07002679
Eric Laurent212532b2014-07-21 15:43:18 -07002680 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07002681 checkAllAliasStreamVolumes();
John Spurlockb6e19e32015-03-10 21:33:44 -04002682 checkMuteAffectedStreams();
Eric Laurent24482012012-05-10 09:41:17 -07002683
Eric Laurentd640bd32012-09-28 18:01:48 -07002684 synchronized (mSafeMediaVolumeState) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002685 mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2686 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2687 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
Eric Laurentd640bd32012-09-28 18:01:48 -07002688 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
John Spurlock90874332015-03-10 16:00:54 -04002689 enforceSafeMediaVolume(TAG);
Eric Laurentf1a457d2012-09-20 16:27:23 -07002690 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07002691 }
Eric Laurent4050c932009-07-08 02:52:14 -07002692 }
2693
Dianne Hackborn961cae92013-03-20 14:59:43 -07002694 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002695 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002696 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2697 return;
2698 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002699
2700 if (on) {
2701 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2702 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2703 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
2704 }
2705 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2706 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2707 mForcedUseForComm = AudioSystem.FORCE_NONE;
2708 }
Eric Laurentfa640152011-03-12 15:59:51 -08002709
Eric Laurentafbb0472011-12-15 09:04:23 -08002710 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002711 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002712 }
2713
2714 /** @see AudioManager#isSpeakerphoneOn() */
2715 public boolean isSpeakerphoneOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002716 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002717 }
2718
Dianne Hackborn961cae92013-03-20 14:59:43 -07002719 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurent48221252015-09-24 18:41:48 -07002720 public void setBluetoothScoOn(boolean on) {
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002721 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2722 return;
2723 }
Eric Laurent48221252015-09-24 18:41:48 -07002724 setBluetoothScoOnInt(on);
2725 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002726
Eric Laurent48221252015-09-24 18:41:48 -07002727 public void setBluetoothScoOnInt(boolean on) {
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002728 if (on) {
2729 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2730 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2731 mForcedUseForComm = AudioSystem.FORCE_NONE;
2732 }
Eric Laurentfa640152011-03-12 15:59:51 -08002733
Eric Laurentafbb0472011-12-15 09:04:23 -08002734 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002735 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08002736 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002737 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002738 }
2739
2740 /** @see AudioManager#isBluetoothScoOn() */
2741 public boolean isBluetoothScoOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002742 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002743 }
2744
Sungsoocf09fe62016-09-28 16:21:48 +09002745 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07002746 public void setBluetoothA2dpOn(boolean on) {
Sungsoocf09fe62016-09-28 16:21:48 +09002747 synchronized (mBluetoothA2dpEnabledLock) {
2748 mBluetoothA2dpEnabled = on;
2749 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2750 AudioSystem.FOR_MEDIA,
2751 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2752 null, 0);
2753 }
Eric Laurent78472112012-05-21 08:57:21 -07002754 }
2755
Sungsoocf09fe62016-09-28 16:21:48 +09002756 /** @see AudioManager#isBluetoothA2dpOn() */
Eric Laurent78472112012-05-21 08:57:21 -07002757 public boolean isBluetoothA2dpOn() {
Sungsoocf09fe62016-09-28 16:21:48 +09002758 synchronized (mBluetoothA2dpEnabledLock) {
2759 return mBluetoothA2dpEnabled;
2760 }
Eric Laurent78472112012-05-21 08:57:21 -07002761 }
2762
Eric Laurent3def1ee2010-03-17 23:26:26 -07002763 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07002764 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
2765 int scoAudioMode =
2766 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
Liejun Taof4e51d82014-07-16 11:18:29 -07002767 SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
Eric Laurent83900752014-05-15 15:14:22 -07002768 startBluetoothScoInt(cb, scoAudioMode);
2769 }
2770
2771 /** @see AudioManager#startBluetoothScoVirtualCall() */
2772 public void startBluetoothScoVirtualCall(IBinder cb) {
2773 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
2774 }
2775
2776 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07002777 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002778 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002779 return;
2780 }
Eric Laurent854938a2011-02-22 12:05:20 -08002781 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002782 // The calling identity must be cleared before calling ScoClient.incCount().
2783 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2784 // and this must be done on behalf of system server to make sure permissions are granted.
2785 // The caller identity must be cleared after getScoClient() because it is needed if a new
2786 // client is created.
2787 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07002788 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08002789 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002790 }
2791
2792 /** @see AudioManager#stopBluetoothSco() */
2793 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07002794 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002795 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002796 return;
2797 }
Eric Laurent854938a2011-02-22 12:05:20 -08002798 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002799 // The calling identity must be cleared before calling ScoClient.decCount().
2800 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2801 // and this must be done on behalf of system server to make sure permissions are granted.
2802 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08002803 if (client != null) {
2804 client.decCount();
2805 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08002806 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002807 }
2808
Eric Laurent78472112012-05-21 08:57:21 -07002809
Eric Laurent3def1ee2010-03-17 23:26:26 -07002810 private class ScoClient implements IBinder.DeathRecipient {
2811 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002812 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002813 private int mStartcount; // number of SCO connections started by this client
2814
2815 ScoClient(IBinder cb) {
2816 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002817 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002818 mStartcount = 0;
2819 }
2820
2821 public void binderDied() {
2822 synchronized(mScoClients) {
2823 Log.w(TAG, "SCO client died");
2824 int index = mScoClients.indexOf(this);
2825 if (index < 0) {
2826 Log.w(TAG, "unregistered SCO client died");
2827 } else {
2828 clearCount(true);
2829 mScoClients.remove(this);
2830 }
2831 }
2832 }
2833
Eric Laurent83900752014-05-15 15:14:22 -07002834 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002835 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07002836 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002837 if (mStartcount == 0) {
2838 try {
2839 mCb.linkToDeath(this, 0);
2840 } catch (RemoteException e) {
2841 // client has already died!
2842 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
2843 }
2844 }
2845 mStartcount++;
2846 }
2847 }
2848
2849 public void decCount() {
2850 synchronized(mScoClients) {
2851 if (mStartcount == 0) {
2852 Log.w(TAG, "ScoClient.decCount() already 0");
2853 } else {
2854 mStartcount--;
2855 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002856 try {
2857 mCb.unlinkToDeath(this, 0);
2858 } catch (NoSuchElementException e) {
2859 Log.w(TAG, "decCount() going to 0 but not registered to binder");
2860 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002861 }
Eric Laurentc18c9132013-04-12 17:24:56 -07002862 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002863 }
2864 }
2865 }
2866
2867 public void clearCount(boolean stopSco) {
2868 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002869 if (mStartcount != 0) {
2870 try {
2871 mCb.unlinkToDeath(this, 0);
2872 } catch (NoSuchElementException e) {
2873 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2874 }
2875 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002876 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002877 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002878 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002879 }
2880 }
2881 }
2882
2883 public int getCount() {
2884 return mStartcount;
2885 }
2886
2887 public IBinder getBinder() {
2888 return mCb;
2889 }
2890
Eric Laurentd7454be2011-09-14 08:45:58 -07002891 public int getPid() {
2892 return mCreatorPid;
2893 }
2894
Eric Laurent3def1ee2010-03-17 23:26:26 -07002895 public int totalCount() {
2896 synchronized(mScoClients) {
2897 int count = 0;
2898 int size = mScoClients.size();
2899 for (int i = 0; i < size; i++) {
2900 count += mScoClients.get(i).getCount();
2901 }
2902 return count;
2903 }
2904 }
2905
Eric Laurent83900752014-05-15 15:14:22 -07002906 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08002907 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07002908 if (totalCount() == 0) {
2909 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2910 // Make sure that the state transitions to CONNECTING even if we cannot initiate
2911 // the connection.
2912 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2913 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002914 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07002915 synchronized(mSetModeDeathHandlers) {
2916 if ((mSetModeDeathHandlers.isEmpty() ||
2917 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2918 (mScoAudioState == SCO_STATE_INACTIVE ||
2919 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2920 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07002921 mScoAudioMode = scoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -07002922 if (scoAudioMode == SCO_MODE_UNDEFINED) {
Andre Eisenbach570cc532014-10-28 17:03:18 -07002923 if (mBluetoothHeadsetDevice != null) {
2924 mScoAudioMode = new Integer(Settings.Global.getInt(
2925 mContentResolver,
2926 "bluetooth_sco_channel_"+
2927 mBluetoothHeadsetDevice.getAddress(),
2928 SCO_MODE_VIRTUAL_CALL));
2929 if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2930 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2931 }
2932 } else {
2933 mScoAudioMode = SCO_MODE_RAW;
Liejun Taof4e51d82014-07-16 11:18:29 -07002934 }
2935 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002936 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002937 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002938 if (mScoAudioMode == SCO_MODE_RAW) {
2939 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002940 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002941 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2942 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002943 } else if (mScoAudioMode == SCO_MODE_VR) {
2944 status = mBluetoothHeadset.startVoiceRecognition(
2945 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002946 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002947
Eric Laurentc18c9132013-04-12 17:24:56 -07002948 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07002949 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2950 } else {
2951 broadcastScoConnectionState(
2952 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2953 }
2954 } else if (getBluetoothHeadset()) {
2955 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07002956 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002957 } else {
2958 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2959 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002960 }
2961 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07002962 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002963 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002964 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002965 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002966 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2967 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2968 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07002969 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002970 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002971 if (mScoAudioMode == SCO_MODE_RAW) {
2972 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002973 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002974 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2975 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002976 } else if (mScoAudioMode == SCO_MODE_VR) {
2977 status = mBluetoothHeadset.stopVoiceRecognition(
2978 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002979 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002980
Eric Laurentc18c9132013-04-12 17:24:56 -07002981 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002982 mScoAudioState = SCO_STATE_INACTIVE;
2983 broadcastScoConnectionState(
2984 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2985 }
2986 } else if (getBluetoothHeadset()) {
2987 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2988 }
2989 } else {
2990 mScoAudioState = SCO_STATE_INACTIVE;
2991 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2992 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002993 }
2994 }
2995 }
2996 }
2997
Eric Laurent62ef7672010-11-24 10:58:32 -08002998 private void checkScoAudioState() {
2999 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07003000 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08003001 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
3002 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
3003 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
3004 }
3005 }
3006
Eric Laurent854938a2011-02-22 12:05:20 -08003007 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07003008 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08003009 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003010 int size = mScoClients.size();
3011 for (int i = 0; i < size; i++) {
3012 client = mScoClients.get(i);
3013 if (client.getBinder() == cb)
3014 return client;
3015 }
Eric Laurent854938a2011-02-22 12:05:20 -08003016 if (create) {
3017 client = new ScoClient(cb);
3018 mScoClients.add(client);
3019 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07003020 return client;
3021 }
3022 }
3023
Eric Laurentd7454be2011-09-14 08:45:58 -07003024 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07003025 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08003026 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003027 int size = mScoClients.size();
3028 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08003029 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07003030 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08003031 cl.clearCount(stopSco);
3032 } else {
3033 savedClient = cl;
3034 }
3035 }
3036 mScoClients.clear();
3037 if (savedClient != null) {
3038 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003039 }
3040 }
3041 }
3042
Eric Laurentdc03c612011-04-01 10:59:41 -07003043 private boolean getBluetoothHeadset() {
3044 boolean result = false;
3045 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
3046 if (adapter != null) {
3047 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
3048 BluetoothProfile.HEADSET);
3049 }
3050 // If we could not get a bluetooth headset proxy, send a failure message
3051 // without delay to reset the SCO audio state and clear SCO clients.
3052 // If we could get a proxy, send a delayed failure message that will reset our state
3053 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08003054 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07003055 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
3056 return result;
3057 }
3058
Eric Laurentd7454be2011-09-14 08:45:58 -07003059 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07003060 synchronized(mScoClients) {
3061 checkScoAudioState();
3062 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
3063 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
3064 if (mBluetoothHeadsetDevice != null) {
3065 if (mBluetoothHeadset != null) {
3066 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07003067 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08003068 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07003069 SENDMSG_REPLACE, 0, 0, null, 0);
3070 }
3071 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
3072 getBluetoothHeadset()) {
3073 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
3074 }
3075 }
3076 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07003077 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07003078 }
3079 }
3080 }
3081
3082 private void resetBluetoothSco() {
3083 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07003084 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07003085 mScoAudioState = SCO_STATE_INACTIVE;
3086 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3087 }
Eric Laurent48221252015-09-24 18:41:48 -07003088 AudioSystem.setParameters("A2dpSuspended=false");
3089 setBluetoothScoOnInt(false);
Eric Laurentdc03c612011-04-01 10:59:41 -07003090 }
3091
3092 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08003093 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
3094 SENDMSG_QUEUE, state, 0, null, 0);
3095 }
3096
3097 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07003098 if (state != mScoConnectionState) {
3099 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
3100 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
3101 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
3102 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003103 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07003104 mScoConnectionState = state;
3105 }
3106 }
3107
Eric Laurent98859b22015-06-12 14:35:59 -07003108 void setBtScoDeviceConnectionState(BluetoothDevice btDevice, int state) {
3109 if (btDevice == null) {
3110 return;
3111 }
3112
3113 String address = btDevice.getAddress();
3114 BluetoothClass btClass = btDevice.getBluetoothClass();
3115 int outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
3116 int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
3117 if (btClass != null) {
3118 switch (btClass.getDeviceClass()) {
3119 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
3120 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
3121 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
3122 break;
3123 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
3124 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
3125 break;
3126 }
3127 }
3128
3129 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
3130 address = "";
3131 }
3132
3133 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
3134
3135 String btDeviceName = btDevice.getName();
3136 boolean success =
3137 handleDeviceConnection(connected, outDevice, address, btDeviceName) &&
3138 handleDeviceConnection(connected, inDevice, address, btDeviceName);
Satish Kodishala29809802016-01-18 14:23:12 +05303139
3140 if (!success) {
3141 return;
3142 }
3143
3144 /* When one BT headset is disconnected while another BT headset
3145 * is connected, don't mess with the headset device.
3146 */
3147 if ((state == BluetoothProfile.STATE_DISCONNECTED ||
3148 state == BluetoothProfile.STATE_DISCONNECTING) &&
3149 mBluetoothHeadset != null &&
3150 mBluetoothHeadset.getAudioState(btDevice) == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
3151 Log.w(TAG, "SCO connected through another device, returning");
3152 return;
3153 }
3154
3155 synchronized (mScoClients) {
3156 if (connected) {
3157 mBluetoothHeadsetDevice = btDevice;
3158 } else {
3159 mBluetoothHeadsetDevice = null;
3160 resetBluetoothSco();
Eric Laurent98859b22015-06-12 14:35:59 -07003161 }
3162 }
3163 }
3164
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07003165 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
3166 new BluetoothProfile.ServiceListener() {
3167 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003168 BluetoothDevice btDevice;
3169 List<BluetoothDevice> deviceList;
3170 switch(profile) {
3171 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09003172 synchronized (mConnectedDevices) {
3173 synchronized (mA2dpAvrcpLock) {
3174 mA2dp = (BluetoothA2dp) proxy;
3175 deviceList = mA2dp.getConnectedDevices();
3176 if (deviceList.size() > 0) {
3177 btDevice = deviceList.get(0);
John Du5a0cf7a2013-07-19 11:30:34 -07003178 int state = mA2dp.getConnectionState(btDevice);
3179 int delay = checkSendBecomingNoisyIntent(
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003180 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3181 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
John Du5a0cf7a2013-07-19 11:30:34 -07003182 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003183 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07003184 state,
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08003185 0 /* arg2 unused */,
John Du5a0cf7a2013-07-19 11:30:34 -07003186 btDevice,
3187 delay);
3188 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003189 }
Eric Laurent62ef7672010-11-24 10:58:32 -08003190 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003191 break;
3192
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003193 case BluetoothProfile.A2DP_SINK:
3194 deviceList = proxy.getConnectedDevices();
3195 if (deviceList.size() > 0) {
3196 btDevice = deviceList.get(0);
3197 synchronized (mConnectedDevices) {
3198 int state = proxy.getConnectionState(btDevice);
3199 queueMsgUnderWakeLock(mAudioHandler,
3200 MSG_SET_A2DP_SRC_CONNECTION_STATE,
3201 state,
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08003202 0 /* arg2 unused */,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003203 btDevice,
3204 0 /* delay */);
3205 }
3206 }
3207 break;
3208
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003209 case BluetoothProfile.HEADSET:
3210 synchronized (mScoClients) {
3211 // Discard timeout message
3212 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
3213 mBluetoothHeadset = (BluetoothHeadset) proxy;
3214 deviceList = mBluetoothHeadset.getConnectedDevices();
3215 if (deviceList.size() > 0) {
3216 mBluetoothHeadsetDevice = deviceList.get(0);
3217 } else {
3218 mBluetoothHeadsetDevice = null;
3219 }
3220 // Refresh SCO audio state
3221 checkScoAudioState();
3222 // Continue pending action if any
3223 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
3224 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
3225 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
3226 boolean status = false;
3227 if (mBluetoothHeadsetDevice != null) {
3228 switch (mScoAudioState) {
3229 case SCO_STATE_ACTIVATE_REQ:
3230 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07003231 if (mScoAudioMode == SCO_MODE_RAW) {
3232 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003233 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003234 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
3235 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003236 } else if (mScoAudioMode == SCO_MODE_VR) {
3237 status = mBluetoothHeadset.startVoiceRecognition(
3238 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003239 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003240 break;
3241 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07003242 if (mScoAudioMode == SCO_MODE_RAW) {
3243 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003244 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003245 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
3246 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003247 } else if (mScoAudioMode == SCO_MODE_VR) {
3248 status = mBluetoothHeadset.stopVoiceRecognition(
3249 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003250 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003251 break;
3252 case SCO_STATE_DEACTIVATE_EXT_REQ:
3253 status = mBluetoothHeadset.stopVoiceRecognition(
3254 mBluetoothHeadsetDevice);
3255 }
3256 }
3257 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08003258 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003259 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07003260 }
3261 }
Eric Laurentdc03c612011-04-01 10:59:41 -07003262 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003263 break;
3264
3265 default:
3266 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003267 }
3268 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07003269 public void onServiceDisconnected(int profile) {
Eric Laurentb70b78a2016-01-13 19:16:04 -08003270
Paul McLean394a8e12015-03-03 10:29:19 -07003271 switch (profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003272 case BluetoothProfile.A2DP:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003273 disconnectA2dp();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003274 break;
3275
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003276 case BluetoothProfile.A2DP_SINK:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003277 disconnectA2dpSink();
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003278 break;
3279
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003280 case BluetoothProfile.HEADSET:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003281 disconnectHeadset();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003282 break;
3283
3284 default:
3285 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003286 }
3287 }
3288 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003289
Eric Laurentb70b78a2016-01-13 19:16:04 -08003290 void disconnectAllBluetoothProfiles() {
3291 disconnectA2dp();
3292 disconnectA2dpSink();
3293 disconnectHeadset();
3294 }
3295
3296 void disconnectA2dp() {
3297 synchronized (mConnectedDevices) {
3298 synchronized (mA2dpAvrcpLock) {
3299 ArraySet<String> toRemove = null;
3300 // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
3301 for (int i = 0; i < mConnectedDevices.size(); i++) {
3302 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
3303 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
3304 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
3305 toRemove.add(deviceSpec.mDeviceAddress);
3306 }
3307 }
3308 if (toRemove != null) {
3309 int delay = checkSendBecomingNoisyIntent(
3310 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3311 0);
3312 for (int i = 0; i < toRemove.size(); i++) {
3313 makeA2dpDeviceUnavailableLater(toRemove.valueAt(i), delay);
3314 }
3315 }
3316 }
3317 }
3318 }
3319
3320 void disconnectA2dpSink() {
3321 synchronized (mConnectedDevices) {
3322 ArraySet<String> toRemove = null;
3323 // Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
3324 for(int i = 0; i < mConnectedDevices.size(); i++) {
3325 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
3326 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) {
3327 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
3328 toRemove.add(deviceSpec.mDeviceAddress);
3329 }
3330 }
3331 if (toRemove != null) {
3332 for (int i = 0; i < toRemove.size(); i++) {
3333 makeA2dpSrcUnavailable(toRemove.valueAt(i));
3334 }
3335 }
3336 }
3337 }
3338
3339 void disconnectHeadset() {
3340 synchronized (mScoClients) {
3341 if (mBluetoothHeadsetDevice != null) {
3342 setBtScoDeviceConnectionState(mBluetoothHeadsetDevice,
3343 BluetoothProfile.STATE_DISCONNECTED);
3344 }
3345 mBluetoothHeadset = null;
3346 }
3347 }
3348
John Spurlock90874332015-03-10 16:00:54 -04003349 private void onCheckMusicActive(String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07003350 synchronized (mSafeMediaVolumeState) {
3351 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07003352 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
3353
3354 if ((device & mSafeMediaVolumeDevices) != 0) {
3355 sendMsg(mAudioHandler,
3356 MSG_CHECK_MUSIC_ACTIVE,
3357 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07003358 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07003359 0,
John Spurlock90874332015-03-10 16:00:54 -04003360 caller,
Eric Laurentc34dcc12012-09-10 13:51:52 -07003361 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07003362 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07003363 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
3364 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07003365 // Approximate cumulative active music time
3366 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
3367 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
John Spurlock90874332015-03-10 16:00:54 -04003368 setSafeMediaVolumeEnabled(true, caller);
Eric Laurentc34dcc12012-09-10 13:51:52 -07003369 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07003370 }
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003371 saveMusicActiveMs();
Eric Laurentc34dcc12012-09-10 13:51:52 -07003372 }
3373 }
3374 }
3375 }
3376 }
3377
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003378 private void saveMusicActiveMs() {
3379 mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
3380 }
3381
John Spurlock90874332015-03-10 16:00:54 -04003382 private void onConfigureSafeVolume(boolean force, String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07003383 synchronized (mSafeMediaVolumeState) {
3384 int mcc = mContext.getResources().getConfiguration().mcc;
3385 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
3386 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
3387 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
John Spurlock35134602014-07-24 18:10:48 -04003388 boolean safeMediaVolumeEnabled =
3389 SystemProperties.getBoolean("audio.safemedia.force", false)
3390 || mContext.getResources().getBoolean(
3391 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08003392
Ricardo Garcia3a30a762015-06-23 15:54:45 -07003393 boolean safeMediaVolumeBypass =
3394 SystemProperties.getBoolean("audio.safemedia.bypass", false);
3395
Eric Laurent05274f32012-11-29 12:48:18 -08003396 // The persisted state is either "disabled" or "active": this is the state applied
3397 // next time we boot and cannot be "inactive"
3398 int persistedState;
Ricardo Garcia3a30a762015-06-23 15:54:45 -07003399 if (safeMediaVolumeEnabled && !safeMediaVolumeBypass) {
Eric Laurent05274f32012-11-29 12:48:18 -08003400 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
3401 // The state can already be "inactive" here if the user has forced it before
3402 // the 30 seconds timeout for forced configuration. In this case we don't reset
3403 // it to "active".
3404 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003405 if (mMusicActiveMs == 0) {
3406 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
John Spurlock90874332015-03-10 16:00:54 -04003407 enforceSafeMediaVolume(caller);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003408 } else {
3409 // We have existing playback time recorded, already confirmed.
3410 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
3411 }
Eric Laurent05274f32012-11-29 12:48:18 -08003412 }
Eric Laurentd640bd32012-09-28 18:01:48 -07003413 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08003414 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07003415 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
3416 }
3417 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08003418 sendMsg(mAudioHandler,
3419 MSG_PERSIST_SAFE_VOLUME_STATE,
3420 SENDMSG_QUEUE,
3421 persistedState,
3422 0,
3423 null,
3424 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07003425 }
3426 }
3427 }
3428
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003429 ///////////////////////////////////////////////////////////////////////////
3430 // Internal methods
3431 ///////////////////////////////////////////////////////////////////////////
3432
3433 /**
3434 * Checks if the adjustment should change ringer mode instead of just
3435 * adjusting volume. If so, this will set the proper ringer mode and volume
3436 * indices on the stream states.
3437 */
Julia Reynoldsed783792016-04-08 15:27:35 -04003438 private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted,
3439 String caller, int flags) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003440 int result = FLAG_ADJUST_VOLUME;
Hank Freund21003f62015-12-08 09:05:46 -08003441 if (isPlatformTelevision()) {
3442 return result;
3443 }
3444
John Spurlock661f2cf2014-11-17 10:29:10 -05003445 int ringerMode = getRingerModeInternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003446
Eric Laurentbffc3d12012-05-07 17:43:49 -07003447 switch (ringerMode) {
3448 case RINGER_MODE_NORMAL:
3449 if (direction == AudioManager.ADJUST_LOWER) {
3450 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07003451 // "step" is the delta in internal index units corresponding to a
3452 // change of 1 in UI index units.
3453 // Because of rounding when rescaling from one stream index range to its alias
3454 // index range, we cannot simply test oldIndex == step:
3455 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
3456 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003457 ringerMode = RINGER_MODE_VIBRATE;
John Spurlock07e72432015-03-13 11:46:52 -04003458 mLoweredFromNormalToVibrateTime = SystemClock.uptimeMillis();
Eric Laurentbffc3d12012-05-07 17:43:49 -07003459 }
3460 } else {
John Spurlockd9c75db2015-04-28 11:19:13 -04003461 if (oldIndex == step && mVolumePolicy.volumeDownToEnterSilent) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003462 ringerMode = RINGER_MODE_SILENT;
3463 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07003464 }
Muyuan Li1ed6df62016-06-18 11:16:52 -07003465 } else if (mIsSingleVolume && (direction == AudioManager.ADJUST_TOGGLE_MUTE
John Spurlocka48d7792015-03-03 17:35:57 -05003466 || direction == AudioManager.ADJUST_MUTE)) {
RoboErik5452e252015-02-06 15:33:53 -08003467 if (mHasVibrator) {
3468 ringerMode = RINGER_MODE_VIBRATE;
3469 } else {
3470 ringerMode = RINGER_MODE_SILENT;
3471 }
3472 // Setting the ringer mode will toggle mute
3473 result &= ~FLAG_ADJUST_VOLUME;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003474 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003475 break;
3476 case RINGER_MODE_VIBRATE:
3477 if (!mHasVibrator) {
3478 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
3479 "but no vibrator is present");
3480 break;
3481 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003482 if ((direction == AudioManager.ADJUST_LOWER)) {
RoboErik5452e252015-02-06 15:33:53 -08003483 // This is the case we were muted with the volume turned up
Muyuan Li1ed6df62016-06-18 11:16:52 -07003484 if (mIsSingleVolume && oldIndex >= 2 * step && isMuted) {
RoboErik5452e252015-02-06 15:33:53 -08003485 ringerMode = RINGER_MODE_NORMAL;
3486 } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
John Spurlocka48d7792015-03-03 17:35:57 -05003487 if (mVolumePolicy.volumeDownToEnterSilent) {
John Spurlock07e72432015-03-13 11:46:52 -04003488 final long diff = SystemClock.uptimeMillis()
3489 - mLoweredFromNormalToVibrateTime;
John Spurlockd9c75db2015-04-28 11:19:13 -04003490 if (diff > mVolumePolicy.vibrateToSilentDebounce
3491 && mRingerModeDelegate.canVolumeDownEnterSilent()) {
John Spurlock07e72432015-03-13 11:46:52 -04003492 ringerMode = RINGER_MODE_SILENT;
3493 }
John Spurlock795a5142014-12-08 14:09:35 -05003494 } else {
3495 result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
3496 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003497 }
RoboErik5452e252015-02-06 15:33:53 -08003498 } else if (direction == AudioManager.ADJUST_RAISE
3499 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3500 || direction == AudioManager.ADJUST_UNMUTE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003501 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07003502 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003503 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003504 break;
3505 case RINGER_MODE_SILENT:
Muyuan Li1ed6df62016-06-18 11:16:52 -07003506 if (mIsSingleVolume && direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
RoboErik5452e252015-02-06 15:33:53 -08003507 // This is the case we were muted with the volume turned up
3508 ringerMode = RINGER_MODE_NORMAL;
3509 } else if (direction == AudioManager.ADJUST_RAISE
3510 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3511 || direction == AudioManager.ADJUST_UNMUTE) {
John Spurlocka48d7792015-03-03 17:35:57 -05003512 if (!mVolumePolicy.volumeUpToExitSilent) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003513 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003514 } else {
RoboErik5452e252015-02-06 15:33:53 -08003515 if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003516 ringerMode = RINGER_MODE_VIBRATE;
3517 } else {
RoboErik5452e252015-02-06 15:33:53 -08003518 // If we don't have a vibrator or they were toggling mute
3519 // go straight back to normal.
John Spurlocka11b4af2014-06-01 11:52:23 -04003520 ringerMode = RINGER_MODE_NORMAL;
3521 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003522 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05003523 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003524 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003525 break;
3526 default:
3527 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
3528 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003529 }
3530
Julia Reynoldsed783792016-04-08 15:27:35 -04003531 if (isAndroidNPlus(caller) && wouldToggleZenMode(ringerMode)
3532 && !mNm.isNotificationPolicyAccessGrantedForPackage(caller)
3533 && (flags & AudioManager.FLAG_FROM_KEY) == 0) {
3534 throw new SecurityException("Not allowed to change Do Not Disturb state");
3535 }
3536
John Spurlock661f2cf2014-11-17 10:29:10 -05003537 setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003538
Eric Laurent25101b02011-02-02 09:33:30 -08003539 mPrevVolDirection = direction;
3540
John Spurlocka11b4af2014-06-01 11:52:23 -04003541 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003542 }
3543
John Spurlock3346a802014-05-20 16:25:37 -04003544 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003545 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07003546 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003547 }
3548
Eric Laurent5b4e6542010-03-19 20:02:21 -07003549 private boolean isStreamMutedByRingerMode(int streamType) {
3550 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
3551 }
3552
John Spurlock50ced3f2015-05-11 16:00:09 -04003553 private boolean updateRingerModeAffectedStreams() {
3554 int ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003555 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3556 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
3557 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
3558 UserHandle.USER_CURRENT);
3559
Muyuan Li1ed6df62016-06-18 11:16:52 -07003560 if (mIsSingleVolume) {
John Spurlock50ced3f2015-05-11 16:00:09 -04003561 ringerModeAffectedStreams = 0;
3562 } else if (mRingerModeDelegate != null) {
3563 ringerModeAffectedStreams = mRingerModeDelegate
3564 .getRingerModeAffectedStreams(ringerModeAffectedStreams);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003565 }
3566 synchronized (mCameraSoundForced) {
3567 if (mCameraSoundForced) {
3568 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3569 } else {
3570 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3571 }
3572 }
3573 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
3574 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
3575 } else {
3576 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
3577 }
3578
3579 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3580 Settings.System.putIntForUser(mContentResolver,
3581 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3582 ringerModeAffectedStreams,
3583 UserHandle.USER_CURRENT);
3584 mRingerModeAffectedStreams = ringerModeAffectedStreams;
3585 return true;
3586 }
3587 return false;
3588 }
3589
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05003590 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003591 public boolean isStreamAffectedByMute(int streamType) {
3592 return (mMuteAffectedStreams & (1 << streamType)) != 0;
3593 }
3594
3595 private void ensureValidDirection(int direction) {
RoboErik4197cb62015-01-21 15:45:32 -08003596 switch (direction) {
3597 case AudioManager.ADJUST_LOWER:
3598 case AudioManager.ADJUST_RAISE:
3599 case AudioManager.ADJUST_SAME:
3600 case AudioManager.ADJUST_MUTE:
3601 case AudioManager.ADJUST_UNMUTE:
3602 case AudioManager.ADJUST_TOGGLE_MUTE:
3603 break;
3604 default:
3605 throw new IllegalArgumentException("Bad direction " + direction);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003606 }
3607 }
3608
3609 private void ensureValidStreamType(int streamType) {
3610 if (streamType < 0 || streamType >= mStreamStates.length) {
3611 throw new IllegalArgumentException("Bad stream type " + streamType);
3612 }
3613 }
3614
RoboErik4197cb62015-01-21 15:45:32 -08003615 private boolean isMuteAdjust(int adjust) {
3616 return adjust == AudioManager.ADJUST_MUTE || adjust == AudioManager.ADJUST_UNMUTE
3617 || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
3618 }
3619
Eric Laurent6d517662012-04-23 18:42:39 -07003620 private boolean isInCommunication() {
Nancy Chen0eb1e402014-08-21 22:52:29 -07003621 boolean IsInCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003622
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003623 TelecomManager telecomManager =
3624 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
Eric Laurent38edfda2014-12-18 17:38:04 -08003625
3626 final long ident = Binder.clearCallingIdentity();
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003627 IsInCall = telecomManager.isInCall();
Eric Laurent38edfda2014-12-18 17:38:04 -08003628 Binder.restoreCallingIdentity(ident);
Santos Cordon9eb45932014-06-27 12:28:43 -07003629
Nancy Chen0eb1e402014-08-21 22:52:29 -07003630 return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
Eric Laurent6d517662012-04-23 18:42:39 -07003631 }
Eric Laurent25101b02011-02-02 09:33:30 -08003632
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003633 /**
3634 * For code clarity for getActiveStreamType(int)
3635 * @param delay_ms max time since last STREAM_MUSIC activity to consider
3636 * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
3637 * in the last "delay_ms" ms.
3638 */
3639 private boolean isAfMusicActiveRecently(int delay_ms) {
3640 return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
3641 || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
3642 }
3643
Eric Laurent6d517662012-04-23 18:42:39 -07003644 private int getActiveStreamType(int suggestedStreamType) {
Muyuan Li1ed6df62016-06-18 11:16:52 -07003645 if (mIsSingleVolume
3646 && suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
3647 return AudioSystem.STREAM_MUSIC;
3648 }
3649
Eric Laurent212532b2014-07-21 15:43:18 -07003650 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003651 case AudioSystem.PLATFORM_VOICE:
Eric Laurent6d517662012-04-23 18:42:39 -07003652 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003653 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3654 == AudioSystem.FORCE_BT_SCO) {
3655 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
3656 return AudioSystem.STREAM_BLUETOOTH_SCO;
3657 } else {
3658 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
3659 return AudioSystem.STREAM_VOICE_CALL;
3660 }
Eric Laurent25101b02011-02-02 09:33:30 -08003661 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Triviac487672016-11-11 10:05:18 -08003662 if (isAfMusicActiveRecently(sStreamOverrideDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003663 if (DEBUG_VOL)
3664 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3665 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003666 } else {
3667 if (DEBUG_VOL)
3668 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
3669 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003670 }
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003671 } else if (isAfMusicActiveRecently(0)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003672 if (DEBUG_VOL)
3673 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3674 return AudioSystem.STREAM_MUSIC;
Eric Laurent25101b02011-02-02 09:33:30 -08003675 }
Eric Laurent212532b2014-07-21 15:43:18 -07003676 break;
Eric Laurent212532b2014-07-21 15:43:18 -07003677 default:
Eric Laurent6d517662012-04-23 18:42:39 -07003678 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003679 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3680 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003681 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08003682 return AudioSystem.STREAM_BLUETOOTH_SCO;
3683 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003684 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08003685 return AudioSystem.STREAM_VOICE_CALL;
3686 }
3687 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
Jean-Michel Triviac487672016-11-11 10:05:18 -08003688 sStreamOverrideDelayMs) ||
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003689 AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
Jean-Michel Triviac487672016-11-11 10:05:18 -08003690 sStreamOverrideDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003691 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08003692 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003693 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Triviac487672016-11-11 10:05:18 -08003694 if (isAfMusicActiveRecently(sStreamOverrideDelayMs)) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003695 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
3696 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003697 } else {
John Spurlockeb1d88d2014-07-19 14:49:19 -04003698 if (DEBUG_VOL) Log.v(TAG,
3699 "getActiveStreamType: using STREAM_NOTIFICATION as default");
3700 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003701 }
Joe Onoratoc7fcba42011-01-05 16:53:11 -08003702 }
Eric Laurent212532b2014-07-21 15:43:18 -07003703 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003704 }
Eric Laurent212532b2014-07-21 15:43:18 -07003705 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
3706 + suggestedStreamType);
3707 return suggestedStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003708 }
3709
John Spurlockbcc10872014-11-28 15:29:21 -05003710 private void broadcastRingerMode(String action, int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003711 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05003712 Intent broadcast = new Intent(action);
Glenn Kastenba195eb2011-12-13 09:30:40 -08003713 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003714 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
3715 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003716 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003717 }
3718
3719 private void broadcastVibrateSetting(int vibrateType) {
3720 // Send broadcast
Sudheer Shankafc46e9b2016-10-21 17:55:27 -07003721 if (mActivityManagerInternal.isSystemReady()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003722 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
3723 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
3724 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003725 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003726 }
3727 }
3728
3729 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003730 /**
3731 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
3732 * Note that the wake lock needs to be released after the message has been handled.
3733 */
3734 private void queueMsgUnderWakeLock(Handler handler, int msg,
3735 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003736 final long ident = Binder.clearCallingIdentity();
3737 // Always acquire the wake lock as AudioService because it is released by the
3738 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003739 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003740 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003741 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
3742 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003743
Eric Laurentafbb0472011-12-15 09:04:23 -08003744 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003745 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003746
3747 if (existingMsgPolicy == SENDMSG_REPLACE) {
3748 handler.removeMessages(msg);
3749 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
3750 return;
3751 }
Eric Laurentadbe8bf2014-11-03 18:26:32 -08003752 synchronized (mLastDeviceConnectMsgTime) {
3753 long time = SystemClock.uptimeMillis() + delay;
3754 handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
3755 if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
3756 msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
3757 msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
3758 mLastDeviceConnectMsgTime = time;
3759 }
3760 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003761 }
3762
3763 boolean checkAudioSettingsPermission(String method) {
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07003764 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003765 == PackageManager.PERMISSION_GRANTED) {
3766 return true;
3767 }
3768 String msg = "Audio Settings Permission Denial: " + method + " from pid="
3769 + Binder.getCallingPid()
3770 + ", uid=" + Binder.getCallingUid();
3771 Log.w(TAG, msg);
3772 return false;
3773 }
3774
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003775 private int getDeviceForStream(int stream) {
John Spurlock8a52c442015-03-26 14:23:58 -04003776 int device = getDevicesForStream(stream);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003777 if ((device & (device - 1)) != 0) {
3778 // Multiple device selection is either:
3779 // - speaker + one other device: give priority to speaker in this case.
3780 // - one A2DP device + another device: happens with duplicated output. In this case
3781 // retain the device on the A2DP output as the other must not correspond to an active
3782 // selection if not the speaker.
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003783 // - HDMI-CEC system audio mode only output: give priority to available item in order.
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003784 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
3785 device = AudioSystem.DEVICE_OUT_SPEAKER;
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003786 } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
3787 device = AudioSystem.DEVICE_OUT_HDMI_ARC;
3788 } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
3789 device = AudioSystem.DEVICE_OUT_SPDIF;
3790 } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
3791 device = AudioSystem.DEVICE_OUT_AUX_LINE;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003792 } else {
3793 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
3794 }
3795 }
3796 return device;
3797 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003798
John Spurlock8a52c442015-03-26 14:23:58 -04003799 private int getDevicesForStream(int stream) {
3800 return getDevicesForStream(stream, true /*checkOthers*/);
3801 }
3802
3803 private int getDevicesForStream(int stream, boolean checkOthers) {
3804 ensureValidStreamType(stream);
3805 synchronized (VolumeStreamState.class) {
3806 return mStreamStates[stream].observeDevicesForStream_syncVSS(checkOthers);
3807 }
3808 }
3809
3810 private void observeDevicesForStreams(int skipStream) {
3811 synchronized (VolumeStreamState.class) {
3812 for (int stream = 0; stream < mStreamStates.length; stream++) {
3813 if (stream != skipStream) {
3814 mStreamStates[stream].observeDevicesForStream_syncVSS(false /*checkOthers*/);
3815 }
3816 }
3817 }
3818 }
3819
Paul McLean10804eb2015-01-28 11:16:35 -08003820 /*
3821 * A class just for packaging up a set of connection parameters.
3822 */
3823 private class WiredDeviceConnectionState {
John Spurlock90874332015-03-10 16:00:54 -04003824 public final int mType;
3825 public final int mState;
3826 public final String mAddress;
3827 public final String mName;
3828 public final String mCaller;
Paul McLean10804eb2015-01-28 11:16:35 -08003829
John Spurlock90874332015-03-10 16:00:54 -04003830 public WiredDeviceConnectionState(int type, int state, String address, String name,
3831 String caller) {
Paul McLean10804eb2015-01-28 11:16:35 -08003832 mType = type;
3833 mState = state;
3834 mAddress = address;
3835 mName = name;
John Spurlock90874332015-03-10 16:00:54 -04003836 mCaller = caller;
Paul McLean10804eb2015-01-28 11:16:35 -08003837 }
3838 }
3839
John Spurlock90874332015-03-10 16:00:54 -04003840 public void setWiredDeviceConnectionState(int type, int state, String address, String name,
3841 String caller) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003842 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07003843 if (DEBUG_DEVICES) {
3844 Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
3845 + address + ")");
3846 }
Paul McLean10804eb2015-01-28 11:16:35 -08003847 int delay = checkSendBecomingNoisyIntent(type, state);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003848 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003849 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08003850 0 /* arg1 unused */,
3851 0 /* arg2 unused */,
John Spurlock90874332015-03-10 16:00:54 -04003852 new WiredDeviceConnectionState(type, state, address, name, caller),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003853 delay);
3854 }
3855 }
3856
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003857 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003858 {
3859 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003860 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
3861 throw new IllegalArgumentException("invalid profile " + profile);
3862 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003863 synchronized (mConnectedDevices) {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003864 if (profile == BluetoothProfile.A2DP) {
3865 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3866 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
3867 } else {
3868 delay = 0;
3869 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003870 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003871 (profile == BluetoothProfile.A2DP ?
3872 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003873 state,
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08003874 0 /* arg2 unused */,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003875 device,
3876 delay);
3877 }
3878 return delay;
3879 }
3880
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08003881 public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device)
3882 {
3883 synchronized (mConnectedDevices) {
3884 queueMsgUnderWakeLock(mAudioHandler,
3885 MSG_A2DP_DEVICE_CONFIG_CHANGE,
3886 0 /* arg1 unused */,
3887 0 /* arg1 unused */,
3888 device,
3889 0 /* delay */);
3890 }
3891 }
3892
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003893 ///////////////////////////////////////////////////////////////////////////
3894 // Inner classes
3895 ///////////////////////////////////////////////////////////////////////////
3896
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003897 // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
3898 // 1 mScoclient OR mSafeMediaVolumeState
3899 // 2 mSetModeDeathHandlers
3900 // 3 mSettingsLock
3901 // 4 VolumeStreamState.class
3902 // 5 mCameraSoundForced
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003903 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003904 private final int mStreamType;
John Spurlockb6e19e32015-03-10 21:33:44 -04003905 private final int mIndexMin;
3906 private final int mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003907
RoboErik4197cb62015-01-21 15:45:32 -08003908 private boolean mIsMuted;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003909 private String mVolumeIndexSettingName;
John Spurlock8a52c442015-03-26 14:23:58 -04003910 private int mObservedDevices;
John Spurlockb6e19e32015-03-10 21:33:44 -04003911
John Spurlock2bb02ec2015-03-02 13:13:06 -05003912 private final SparseIntArray mIndexMap = new SparseIntArray(8);
John Spurlockf63860c2015-02-19 09:46:27 -05003913 private final Intent mVolumeChanged;
John Spurlock8a52c442015-03-26 14:23:58 -04003914 private final Intent mStreamDevicesChanged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003915
Eric Laurenta553c252009-07-17 12:17:14 -07003916 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003917
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003918 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003919
3920 mStreamType = streamType;
John Spurlockb6e19e32015-03-10 21:33:44 -04003921 mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;
3922 mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;
3923 AudioSystem.initStreamVolume(streamType, mIndexMin / 10, mIndexMax / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003924
Eric Laurent33902db2012-10-07 16:15:07 -07003925 readSettings();
John Spurlockf63860c2015-02-19 09:46:27 -05003926 mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
3927 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
John Spurlock8a52c442015-03-26 14:23:58 -04003928 mStreamDevicesChanged = new Intent(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
3929 mStreamDevicesChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
3930 }
3931
3932 public int observeDevicesForStream_syncVSS(boolean checkOthers) {
3933 final int devices = AudioSystem.getDevicesForStream(mStreamType);
3934 if (devices == mObservedDevices) {
3935 return devices;
3936 }
3937 final int prevDevices = mObservedDevices;
3938 mObservedDevices = devices;
3939 if (checkOthers) {
3940 // one stream's devices have changed, check the others
3941 observeDevicesForStreams(mStreamType);
3942 }
3943 // log base stream changes to the event log
3944 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
3945 EventLogTags.writeStreamDevicesChanged(mStreamType, prevDevices, devices);
3946 }
3947 sendBroadcastToAll(mStreamDevicesChanged
3948 .putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, prevDevices)
3949 .putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, devices));
3950 return devices;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003951 }
3952
Eric Laurent42b041e2013-03-29 11:36:03 -07003953 public String getSettingNameForDevice(int device) {
3954 String name = mVolumeIndexSettingName;
Eric Laurent948d3272014-05-16 15:18:45 -07003955 String suffix = AudioSystem.getOutputDeviceName(device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003956 if (suffix.isEmpty()) {
3957 return name;
3958 }
3959 return name + "_" + suffix;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003960 }
3961
Eric Laurentfdbee862014-05-12 15:26:12 -07003962 public void readSettings() {
3963 synchronized (VolumeStreamState.class) {
John Spurlockee5ad722015-03-03 16:17:21 -05003964 // force maximum volume on all streams if fixed volume property is set
3965 if (mUseFixedVolume) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003966 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07003967 return;
3968 }
3969 // do not read system stream volume from settings: this stream is always aliased
3970 // to another stream type and its volume is never persisted. Values in settings can
3971 // only be stale values
3972 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3973 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
John Spurlock61560172015-02-06 19:46:04 -05003974 int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
Eric Laurentfdbee862014-05-12 15:26:12 -07003975 synchronized (mCameraSoundForced) {
3976 if (mCameraSoundForced) {
3977 index = mIndexMax;
3978 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003979 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003980 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003981 return;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003982 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003983
Eric Laurentfdbee862014-05-12 15:26:12 -07003984 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
3985
3986 for (int i = 0; remainingDevices != 0; i++) {
3987 int device = (1 << i);
3988 if ((device & remainingDevices) == 0) {
3989 continue;
3990 }
3991 remainingDevices &= ~device;
3992
3993 // retrieve current volume for device
3994 String name = getSettingNameForDevice(device);
3995 // if no volume stored for current stream and device, use default volume if default
3996 // device, continue otherwise
3997 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
John Spurlock61560172015-02-06 19:46:04 -05003998 AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
Eric Laurentfdbee862014-05-12 15:26:12 -07003999 int index = Settings.System.getIntForUser(
4000 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
4001 if (index == -1) {
4002 continue;
4003 }
4004
John Spurlock2bb02ec2015-03-02 13:13:06 -05004005 mIndexMap.put(device, getValidIndex(10 * index));
Eric Laurentdd45d012012-10-08 09:04:34 -07004006 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004007 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004008 }
4009
Liejun Tao39fb5672016-03-09 15:52:13 -06004010 private int getAbsoluteVolumeIndex(int index) {
4011 /* Special handling for Bluetooth Absolute Volume scenario
4012 * If we send full audio gain, some accessories are too loud even at its lowest
4013 * volume. We are not able to enumerate all such accessories, so here is the
4014 * workaround from phone side.
4015 * Pre-scale volume at lowest volume steps 1 2 and 3.
4016 * For volume step 0, set audio gain to 0 as some accessories won't mute on their end.
4017 */
4018 if (index == 0) {
4019 // 0% for volume 0
4020 index = 0;
4021 } else if (index == 1) {
4022 // 50% for volume 1
4023 index = (int)(mIndexMax * 0.5) /10;
4024 } else if (index == 2) {
4025 // 70% for volume 2
4026 index = (int)(mIndexMax * 0.70) /10;
4027 } else if (index == 3) {
4028 // 85% for volume 3
4029 index = (int)(mIndexMax * 0.85) /10;
4030 } else {
4031 // otherwise, full gain
4032 index = (mIndexMax + 5)/10;
4033 }
4034 return index;
4035 }
4036
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004037 // must be called while synchronized VolumeStreamState.class
4038 public void applyDeviceVolume_syncVSS(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07004039 int index;
RoboErik4197cb62015-01-21 15:45:32 -08004040 if (mIsMuted) {
Eric Laurent42b041e2013-03-29 11:36:03 -07004041 index = 0;
Liejun Tao4565a472016-01-20 17:52:20 -06004042 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) {
Liejun Tao39fb5672016-03-09 15:52:13 -06004043 index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
Liejun Tao4565a472016-01-20 17:52:20 -06004044 } else if ((device & mFullVolumeDevices) != 0) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004045 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07004046 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07004047 index = (getIndex(device) + 5)/10;
4048 }
4049 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004050 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004051
Eric Laurentfdbee862014-05-12 15:26:12 -07004052 public void applyAllVolumes() {
4053 synchronized (VolumeStreamState.class) {
Eric Laurentd9ac2be2016-04-07 14:04:23 -07004054 // apply device specific volumes first
Eric Laurentfdbee862014-05-12 15:26:12 -07004055 int index;
John Spurlock2bb02ec2015-03-02 13:13:06 -05004056 for (int i = 0; i < mIndexMap.size(); i++) {
Eric Laurentd9ac2be2016-04-07 14:04:23 -07004057 final int device = mIndexMap.keyAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07004058 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
RoboErik4197cb62015-01-21 15:45:32 -08004059 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004060 index = 0;
Liejun Tao39fb5672016-03-09 15:52:13 -06004061 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
4062 mAvrcpAbsVolSupported) {
4063 index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
4064 } else if ((device & mFullVolumeDevices) != 0) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004065 index = (mIndexMax + 5)/10;
4066 } else {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004067 index = (mIndexMap.valueAt(i) + 5)/10;
Eric Laurentfdbee862014-05-12 15:26:12 -07004068 }
4069 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07004070 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004071 }
Eric Laurentd9ac2be2016-04-07 14:04:23 -07004072 // apply default volume last: by convention , default device volume will be used
4073 // by audio policy manager if no explicit volume is present for a given device type
4074 if (mIsMuted) {
4075 index = 0;
4076 } else {
4077 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
4078 }
4079 AudioSystem.setStreamVolumeIndex(
4080 mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004081 }
4082 }
4083
John Spurlock90874332015-03-10 16:00:54 -04004084 public boolean adjustIndex(int deltaIndex, int device, String caller) {
4085 return setIndex(getIndex(device) + deltaIndex, device, caller);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004086 }
4087
John Spurlock90874332015-03-10 16:00:54 -04004088 public boolean setIndex(int index, int device, String caller) {
John Spurlockf63860c2015-02-19 09:46:27 -05004089 boolean changed = false;
4090 int oldIndex;
Eric Laurentfdbee862014-05-12 15:26:12 -07004091 synchronized (VolumeStreamState.class) {
John Spurlockf63860c2015-02-19 09:46:27 -05004092 oldIndex = getIndex(device);
Eric Laurentfdbee862014-05-12 15:26:12 -07004093 index = getValidIndex(index);
4094 synchronized (mCameraSoundForced) {
4095 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
4096 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07004097 }
4098 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05004099 mIndexMap.put(device, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07004100
John Spurlockf63860c2015-02-19 09:46:27 -05004101 changed = oldIndex != index;
Eric Laurent3fb608e2016-11-03 16:27:40 -07004102 // Apply change to all streams using this one as alias if:
4103 // - the index actually changed OR
4104 // - there is no volume index stored for this device on alias stream.
4105 // If changing volume of current device, also change volume of current
4106 // device on aliased stream
4107 final boolean currentDevice = (device == getDeviceForStream(mStreamType));
4108 final int numStreamTypes = AudioSystem.getNumStreamTypes();
4109 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4110 final VolumeStreamState aliasStreamState = mStreamStates[streamType];
4111 if (streamType != mStreamType &&
4112 mStreamVolumeAlias[streamType] == mStreamType &&
4113 (changed || !aliasStreamState.hasIndexForDevice(device))) {
4114 final int scaledIndex = rescaleIndex(index, mStreamType, streamType);
4115 aliasStreamState.setIndex(scaledIndex, device, caller);
4116 if (currentDevice) {
4117 aliasStreamState.setIndex(scaledIndex,
4118 getDeviceForStream(streamType), caller);
Eric Laurentfdbee862014-05-12 15:26:12 -07004119 }
4120 }
Eric Laurentfdbee862014-05-12 15:26:12 -07004121 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004122 }
John Spurlockf63860c2015-02-19 09:46:27 -05004123 if (changed) {
4124 oldIndex = (oldIndex + 5) / 10;
4125 index = (index + 5) / 10;
John Spurlock90874332015-03-10 16:00:54 -04004126 // log base stream changes to the event log
4127 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
4128 if (caller == null) {
4129 Log.w(TAG, "No caller for volume_changed event", new Throwable());
4130 }
4131 EventLogTags.writeVolumeChanged(mStreamType, oldIndex, index, mIndexMax / 10,
4132 caller);
4133 }
4134 // fire changed intents for all streams
John Spurlockf63860c2015-02-19 09:46:27 -05004135 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
4136 mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
Jean-Michel Trivi560877d2015-06-25 17:38:35 -07004137 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
4138 mStreamVolumeAlias[mStreamType]);
John Spurlockf63860c2015-02-19 09:46:27 -05004139 sendBroadcastToAll(mVolumeChanged);
4140 }
4141 return changed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004142 }
4143
Eric Laurentfdbee862014-05-12 15:26:12 -07004144 public int getIndex(int device) {
4145 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004146 int index = mIndexMap.get(device, -1);
4147 if (index == -1) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004148 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
John Spurlock2bb02ec2015-03-02 13:13:06 -05004149 index = mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurentfdbee862014-05-12 15:26:12 -07004150 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05004151 return index;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004152 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07004153 }
4154
Eric Laurent3fb608e2016-11-03 16:27:40 -07004155 public boolean hasIndexForDevice(int device) {
4156 synchronized (VolumeStreamState.class) {
4157 return (mIndexMap.get(device, -1) != -1);
4158 }
4159 }
4160
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004161 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07004162 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004163 }
4164
John Spurlockb6e19e32015-03-10 21:33:44 -04004165 public int getMinIndex() {
4166 return mIndexMin;
4167 }
4168
John Spurlock90874332015-03-10 16:00:54 -04004169 public void setAllIndexes(VolumeStreamState srcStream, String caller) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004170 synchronized (VolumeStreamState.class) {
4171 int srcStreamType = srcStream.getStreamType();
4172 // apply default device volume from source stream to all devices first in case
4173 // some devices are present in this stream state but not in source stream state
4174 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004175 index = rescaleIndex(index, srcStreamType, mStreamType);
John Spurlock2bb02ec2015-03-02 13:13:06 -05004176 for (int i = 0; i < mIndexMap.size(); i++) {
4177 mIndexMap.put(mIndexMap.keyAt(i), index);
Eric Laurentfdbee862014-05-12 15:26:12 -07004178 }
4179 // Now apply actual volume for devices in source stream state
John Spurlock2bb02ec2015-03-02 13:13:06 -05004180 SparseIntArray srcMap = srcStream.mIndexMap;
4181 for (int i = 0; i < srcMap.size(); i++) {
4182 int device = srcMap.keyAt(i);
4183 index = srcMap.valueAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07004184 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07004185
John Spurlock90874332015-03-10 16:00:54 -04004186 setIndex(index, device, caller);
Eric Laurentfdbee862014-05-12 15:26:12 -07004187 }
Eric Laurent6d517662012-04-23 18:42:39 -07004188 }
4189 }
4190
Eric Laurentfdbee862014-05-12 15:26:12 -07004191 public void setAllIndexesToMax() {
4192 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004193 for (int i = 0; i < mIndexMap.size(); i++) {
4194 mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07004195 }
Eric Laurentdd45d012012-10-08 09:04:34 -07004196 }
Eric Laurentdd45d012012-10-08 09:04:34 -07004197 }
4198
RoboErik4197cb62015-01-21 15:45:32 -08004199 public void mute(boolean state) {
John Spurlock22b9ee12015-02-18 22:51:44 -05004200 boolean changed = false;
Eric Laurentfdbee862014-05-12 15:26:12 -07004201 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08004202 if (state != mIsMuted) {
John Spurlock22b9ee12015-02-18 22:51:44 -05004203 changed = true;
RoboErik4197cb62015-01-21 15:45:32 -08004204 mIsMuted = state;
John Spurlock22b9ee12015-02-18 22:51:44 -05004205
RoboErik4197cb62015-01-21 15:45:32 -08004206 // Set the new mute volume. This propagates the values to
4207 // the audio system, otherwise the volume won't be changed
4208 // at the lower level.
4209 sendMsg(mAudioHandler,
4210 MSG_SET_ALL_VOLUMES,
4211 SENDMSG_QUEUE,
4212 0,
4213 0,
4214 this, 0);
Eric Laurentfdbee862014-05-12 15:26:12 -07004215 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004216 }
John Spurlock22b9ee12015-02-18 22:51:44 -05004217 if (changed) {
4218 // Stream mute changed, fire the intent.
4219 Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
4220 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
4221 intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
4222 sendBroadcastToAll(intent);
4223 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004224 }
4225
Eric Laurent6d517662012-04-23 18:42:39 -07004226 public int getStreamType() {
4227 return mStreamType;
4228 }
4229
Eric Laurent212532b2014-07-21 15:43:18 -07004230 public void checkFixedVolumeDevices() {
4231 synchronized (VolumeStreamState.class) {
4232 // ignore settings for fixed volume devices: volume should always be at max or 0
4233 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004234 for (int i = 0; i < mIndexMap.size(); i++) {
4235 int device = mIndexMap.keyAt(i);
4236 int index = mIndexMap.valueAt(i);
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07004237 if (((device & mFullVolumeDevices) != 0)
4238 || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004239 mIndexMap.put(device, mIndexMax);
Eric Laurent212532b2014-07-21 15:43:18 -07004240 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004241 applyDeviceVolume_syncVSS(device);
Eric Laurent212532b2014-07-21 15:43:18 -07004242 }
4243 }
4244 }
4245 }
4246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004247 private int getValidIndex(int index) {
John Spurlockb6e19e32015-03-10 21:33:44 -04004248 if (index < mIndexMin) {
4249 return mIndexMin;
John Spurlockee5ad722015-03-03 16:17:21 -05004250 } else if (mUseFixedVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07004251 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004252 }
4253
4254 return index;
4255 }
4256
Eric Laurentbffc3d12012-05-07 17:43:49 -07004257 private void dump(PrintWriter pw) {
RoboErik4197cb62015-01-21 15:45:32 -08004258 pw.print(" Muted: ");
4259 pw.println(mIsMuted);
John Spurlockb6e19e32015-03-10 21:33:44 -04004260 pw.print(" Min: ");
4261 pw.println((mIndexMin + 5) / 10);
John Spurlock2b29bc42014-08-26 16:40:35 -04004262 pw.print(" Max: ");
4263 pw.println((mIndexMax + 5) / 10);
Eric Laurentbffc3d12012-05-07 17:43:49 -07004264 pw.print(" Current: ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05004265 for (int i = 0; i < mIndexMap.size(); i++) {
4266 if (i > 0) {
4267 pw.print(", ");
4268 }
4269 final int device = mIndexMap.keyAt(i);
John Spurlock2b29bc42014-08-26 16:40:35 -04004270 pw.print(Integer.toHexString(device));
4271 final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
4272 : AudioSystem.getOutputDeviceName(device);
4273 if (!deviceName.isEmpty()) {
4274 pw.print(" (");
4275 pw.print(deviceName);
4276 pw.print(")");
4277 }
4278 pw.print(": ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05004279 final int index = (mIndexMap.valueAt(i) + 5) / 10;
John Spurlock2b29bc42014-08-26 16:40:35 -04004280 pw.print(index);
Eric Laurentbffc3d12012-05-07 17:43:49 -07004281 }
John Spurlockb32fc972015-03-05 13:58:00 -05004282 pw.println();
4283 pw.print(" Devices: ");
John Spurlock8a52c442015-03-26 14:23:58 -04004284 final int devices = getDevicesForStream(mStreamType);
John Spurlockb32fc972015-03-05 13:58:00 -05004285 int device, i = 0, n = 0;
John Spurlock1ff1e6e2015-03-09 14:21:20 -04004286 // iterate all devices from 1 to DEVICE_OUT_DEFAULT exclusive
4287 // (the default device is not returned by getDevicesForStream)
4288 while ((device = 1 << i) != AudioSystem.DEVICE_OUT_DEFAULT) {
John Spurlockb32fc972015-03-05 13:58:00 -05004289 if ((devices & device) != 0) {
4290 if (n++ > 0) {
4291 pw.print(", ");
4292 }
4293 pw.print(AudioSystem.getOutputDeviceName(device));
4294 }
4295 i++;
4296 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07004297 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004298 }
4299
4300 /** Thread that handles native AudioSystem control. */
4301 private class AudioSystemThread extends Thread {
4302 AudioSystemThread() {
4303 super("AudioService");
4304 }
4305
4306 @Override
4307 public void run() {
4308 // Set this thread up so the handler will work on it
4309 Looper.prepare();
4310
4311 synchronized(AudioService.this) {
4312 mAudioHandler = new AudioHandler();
4313
4314 // Notify that the handler has been created
4315 AudioService.this.notify();
4316 }
4317
4318 // Listen for volume change requests that are set by VolumePanel
4319 Looper.loop();
4320 }
4321 }
4322
4323 /** Handles internal volume messages in separate volume thread. */
4324 private class AudioHandler extends Handler {
4325
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004326 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004327
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004328 synchronized (VolumeStreamState.class) {
4329 // Apply volume
4330 streamState.applyDeviceVolume_syncVSS(device);
Eric Laurenta553c252009-07-17 12:17:14 -07004331
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004332 // Apply change to all streams using this one as alias
4333 int numStreamTypes = AudioSystem.getNumStreamTypes();
4334 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4335 if (streamType != streamState.mStreamType &&
4336 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
4337 // Make sure volume is also maxed out on A2DP device for aliased stream
4338 // that may have a different device selected
4339 int streamDevice = getDeviceForStream(streamType);
4340 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
4341 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
4342 mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
4343 }
4344 mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
Eric Laurentcd772d02013-10-30 18:31:07 -07004345 }
Eric Laurenta553c252009-07-17 12:17:14 -07004346 }
4347 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004348 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08004349 sendMsg(mAudioHandler,
4350 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08004351 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004352 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07004353 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08004354 streamState,
4355 PERSIST_DELAY);
4356
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004357 }
4358
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004359 private void setAllVolumes(VolumeStreamState streamState) {
4360
4361 // Apply volume
4362 streamState.applyAllVolumes();
4363
4364 // Apply change to all streams using this one as alias
4365 int numStreamTypes = AudioSystem.getNumStreamTypes();
4366 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4367 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07004368 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004369 mStreamStates[streamType].applyAllVolumes();
4370 }
4371 }
4372 }
4373
Eric Laurent42b041e2013-03-29 11:36:03 -07004374 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07004375 if (mUseFixedVolume) {
4376 return;
4377 }
Muyuan Li1ed6df62016-06-18 11:16:52 -07004378 if (mIsSingleVolume && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
Eric Laurent212532b2014-07-21 15:43:18 -07004379 return;
4380 }
Eric Laurent42b041e2013-03-29 11:36:03 -07004381 System.putIntForUser(mContentResolver,
4382 streamState.getSettingNameForDevice(device),
4383 (streamState.getIndex(device) + 5)/ 10,
4384 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004385 }
4386
Glenn Kastenba195eb2011-12-13 09:30:40 -08004387 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07004388 if (mUseFixedVolume) {
4389 return;
4390 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07004391 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004392 }
4393
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004394 private boolean onLoadSoundEffects() {
4395 int status;
4396
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004397 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004398 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004399 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
4400 return false;
4401 }
4402
4403 if (mSoundPool != null) {
4404 return true;
4405 }
4406
4407 loadTouchSoundAssets();
4408
Jean-Michel Trivi55a30c42014-07-20 17:56:11 -07004409 mSoundPool = new SoundPool.Builder()
4410 .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
4411 .setAudioAttributes(new AudioAttributes.Builder()
4412 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
4413 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
4414 .build())
4415 .build();
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004416 mSoundPoolCallBack = null;
4417 mSoundPoolListenerThread = new SoundPoolListenerThread();
4418 mSoundPoolListenerThread.start();
4419 int attempts = 3;
4420 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
4421 try {
4422 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07004423 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004424 } catch (InterruptedException e) {
4425 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
4426 }
4427 }
4428
4429 if (mSoundPoolCallBack == null) {
4430 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
4431 if (mSoundPoolLooper != null) {
4432 mSoundPoolLooper.quit();
4433 mSoundPoolLooper = null;
4434 }
4435 mSoundPoolListenerThread = null;
4436 mSoundPool.release();
4437 mSoundPool = null;
4438 return false;
4439 }
4440 /*
4441 * poolId table: The value -1 in this table indicates that corresponding
4442 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
4443 * Once loaded, the value in poolId is the sample ID and the same
4444 * sample can be reused for another effect using the same file.
4445 */
4446 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4447 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4448 poolId[fileIdx] = -1;
4449 }
4450 /*
4451 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
4452 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
4453 * this indicates we have a valid sample loaded for this effect.
4454 */
4455
4456 int numSamples = 0;
4457 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4458 // Do not load sample if this effect uses the MediaPlayer
4459 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
4460 continue;
4461 }
4462 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
4463 String filePath = Environment.getRootDirectory()
4464 + SOUND_EFFECTS_PATH
4465 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
4466 int sampleId = mSoundPool.load(filePath, 0);
4467 if (sampleId <= 0) {
4468 Log.w(TAG, "Soundpool could not load file: "+filePath);
4469 } else {
4470 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
4471 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
4472 numSamples++;
4473 }
4474 } else {
4475 SOUND_EFFECT_FILES_MAP[effect][1] =
4476 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
4477 }
4478 }
4479 // wait for all samples to be loaded
4480 if (numSamples > 0) {
4481 mSoundPoolCallBack.setSamples(poolId);
4482
4483 attempts = 3;
4484 status = 1;
4485 while ((status == 1) && (attempts-- > 0)) {
4486 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07004487 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004488 status = mSoundPoolCallBack.status();
4489 } catch (InterruptedException e) {
4490 Log.w(TAG, "Interrupted while waiting sound pool callback.");
4491 }
4492 }
4493 } else {
4494 status = -1;
4495 }
4496
4497 if (mSoundPoolLooper != null) {
4498 mSoundPoolLooper.quit();
4499 mSoundPoolLooper = null;
4500 }
4501 mSoundPoolListenerThread = null;
4502 if (status != 0) {
4503 Log.w(TAG,
4504 "onLoadSoundEffects(), Error "+status+ " while loading samples");
4505 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4506 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
4507 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4508 }
4509 }
4510
4511 mSoundPool.release();
4512 mSoundPool = null;
4513 }
4514 }
4515 return (status == 0);
4516 }
4517
4518 /**
4519 * Unloads samples from the sound pool.
4520 * This method can be called to free some memory when
4521 * sound effects are disabled.
4522 */
4523 private void onUnloadSoundEffects() {
4524 synchronized (mSoundEffectsLock) {
4525 if (mSoundPool == null) {
4526 return;
4527 }
4528
4529 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4530 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4531 poolId[fileIdx] = 0;
4532 }
4533
4534 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4535 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
4536 continue;
4537 }
4538 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
4539 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
4540 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4541 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
4542 }
4543 }
4544 mSoundPool.release();
4545 mSoundPool = null;
4546 }
4547 }
4548
4549 private void onPlaySoundEffect(int effectType, int volume) {
4550 synchronized (mSoundEffectsLock) {
4551
4552 onLoadSoundEffects();
4553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004554 if (mSoundPool == null) {
4555 return;
4556 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004557 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08004558 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004559 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07004560 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004561 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07004562 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004563 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004564
4565 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004566 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
4567 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004568 } else {
4569 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004570 try {
Eric Laurente78fced2013-03-15 16:03:47 -07004571 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
4572 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004573 mediaPlayer.setDataSource(filePath);
4574 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
4575 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08004576 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004577 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
4578 public void onCompletion(MediaPlayer mp) {
4579 cleanupPlayer(mp);
4580 }
4581 });
4582 mediaPlayer.setOnErrorListener(new OnErrorListener() {
4583 public boolean onError(MediaPlayer mp, int what, int extra) {
4584 cleanupPlayer(mp);
4585 return true;
4586 }
4587 });
4588 mediaPlayer.start();
4589 } catch (IOException ex) {
4590 Log.w(TAG, "MediaPlayer IOException: "+ex);
4591 } catch (IllegalArgumentException ex) {
4592 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
4593 } catch (IllegalStateException ex) {
4594 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004595 }
4596 }
4597 }
4598 }
4599
4600 private void cleanupPlayer(MediaPlayer mp) {
4601 if (mp != null) {
4602 try {
4603 mp.stop();
4604 mp.release();
4605 } catch (IllegalStateException ex) {
4606 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
4607 }
4608 }
4609 }
4610
Eric Laurentfa640152011-03-12 15:59:51 -08004611 private void setForceUse(int usage, int config) {
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004612 synchronized (mConnectedDevices) {
4613 setForceUseInt_SyncDevices(usage, config);
4614 }
Eric Laurentfa640152011-03-12 15:59:51 -08004615 }
4616
Eric Laurent05274f32012-11-29 12:48:18 -08004617 private void onPersistSafeVolumeState(int state) {
4618 Settings.Global.putInt(mContentResolver,
4619 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
4620 state);
4621 }
4622
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004623 @Override
4624 public void handleMessage(Message msg) {
Eric Laurentafbb0472011-12-15 09:04:23 -08004625 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004626
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004627 case MSG_SET_DEVICE_VOLUME:
4628 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
4629 break;
4630
4631 case MSG_SET_ALL_VOLUMES:
4632 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004633 break;
4634
4635 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07004636 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004637 break;
4638
4639 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08004640 // note that the value persisted is the current ringer mode, not the
4641 // value of ringer mode as of the time the request was made to persist
John Spurlock661f2cf2014-11-17 10:29:10 -05004642 persistRingerMode(getRingerModeInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004643 break;
4644
Andy Hunged0ea402015-10-30 14:11:46 -07004645 case MSG_AUDIO_SERVER_DIED:
4646 onAudioServerDied();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004647 break;
4648
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004649 case MSG_UNLOAD_SOUND_EFFECTS:
4650 onUnloadSoundEffects();
4651 break;
4652
Eric Laurent117b7bb2011-01-16 17:07:27 -08004653 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004654 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
4655 // can take several dozens of milliseconds to complete
4656 boolean loaded = onLoadSoundEffects();
4657 if (msg.obj != null) {
4658 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
4659 synchronized (reply) {
4660 reply.mStatus = loaded ? 0 : -1;
4661 reply.notify();
4662 }
4663 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08004664 break;
4665
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004666 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004667 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004668 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004669
4670 case MSG_BTA2DP_DOCK_TIMEOUT:
4671 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004672 synchronized (mConnectedDevices) {
4673 makeA2dpDeviceUnavailableNow( (String) msg.obj );
4674 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004675 break;
Eric Laurentfa640152011-03-12 15:59:51 -08004676
4677 case MSG_SET_FORCE_USE:
Sungsoocf09fe62016-09-28 16:21:48 +09004678 case MSG_SET_FORCE_BT_A2DP_USE:
Eric Laurentfa640152011-03-12 15:59:51 -08004679 setForceUse(msg.arg1, msg.arg2);
4680 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07004681
Eric Laurentdc03c612011-04-01 10:59:41 -07004682 case MSG_BT_HEADSET_CNCT_FAILED:
4683 resetBluetoothSco();
4684 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004685
4686 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
Paul McLean10804eb2015-01-28 11:16:35 -08004687 { WiredDeviceConnectionState connectState =
4688 (WiredDeviceConnectionState)msg.obj;
4689 onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
John Spurlock90874332015-03-10 16:00:54 -04004690 connectState.mAddress, connectState.mName, connectState.mCaller);
Paul McLean10804eb2015-01-28 11:16:35 -08004691 mAudioEventWakeLock.release();
4692 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004693 break;
4694
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004695 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
4696 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
4697 mAudioEventWakeLock.release();
4698 break;
4699
4700 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
4701 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004702 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004703 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004704
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08004705 case MSG_A2DP_DEVICE_CONFIG_CHANGE:
4706 onBluetoothA2dpDeviceConfigChange((BluetoothDevice)msg.obj);
4707 mAudioEventWakeLock.release();
4708 break;
4709
Dianne Hackborn632ca412012-06-14 19:34:10 -07004710 case MSG_REPORT_NEW_ROUTES: {
4711 int N = mRoutesObservers.beginBroadcast();
4712 if (N > 0) {
4713 AudioRoutesInfo routes;
4714 synchronized (mCurAudioRoutes) {
4715 routes = new AudioRoutesInfo(mCurAudioRoutes);
4716 }
4717 while (N > 0) {
4718 N--;
4719 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
4720 try {
4721 obs.dispatchAudioRoutesChanged(routes);
4722 } catch (RemoteException e) {
4723 }
4724 }
4725 }
4726 mRoutesObservers.finishBroadcast();
John Spurlock8a52c442015-03-26 14:23:58 -04004727 observeDevicesForStreams(-1);
Dianne Hackborn632ca412012-06-14 19:34:10 -07004728 break;
4729 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004730
Eric Laurentc34dcc12012-09-10 13:51:52 -07004731 case MSG_CHECK_MUSIC_ACTIVE:
John Spurlock90874332015-03-10 16:00:54 -04004732 onCheckMusicActive((String) msg.obj);
Eric Laurentc34dcc12012-09-10 13:51:52 -07004733 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004734
4735 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
4736 onSendBecomingNoisyIntent();
4737 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07004738
4739 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
4740 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
John Spurlock90874332015-03-10 16:00:54 -04004741 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED),
4742 (String) msg.obj);
Eric Laurentd640bd32012-09-28 18:01:48 -07004743 break;
Eric Laurent05274f32012-11-29 12:48:18 -08004744 case MSG_PERSIST_SAFE_VOLUME_STATE:
4745 onPersistSafeVolumeState(msg.arg1);
4746 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08004747
Eric Laurent2a57ca92013-03-07 17:29:27 -08004748 case MSG_BROADCAST_BT_CONNECTION_STATE:
4749 onBroadcastScoConnectionState(msg.arg1);
4750 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004751
4752 case MSG_SYSTEM_READY:
4753 onSystemReady();
4754 break;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004755
Eric Laurent0867bed2015-05-20 14:49:08 -07004756 case MSG_INDICATE_SYSTEM_READY:
4757 onIndicateSystemReady();
4758 break;
4759
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004760 case MSG_PERSIST_MUSIC_ACTIVE_MS:
4761 final int musicActiveMs = msg.arg1;
4762 Settings.Secure.putIntForUser(mContentResolver,
4763 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
4764 UserHandle.USER_CURRENT);
4765 break;
Eric Laurentc0232482016-03-15 18:19:23 -07004766
RoboErik5452e252015-02-06 15:33:53 -08004767 case MSG_UNMUTE_STREAM:
4768 onUnmuteStream(msg.arg1, msg.arg2);
4769 break;
Eric Laurentc0232482016-03-15 18:19:23 -07004770
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07004771 case MSG_DYN_POLICY_MIX_STATE_UPDATE:
4772 onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1);
4773 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004774 }
4775 }
4776 }
4777
Jason Parekhb1096152009-03-24 17:48:25 -07004778 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07004779
Phil Burked43bf52016-03-01 17:01:35 -08004780 private int mEncodedSurroundMode;
4781
Jason Parekhb1096152009-03-24 17:48:25 -07004782 SettingsObserver() {
4783 super(new Handler());
4784 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4785 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004786 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4787 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Andy Hung7b98e9a2016-02-25 18:34:50 -08004788 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4789 Settings.System.MASTER_MONO), false, this);
Phil Burked43bf52016-03-01 17:01:35 -08004790
4791 mEncodedSurroundMode = Settings.Global.getInt(
4792 mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT,
4793 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
4794 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4795 Settings.Global.ENCODED_SURROUND_OUTPUT), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07004796 }
4797
4798 @Override
4799 public void onChange(boolean selfChange) {
4800 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08004801 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
4802 // However there appear to be some missing locks around mRingerModeMutedStreams
4803 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
4804 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07004805 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004806 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07004807 /*
4808 * Ensure all stream types that should be affected by ringer mode
4809 * are in the proper state.
4810 */
John Spurlock661f2cf2014-11-17 10:29:10 -05004811 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurenta553c252009-07-17 12:17:14 -07004812 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004813 readDockAudioSettings(mContentResolver);
Andy Hung7b98e9a2016-02-25 18:34:50 -08004814 updateMasterMono(mContentResolver);
Phil Burked43bf52016-03-01 17:01:35 -08004815 updateEncodedSurroundOutput();
4816 }
4817 }
4818
4819 private void updateEncodedSurroundOutput() {
4820 int newSurroundMode = Settings.Global.getInt(
4821 mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT,
4822 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
4823 // Did it change?
4824 if (mEncodedSurroundMode != newSurroundMode) {
4825 // Send to AudioPolicyManager
4826 sendEncodedSurroundMode(newSurroundMode);
4827 synchronized(mConnectedDevices) {
4828 // Is HDMI connected?
4829 String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_HDMI, "");
4830 DeviceListSpec deviceSpec = mConnectedDevices.get(key);
4831 if (deviceSpec != null) {
4832 // Toggle HDMI to retrigger broadcast with proper formats.
4833 setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
4834 AudioSystem.DEVICE_STATE_UNAVAILABLE, "", "",
4835 "android"); // disconnect
4836 setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
4837 AudioSystem.DEVICE_STATE_AVAILABLE, "", "",
4838 "android"); // reconnect
4839 }
4840 }
4841 mEncodedSurroundMode = newSurroundMode;
Eric Laurenta553c252009-07-17 12:17:14 -07004842 }
Jason Parekhb1096152009-03-24 17:48:25 -07004843 }
Jason Parekhb1096152009-03-24 17:48:25 -07004844 }
Eric Laurenta553c252009-07-17 12:17:14 -07004845
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004846 // must be called synchronized on mConnectedDevices
Paul McLean20eec5b2015-05-09 13:02:18 -07004847 private void makeA2dpDeviceAvailable(String address, String name) {
Eric Laurent78472112012-05-21 08:57:21 -07004848 // enable A2DP before notifying A2DP connection to avoid unecessary processing in
4849 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004850 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4851 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4852 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Sungsoocf09fe62016-09-28 16:21:48 +09004853 setBluetoothA2dpOnInt(true);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004854 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004855 AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004856 // Reset A2DP suspend state each time a new sink is connected
4857 AudioSystem.setParameters("A2dpSuspended=false");
Paul McLean394a8e12015-03-03 10:29:19 -07004858 mConnectedDevices.put(
4859 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
Paul McLean20eec5b2015-05-09 13:02:18 -07004860 new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
Paul McLean394a8e12015-03-03 10:29:19 -07004861 address));
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004862 }
4863
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004864 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004865 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07004866 }
4867
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004868 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004869 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004870 synchronized (mA2dpAvrcpLock) {
4871 mAvrcpAbsVolSupported = false;
4872 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004873 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004874 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004875 mConnectedDevices.remove(
4876 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
RoboErik5535ea82014-09-25 14:53:16 -07004877 synchronized (mCurAudioRoutes) {
4878 // Remove A2DP routes as well
John Spurlock61560172015-02-06 19:46:04 -05004879 if (mCurAudioRoutes.bluetoothName != null) {
4880 mCurAudioRoutes.bluetoothName = null;
RoboErik5535ea82014-09-25 14:53:16 -07004881 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4882 SENDMSG_NOOP, 0, 0, null, 0);
4883 }
4884 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004885 }
4886
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004887 // must be called synchronized on mConnectedDevices
Eric Laurentd138e4e2015-05-15 16:41:15 -07004888 private void makeA2dpDeviceUnavailableLater(String address, int delayMs) {
Eric Laurent3b591262010-04-20 07:01:00 -07004889 // prevent any activity on the A2DP audio output to avoid unwanted
4890 // reconnection of the sink.
4891 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004892 // the device will be made unavailable later, so consider it disconnected right away
Paul McLean394a8e12015-03-03 10:29:19 -07004893 mConnectedDevices.remove(
4894 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004895 // send the delayed message to make the device unavailable later
4896 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
Eric Laurentd138e4e2015-05-15 16:41:15 -07004897 mAudioHandler.sendMessageDelayed(msg, delayMs);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004898
4899 }
4900
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004901 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004902 private void makeA2dpSrcAvailable(String address) {
4903 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004904 AudioSystem.DEVICE_STATE_AVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004905 mConnectedDevices.put(
4906 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
Paul McLean20eec5b2015-05-09 13:02:18 -07004907 new DeviceListSpec(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "",
Paul McLean394a8e12015-03-03 10:29:19 -07004908 address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004909 }
4910
4911 // must be called synchronized on mConnectedDevices
4912 private void makeA2dpSrcUnavailable(String address) {
4913 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004914 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004915 mConnectedDevices.remove(
4916 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004917 }
4918
4919 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004920 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004921 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4922 }
4923
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004924 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004925 private boolean hasScheduledA2dpDockTimeout() {
4926 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4927 }
4928
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004929 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004930 {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004931 if (DEBUG_VOL) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08004932 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice+"state=" + state);
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004933 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004934 if (btDevice == null) {
4935 return;
4936 }
4937 String address = btDevice.getAddress();
4938 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4939 address = "";
4940 }
John Du5a0cf7a2013-07-19 11:30:34 -07004941
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004942 synchronized (mConnectedDevices) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08004943 final String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4944 btDevice.getAddress());
4945 final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
Paul McLean394a8e12015-03-03 10:29:19 -07004946 boolean isConnected = deviceSpec != null;
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004947
4948 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4949 if (btDevice.isBluetoothDock()) {
4950 if (state == BluetoothProfile.STATE_DISCONNECTED) {
4951 // introduction of a delay for transient disconnections of docks when
4952 // power is rapidly turned off/on, this message will be canceled if
4953 // we reconnect the dock under a preset delay
Eric Laurentd138e4e2015-05-15 16:41:15 -07004954 makeA2dpDeviceUnavailableLater(address, BTA2DP_DOCK_TIMEOUT_MILLIS);
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004955 // the next time isConnected is evaluated, it will be false for the dock
4956 }
4957 } else {
4958 makeA2dpDeviceUnavailableNow(address);
4959 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07004960 synchronized (mCurAudioRoutes) {
John Spurlock61560172015-02-06 19:46:04 -05004961 if (mCurAudioRoutes.bluetoothName != null) {
4962 mCurAudioRoutes.bluetoothName = null;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004963 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4964 SENDMSG_NOOP, 0, 0, null, 0);
4965 }
4966 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004967 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4968 if (btDevice.isBluetoothDock()) {
4969 // this could be a reconnection after a transient disconnection
4970 cancelA2dpDeviceTimeout();
4971 mDockAddress = address;
4972 } else {
4973 // this could be a connection of another A2DP device before the timeout of
4974 // a dock: cancel the dock timeout, and make the dock unavailable now
4975 if(hasScheduledA2dpDockTimeout()) {
4976 cancelA2dpDeviceTimeout();
4977 makeA2dpDeviceUnavailableNow(mDockAddress);
4978 }
4979 }
Paul McLean20eec5b2015-05-09 13:02:18 -07004980 makeA2dpDeviceAvailable(address, btDevice.getName());
Dianne Hackborn632ca412012-06-14 19:34:10 -07004981 synchronized (mCurAudioRoutes) {
4982 String name = btDevice.getAliasName();
John Spurlock61560172015-02-06 19:46:04 -05004983 if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
4984 mCurAudioRoutes.bluetoothName = name;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004985 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4986 SENDMSG_NOOP, 0, 0, null, 0);
4987 }
4988 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004989 }
4990 }
4991 }
4992
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004993 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
4994 {
4995 if (DEBUG_VOL) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08004996 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice=" + btDevice + " state=" + state);
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004997 }
4998 if (btDevice == null) {
4999 return;
5000 }
5001 String address = btDevice.getAddress();
5002 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
5003 address = "";
5004 }
5005
5006 synchronized (mConnectedDevices) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005007 final String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
5008 final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
Paul McLean394a8e12015-03-03 10:29:19 -07005009 boolean isConnected = deviceSpec != null;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005010
5011 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
5012 makeA2dpSrcUnavailable(address);
5013 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
5014 makeA2dpSrcAvailable(address);
5015 }
5016 }
5017 }
5018
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005019 private void onBluetoothA2dpDeviceConfigChange(BluetoothDevice btDevice)
5020 {
5021 if (DEBUG_VOL) {
5022 Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice);
5023 }
5024 if (btDevice == null) {
5025 return;
5026 }
5027 String address = btDevice.getAddress();
5028 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
5029 address = "";
5030 }
5031
5032 int device = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
5033 synchronized (mConnectedDevices) {
5034 final String key = makeDeviceListKey(device, address);
5035 final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
5036 if (deviceSpec != null) {
5037 // Device is connected
5038 AudioSystem.handleDeviceConfigChange(device, address,
5039 btDevice.getName());
5040 }
5041 }
5042 }
5043
John Du5a0cf7a2013-07-19 11:30:34 -07005044 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
5045 // address is not used for now, but may be used when multiple a2dp devices are supported
5046 synchronized (mA2dpAvrcpLock) {
5047 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07005048 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07005049 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
5050 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
5051 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
5052 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
5053 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07005054 }
5055 }
5056
Paul McLean394a8e12015-03-03 10:29:19 -07005057 private boolean handleDeviceConnection(boolean connect, int device, String address,
5058 String deviceName) {
5059 if (DEBUG_DEVICES) {
5060 Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device)
5061 + " address:" + address + " name:" + deviceName + ")");
5062 }
Eric Laurent59f48272012-04-05 19:42:21 -07005063 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07005064 String deviceKey = makeDeviceListKey(device, address);
5065 if (DEBUG_DEVICES) {
5066 Slog.i(TAG, "deviceKey:" + deviceKey);
5067 }
5068 DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
5069 boolean isConnected = deviceSpec != null;
5070 if (DEBUG_DEVICES) {
5071 Slog.i(TAG, "deviceSpec:" + deviceSpec + " is(already)Connected:" + isConnected);
5072 }
5073 if (connect && !isConnected) {
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07005074 final int res = AudioSystem.setDeviceConnectionState(device,
5075 AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);
5076 if (res != AudioSystem.AUDIO_STATUS_OK) {
5077 Slog.e(TAG, "not connecting device 0x" + Integer.toHexString(device) +
5078 " due to command error " + res );
5079 return false;
5080 }
Paul McLean394a8e12015-03-03 10:29:19 -07005081 mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
5082 return true;
5083 } else if (!connect && isConnected) {
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07005084 AudioSystem.setDeviceConnectionState(device,
5085 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName);
5086 // always remove even if disconnection failed
Paul McLean394a8e12015-03-03 10:29:19 -07005087 mConnectedDevices.remove(deviceKey);
5088 return true;
Eric Laurent59f48272012-04-05 19:42:21 -07005089 }
5090 }
5091 return false;
5092 }
5093
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005094 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
5095 // sent if none of these devices is connected.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005096 // Access synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005097 int mBecomingNoisyIntentDevices =
5098 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07005099 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07005100 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Jon Eklund43cc8bb2014-07-28 16:07:24 -05005101 AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005102
5103 // must be called before removing the device from mConnectedDevices
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005104 // Called synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005105 private int checkSendBecomingNoisyIntent(int device, int state) {
5106 int delay = 0;
5107 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
5108 int devices = 0;
John Spurlock8c3dc852015-04-23 21:32:37 -04005109 for (int i = 0; i < mConnectedDevices.size(); i++) {
5110 int dev = mConnectedDevices.valueAt(i).mDeviceType;
Paul McLean394a8e12015-03-03 10:29:19 -07005111 if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
5112 && ((dev & mBecomingNoisyIntentDevices) != 0)) {
5113 devices |= dev;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005114 }
5115 }
5116 if (devices == device) {
Eric Laurent5bfaeae2012-09-21 18:44:48 -07005117 sendMsg(mAudioHandler,
5118 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
5119 SENDMSG_REPLACE,
5120 0,
5121 0,
5122 null,
5123 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005124 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005125 }
5126 }
5127
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005128 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
5129 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005130 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
Eric Laurentadbe8bf2014-11-03 18:26:32 -08005131 synchronized (mLastDeviceConnectMsgTime) {
5132 long time = SystemClock.uptimeMillis();
5133 if (mLastDeviceConnectMsgTime > time) {
Matthew Xiec525cf72015-01-22 20:13:17 -08005134 delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
Eric Laurentadbe8bf2014-11-03 18:26:32 -08005135 }
5136 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005137 }
5138 return delay;
5139 }
5140
Paul McLean394a8e12015-03-03 10:29:19 -07005141 private void sendDeviceConnectionIntent(int device, int state, String address,
5142 String deviceName) {
5143 if (DEBUG_DEVICES) {
5144 Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
5145 " state:0x" + Integer.toHexString(state) + " address:" + address +
5146 " name:" + deviceName + ");");
5147 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005148 Intent intent = new Intent();
5149
Paul McLean10804eb2015-01-28 11:16:35 -08005150 intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
5151 intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
5152 intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
5153
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005154 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
5155
Dianne Hackborn632ca412012-06-14 19:34:10 -07005156 int connType = 0;
5157
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005158 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07005159 connType = AudioRoutesInfo.MAIN_HEADSET;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005160 intent.setAction(Intent.ACTION_HEADSET_PLUG);
5161 intent.putExtra("microphone", 1);
Jon Eklund43cc8bb2014-07-28 16:07:24 -05005162 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
5163 device == AudioSystem.DEVICE_OUT_LINE) {
5164 /*do apps care about line-out vs headphones?*/
Dianne Hackborn632ca412012-06-14 19:34:10 -07005165 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005166 intent.setAction(Intent.ACTION_HEADSET_PLUG);
5167 intent.putExtra("microphone", 0);
Eric Laurent6fa42452015-01-09 15:09:40 -08005168 } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
5169 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07005170 connType = AudioRoutesInfo.MAIN_HDMI;
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005171 configureHdmiPlugIntent(intent, state);
Paul McLean10804eb2015-01-28 11:16:35 -08005172 } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE) {
5173 connType = AudioRoutesInfo.MAIN_USB;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005174 }
5175
Dianne Hackborn632ca412012-06-14 19:34:10 -07005176 synchronized (mCurAudioRoutes) {
5177 if (connType != 0) {
John Spurlock61560172015-02-06 19:46:04 -05005178 int newConn = mCurAudioRoutes.mainType;
Dianne Hackborn632ca412012-06-14 19:34:10 -07005179 if (state != 0) {
5180 newConn |= connType;
5181 } else {
5182 newConn &= ~connType;
5183 }
John Spurlock61560172015-02-06 19:46:04 -05005184 if (newConn != mCurAudioRoutes.mainType) {
5185 mCurAudioRoutes.mainType = newConn;
Dianne Hackborn632ca412012-06-14 19:34:10 -07005186 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
5187 SENDMSG_NOOP, 0, 0, null, 0);
5188 }
5189 }
5190 }
5191
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005192 final long ident = Binder.clearCallingIdentity();
5193 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08005194 ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005195 } finally {
5196 Binder.restoreCallingIdentity(ident);
5197 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005198 }
5199
Paul McLean10804eb2015-01-28 11:16:35 -08005200 private void onSetWiredDeviceConnectionState(int device, int state, String address,
John Spurlock90874332015-03-10 16:00:54 -04005201 String deviceName, String caller) {
Paul McLean394a8e12015-03-03 10:29:19 -07005202 if (DEBUG_DEVICES) {
John Spurlock90874332015-03-10 16:00:54 -04005203 Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
5204 + " state:" + Integer.toHexString(state)
5205 + " address:" + address
5206 + " deviceName:" + deviceName
5207 + " caller: " + caller + ");");
Paul McLean394a8e12015-03-03 10:29:19 -07005208 }
Paul McLean10804eb2015-01-28 11:16:35 -08005209
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005210 synchronized (mConnectedDevices) {
Sungsoocf09fe62016-09-28 16:21:48 +09005211 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
5212 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
5213 (device == AudioSystem.DEVICE_OUT_LINE))) {
5214 setBluetoothA2dpOnInt(true);
5215 }
Eric Laurentae4506e2014-05-29 16:04:32 -07005216 boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
5217 (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
5218 ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07005219 if (!handleDeviceConnection(state == 1, device, address, deviceName)) {
5220 // change of connection state failed, bailout
5221 return;
5222 }
Eric Laurentf1a457d2012-09-20 16:27:23 -07005223 if (state != 0) {
Sungsoocf09fe62016-09-28 16:21:48 +09005224 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
5225 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
5226 (device == AudioSystem.DEVICE_OUT_LINE)) {
5227 setBluetoothA2dpOnInt(false);
5228 }
Eric Laurentf1a457d2012-09-20 16:27:23 -07005229 if ((device & mSafeMediaVolumeDevices) != 0) {
5230 sendMsg(mAudioHandler,
5231 MSG_CHECK_MUSIC_ACTIVE,
5232 SENDMSG_REPLACE,
5233 0,
5234 0,
John Spurlock90874332015-03-10 16:00:54 -04005235 caller,
Eric Laurentf1a457d2012-09-20 16:27:23 -07005236 MUSIC_ACTIVE_POLL_PERIOD_MS);
5237 }
Eric Laurent212532b2014-07-21 15:43:18 -07005238 // Television devices without CEC service apply software volume on HDMI output
5239 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
5240 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
5241 checkAllFixedVolumeDevices();
5242 if (mHdmiManager != null) {
5243 synchronized (mHdmiManager) {
5244 if (mHdmiPlaybackClient != null) {
5245 mHdmiCecSink = false;
5246 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
5247 }
5248 }
5249 }
5250 }
5251 } else {
5252 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
5253 if (mHdmiManager != null) {
5254 synchronized (mHdmiManager) {
5255 mHdmiCecSink = false;
5256 }
5257 }
5258 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005259 }
Paul McLean10804eb2015-01-28 11:16:35 -08005260 if (!isUsb && device != AudioSystem.DEVICE_IN_WIRED_HEADSET) {
5261 sendDeviceConnectionIntent(device, state, address, deviceName);
Mike Lockwooddb454842012-09-18 11:16:57 -07005262 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005263 }
5264 }
5265
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005266 private void configureHdmiPlugIntent(Intent intent, int state) {
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005267 intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
5268 intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005269 if (state == 1) {
5270 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
5271 int[] portGeneration = new int[1];
5272 int status = AudioSystem.listAudioPorts(ports, portGeneration);
5273 if (status == AudioManager.SUCCESS) {
5274 for (AudioPort port : ports) {
5275 if (port instanceof AudioDevicePort) {
5276 final AudioDevicePort devicePort = (AudioDevicePort) port;
Eric Laurent6fa42452015-01-09 15:09:40 -08005277 if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
5278 devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005279 // format the list of supported encodings
Eric Laurentcae34662015-05-19 16:46:52 -07005280 int[] formats = AudioFormat.filterPublicFormats(devicePort.formats());
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005281 if (formats.length > 0) {
5282 ArrayList<Integer> encodingList = new ArrayList(1);
5283 for (int format : formats) {
5284 // a format in the list can be 0, skip it
5285 if (format != AudioFormat.ENCODING_INVALID) {
5286 encodingList.add(format);
5287 }
5288 }
5289 int[] encodingArray = new int[encodingList.size()];
5290 for (int i = 0 ; i < encodingArray.length ; i++) {
5291 encodingArray[i] = encodingList.get(i);
5292 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005293 intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005294 }
5295 // find the maximum supported number of channels
5296 int maxChannels = 0;
5297 for (int mask : devicePort.channelMasks()) {
5298 int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
5299 if (channelCount > maxChannels) {
5300 maxChannels = channelCount;
5301 }
5302 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005303 intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005304 }
5305 }
5306 }
5307 }
5308 }
5309 }
5310
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07005311 /* cache of the address of the last dock the device was connected to */
5312 private String mDockAddress;
5313
Eric Laurenta553c252009-07-17 12:17:14 -07005314 /**
5315 * Receiver for misc intent broadcasts the Phone app cares about.
5316 */
5317 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
5318 @Override
5319 public void onReceive(Context context, Intent intent) {
5320 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07005321 int outDevice;
5322 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07005323 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07005324
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08005325 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
5326 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
5327 Intent.EXTRA_DOCK_STATE_UNDOCKED);
5328 int config;
5329 switch (dockState) {
5330 case Intent.EXTRA_DOCK_STATE_DESK:
5331 config = AudioSystem.FORCE_BT_DESK_DOCK;
5332 break;
5333 case Intent.EXTRA_DOCK_STATE_CAR:
5334 config = AudioSystem.FORCE_BT_CAR_DOCK;
5335 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05005336 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08005337 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05005338 break;
5339 case Intent.EXTRA_DOCK_STATE_HE_DESK:
5340 config = AudioSystem.FORCE_DIGITAL_DOCK;
5341 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08005342 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
5343 default:
5344 config = AudioSystem.FORCE_NONE;
5345 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08005346 // Low end docks have a menu to enable or disable audio
5347 // (see mDockAudioMediaEnabled)
5348 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
5349 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
5350 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
5351 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
5352 }
5353 mDockState = dockState;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07005354 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
Eric Laurent59f48272012-04-05 19:42:21 -07005355 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07005356 BluetoothProfile.STATE_DISCONNECTED);
Eric Laurentdca56b92011-09-02 14:20:56 -07005357 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Eric Laurent98859b22015-06-12 14:35:59 -07005358 setBtScoDeviceConnectionState(btDevice, state);
Paul McLeandf361462014-04-10 16:02:55 -07005359 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005360 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07005361 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005362 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005363 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07005364 // broadcast intent if the connection was initated by AudioService
5365 if (!mScoClients.isEmpty() &&
5366 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
5367 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
5368 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005369 broadcast = true;
5370 }
5371 switch (btState) {
5372 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07005373 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07005374 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5375 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5376 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005377 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005378 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005379 break;
5380 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07005381 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08005382 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07005383 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08005384 break;
5385 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07005386 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5387 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5388 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005389 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005390 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005391 default:
5392 // do not broadcast CONNECTING or invalid state
5393 broadcast = false;
5394 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005395 }
5396 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005397 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07005398 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07005399 //FIXME: this is to maintain compatibility with deprecated intent
5400 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08005401 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07005402 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005403 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08005404 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005405 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06005406 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005407 RotationHelper.enable();
Jon Eklund318f0fe2014-01-23 17:53:48 -06005408 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005409 AudioSystem.setParameters("screen_state=on");
5410 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06005411 if (mMonitorRotation) {
5412 //reduce wakeups (save current) by only listening when display is on
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005413 RotationHelper.disable();
Jon Eklund318f0fe2014-01-23 17:53:48 -06005414 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005415 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07005416 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005417 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07005418 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Yasuhiro Matsuda4ced7192015-07-10 22:08:44 +09005419 if (mUserSwitchedReceived) {
5420 // attempt to stop music playback for background user except on first user
5421 // switch (i.e. first boot)
5422 sendMsg(mAudioHandler,
5423 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
5424 SENDMSG_REPLACE,
5425 0,
5426 0,
5427 null,
5428 0);
5429 }
5430 mUserSwitchedReceived = true;
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07005431 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005432 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07005433
Eric Laurent5bfaeae2012-09-21 18:44:48 -07005434 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07005435 readAudioSettings(true /*userSwitch*/);
5436 // preserve STREAM_MUSIC volume from one user to the next.
5437 sendMsg(mAudioHandler,
5438 MSG_SET_ALL_VOLUMES,
5439 SENDMSG_QUEUE,
5440 0,
5441 0,
5442 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005443 } else if (action.equals(Intent.ACTION_USER_BACKGROUND)) {
5444 // Disable audio recording for the background user/profile
5445 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
5446 if (userId >= 0) {
5447 // TODO Kill recording streams instead of killing processes holding permission
5448 UserInfo userInfo = UserManagerService.getInstance().getUserInfo(userId);
5449 killBackgroundUserProcessesWithRecordAudioPermission(userInfo);
5450 }
Makoto Onukiac65e1e2015-11-20 15:33:17 -08005451 UserManagerService.getInstance().setUserRestriction(
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005452 UserManager.DISALLOW_RECORD_AUDIO, true, userId);
5453 } else if (action.equals(Intent.ACTION_USER_FOREGROUND)) {
5454 // Enable audio recording for foreground user/profile
5455 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Makoto Onukiac65e1e2015-11-20 15:33:17 -08005456 UserManagerService.getInstance().setUserRestriction(
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005457 UserManager.DISALLOW_RECORD_AUDIO, false, userId);
Eric Laurentb70b78a2016-01-13 19:16:04 -08005458 } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
5459 state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
5460 if (state == BluetoothAdapter.STATE_OFF ||
5461 state == BluetoothAdapter.STATE_TURNING_OFF) {
5462 disconnectAllBluetoothProfiles();
5463 }
Eric Laurenta553c252009-07-17 12:17:14 -07005464 }
5465 }
Paul McLeanc837a452014-04-09 09:04:43 -07005466 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005467
Makoto Onukid45a4a22015-11-02 17:17:38 -08005468 private class AudioServiceUserRestrictionsListener implements UserRestrictionsListener {
5469
5470 @Override
5471 public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
5472 Bundle prevRestrictions) {
5473 // Update mic mute state.
5474 {
5475 final boolean wasRestricted =
5476 prevRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
5477 final boolean isRestricted =
5478 newRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
5479 if (wasRestricted != isRestricted) {
5480 setMicrophoneMuteNoCallerCheck(isRestricted, userId);
5481 }
5482 }
5483
5484 // Update speaker mute state.
5485 {
5486 final boolean wasRestricted =
Tony Makc1205112016-07-22 16:02:59 +01005487 prevRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)
5488 || prevRestrictions.getBoolean(UserManager.DISALLLOW_UNMUTE_DEVICE);
Makoto Onukid45a4a22015-11-02 17:17:38 -08005489 final boolean isRestricted =
Tony Makc1205112016-07-22 16:02:59 +01005490 newRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)
5491 || newRestrictions.getBoolean(UserManager.DISALLLOW_UNMUTE_DEVICE);
Makoto Onukid45a4a22015-11-02 17:17:38 -08005492 if (wasRestricted != isRestricted) {
5493 setMasterMuteInternalNoCallerCheck(isRestricted, /* flags =*/ 0, userId);
5494 }
5495 }
5496 }
5497 } // end class AudioServiceUserRestrictionsListener
5498
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005499 private void killBackgroundUserProcessesWithRecordAudioPermission(UserInfo oldUser) {
5500 PackageManager pm = mContext.getPackageManager();
5501 // Find the home activity of the user. It should not be killed to avoid expensive restart,
5502 // when the user switches back. For managed profiles, we should kill all recording apps
5503 ComponentName homeActivityName = null;
5504 if (!oldUser.isManagedProfile()) {
Sudheer Shankafc46e9b2016-10-21 17:55:27 -07005505 homeActivityName = mActivityManagerInternal.getHomeActivityForUser(oldUser.id);
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005506 }
5507 final String[] permissions = { Manifest.permission.RECORD_AUDIO };
5508 List<PackageInfo> packages;
5509 try {
5510 packages = AppGlobals.getPackageManager()
5511 .getPackagesHoldingPermissions(permissions, 0, oldUser.id).getList();
5512 } catch (RemoteException e) {
5513 throw new AndroidRuntimeException(e);
5514 }
5515 for (int j = packages.size() - 1; j >= 0; j--) {
5516 PackageInfo pkg = packages.get(j);
Fyodor Kupolovbcb6c1e2015-05-11 12:05:15 -07005517 // Skip system processes
5518 if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
5519 continue;
5520 }
Amith Yamasanic1cbaab2015-07-21 11:46:14 -07005521 // Skip packages that have permission to interact across users
5522 if (pm.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS, pkg.packageName)
5523 == PackageManager.PERMISSION_GRANTED) {
5524 continue;
5525 }
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005526 if (homeActivityName != null
5527 && pkg.packageName.equals(homeActivityName.getPackageName())
5528 && pkg.applicationInfo.isSystemApp()) {
5529 continue;
5530 }
5531 try {
Svetoslavaa41add2015-08-06 15:03:55 -07005532 final int uid = pkg.applicationInfo.uid;
Sudheer Shankadc589ac2016-11-10 15:30:17 -08005533 ActivityManager.getService().killUid(UserHandle.getAppId(uid),
Svetoslavaa41add2015-08-06 15:03:55 -07005534 UserHandle.getUserId(uid),
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005535 "killBackgroundUserProcessesWithAudioRecordPermission");
5536 } catch (RemoteException e) {
5537 Log.w(TAG, "Error calling killUid", e);
5538 }
5539 }
5540 }
5541
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005542
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005543 //==========================================================================================
5544 // Audio Focus
5545 //==========================================================================================
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005546 public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005547 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005548 IAudioPolicyCallback pcb) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005549 // permission checks
5550 if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
John Spurlock61560172015-02-06 19:46:04 -05005551 if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005552 if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
5553 android.Manifest.permission.MODIFY_PHONE_STATE)) {
5554 Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
5555 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5556 }
5557 } else {
5558 // only a registered audio policy can be used to lock focus
5559 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005560 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
5561 Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005562 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5563 }
5564 }
5565 }
5566 }
5567
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005568 return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
5569 clientId, callingPackageName, flags);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005570 }
5571
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005572 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
5573 return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005574 }
5575
5576 public void unregisterAudioFocusClient(String clientId) {
5577 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005578 }
5579
Jean-Michel Trivi23805662013-07-31 14:19:18 -07005580 public int getCurrentAudioFocus() {
5581 return mMediaFocusControl.getCurrentAudioFocus();
5582 }
5583
John Spurlock5e783732015-02-19 10:28:59 -05005584 private boolean readCameraSoundForced() {
5585 return SystemProperties.getBoolean("audio.camerasound.force", false) ||
5586 mContext.getResources().getBoolean(
5587 com.android.internal.R.bool.config_camera_sound_forced);
5588 }
5589
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005590 //==========================================================================================
5591 // Device orientation
5592 //==========================================================================================
5593 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005594 * Handles device configuration changes that may map to a change in the orientation
5595 * or orientation.
5596 * Monitoring orientation and rotation is optional, and is defined by the definition and value
5597 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005598 */
5599 private void handleConfigurationChanged(Context context) {
5600 try {
5601 // reading new orientation "safely" (i.e. under try catch) in case anything
5602 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07005603 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005604 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07005605 if (mMonitorOrientation) {
5606 int newOrientation = config.orientation;
5607 if (newOrientation != mDeviceOrientation) {
5608 mDeviceOrientation = newOrientation;
5609 setOrientationForAudioSystem();
5610 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005611 }
Eric Laurentd640bd32012-09-28 18:01:48 -07005612 sendMsg(mAudioHandler,
5613 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
5614 SENDMSG_REPLACE,
5615 0,
5616 0,
John Spurlock90874332015-03-10 16:00:54 -04005617 TAG,
Eric Laurentd640bd32012-09-28 18:01:48 -07005618 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07005619
John Spurlock5e783732015-02-19 10:28:59 -05005620 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -07005621 synchronized (mSettingsLock) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005622 boolean cameraSoundForcedChanged = false;
Eric Laurentdd45d012012-10-08 09:04:34 -07005623 synchronized (mCameraSoundForced) {
5624 if (cameraSoundForced != mCameraSoundForced) {
5625 mCameraSoundForced = cameraSoundForced;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005626 cameraSoundForcedChanged = true;
Eric Laurentdd45d012012-10-08 09:04:34 -07005627 }
5628 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005629 if (cameraSoundForcedChanged) {
Muyuan Li1ed6df62016-06-18 11:16:52 -07005630 if (!mIsSingleVolume) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005631 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
5632 if (cameraSoundForced) {
5633 s.setAllIndexesToMax();
5634 mRingerModeAffectedStreams &=
5635 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5636 } else {
John Spurlock90874332015-03-10 16:00:54 -04005637 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005638 mRingerModeAffectedStreams |=
5639 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5640 }
5641 // take new state into account for streams muted by ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05005642 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005643 }
5644
5645 sendMsg(mAudioHandler,
5646 MSG_SET_FORCE_USE,
5647 SENDMSG_QUEUE,
5648 AudioSystem.FOR_SYSTEM,
5649 cameraSoundForced ?
5650 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
5651 null,
5652 0);
5653
5654 sendMsg(mAudioHandler,
5655 MSG_SET_ALL_VOLUMES,
5656 SENDMSG_QUEUE,
5657 0,
5658 0,
5659 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
5660 }
Eric Laurentdd45d012012-10-08 09:04:34 -07005661 }
John Spurlock3346a802014-05-20 16:25:37 -04005662 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005663 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005664 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005665 }
5666 }
5667
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005668 //TODO move to an external "orientation helper" class
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005669 private void setOrientationForAudioSystem() {
5670 switch (mDeviceOrientation) {
5671 case Configuration.ORIENTATION_LANDSCAPE:
5672 //Log.i(TAG, "orientation is landscape");
5673 AudioSystem.setParameters("orientation=landscape");
5674 break;
5675 case Configuration.ORIENTATION_PORTRAIT:
5676 //Log.i(TAG, "orientation is portrait");
5677 AudioSystem.setParameters("orientation=portrait");
5678 break;
5679 case Configuration.ORIENTATION_SQUARE:
5680 //Log.i(TAG, "orientation is square");
5681 AudioSystem.setParameters("orientation=square");
5682 break;
5683 case Configuration.ORIENTATION_UNDEFINED:
5684 //Log.i(TAG, "orientation is undefined");
5685 AudioSystem.setParameters("orientation=undefined");
5686 break;
5687 default:
5688 Log.e(TAG, "Unknown orientation");
5689 }
5690 }
5691
Sungsoocf09fe62016-09-28 16:21:48 +09005692 // Handles request to override default use of A2DP for media.
5693 // Must be called synchronized on mConnectedDevices
5694 public void setBluetoothA2dpOnInt(boolean on) {
5695 synchronized (mBluetoothA2dpEnabledLock) {
5696 mBluetoothA2dpEnabled = on;
5697 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
5698 setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
5699 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
5700 }
5701 }
5702
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005703 // Must be called synchronized on mConnectedDevices
5704 private void setForceUseInt_SyncDevices(int usage, int config) {
5705 switch (usage) {
Sungsoocf09fe62016-09-28 16:21:48 +09005706 case AudioSystem.FOR_MEDIA:
5707 if (config == AudioSystem.FORCE_NO_BT_A2DP) {
5708 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ALL_A2DP;
5709 } else { // config == AudioSystem.FORCE_NONE
5710 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
5711 }
Sungsoo71f35632016-09-28 16:26:49 +09005712 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
5713 SENDMSG_NOOP, 0, 0, null, 0);
Sungsoocf09fe62016-09-28 16:21:48 +09005714 break;
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005715 case AudioSystem.FOR_DOCK:
5716 if (config == AudioSystem.FORCE_ANALOG_DOCK) {
5717 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5718 } else { // config == AudioSystem.FORCE_NONE
5719 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5720 }
5721 break;
5722 default:
5723 // usage doesn't affect the broadcast of ACTION_AUDIO_BECOMING_NOISY
5724 }
5725 AudioSystem.setForceUse(usage, config);
5726 }
5727
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005728 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07005729 public void setRingtonePlayer(IRingtonePlayer player) {
5730 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5731 mRingtonePlayer = player;
5732 }
5733
5734 @Override
5735 public IRingtonePlayer getRingtonePlayer() {
5736 return mRingtonePlayer;
5737 }
5738
5739 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07005740 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5741 synchronized (mCurAudioRoutes) {
5742 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5743 mRoutesObservers.register(observer);
5744 return routes;
5745 }
5746 }
5747
Eric Laurentc34dcc12012-09-10 13:51:52 -07005748
5749 //==========================================================================================
5750 // Safe media volume management.
5751 // MUSIC stream volume level is limited when headphones are connected according to safety
5752 // regulation. When the user attempts to raise the volume above the limit, a warning is
5753 // displayed and the user has to acknowlegde before the volume is actually changed.
5754 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
5755 // property. Platforms with a different limit must set this property accordingly in their
5756 // overlay.
5757 //==========================================================================================
5758
Eric Laurentd640bd32012-09-28 18:01:48 -07005759 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
5760 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
5761 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
5762 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
5763 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
5764 // (when user opts out).
John Spurlock35134602014-07-24 18:10:48 -04005765 private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
5766 private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
5767 private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed
5768 private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
Eric Laurentd640bd32012-09-28 18:01:48 -07005769 private Integer mSafeMediaVolumeState;
5770
5771 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005772 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07005773 private int mSafeMediaVolumeIndex;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005774 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
5775 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
5776 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
5777 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
5778 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
5779 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
5780 private int mMusicActiveMs;
5781 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
5782 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07005783 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07005784
John Spurlock90874332015-03-10 16:00:54 -04005785 private void setSafeMediaVolumeEnabled(boolean on, String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005786 synchronized (mSafeMediaVolumeState) {
5787 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
5788 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
5789 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
5790 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
John Spurlock90874332015-03-10 16:00:54 -04005791 enforceSafeMediaVolume(caller);
Eric Laurentd640bd32012-09-28 18:01:48 -07005792 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
5793 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005794 mMusicActiveMs = 1; // nonzero = confirmed
5795 saveMusicActiveMs();
Eric Laurentd640bd32012-09-28 18:01:48 -07005796 sendMsg(mAudioHandler,
5797 MSG_CHECK_MUSIC_ACTIVE,
5798 SENDMSG_REPLACE,
5799 0,
5800 0,
John Spurlock90874332015-03-10 16:00:54 -04005801 caller,
Eric Laurentd640bd32012-09-28 18:01:48 -07005802 MUSIC_ACTIVE_POLL_PERIOD_MS);
5803 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005804 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005805 }
5806 }
5807
John Spurlock90874332015-03-10 16:00:54 -04005808 private void enforceSafeMediaVolume(String caller) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005809 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07005810 int devices = mSafeMediaVolumeDevices;
5811 int i = 0;
5812
5813 while (devices != 0) {
5814 int device = 1 << i++;
5815 if ((device & devices) == 0) {
5816 continue;
5817 }
Eric Laurent42b041e2013-03-29 11:36:03 -07005818 int index = streamState.getIndex(device);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005819 if (index > mSafeMediaVolumeIndex) {
John Spurlock90874332015-03-10 16:00:54 -04005820 streamState.setIndex(mSafeMediaVolumeIndex, device, caller);
Eric Laurent42b041e2013-03-29 11:36:03 -07005821 sendMsg(mAudioHandler,
5822 MSG_SET_DEVICE_VOLUME,
5823 SENDMSG_QUEUE,
5824 device,
5825 0,
5826 streamState,
5827 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005828 }
5829 devices &= ~device;
5830 }
5831 }
5832
5833 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005834 synchronized (mSafeMediaVolumeState) {
5835 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07005836 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
5837 ((device & mSafeMediaVolumeDevices) != 0) &&
5838 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005839 return false;
5840 }
5841 return true;
5842 }
5843 }
5844
John Spurlock3346a802014-05-20 16:25:37 -04005845 @Override
John Spurlock90874332015-03-10 16:00:54 -04005846 public void disableSafeMediaVolume(String callingPackage) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005847 enforceVolumeController("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07005848 synchronized (mSafeMediaVolumeState) {
John Spurlock90874332015-03-10 16:00:54 -04005849 setSafeMediaVolumeEnabled(false, callingPackage);
Eric Laurentfde16d52012-12-03 14:42:39 -08005850 if (mPendingVolumeCommand != null) {
5851 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
5852 mPendingVolumeCommand.mIndex,
5853 mPendingVolumeCommand.mFlags,
John Spurlock90874332015-03-10 16:00:54 -04005854 mPendingVolumeCommand.mDevice,
5855 callingPackage);
Eric Laurentfde16d52012-12-03 14:42:39 -08005856 mPendingVolumeCommand = null;
5857 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005858 }
5859 }
5860
Jungshik Jang41d97462014-06-30 22:26:29 +09005861 //==========================================================================================
5862 // Hdmi Cec system audio mode.
John Spurlockbc82b122015-03-02 16:12:38 -05005863 // If Hdmi Cec's system audio mode is on, audio service should send the volume change
5864 // to HdmiControlService so that the audio receiver can handle it.
Jungshik Jang41d97462014-06-30 22:26:29 +09005865 //==========================================================================================
5866
Eric Laurent212532b2014-07-21 15:43:18 -07005867 private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
5868 public void onComplete(int status) {
5869 if (mHdmiManager != null) {
5870 synchronized (mHdmiManager) {
5871 mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
5872 // Television devices without CEC service apply software volume on HDMI output
5873 if (isPlatformTelevision() && !mHdmiCecSink) {
5874 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5875 }
5876 checkAllFixedVolumeDevices();
5877 }
5878 }
5879 }
5880 };
5881
Jungshik Jang41d97462014-06-30 22:26:29 +09005882 // If HDMI-CEC system audio is supported
5883 private boolean mHdmiSystemAudioSupported = false;
5884 // Set only when device is tv.
5885 private HdmiTvClient mHdmiTvClient;
Eric Laurent0b03f992014-11-18 18:08:02 -08005886 // true if the device has system feature PackageManager.FEATURE_LEANBACK.
Eric Laurent212532b2014-07-21 15:43:18 -07005887 // cached HdmiControlManager interface
5888 private HdmiControlManager mHdmiManager;
5889 // Set only when device is a set-top box.
5890 private HdmiPlaybackClient mHdmiPlaybackClient;
5891 // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5892 private boolean mHdmiCecSink;
5893
5894 private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
Jungshik Jang41d97462014-06-30 22:26:29 +09005895
5896 @Override
Jungshik Jang12307ca2014-07-15 19:27:56 +09005897 public int setHdmiSystemAudioSupported(boolean on) {
Eric Laurent212532b2014-07-21 15:43:18 -07005898 int device = AudioSystem.DEVICE_NONE;
5899 if (mHdmiManager != null) {
5900 synchronized (mHdmiManager) {
5901 if (mHdmiTvClient == null) {
5902 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5903 return device;
5904 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005905
Eric Laurent212532b2014-07-21 15:43:18 -07005906 synchronized (mHdmiTvClient) {
5907 if (mHdmiSystemAudioSupported != on) {
5908 mHdmiSystemAudioSupported = on;
5909 AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5910 on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5911 AudioSystem.FORCE_NONE);
5912 }
John Spurlock8a52c442015-03-26 14:23:58 -04005913 device = getDevicesForStream(AudioSystem.STREAM_MUSIC);
Eric Laurent212532b2014-07-21 15:43:18 -07005914 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005915 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005916 }
Eric Laurent212532b2014-07-21 15:43:18 -07005917 return device;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005918 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005919
Terry Heoe7d6d972014-09-04 21:05:28 +09005920 @Override
5921 public boolean isHdmiSystemAudioSupported() {
5922 return mHdmiSystemAudioSupported;
5923 }
5924
Eric Laurentdd45d012012-10-08 09:04:34 -07005925 //==========================================================================================
Jean-Michel Triviac487672016-11-11 10:05:18 -08005926 // Accessibility
5927
5928 private void initA11yMonitoring(Context ctxt) {
5929 AccessibilityManager accessibilityManager =
5930 (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
5931 updateDefaultStreamOverrideDelay(accessibilityManager.isTouchExplorationEnabled());
5932 updateA11yVolumeAlias(accessibilityManager.isEnabled());
5933 accessibilityManager.addTouchExplorationStateChangeListener(this);
5934 accessibilityManager.addAccessibilityStateChangeListener(this);
5935 }
5936
5937 //---------------------------------------------------------------------------------
5938 // A11y: taking touch exploration into account for selecting the default
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005939 // stream override timeout when adjusting volume
Jean-Michel Triviac487672016-11-11 10:05:18 -08005940 //---------------------------------------------------------------------------------
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005941
Jean-Michel Triviac487672016-11-11 10:05:18 -08005942 // AudioService.getActiveStreamType() will return:
5943 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
5944 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
5945 // stopped
5946 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 0;
5947 private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005948
Jean-Michel Triviac487672016-11-11 10:05:18 -08005949 private static int sStreamOverrideDelayMs;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005950
Jean-Michel Triviac487672016-11-11 10:05:18 -08005951 @Override
5952 public void onTouchExplorationStateChanged(boolean enabled) {
5953 updateDefaultStreamOverrideDelay(enabled);
5954 }
5955
5956 private void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
5957 if (touchExploreEnabled) {
5958 sStreamOverrideDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
5959 } else {
5960 sStreamOverrideDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005961 }
Jean-Michel Triviac487672016-11-11 10:05:18 -08005962 if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
5963 + " stream override delay is now " + sStreamOverrideDelayMs + " ms");
5964 }
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005965
Jean-Michel Triviac487672016-11-11 10:05:18 -08005966 //---------------------------------------------------------------------------------
5967 // A11y: taking a11y state into account for the handling of a11y prompts volume
5968 //---------------------------------------------------------------------------------
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005969
Jean-Michel Triviac487672016-11-11 10:05:18 -08005970 private static boolean sIndependentA11yVolume = false;
5971
5972 @Override
5973 public void onAccessibilityStateChanged(boolean enabled) {
5974 updateA11yVolumeAlias(enabled);
5975 }
5976
5977 private void updateA11yVolumeAlias(boolean a11Enabled) {
5978 if (DEBUG_VOL) Log.d(TAG, "Accessibility mode changed to " + a11Enabled);
5979 // a11y has its own volume stream when a11y service is enabled
5980 sIndependentA11yVolume = a11Enabled;
5981 // update the volume mapping scheme
5982 updateStreamVolumeAlias(true /*updateVolumes*/, TAG);
5983 // update the volume controller behavior
5984 mVolumeController.setA11yMode(sIndependentA11yVolume ?
5985 VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME :
5986 VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME);
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005987 }
5988
5989 //==========================================================================================
Eric Laurentdd45d012012-10-08 09:04:34 -07005990 // Camera shutter sound policy.
5991 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5992 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5993 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5994 //==========================================================================================
5995
5996 // cached value of com.android.internal.R.bool.config_camera_sound_forced
5997 private Boolean mCameraSoundForced;
5998
5999 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
6000 public boolean isCameraSoundForced() {
6001 synchronized (mCameraSoundForced) {
6002 return mCameraSoundForced;
6003 }
6004 }
6005
6006 private static final String[] RINGER_MODE_NAMES = new String[] {
6007 "SILENT",
6008 "VIBRATE",
6009 "NORMAL"
6010 };
6011
6012 private void dumpRingerMode(PrintWriter pw) {
6013 pw.println("\nRinger mode: ");
John Spurlock661f2cf2014-11-17 10:29:10 -05006014 pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
6015 pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
John Spurlock50ced3f2015-05-11 16:00:09 -04006016 dumpRingerModeStreams(pw, "affected", mRingerModeAffectedStreams);
6017 dumpRingerModeStreams(pw, "muted", mRingerModeMutedStreams);
John Spurlock661f2cf2014-11-17 10:29:10 -05006018 pw.print("- delegate = "); pw.println(mRingerModeDelegate);
Eric Laurentdd45d012012-10-08 09:04:34 -07006019 }
6020
John Spurlock50ced3f2015-05-11 16:00:09 -04006021 private void dumpRingerModeStreams(PrintWriter pw, String type, int streams) {
6022 pw.print("- ringer mode "); pw.print(type); pw.print(" streams = 0x");
6023 pw.print(Integer.toHexString(streams));
6024 if (streams != 0) {
6025 pw.print(" (");
6026 boolean first = true;
6027 for (int i = 0; i < AudioSystem.STREAM_NAMES.length; i++) {
6028 final int stream = (1 << i);
6029 if ((streams & stream) != 0) {
6030 if (!first) pw.print(',');
6031 pw.print(AudioSystem.STREAM_NAMES[i]);
6032 streams &= ~stream;
6033 first = false;
6034 }
6035 }
6036 if (streams != 0) {
6037 if (!first) pw.print(',');
6038 pw.print(streams);
6039 }
6040 pw.print(')');
6041 }
6042 pw.println();
6043 }
6044
Dianne Hackborn632ca412012-06-14 19:34:10 -07006045 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08006046 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07006047 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
6048
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07006049 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07006050 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07006051 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07006052 pw.println("\nAudio routes:");
John Spurlock61560172015-02-06 19:46:04 -05006053 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
6054 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
John Spurlock35134602014-07-24 18:10:48 -04006055
6056 pw.println("\nOther state:");
John Spurlock3346a802014-05-20 16:25:37 -04006057 pw.print(" mVolumeController="); pw.println(mVolumeController);
John Spurlock35134602014-07-24 18:10:48 -04006058 pw.print(" mSafeMediaVolumeState=");
6059 pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
6060 pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
6061 pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
6062 pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04006063 pw.print(" mMcc="); pw.println(mMcc);
John Spurlock5e783732015-02-19 10:28:59 -05006064 pw.print(" mCameraSoundForced="); pw.println(mCameraSoundForced);
John Spurlock661f2cf2014-11-17 10:29:10 -05006065 pw.print(" mHasVibrator="); pw.println(mHasVibrator);
John Spurlocka48d7792015-03-03 17:35:57 -05006066 pw.print(" mVolumePolicy="); pw.println(mVolumePolicy);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006067
6068 dumpAudioPolicies(pw);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08006069
6070 mPlaybackMonitor.dump(pw);
John Spurlock35134602014-07-24 18:10:48 -04006071 }
6072
6073 private static String safeMediaVolumeStateToString(Integer state) {
6074 switch(state) {
6075 case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
6076 case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
6077 case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
6078 case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
6079 }
6080 return null;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08006081 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07006082
6083 // Inform AudioFlinger of our device's low RAM attribute
6084 private static void readAndSetLowRamDevice()
6085 {
6086 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
6087 if (status != 0) {
6088 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
6089 }
6090 }
John Spurlock3346a802014-05-20 16:25:37 -04006091
John Spurlockcdb57ae2015-02-11 19:04:11 -05006092 private void enforceVolumeController(String action) {
John Spurlock3346a802014-05-20 16:25:37 -04006093 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
6094 "Only SystemUI can " + action);
6095 }
6096
6097 @Override
6098 public void setVolumeController(final IVolumeController controller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05006099 enforceVolumeController("set the volume controller");
John Spurlock3346a802014-05-20 16:25:37 -04006100
6101 // return early if things are not actually changing
6102 if (mVolumeController.isSameBinder(controller)) {
6103 return;
6104 }
6105
6106 // dismiss the old volume controller
6107 mVolumeController.postDismiss();
6108 if (controller != null) {
6109 // we are about to register a new controller, listen for its death
6110 try {
6111 controller.asBinder().linkToDeath(new DeathRecipient() {
6112 @Override
6113 public void binderDied() {
6114 if (mVolumeController.isSameBinder(controller)) {
6115 Log.w(TAG, "Current remote volume controller died, unregistering");
6116 setVolumeController(null);
6117 }
6118 }
6119 }, 0);
6120 } catch (RemoteException e) {
6121 // noop
6122 }
6123 }
6124 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04006125 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
6126 }
6127
6128 @Override
6129 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05006130 enforceVolumeController("notify about volume controller visibility");
John Spurlock33f4e042014-07-11 13:10:58 -04006131
6132 // return early if the controller is not current
6133 if (!mVolumeController.isSameBinder(controller)) {
6134 return;
6135 }
6136
6137 mVolumeController.setVisible(visible);
6138 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04006139 }
RoboErikd09bd0c2014-06-24 17:45:19 -07006140
John Spurlocka48d7792015-03-03 17:35:57 -05006141 @Override
6142 public void setVolumePolicy(VolumePolicy policy) {
6143 enforceVolumeController("set volume policy");
John Spurlockb02c7442015-04-14 09:32:25 -04006144 if (policy != null && !policy.equals(mVolumePolicy)) {
John Spurlocka48d7792015-03-03 17:35:57 -05006145 mVolumePolicy = policy;
John Spurlockb02c7442015-04-14 09:32:25 -04006146 if (DEBUG_VOL) Log.d(TAG, "Volume policy changed: " + mVolumePolicy);
John Spurlocka48d7792015-03-03 17:35:57 -05006147 }
6148 }
6149
RoboErikd09bd0c2014-06-24 17:45:19 -07006150 public static class VolumeController {
6151 private static final String TAG = "VolumeController";
6152
6153 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04006154 private boolean mVisible;
6155 private long mNextLongPress;
6156 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07006157
6158 public void setController(IVolumeController controller) {
6159 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04006160 mVisible = false;
6161 }
6162
6163 public void loadSettings(ContentResolver cr) {
6164 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
6165 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
6166 }
6167
RoboErik4197cb62015-01-21 15:45:32 -08006168 public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
6169 if (isMute) {
6170 return false;
6171 }
John Spurlock33f4e042014-07-11 13:10:58 -04006172 boolean suppress = false;
6173 if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
6174 final long now = SystemClock.uptimeMillis();
6175 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
6176 // ui will become visible
6177 if (mNextLongPress < now) {
6178 mNextLongPress = now + mLongPressTimeout;
6179 }
6180 suppress = true;
6181 } else if (mNextLongPress > 0) { // in a long-press
6182 if (now > mNextLongPress) {
6183 // long press triggered, no more suppression
6184 mNextLongPress = 0;
6185 } else {
6186 // keep suppressing until the long press triggers
6187 suppress = true;
6188 }
6189 }
6190 }
6191 return suppress;
6192 }
6193
6194 public void setVisible(boolean visible) {
6195 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07006196 }
6197
6198 public boolean isSameBinder(IVolumeController controller) {
6199 return Objects.equals(asBinder(), binder(controller));
6200 }
6201
6202 public IBinder asBinder() {
6203 return binder(mController);
6204 }
6205
6206 private static IBinder binder(IVolumeController controller) {
6207 return controller == null ? null : controller.asBinder();
6208 }
6209
6210 @Override
6211 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04006212 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07006213 }
6214
6215 public void postDisplaySafeVolumeWarning(int flags) {
6216 if (mController == null)
6217 return;
6218 try {
6219 mController.displaySafeVolumeWarning(flags);
6220 } catch (RemoteException e) {
6221 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
6222 }
6223 }
6224
6225 public void postVolumeChanged(int streamType, int flags) {
6226 if (mController == null)
6227 return;
6228 try {
6229 mController.volumeChanged(streamType, flags);
6230 } catch (RemoteException e) {
6231 Log.w(TAG, "Error calling volumeChanged", e);
6232 }
6233 }
6234
RoboErikd09bd0c2014-06-24 17:45:19 -07006235 public void postMasterMuteChanged(int flags) {
6236 if (mController == null)
6237 return;
6238 try {
6239 mController.masterMuteChanged(flags);
6240 } catch (RemoteException e) {
6241 Log.w(TAG, "Error calling masterMuteChanged", e);
6242 }
6243 }
6244
6245 public void setLayoutDirection(int layoutDirection) {
6246 if (mController == null)
6247 return;
6248 try {
6249 mController.setLayoutDirection(layoutDirection);
6250 } catch (RemoteException e) {
6251 Log.w(TAG, "Error calling setLayoutDirection", e);
6252 }
6253 }
6254
6255 public void postDismiss() {
6256 if (mController == null)
6257 return;
6258 try {
6259 mController.dismiss();
6260 } catch (RemoteException e) {
6261 Log.w(TAG, "Error calling dismiss", e);
6262 }
6263 }
Jean-Michel Triviac487672016-11-11 10:05:18 -08006264
6265 public void setA11yMode(int a11yMode) {
6266 if (mController == null)
6267 return;
6268 try {
6269 mController.setA11yMode(a11yMode);
6270 } catch (RemoteException e) {
6271 Log.w(TAG, "Error calling setA11Mode", e);
6272 }
6273 }
RoboErikd09bd0c2014-06-24 17:45:19 -07006274 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006275
RoboErik0dac35a2014-08-12 15:48:49 -07006276 /**
6277 * Interface for system components to get some extra functionality through
6278 * LocalServices.
6279 */
6280 final class AudioServiceInternal extends AudioManagerInternal {
John Spurlock661f2cf2014-11-17 10:29:10 -05006281 @Override
6282 public void setRingerModeDelegate(RingerModeDelegate delegate) {
6283 mRingerModeDelegate = delegate;
6284 if (mRingerModeDelegate != null) {
John Spurlock50ced3f2015-05-11 16:00:09 -04006285 updateRingerModeAffectedStreams();
John Spurlock661f2cf2014-11-17 10:29:10 -05006286 setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
6287 }
6288 }
RoboErik272e1612014-09-05 11:39:29 -07006289
6290 @Override
6291 public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
6292 String callingPackage, int uid) {
6293 // direction and stream type swap here because the public
6294 // adjustSuggested has a different order than the other methods.
John Spurlock90874332015-03-10 16:00:54 -04006295 adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage,
6296 callingPackage, uid);
RoboErik272e1612014-09-05 11:39:29 -07006297 }
6298
RoboErik0dac35a2014-08-12 15:48:49 -07006299 @Override
6300 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
6301 String callingPackage, int uid) {
John Spurlock90874332015-03-10 16:00:54 -04006302 adjustStreamVolume(streamType, direction, flags, callingPackage,
6303 callingPackage, uid);
RoboErik0dac35a2014-08-12 15:48:49 -07006304 }
6305
6306 @Override
6307 public void setStreamVolumeForUid(int streamType, int direction, int flags,
6308 String callingPackage, int uid) {
John Spurlock90874332015-03-10 16:00:54 -04006309 setStreamVolume(streamType, direction, flags, callingPackage, callingPackage, uid);
RoboErik0dac35a2014-08-12 15:48:49 -07006310 }
RoboErik519c7742014-11-18 10:59:09 -08006311
6312 @Override
John Spurlock661f2cf2014-11-17 10:29:10 -05006313 public int getRingerModeInternal() {
6314 return AudioService.this.getRingerModeInternal();
6315 }
6316
6317 @Override
6318 public void setRingerModeInternal(int ringerMode, String caller) {
6319 AudioService.this.setRingerModeInternal(ringerMode, caller);
6320 }
John Spurlockcdb57ae2015-02-11 19:04:11 -05006321
6322 @Override
John Spurlock50ced3f2015-05-11 16:00:09 -04006323 public void updateRingerModeAffectedStreamsInternal() {
6324 synchronized (mSettingsLock) {
6325 if (updateRingerModeAffectedStreams()) {
6326 setRingerModeInt(getRingerModeInternal(), false);
6327 }
6328 }
6329 }
RoboErik0dac35a2014-08-12 15:48:49 -07006330 }
6331
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006332 //==========================================================================================
6333 // Audio policy management
6334 //==========================================================================================
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006335 public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
6336 boolean hasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006337 AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
6338
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006339 if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
6340 + " with config:" + policyConfig);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006341 String regId = null;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006342 // error handling
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006343 boolean hasPermissionForPolicy =
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006344 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006345 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
6346 if (!hasPermissionForPolicy) {
6347 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
6348 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006349 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006350 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006351
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006352 synchronized (mAudioPolicies) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006353 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006354 if (mAudioPolicies.containsKey(pcb.asBinder())) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006355 Slog.e(TAG, "Cannot re-register policy");
6356 return null;
6357 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006358 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
6359 pcb.asBinder().linkToDeath(app, 0/*flags*/);
6360 regId = app.getRegistrationId();
6361 mAudioPolicies.put(pcb.asBinder(), app);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006362 } catch (RemoteException e) {
6363 // audio policy owner has already died!
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006364 Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006365 " binder death", e);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006366 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006367 }
6368 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006369 return regId;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006370 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006371
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006372 public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
6373 if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006374 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006375 AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006376 if (app == null) {
6377 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
6378 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006379 return;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006380 } else {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006381 pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006382 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006383 app.release();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006384 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006385 // TODO implement clearing mix attribute matching info in native audio policy
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006386 }
6387
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006388 public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
6389 if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
6390 + " policy " + pcb.asBinder());
6391 // error handling
6392 boolean hasPermissionForPolicy =
6393 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
6394 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
6395 if (!hasPermissionForPolicy) {
6396 Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
6397 + Binder.getCallingPid() + " / uid "
6398 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
6399 return AudioManager.ERROR;
6400 }
6401
6402 synchronized (mAudioPolicies) {
6403 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
6404 Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
6405 return AudioManager.ERROR;
6406 }
6407 final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
6408 if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6409 // is there already one policy managing ducking?
Eric Laurent0867bed2015-05-20 14:49:08 -07006410 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006411 if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6412 Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
6413 return AudioManager.ERROR;
6414 }
6415 }
6416 }
6417 app.mFocusDuckBehavior = duckingBehavior;
6418 mMediaFocusControl.setDuckingInExtPolicyAvailable(
6419 duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
6420 }
6421 return AudioManager.SUCCESS;
6422 }
6423
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006424 private void dumpAudioPolicies(PrintWriter pw) {
6425 pw.println("\nAudio policies:");
6426 synchronized (mAudioPolicies) {
Eric Laurent0867bed2015-05-20 14:49:08 -07006427 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006428 pw.println(policy.toLogFriendlyString());
6429 }
6430 }
6431 }
6432
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006433 //======================
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08006434 // Audio policy callbacks from AudioSystem for dynamic policies
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006435 //======================
6436 private final AudioSystem.DynamicPolicyCallback mDynPolicyCallback =
6437 new AudioSystem.DynamicPolicyCallback() {
6438 public void onDynamicPolicyMixStateUpdate(String regId, int state) {
6439 if (!TextUtils.isEmpty(regId)) {
6440 sendMsg(mAudioHandler, MSG_DYN_POLICY_MIX_STATE_UPDATE, SENDMSG_QUEUE,
6441 state /*arg1*/, 0 /*arg2 ignored*/, regId /*obj*/, 0 /*delay*/);
6442 }
6443 }
6444 };
6445
6446 private void onDynPolicyMixStateUpdate(String regId, int state) {
6447 if (DEBUG_AP) Log.d(TAG, "onDynamicPolicyMixStateUpdate("+ regId + ", " + state +")");
6448 synchronized (mAudioPolicies) {
6449 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
6450 for (AudioMix mix : policy.getMixes()) {
6451 if (mix.getRegistration().equals(regId)) {
6452 try {
6453 policy.mPolicyCallback.notifyMixStateUpdate(regId, state);
6454 } catch (RemoteException e) {
6455 Log.e(TAG, "Can't call notifyMixStateUpdate() on IAudioPolicyCallback "
6456 + policy.mPolicyCallback.asBinder(), e);
6457 }
6458 return;
6459 }
6460 }
6461 }
6462 }
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08006463 }
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006464
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08006465 //======================
6466 // Audio policy callbacks from AudioSystem for recording configuration updates
6467 //======================
6468 private final RecordingActivityMonitor mRecordMonitor = new RecordingActivityMonitor();
6469
6470 public void registerRecordingCallback(IRecordingConfigDispatcher rcdb) {
6471 mRecordMonitor.registerRecordingCallback(rcdb);
6472 }
6473
6474 public void unregisterRecordingCallback(IRecordingConfigDispatcher rcdb) {
6475 mRecordMonitor.unregisterRecordingCallback(rcdb);
6476 }
6477
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07006478 public List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08006479 return mRecordMonitor.getActiveRecordingConfigurations();
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006480 }
6481
6482 //======================
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -08006483 // Audio playback notification
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08006484 //======================
6485 private final PlaybackActivityMonitor mPlaybackMonitor = new PlaybackActivityMonitor();
6486
6487 public void registerPlaybackCallback(IPlaybackConfigDispatcher pcdb) {
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -08006488 final boolean isPrivileged =
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08006489 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
6490 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
6491 mPlaybackMonitor.registerPlaybackCallback(pcdb, isPrivileged);
6492 }
6493
6494 public void unregisterPlaybackCallback(IPlaybackConfigDispatcher pcdb) {
6495 mPlaybackMonitor.unregisterPlaybackCallback(pcdb);
6496 }
6497
6498 public List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() {
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -08006499 final boolean isPrivileged =
6500 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
6501 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
6502 return mPlaybackMonitor.getActivePlaybackConfigurations(isPrivileged);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08006503 }
6504
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -08006505 public int trackPlayer(PlayerBase.PlayerIdCard pic) {
6506 return mPlaybackMonitor.trackPlayer(pic);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08006507 }
6508
6509 public void playerAttributes(int piid, AudioAttributes attr) {
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -08006510 mPlaybackMonitor.playerAttributes(piid, attr, Binder.getCallingUid());
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08006511 }
6512
6513 public void playerEvent(int piid, int event) {
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -08006514 mPlaybackMonitor.playerEvent(piid, event, Binder.getCallingUid());
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08006515 }
6516
6517 public void releasePlayer(int piid) {
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -08006518 mPlaybackMonitor.releasePlayer(piid, Binder.getCallingUid());
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08006519 }
6520
6521 //======================
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006522 // Audio policy proxy
6523 //======================
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006524 /**
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006525 * This internal class inherits from AudioPolicyConfig, each instance contains all the
6526 * mixes of an AudioPolicy and their configurations.
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006527 */
6528 public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006529 private static final String TAG = "AudioPolicyProxy";
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006530 IAudioPolicyCallback mPolicyCallback;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006531 boolean mHasFocusListener;
6532 /**
6533 * Audio focus ducking behavior for an audio policy.
6534 * This variable reflects the value that was successfully set in
6535 * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
6536 * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
6537 * is handling ducking for audio focus.
6538 */
6539 int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
6540
6541 AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
6542 boolean hasFocusListener) {
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006543 super(config);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006544 setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006545 mPolicyCallback = token;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006546 mHasFocusListener = hasFocusListener;
6547 if (mHasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006548 mMediaFocusControl.addFocusFollower(mPolicyCallback);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006549 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006550 connectMixes();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006551 }
6552
6553 public void binderDied() {
6554 synchronized (mAudioPolicies) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006555 Log.i(TAG, "audio policy " + mPolicyCallback + " died");
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006556 release();
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006557 mAudioPolicies.remove(mPolicyCallback.asBinder());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006558 }
6559 }
6560
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006561 String getRegistrationId() {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006562 return getRegistration();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006563 }
6564
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006565 void release() {
6566 if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6567 mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
6568 }
6569 if (mHasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006570 mMediaFocusControl.removeFocusFollower(mPolicyCallback);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006571 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006572 AudioSystem.registerPolicyMixes(mMixes, false);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006573 }
6574
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006575 void connectMixes() {
6576 AudioSystem.registerPolicyMixes(mMixes, true);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006577 }
6578 };
6579
6580 private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
6581 new HashMap<IBinder, AudioPolicyProxy>();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006582 private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
Phil Burkac0f7042016-02-24 12:19:08 -08006583}