blob: 592453fb278b6c9af7e524fa4d5b1b579f8bcc40 [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;
Beverlyd6964762018-02-16 14:07:03 -050023import static android.media.AudioManager.STREAM_ALARM;
24import static android.media.AudioManager.STREAM_MUSIC;
25import static android.media.AudioManager.STREAM_SYSTEM;
Fyodor Kupolovbcb6c1e2015-05-11 12:05:15 -070026import static android.os.Process.FIRST_APPLICATION_UID;
Mike Digman55272862018-02-20 14:35:17 -080027import static android.provider.Settings.Secure.VOLUME_HUSH_MUTE;
28import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
29import static android.provider.Settings.Secure.VOLUME_HUSH_VIBRATE;
Amith Yamasanic696a532011-10-28 17:02:37 -070030
Fyodor Kupolovb5013302015-04-17 17:59:14 -070031import android.Manifest;
Jean-Michel Trivi7ed71472018-02-02 16:52:09 -080032import android.annotation.NonNull;
Jean-Michel Trivia53b7052017-04-12 18:27:01 -070033import android.annotation.Nullable;
Glenn Kastenfd116ad2013-07-12 17:10:39 -070034import android.app.ActivityManager;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070035import android.app.ActivityManagerInternal;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070036import android.app.AppGlobals;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -070037import android.app.AppOpsManager;
Dianne Hackborn3e99f652017-07-05 16:33:56 -070038import android.app.IUidObserver;
Julia Reynolds48034f82016-03-09 10:15:16 -050039import android.app.NotificationManager;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070040import android.bluetooth.BluetoothA2dp;
41import android.bluetooth.BluetoothAdapter;
42import android.bluetooth.BluetoothClass;
43import android.bluetooth.BluetoothDevice;
44import android.bluetooth.BluetoothHeadset;
Jakub Pawlowskif9570f32018-02-21 17:15:12 -080045import android.bluetooth.BluetoothHearingAid;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070046import android.bluetooth.BluetoothProfile;
Nick Pellybd022f42009-08-14 18:33:38 -070047import android.content.BroadcastReceiver;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070048import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.content.ContentResolver;
50import android.content.Context;
51import android.content.Intent;
Eric Laurenta553c252009-07-17 12:17:14 -070052import android.content.IntentFilter;
Julia Reynolds48034f82016-03-09 10:15:16 -050053import android.content.pm.ApplicationInfo;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070054import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.content.pm.PackageManager;
Marco Nelissenfb6df0b2017-02-15 15:25:24 -080056import android.content.pm.ResolveInfo;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070057import android.content.pm.UserInfo;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -070058import android.content.res.Configuration;
Eric Laurente78fced2013-03-15 16:03:47 -070059import android.content.res.Resources;
60import android.content.res.XmlResourceParser;
Jason Parekhb1096152009-03-24 17:48:25 -070061import android.database.ContentObserver;
Jungshik Jang41d97462014-06-30 22:26:29 +090062import android.hardware.hdmi.HdmiControlManager;
Eric Laurent212532b2014-07-21 15:43:18 -070063import android.hardware.hdmi.HdmiPlaybackClient;
Jungshik Jang41d97462014-06-30 22:26:29 +090064import android.hardware.hdmi.HdmiTvClient;
Paul McLeanc837a452014-04-09 09:04:43 -070065import android.hardware.usb.UsbManager;
John Spurlock61560172015-02-06 19:46:04 -050066import android.media.AudioAttributes;
67import android.media.AudioDevicePort;
Jean-Michel Trivi126cf032017-04-02 23:19:02 -070068import android.media.AudioFocusInfo;
Jean-Michel Trivi9228af62018-01-05 17:06:17 -080069import android.media.AudioFocusRequest;
John Spurlock61560172015-02-06 19:46:04 -050070import android.media.AudioFormat;
71import android.media.AudioManager;
72import android.media.AudioManagerInternal;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080073import android.media.AudioPlaybackConfiguration;
Beverly925cde82018-01-23 09:31:23 -050074import android.media.AudioPort;
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -080075import android.media.AudioRecordingConfiguration;
John Spurlock61560172015-02-06 19:46:04 -050076import android.media.AudioRoutesInfo;
Beverly925cde82018-01-23 09:31:23 -050077import android.media.AudioSystem;
John Spurlock61560172015-02-06 19:46:04 -050078import android.media.IAudioFocusDispatcher;
79import android.media.IAudioRoutesObserver;
Eric Laurent1d3cdce2018-01-20 10:31:21 -080080import android.media.IAudioServerStateDispatcher;
John Spurlock61560172015-02-06 19:46:04 -050081import android.media.IAudioService;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080082import android.media.IPlaybackConfigDispatcher;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -080083import android.media.IRecordingConfigDispatcher;
John Spurlock61560172015-02-06 19:46:04 -050084import android.media.IRingtonePlayer;
85import android.media.IVolumeController;
86import android.media.MediaPlayer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087import android.media.MediaPlayer.OnCompletionListener;
88import android.media.MediaPlayer.OnErrorListener;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080089import android.media.PlayerBase;
Beverly925cde82018-01-23 09:31:23 -050090import android.media.SoundPool;
91import android.media.VolumePolicy;
92import android.media.audiofx.AudioEffect;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -070093import android.media.audiopolicy.AudioMix;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -080094import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070095import android.media.audiopolicy.AudioPolicyConfig;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -080096import android.media.audiopolicy.IAudioPolicyCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097import android.os.Binder;
Eric Laurentc18c9132013-04-12 17:24:56 -070098import android.os.Build;
Makoto Onukid45a4a22015-11-02 17:17:38 -080099import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100import android.os.Environment;
101import android.os.Handler;
102import android.os.IBinder;
103import android.os.Looper;
104import android.os.Message;
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700105import android.os.PowerManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -0700106import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107import android.os.RemoteException;
John Spurlock33f4e042014-07-11 13:10:58 -0400108import android.os.SystemClock;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700109import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700110import android.os.UserHandle;
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700111import android.os.UserManager;
Makoto Onukid45a4a22015-11-02 17:17:38 -0800112import android.os.UserManagerInternal;
113import android.os.UserManagerInternal.UserRestrictionsListener;
Mike Digman55272862018-02-20 14:35:17 -0800114import android.os.VibrationEffect;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700115import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116import android.provider.Settings;
117import android.provider.Settings.System;
Beverly925cde82018-01-23 09:31:23 -0500118import android.service.notification.ZenModeConfig;
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700119import android.telecom.TelecomManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -0700120import android.text.TextUtils;
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700121import android.util.AndroidRuntimeException;
John Spurlock8c3dc852015-04-23 21:32:37 -0400122import android.util.ArrayMap;
123import android.util.ArraySet;
Phil Weaverf1a9aff2017-03-23 17:21:29 -0700124import android.util.IntArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125import android.util.Log;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400126import android.util.MathUtils;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -0700127import android.util.Slog;
John Spurlock2bb02ec2015-03-02 13:13:06 -0500128import android.util.SparseIntArray;
Jean-Michel Trivid327f212010-03-16 21:44:33 -0700129import android.view.KeyEvent;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700130import android.view.accessibility.AccessibilityManager;
Mike Digman55272862018-02-20 14:35:17 -0800131import android.widget.Toast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -0800133import com.android.internal.annotations.GuardedBy;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600134import com.android.internal.util.DumpUtils;
Eric Laurente78fced2013-03-15 16:03:47 -0700135import com.android.internal.util.XmlUtils;
John Spurlock90874332015-03-10 16:00:54 -0400136import com.android.server.EventLogTags;
RoboErik0dac35a2014-08-12 15:48:49 -0700137import com.android.server.LocalServices;
Makoto Onukie1aef852015-10-15 17:28:35 -0700138import com.android.server.SystemService;
Beverly925cde82018-01-23 09:31:23 -0500139import com.android.server.audio.AudioServiceEvents.ForceUseEvent;
140import com.android.server.audio.AudioServiceEvents.PhoneStateEvent;
141import com.android.server.audio.AudioServiceEvents.VolumeEvent;
142import com.android.server.audio.AudioServiceEvents.WiredDevConnectEvent;
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700143import com.android.server.pm.UserManagerService;
Eric Laurente78fced2013-03-15 16:03:47 -0700144
145import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146
Jaekyun Seokc31033f2018-01-15 14:53:17 +0900147import java.io.File;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800148import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149import java.io.IOException;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800150import java.io.PrintWriter;
Eric Laurente78fced2013-03-15 16:03:47 -0700151import java.lang.reflect.Field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152import java.util.ArrayList;
Jean-Michel Trivi7db2d8f2018-03-06 10:30:59 -0800153import java.util.Collection;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700154import java.util.HashMap;
155import java.util.Iterator;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -0700156import java.util.List;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700157import java.util.NoSuchElementException;
RoboErikd09bd0c2014-06-24 17:45:19 -0700158import java.util.Objects;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159
160/**
161 * The implementation of the volume manager service.
162 * <p>
163 * This implementation focuses on delivering a responsive UI. Most methods are
164 * asynchronous to external calls. For example, the task of setting a volume
165 * will update our internal state, but in a separate thread will set the system
166 * volume and later persist to the database. Similarly, setting the ringer mode
167 * will update the state and broadcast a change and in a separate thread later
168 * persist the ringer mode.
169 *
170 * @hide
171 */
Jean-Michel Triviac487672016-11-11 10:05:18 -0800172public class AudioService extends IAudioService.Stub
173 implements AccessibilityManager.TouchExplorationStateChangeListener,
Jean-Michel Trivicfa55532017-01-18 11:17:51 -0800174 AccessibilityManager.AccessibilityServicesStateChangeListener {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175
176 private static final String TAG = "AudioService";
177
Jean-Michel Trivi339567d2014-07-29 09:53:34 -0700178 /** Debug audio mode */
179 protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -0700180
181 /** Debug audio policy feature */
182 protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);
183
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700184 /** Debug volumes */
John Spurlockae641c92014-06-30 18:11:40 -0400185 protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700186
Paul McLean394a8e12015-03-03 10:29:19 -0700187 /** debug calls to devices APIs */
188 protected static final boolean DEBUG_DEVICES = Log.isLoggable(TAG + ".DEVICES", Log.DEBUG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 /** How long to delay before persisting a change in volume/ringer mode. */
RoboErik45edba12012-03-27 17:54:36 -0700190 private static final int PERSIST_DELAY = 500;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191
RoboErik5452e252015-02-06 15:33:53 -0800192 /** How long to delay after a volume down event before unmuting a stream */
193 private static final int UNMUTE_STREAM_DELAY = 350;
194
John Spurlock3346a802014-05-20 16:25:37 -0400195 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400196 * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
197 */
198 private static final int FLAG_ADJUST_VOLUME = 1;
199
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700200 private final Context mContext;
201 private final ContentResolver mContentResolver;
202 private final AppOpsManager mAppOps;
Eric Laurent212532b2014-07-21 15:43:18 -0700203
Eric Laurent212532b2014-07-21 15:43:18 -0700204 // the platform type affects volume and silent mode behavior
205 private final int mPlatformType;
206
Muyuan Li1ed6df62016-06-18 11:16:52 -0700207 // indicates whether the system maps all streams to a single stream.
208 private final boolean mIsSingleVolume;
209
Eric Laurent212532b2014-07-21 15:43:18 -0700210 private boolean isPlatformVoice() {
John Spurlock61560172015-02-06 19:46:04 -0500211 return mPlatformType == AudioSystem.PLATFORM_VOICE;
Eric Laurent212532b2014-07-21 15:43:18 -0700212 }
213
214 private boolean isPlatformTelevision() {
John Spurlock61560172015-02-06 19:46:04 -0500215 return mPlatformType == AudioSystem.PLATFORM_TELEVISION;
Eric Laurent212532b2014-07-21 15:43:18 -0700216 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800217
Hongwei Wangdaba1242018-05-29 14:36:16 -0700218 private boolean isPlatformAutomotive() {
219 return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
220 }
221
John Spurlock3346a802014-05-20 16:25:37 -0400222 /** The controller for the volume UI. */
223 private final VolumeController mVolumeController = new VolumeController();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224
225 // sendMsg() flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 /** If the msg is already queued, replace it with this one. */
227 private static final int SENDMSG_REPLACE = 0;
228 /** If the msg is already queued, ignore this one and leave the old. */
229 private static final int SENDMSG_NOOP = 1;
230 /** If the msg is already queued, queue this one and leave the old. */
231 private static final int SENDMSG_QUEUE = 2;
232
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700233 // AudioHandler messages
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800234 private static final int MSG_SET_DEVICE_VOLUME = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 private static final int MSG_PERSIST_VOLUME = 1;
236 private static final int MSG_PERSIST_RINGER_MODE = 3;
Andy Hunged0ea402015-10-30 14:11:46 -0700237 private static final int MSG_AUDIO_SERVER_DIED = 4;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700238 private static final int MSG_PLAY_SOUND_EFFECT = 5;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700239 private static final int MSG_LOAD_SOUND_EFFECTS = 7;
240 private static final int MSG_SET_FORCE_USE = 8;
241 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
242 private static final int MSG_SET_ALL_VOLUMES = 10;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700243 private static final int MSG_REPORT_NEW_ROUTES = 12;
Sungsoocf09fe62016-09-28 16:21:48 +0900244 private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700245 private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
246 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
247 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
248 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
249 private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
250 private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
251 private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700252 private static final int MSG_SYSTEM_READY = 21;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400253 private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
RoboErik5452e252015-02-06 15:33:53 -0800254 private static final int MSG_UNMUTE_STREAM = 24;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -0700255 private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 25;
Eric Laurent0867bed2015-05-20 14:49:08 -0700256 private static final int MSG_INDICATE_SYSTEM_READY = 26;
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -0700257 private static final int MSG_ACCESSORY_PLUG_MEDIA_UNMUTE = 27;
Jean-Michel Trivi7ed71472018-02-02 16:52:09 -0800258 private static final int MSG_NOTIFY_VOL_EVENT = 28;
Eric Laurent1d3cdce2018-01-20 10:31:21 -0800259 private static final int MSG_DISPATCH_AUDIO_SERVER_STATE = 29;
jiabin39940752018-04-02 18:18:45 -0700260 private static final int MSG_ENABLE_SURROUND_FORMATS = 30;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700261 // start of messages handled under wakelock
262 // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
Jean-Michel Trivie12c39b2012-06-06 10:51:58 -0700263 // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700264 private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
Mike Lockwood0a40ec22014-05-21 10:08:50 -0700265 private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
266 private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800267 private static final int MSG_A2DP_DEVICE_CONFIG_CHANGE = 103;
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -0700268 private static final int MSG_DISABLE_AUDIO_FOR_UID = 104;
Jakub Pawlowskif9570f32018-02-21 17:15:12 -0800269 private static final int MSG_SET_HEARING_AID_CONNECTION_STATE = 105;
Eric Laurent3c4636c2018-06-13 19:36:42 -0700270 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 106;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700271 // end of messages handled under wakelock
Eric Laurentafbb0472011-12-15 09:04:23 -0800272
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -0700273 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
Eric Laurentdc03c612011-04-01 10:59:41 -0700274 // Timeout for connection to bluetooth headset service
275 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
276
Eric Laurent0867bed2015-05-20 14:49:08 -0700277 // retry delay in case of failure to indicate system ready to AudioFlinger
278 private static final int INDICATE_SYSTEM_READY_RETRY_DELAY_MS = 1000;
279
Jakub Pawlowskif9570f32018-02-21 17:15:12 -0800280 private static final int BT_HEARING_AID_GAIN_MIN = -128;
281
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282 /** @see AudioSystemThread */
283 private AudioSystemThread mAudioSystemThread;
284 /** @see AudioHandler */
285 private AudioHandler mAudioHandler;
286 /** @see VolumeStreamState */
287 private VolumeStreamState[] mStreamStates;
Jason Parekhb1096152009-03-24 17:48:25 -0700288 private SettingsObserver mSettingsObserver;
Eric Laurenta553c252009-07-17 12:17:14 -0700289
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700290 private int mMode = AudioSystem.MODE_NORMAL;
Glenn Kastenba195eb2011-12-13 09:30:40 -0800291 // protects mRingerMode
292 private final Object mSettingsLock = new Object();
Eric Laurent45c90ce2012-04-24 18:44:22 -0700293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 private SoundPool mSoundPool;
Glenn Kasten30c918c2011-11-10 17:56:41 -0800295 private final Object mSoundEffectsLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 private static final int NUM_SOUNDPOOL_CHANNELS = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297
298 /* Sound effect file names */
299 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
Eric Laurente78fced2013-03-15 16:03:47 -0700300 private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301
302 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
303 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
304 * uses soundpool (second column) */
Eric Laurente78fced2013-03-15 16:03:47 -0700305 private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306
John Spurlockb6e19e32015-03-10 21:33:44 -0400307 /** Maximum volume index values for audio streams */
Chinyue Chen6affe932018-01-24 14:51:43 +0800308 protected static int[] MAX_STREAM_VOLUME = new int[] {
Eric Laurent6ee99522009-08-25 06:30:59 -0700309 5, // STREAM_VOICE_CALL
310 7, // STREAM_SYSTEM
311 7, // STREAM_RING
312 15, // STREAM_MUSIC
313 7, // STREAM_ALARM
314 7, // STREAM_NOTIFICATION
315 15, // STREAM_BLUETOOTH_SCO
316 7, // STREAM_SYSTEM_ENFORCED
317 15, // STREAM_DTMF
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800318 15, // STREAM_TTS
319 15 // STREAM_ACCESSIBILITY
Jared Suttles59820132009-08-13 21:50:52 -0500320 };
Eric Laurent91377de2014-10-10 15:24:04 -0700321
John Spurlockb6e19e32015-03-10 21:33:44 -0400322 /** Minimum volume index values for audio streams */
Chinyue Chen6affe932018-01-24 14:51:43 +0800323 protected static int[] MIN_STREAM_VOLUME = new int[] {
John Spurlockb6e19e32015-03-10 21:33:44 -0400324 1, // STREAM_VOICE_CALL
325 0, // STREAM_SYSTEM
326 0, // STREAM_RING
327 0, // STREAM_MUSIC
Jean-Michel Trivie05eef82018-03-08 18:56:34 -0800328 1, // STREAM_ALARM
John Spurlockb6e19e32015-03-10 21:33:44 -0400329 0, // STREAM_NOTIFICATION
Eric Laurente4381ec2015-10-29 17:52:48 -0700330 0, // STREAM_BLUETOOTH_SCO
John Spurlockb6e19e32015-03-10 21:33:44 -0400331 0, // STREAM_SYSTEM_ENFORCED
332 0, // STREAM_DTMF
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800333 0, // STREAM_TTS
Jean-Michel Trivie05eef82018-03-08 18:56:34 -0800334 1 // STREAM_ACCESSIBILITY
John Spurlockb6e19e32015-03-10 21:33:44 -0400335 };
336
Eric Laurent6d517662012-04-23 18:42:39 -0700337 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
Eric Laurenta553c252009-07-17 12:17:14 -0700338 * of another stream: This avoids multiplying the volume settings for hidden
339 * stream types that follow other stream behavior for volume settings
Eric Laurent6d517662012-04-23 18:42:39 -0700340 * NOTE: do not create loops in aliases!
341 * Some streams alias to different streams according to device category (phone or tablet) or
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700342 * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
Eric Laurent212532b2014-07-21 15:43:18 -0700343 * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
344 * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
345 * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
346 private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700347 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
348 AudioSystem.STREAM_RING, // STREAM_SYSTEM
349 AudioSystem.STREAM_RING, // STREAM_RING
350 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
351 AudioSystem.STREAM_ALARM, // STREAM_ALARM
352 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
353 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
354 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
355 AudioSystem.STREAM_RING, // STREAM_DTMF
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800356 AudioSystem.STREAM_MUSIC, // STREAM_TTS
357 AudioSystem.STREAM_MUSIC // STREAM_ACCESSIBILITY
Eric Laurenta553c252009-07-17 12:17:14 -0700358 };
Eric Laurent212532b2014-07-21 15:43:18 -0700359 private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
360 AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL
361 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
362 AudioSystem.STREAM_MUSIC, // STREAM_RING
363 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
364 AudioSystem.STREAM_MUSIC, // STREAM_ALARM
365 AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
366 AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO
367 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
368 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800369 AudioSystem.STREAM_MUSIC, // STREAM_TTS
370 AudioSystem.STREAM_MUSIC // STREAM_ACCESSIBILITY
Eric Laurent212532b2014-07-21 15:43:18 -0700371 };
372 private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700373 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
John Spurlock4f0f1202014-08-05 13:28:33 -0400374 AudioSystem.STREAM_RING, // STREAM_SYSTEM
Eric Laurent6d517662012-04-23 18:42:39 -0700375 AudioSystem.STREAM_RING, // STREAM_RING
376 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
377 AudioSystem.STREAM_ALARM, // STREAM_ALARM
378 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
379 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
John Spurlock4f0f1202014-08-05 13:28:33 -0400380 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
381 AudioSystem.STREAM_RING, // STREAM_DTMF
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800382 AudioSystem.STREAM_MUSIC, // STREAM_TTS
383 AudioSystem.STREAM_MUSIC // STREAM_ACCESSIBILITY
Eric Laurent6d517662012-04-23 18:42:39 -0700384 };
Yue Li949865b2017-05-24 17:25:28 -0700385 protected static int[] mStreamVolumeAlias;
Eric Laurenta553c252009-07-17 12:17:14 -0700386
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700387 /**
388 * Map AudioSystem.STREAM_* constants to app ops. This should be used
389 * after mapping through mStreamVolumeAlias.
390 */
John Spurlock59dc9c12015-03-02 11:20:15 -0500391 private static final int[] STREAM_VOLUME_OPS = new int[] {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700392 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL
393 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM
394 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING
395 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC
396 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM
397 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION
398 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO
399 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED
400 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF
401 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800402 AppOpsManager.OP_AUDIO_ACCESSIBILITY_VOLUME, // STREAM_ACCESSIBILITY
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700403 };
404
Eric Laurent83a017b2013-03-19 18:15:31 -0700405 private final boolean mUseFixedVolume;
406
Julia Reynoldseb0ce472018-05-04 15:34:55 -0400407 /**
408 * Default stream type used for volume control in the absence of playback
409 * e.g. user on homescreen, no app playing anything, presses hardware volume buttons, this
410 * stream type is controlled.
411 */
412 protected static final int DEFAULT_VOL_STREAM_NO_PLAYBACK = AudioSystem.STREAM_MUSIC;
413
Glenn Kasten30c918c2011-11-10 17:56:41 -0800414 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 public void onError(int error) {
416 switch (error) {
417 case AudioSystem.AUDIO_STATUS_SERVER_DIED:
Andy Hunged0ea402015-10-30 14:11:46 -0700418 sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED,
Eric Laurentdfb881f2013-07-18 14:41:39 -0700419 SENDMSG_NOOP, 0, 0, null, 0);
Eric Laurent1d3cdce2018-01-20 10:31:21 -0800420 sendMsg(mAudioHandler, MSG_DISPATCH_AUDIO_SERVER_STATE,
421 SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 break;
423 default:
424 break;
425 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700426 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 };
428
429 /**
430 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
431 * {@link AudioManager#RINGER_MODE_SILENT}, or
432 * {@link AudioManager#RINGER_MODE_VIBRATE}.
433 */
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -0800434 @GuardedBy("mSettingsLock")
John Spurlock661f2cf2014-11-17 10:29:10 -0500435 private int mRingerMode; // internal ringer mode, affects muting of underlying streams
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -0800436 @GuardedBy("mSettingsLock")
John Spurlock661f2cf2014-11-17 10:29:10 -0500437 private int mRingerModeExternal = -1; // reported ringer mode to outside clients (AudioManager)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438
Eric Laurent9bcf4012009-06-12 06:09:28 -0700439 /** @see System#MODE_RINGER_STREAMS_AFFECTED */
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700440 private int mRingerModeAffectedStreams = 0;
Eric Laurent9bcf4012009-06-12 06:09:28 -0700441
Beverlyd6964762018-02-16 14:07:03 -0500442 private int mZenModeAffectedStreams = 0;
443
444 // Streams currently muted by ringer mode and dnd
445 private int mRingerAndZenModeMutedStreams;
Eric Laurent5b4e6542010-03-19 20:02:21 -0700446
John Spurlock3ce37252015-02-17 13:20:45 -0500447 /** Streams that can be muted. Do not resolve to aliases when checking.
448 * @see System#MUTE_STREAMS_AFFECTED */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 private int mMuteAffectedStreams;
450
451 /**
Eric Laurentbffc3d12012-05-07 17:43:49 -0700452 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
453 * mVibrateSetting is just maintained during deprecation period but vibration policy is
454 * now only controlled by mHasVibrator and mRingerMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 */
456 private int mVibrateSetting;
457
Eric Laurentbffc3d12012-05-07 17:43:49 -0700458 // Is there a vibrator
459 private final boolean mHasVibrator;
Mike Digman55272862018-02-20 14:35:17 -0800460 // Used to play vibrations
461 private Vibrator mVibrator;
462 private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
463 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
464 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
465 .build();
Eric Laurentbffc3d12012-05-07 17:43:49 -0700466
Eric Laurenta553c252009-07-17 12:17:14 -0700467 // Broadcast receiver for device connections intent broadcasts
468 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
469
Makoto Onukid45a4a22015-11-02 17:17:38 -0800470 /** Interface for UserManagerService. */
471 private final UserManagerInternal mUserManagerInternal;
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700472 private final ActivityManagerInternal mActivityManagerInternal;
Makoto Onukid45a4a22015-11-02 17:17:38 -0800473
474 private final UserRestrictionsListener mUserRestrictionsListener =
475 new AudioServiceUserRestrictionsListener();
476
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700477 // Devices currently connected
Paul McLean394a8e12015-03-03 10:29:19 -0700478 // Use makeDeviceListKey() to make a unique key for this list.
479 private class DeviceListSpec {
480 int mDeviceType;
481 String mDeviceName;
482 String mDeviceAddress;
483
484 public DeviceListSpec(int deviceType, String deviceName, String deviceAddress) {
485 mDeviceType = deviceType;
486 mDeviceName = deviceName;
487 mDeviceAddress = deviceAddress;
488 }
489
490 public String toString() {
491 return "[type:0x" + Integer.toHexString(mDeviceType) + " name:" + mDeviceName
492 + " address:" + mDeviceAddress + "]";
493 }
494 }
495
496 // Generate a unique key for the mConnectedDevices List by composing the device "type"
497 // and the "address" associated with a specific instance of that device type
498 private String makeDeviceListKey(int device, String deviceAddress) {
499 return "0x" + Integer.toHexString(device) + ":" + deviceAddress;
500 }
501
John Spurlock8c3dc852015-04-23 21:32:37 -0400502 private final ArrayMap<String, DeviceListSpec> mConnectedDevices = new ArrayMap<>();
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700503
504 // Forced device usage for communications
505 private int mForcedUseForComm;
Sharad Sangle1d188442017-05-09 16:05:40 +0530506 private int mForcedUseForCommExt; // External state returned by getters: always consistent
507 // with requests by setters
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700508
Eric Laurent9272b4b2010-01-23 17:12:59 -0800509 // List of binder death handlers for setMode() client processes.
510 // The last process to have called setMode() is at the top of the list.
Glenn Kasten30c918c2011-11-10 17:56:41 -0800511 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
Eric Laurenteb14a782009-12-17 03:12:59 -0800512
Eric Laurent3def1ee2010-03-17 23:26:26 -0700513 // List of clients having issued a SCO start request
Glenn Kasten30c918c2011-11-10 17:56:41 -0800514 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
Eric Laurent3def1ee2010-03-17 23:26:26 -0700515
516 // BluetoothHeadset API to control SCO connection
517 private BluetoothHeadset mBluetoothHeadset;
518
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700519 // Bluetooth headset device
520 private BluetoothDevice mBluetoothHeadsetDevice;
Eric Laurent3def1ee2010-03-17 23:26:26 -0700521
Eric Laurent62ef7672010-11-24 10:58:32 -0800522 // Indicate if SCO audio connection is currently active and if the initiator is
523 // audio service (internal) or bluetooth headset (external)
524 private int mScoAudioState;
525 // SCO audio state is not active
526 private static final int SCO_STATE_INACTIVE = 0;
Eric Laurentdc03c612011-04-01 10:59:41 -0700527 // SCO audio activation request waiting for headset service to connect
528 private static final int SCO_STATE_ACTIVATE_REQ = 1;
Eric Laurent25fc29b2013-04-05 12:13:54 -0700529 // SCO audio state is active or starting due to a request from AudioManager API
Eric Laurentdc03c612011-04-01 10:59:41 -0700530 private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
531 // SCO audio deactivation request waiting for headset service to connect
Jack He33c3a172018-05-08 14:51:07 -0700532 private static final int SCO_STATE_DEACTIVATE_REQ = 4;
Jack He89f97982018-05-02 19:10:56 -0700533 // SCO audio deactivation in progress, waiting for Bluetooth audio intent
Jack He33c3a172018-05-08 14:51:07 -0700534 private static final int SCO_STATE_DEACTIVATING = 5;
Eric Laurentdc03c612011-04-01 10:59:41 -0700535
Eric Laurent62ef7672010-11-24 10:58:32 -0800536 // SCO audio state is active due to an action in BT handsfree (either voice recognition or
537 // in call audio)
538 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
Eric Laurentdc03c612011-04-01 10:59:41 -0700539
Eric Laurentc18c9132013-04-12 17:24:56 -0700540 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
541 // originated from an app targeting an API version before JB MR2 and raw audio after that.
542 private int mScoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -0700543 // SCO audio mode is undefined
544 private static final int SCO_MODE_UNDEFINED = -1;
Eric Laurentc18c9132013-04-12 17:24:56 -0700545 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
546 private static final int SCO_MODE_VIRTUAL_CALL = 0;
547 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
548 private static final int SCO_MODE_RAW = 1;
Liejun Taof4e51d82014-07-16 11:18:29 -0700549 // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
550 private static final int SCO_MODE_VR = 2;
551
552 private static final int SCO_MODE_MAX = 2;
Eric Laurentc18c9132013-04-12 17:24:56 -0700553
Eric Laurentdc03c612011-04-01 10:59:41 -0700554 // Current connection state indicated by bluetooth headset
555 private int mScoConnectionState;
Eric Laurent62ef7672010-11-24 10:58:32 -0800556
Eric Laurenta60e2122010-12-28 16:49:07 -0800557 // true if boot sequence has been completed
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700558 private boolean mSystemReady;
Yasuhiro Matsuda4ced7192015-07-10 22:08:44 +0900559 // true if Intent.ACTION_USER_SWITCHED has ever been received
560 private boolean mUserSwitchedReceived;
Eric Laurenta60e2122010-12-28 16:49:07 -0800561 // listener for SoundPool sample load completion indication
562 private SoundPoolCallback mSoundPoolCallBack;
563 // thread for SoundPool listener
564 private SoundPoolListenerThread mSoundPoolListenerThread;
565 // message looper for SoundPool listener
566 private Looper mSoundPoolLooper = null;
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700567 // volume applied to sound played with playSoundEffect()
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700568 private static int sSoundEffectVolumeDb;
Eric Laurent25101b02011-02-02 09:33:30 -0800569 // previous volume adjustment direction received by checkForRingerModeChange()
570 private int mPrevVolDirection = AudioManager.ADJUST_SAME;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700571 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
572 // is controlled by Vol keys.
Jean-Michel Trivia7880d42017-04-15 12:41:05 -0700573 private int mVolumeControlStream = -1;
574 // interpretation of whether the volume stream has been selected by the user by clicking on a
575 // volume slider to change which volume is controlled by the volume keys. Is false
576 // when mVolumeControlStream is -1.
577 private boolean mUserSelectedVolumeControlStream = false;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700578 private final Object mForceControlStreamLock = new Object();
579 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
580 // server process so in theory it is not necessary to monitor the client death.
581 // However it is good to be ready for future evolutions.
582 private ForceControlStreamClient mForceControlStreamClient = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700583 // Used to play ringtones outside system_server
584 private volatile IRingtonePlayer mRingtonePlayer;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800585
Eric Laurent78472112012-05-21 08:57:21 -0700586 // Request to override default use of A2DP for media.
Sungsoo486f7d32016-09-28 16:20:52 +0900587 private boolean mBluetoothA2dpEnabled;
Eric Laurent78472112012-05-21 08:57:21 -0700588 private final Object mBluetoothA2dpEnabledLock = new Object();
589
Dianne Hackborn632ca412012-06-14 19:34:10 -0700590 // Monitoring of audio routes. Protected by mCurAudioRoutes.
591 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
592 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
593 = new RemoteCallbackList<IAudioRoutesObserver>();
594
Eric Laurent4bbcc652012-09-24 14:26:30 -0700595 // Devices for which the volume is fixed and VolumePanel slider should be disabled
Eric Laurent212532b2014-07-21 15:43:18 -0700596 int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700597 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Eric Laurent212532b2014-07-21 15:43:18 -0700598 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
599 AudioSystem.DEVICE_OUT_HDMI_ARC |
600 AudioSystem.DEVICE_OUT_SPDIF |
601 AudioSystem.DEVICE_OUT_AUX_LINE;
Jakub Pawlowskic274fb22018-04-04 10:15:12 -0700602 int mFullVolumeDevices = 0;
Eric Laurent4bbcc652012-09-24 14:26:30 -0700603
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700604 private final boolean mMonitorRotation;
Eric Laurentd640bd32012-09-28 18:01:48 -0700605
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700606 private boolean mDockAudioMediaEnabled = true;
607
Eric Laurent08ed1b92012-11-05 14:54:12 -0800608 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
609
Eric Laurentfde16d52012-12-03 14:42:39 -0800610 // Used when safe volume warning message display is requested by setStreamVolume(). In this
611 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
612 // and used later when/if disableSafeMediaVolume() is called.
613 private StreamVolumeCommand mPendingVolumeCommand;
614
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700615 private PowerManager.WakeLock mAudioEventWakeLock;
616
617 private final MediaFocusControl mMediaFocusControl;
618
Jakub Pawlowskif9570f32018-02-21 17:15:12 -0800619 // Reference to BluetoothA2dp to query for volume.
620 private BluetoothHearingAid mHearingAid;
621 // lock always taken synchronized on mConnectedDevices
622 private final Object mHearingAidLock = new Object();
John Du5a0cf7a2013-07-19 11:30:34 -0700623 // Reference to BluetoothA2dp to query for AbsoluteVolume.
624 private BluetoothA2dp mA2dp;
seunghwan.hong4fe77952014-10-29 17:43:20 +0900625 // lock always taken synchronized on mConnectedDevices
John Du5a0cf7a2013-07-19 11:30:34 -0700626 private final Object mA2dpAvrcpLock = new Object();
627 // If absolute volume is supported in AVRCP device
628 private boolean mAvrcpAbsVolSupported = false;
629
Eric Laurentadbe8bf2014-11-03 18:26:32 -0800630 private static Long mLastDeviceConnectMsgTime = new Long(0);
631
Julia Reynolds48034f82016-03-09 10:15:16 -0500632 private NotificationManager mNm;
John Spurlock661f2cf2014-11-17 10:29:10 -0500633 private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
John Spurlocka48d7792015-03-03 17:35:57 -0500634 private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
John Spurlock07e72432015-03-13 11:46:52 -0400635 private long mLoweredFromNormalToVibrateTime;
John Spurlock661f2cf2014-11-17 10:29:10 -0500636
Phil Weaverf1a9aff2017-03-23 17:21:29 -0700637 // Array of Uids of valid accessibility services to check if caller is one of them
638 private int[] mAccessibilityServiceUids;
639 private final Object mAccessibilityServiceUidsLock = new Object();
640
jiabin39940752018-04-02 18:18:45 -0700641 private int mEncodedSurroundMode;
642 private String mEnabledSurroundFormats;
643 private boolean mSurroundModeChanged;
644
Paul McLean10804eb2015-01-28 11:16:35 -0800645 // Intent "extra" data keys.
646 public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName";
647 public static final String CONNECT_INTENT_KEY_STATE = "state";
648 public static final String CONNECT_INTENT_KEY_ADDRESS = "address";
649 public static final String CONNECT_INTENT_KEY_HAS_PLAYBACK = "hasPlayback";
650 public static final String CONNECT_INTENT_KEY_HAS_CAPTURE = "hasCapture";
651 public static final String CONNECT_INTENT_KEY_HAS_MIDI = "hasMIDI";
652 public static final String CONNECT_INTENT_KEY_DEVICE_CLASS = "class";
653
654 // Defines the format for the connection "address" for ALSA devices
655 public static String makeAlsaAddressString(int card, int device) {
656 return "card=" + card + ";device=" + device + ";";
657 }
658
Makoto Onukie1aef852015-10-15 17:28:35 -0700659 public static final class Lifecycle extends SystemService {
660 private AudioService mService;
661
662 public Lifecycle(Context context) {
663 super(context);
664 mService = new AudioService(context);
665 }
666
667 @Override
668 public void onStart() {
669 publishBinderService(Context.AUDIO_SERVICE, mService);
670 }
671
672 @Override
673 public void onBootPhase(int phase) {
674 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
675 mService.systemReady();
676 }
677 }
678 }
679
Dianne Hackborn3e99f652017-07-05 16:33:56 -0700680 final private IUidObserver mUidObserver = new IUidObserver.Stub() {
681 @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
682 }
683
684 @Override public void onUidGone(int uid, boolean disabled) {
685 // Once the uid is no longer running, no need to keep trying to disable its audio.
686 disableAudioForUid(false, uid);
687 }
688
689 @Override public void onUidActive(int uid) throws RemoteException {
690 }
691
692 @Override public void onUidIdle(int uid, boolean disabled) {
693 }
694
695 @Override public void onUidCachedChanged(int uid, boolean cached) {
696 disableAudioForUid(cached, uid);
697 }
698
699 private void disableAudioForUid(boolean disable, int uid) {
700 queueMsgUnderWakeLock(mAudioHandler, MSG_DISABLE_AUDIO_FOR_UID,
701 disable ? 1 : 0 /* arg1 */, uid /* arg2 */,
702 null /* obj */, 0 /* delay */);
703 }
704 };
705
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800706 ///////////////////////////////////////////////////////////////////////////
707 // Construction
708 ///////////////////////////////////////////////////////////////////////////
709
710 /** @hide */
711 public AudioService(Context context) {
712 mContext = context;
713 mContentResolver = context.getContentResolver();
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700714 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700715
John Spurlock61560172015-02-06 19:46:04 -0500716 mPlatformType = AudioSystem.getPlatformType(context);
Jared Suttles59820132009-08-13 21:50:52 -0500717
Muyuan Li1ed6df62016-06-18 11:16:52 -0700718 mIsSingleVolume = AudioSystem.isSingleVolume(context);
719
Makoto Onukid45a4a22015-11-02 17:17:38 -0800720 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700721 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
Makoto Onukid45a4a22015-11-02 17:17:38 -0800722
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700723 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700724 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700725
Mike Digman55272862018-02-20 14:35:17 -0800726 mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
727 mHasVibrator = mVibrator == null ? false : mVibrator.hasVibrator();
Eric Laurentbffc3d12012-05-07 17:43:49 -0700728
John Spurlockb6e19e32015-03-10 21:33:44 -0400729 // Initialize volume
Eric Laurent403bd342017-07-11 16:21:44 -0700730 int maxCallVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps", -1);
731 if (maxCallVolume != -1) {
732 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxCallVolume;
Shuhei Miyazaki89091ba2018-01-11 18:17:04 +0900733 }
734
735 int defaultCallVolume = SystemProperties.getInt("ro.config.vc_call_vol_default", -1);
736 if (defaultCallVolume != -1 &&
737 defaultCallVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] &&
738 defaultCallVolume >= MIN_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
739 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = defaultCallVolume;
740 } else {
Eric Laurent403bd342017-07-11 16:21:44 -0700741 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] =
742 (maxCallVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700743 }
Eric Laurent403bd342017-07-11 16:21:44 -0700744
745 int maxMusicVolume = SystemProperties.getInt("ro.config.media_vol_steps", -1);
746 if (maxMusicVolume != -1) {
747 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxMusicVolume;
748 }
749
750 int defaultMusicVolume = SystemProperties.getInt("ro.config.media_vol_default", -1);
751 if (defaultMusicVolume != -1 &&
Shuhei Miyazaki89091ba2018-01-11 18:17:04 +0900752 defaultMusicVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] &&
753 defaultMusicVolume >= MIN_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
Eric Laurent403bd342017-07-11 16:21:44 -0700754 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = defaultMusicVolume;
755 } else {
Hank Freund45926dc2015-12-11 10:50:45 -0800756 if (isPlatformTelevision()) {
Eric Laurent403bd342017-07-11 16:21:44 -0700757 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] =
758 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] / 4;
Hank Freund45926dc2015-12-11 10:50:45 -0800759 } else {
Eric Laurent403bd342017-07-11 16:21:44 -0700760 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] =
761 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] / 3;
Hank Freund45926dc2015-12-11 10:50:45 -0800762 }
Eric Laurent91377de2014-10-10 15:24:04 -0700763 }
Jared Suttles59820132009-08-13 21:50:52 -0500764
Chris Kuiper09b6c212018-01-03 22:22:13 -0800765 int maxAlarmVolume = SystemProperties.getInt("ro.config.alarm_vol_steps", -1);
766 if (maxAlarmVolume != -1) {
767 MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM] = maxAlarmVolume;
768 }
769
770 int defaultAlarmVolume = SystemProperties.getInt("ro.config.alarm_vol_default", -1);
771 if (defaultAlarmVolume != -1 &&
772 defaultAlarmVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM]) {
773 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_ALARM] = defaultAlarmVolume;
774 } else {
775 // Default is 6 out of 7 (default maximum), so scale accordingly.
776 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_ALARM] =
777 6 * MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM] / 7;
778 }
779
780 int maxSystemVolume = SystemProperties.getInt("ro.config.system_vol_steps", -1);
781 if (maxSystemVolume != -1) {
782 MAX_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM] = maxSystemVolume;
783 }
784
785 int defaultSystemVolume = SystemProperties.getInt("ro.config.system_vol_default", -1);
786 if (defaultSystemVolume != -1 &&
787 defaultSystemVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM]) {
788 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM] = defaultSystemVolume;
789 } else {
790 // Default is to use maximum.
791 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM] =
792 MAX_STREAM_VOLUME[AudioSystem.STREAM_SYSTEM];
793 }
794
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700795 sSoundEffectVolumeDb = context.getResources().getInteger(
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700796 com.android.internal.R.integer.config_soundEffectVolumeDb);
Eric Laurent25101b02011-02-02 09:33:30 -0800797
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700798 mForcedUseForComm = AudioSystem.FORCE_NONE;
Eric Laurentdd45d012012-10-08 09:04:34 -0700799
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800800 createAudioSystemThread();
Eric Laurentdd45d012012-10-08 09:04:34 -0700801
Eric Laurentdfb881f2013-07-18 14:41:39 -0700802 AudioSystem.setErrorCallback(mAudioSystemCallback);
803
John Spurlock5e783732015-02-19 10:28:59 -0500804 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -0700805 mCameraSoundForced = new Boolean(cameraSoundForced);
806 sendMsg(mAudioHandler,
807 MSG_SET_FORCE_USE,
808 SENDMSG_QUEUE,
809 AudioSystem.FOR_SYSTEM,
810 cameraSoundForced ?
811 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700812 new String("AudioService ctor"),
Eric Laurentdd45d012012-10-08 09:04:34 -0700813 0);
814
Eric Laurent05274f32012-11-29 12:48:18 -0800815 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
816 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
817 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
818 // The default safe volume index read here will be replaced by the actual value when
819 // the mcc is read by onConfigureSafeVolume()
820 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
821 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
822
Eric Laurent83a017b2013-03-19 18:15:31 -0700823 mUseFixedVolume = mContext.getResources().getBoolean(
824 com.android.internal.R.bool.config_useFixedVolume);
825
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700826 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
827 // array initialized by updateStreamVolumeAlias()
John Spurlock90874332015-03-10 16:00:54 -0400828 updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 readPersistedSettings();
Eric Laurentc0232482016-03-15 18:19:23 -0700830 readUserRestrictions();
Eric Laurentc1d41662011-07-19 11:21:13 -0700831 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700832 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700833
Eric Laurentb378a13a2017-07-11 14:08:11 -0700834 // mSafeUsbMediaVolumeIndex must be initialized after createStreamStates() because it
835 // relies on audio policy having correct ranges for volume indexes.
836 mSafeUsbMediaVolumeIndex = getSafeUsbMediaVolumeIndex();
837
Eric Laurente5a351c2017-09-27 20:11:51 -0700838 mPlaybackMonitor =
839 new PlaybackActivityMonitor(context, MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM]);
840
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800841 mMediaFocusControl = new MediaFocusControl(mContext, mPlaybackMonitor);
John Spurlockb6e19e32015-03-10 21:33:44 -0400842
Jean-Michel Trivi66ffacf2017-02-04 17:25:31 -0800843 mRecordMonitor = new RecordingActivityMonitor(mContext);
844
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700845 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700846
847 // Call setRingerModeInt() to apply correct mute
848 // state on streams affected by ringer mode.
Beverlyd6964762018-02-16 14:07:03 -0500849 mRingerAndZenModeMutedStreams = 0;
John Spurlock661f2cf2014-11-17 10:29:10 -0500850 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3891c4c2010-04-20 09:40:57 -0700851
Eric Laurenta553c252009-07-17 12:17:14 -0700852 // Register for device connection intent broadcasts.
853 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700854 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jack He8dd33942018-01-17 15:45:12 -0800855 intentFilter.addAction(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700856 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700857 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
858 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700859 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700860 intentFilter.addAction(Intent.ACTION_USER_BACKGROUND);
861 intentFilter.addAction(Intent.ACTION_USER_FOREGROUND);
Paul McLeanc837a452014-04-09 09:04:43 -0700862 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Eric Laurentb70b78a2016-01-13 19:16:04 -0800863 intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700864
Eric Laurentd640bd32012-09-28 18:01:48 -0700865 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700866 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
867 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -0700868 RotationHelper.init(mContext, mAudioHandler);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700869 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700870
Marco Nelissenfb6df0b2017-02-15 15:25:24 -0800871 intentFilter.addAction(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
872 intentFilter.addAction(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
873
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700874 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null);
Jared Suttles59820132009-08-13 21:50:52 -0500875
RoboErik0dac35a2014-08-12 15:48:49 -0700876 LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
Makoto Onukid45a4a22015-11-02 17:17:38 -0800877
878 mUserManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -0800879
880 mRecordMonitor.initMonitor();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800881 }
882
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700883 public void systemReady() {
884 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
885 0, 0, null, 0);
Dianne Hackborn3e3600e2017-08-31 11:15:26 -0700886 if (false) {
887 // This is turned off for now, because it is racy and thus causes apps to break.
888 // Currently banning a uid means that if an app tries to start playing an audio
889 // stream, that will be preventing, and unbanning it will not allow that stream
890 // to resume. However these changes in uid state are racy with what the app is doing,
891 // so that after taking a process out of the cached state we can't guarantee that
892 // we will unban the uid before the app actually tries to start playing audio.
893 // (To do that, the activity manager would need to wait until it knows for sure
894 // that the ban has been removed, before telling the app to do whatever it is
895 // supposed to do that caused it to go out of the cached state.)
896 try {
897 ActivityManager.getService().registerUidObserver(mUidObserver,
898 ActivityManager.UID_OBSERVER_CACHED | ActivityManager.UID_OBSERVER_GONE,
899 ActivityManager.PROCESS_STATE_UNKNOWN, null);
900 } catch (RemoteException e) {
901 // ignored; both services live in system_server
902 }
Dianne Hackborn3e99f652017-07-05 16:33:56 -0700903 }
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700904 }
905
906 public void onSystemReady() {
907 mSystemReady = true;
908 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
909 0, 0, null, 0);
910
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700911 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
912 resetBluetoothSco();
913 getBluetoothHeadset();
914 //FIXME: this is to maintain compatibility with deprecated intent
915 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
916 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
917 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
918 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
919 sendStickyBroadcastToAll(newIntent);
920
921 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
922 if (adapter != null) {
923 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
924 BluetoothProfile.A2DP);
Jakub Pawlowskif9570f32018-02-21 17:15:12 -0800925 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
926 BluetoothProfile.HEARING_AID);
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700927 }
928
Jeff Sharkey73ea0ae2016-08-10 17:30:38 -0600929 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_HDMI_CEC)) {
930 mHdmiManager = mContext.getSystemService(HdmiControlManager.class);
Eric Laurent212532b2014-07-21 15:43:18 -0700931 synchronized (mHdmiManager) {
932 mHdmiTvClient = mHdmiManager.getTvClient();
Jungshik Jangc9ff9682014-09-15 17:41:06 +0900933 if (mHdmiTvClient != null) {
934 mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
935 }
Eric Laurent212532b2014-07-21 15:43:18 -0700936 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
937 mHdmiCecSink = false;
938 }
939 }
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900940
Julia Reynolds48034f82016-03-09 10:15:16 -0500941 mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
942
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700943 sendMsg(mAudioHandler,
944 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
945 SENDMSG_REPLACE,
946 0,
947 0,
John Spurlock90874332015-03-10 16:00:54 -0400948 TAG,
Eric Laurent03332ab2017-02-09 18:29:15 -0800949 SystemProperties.getBoolean("audio.safemedia.bypass", false) ?
950 0 : SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700951
Jean-Michel Trivicfa55532017-01-18 11:17:51 -0800952 initA11yMonitoring();
Eric Laurent0867bed2015-05-20 14:49:08 -0700953 onIndicateSystemReady();
954 }
955
956 void onIndicateSystemReady() {
957 if (AudioSystem.systemReady() == AudioSystem.SUCCESS) {
958 return;
959 }
960 sendMsg(mAudioHandler,
961 MSG_INDICATE_SYSTEM_READY,
962 SENDMSG_REPLACE,
963 0,
964 0,
965 null,
966 INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
967 }
968
Andy Hunged0ea402015-10-30 14:11:46 -0700969 public void onAudioServerDied() {
Eric Laurent0867bed2015-05-20 14:49:08 -0700970 if (!mSystemReady ||
971 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Andy Hunged0ea402015-10-30 14:11:46 -0700972 Log.e(TAG, "Audioserver died.");
973 sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent0867bed2015-05-20 14:49:08 -0700974 null, 500);
975 return;
976 }
Andy Hunged0ea402015-10-30 14:11:46 -0700977 Log.e(TAG, "Audioserver started.");
Eric Laurent0867bed2015-05-20 14:49:08 -0700978
979 // indicate to audio HAL that we start the reconfiguration phase after a media
980 // server crash
981 // Note that we only execute this when the media server
982 // process restarts after a crash, not the first time it is started.
983 AudioSystem.setParameters("restarting=true");
984
985 readAndSetLowRamDevice();
986
987 // Restore device connection states
988 synchronized (mConnectedDevices) {
989 for (int i = 0; i < mConnectedDevices.size(); i++) {
990 DeviceListSpec spec = mConnectedDevices.valueAt(i);
991 AudioSystem.setDeviceConnectionState(
992 spec.mDeviceType,
993 AudioSystem.DEVICE_STATE_AVAILABLE,
994 spec.mDeviceAddress,
995 spec.mDeviceName);
996 }
997 }
998 // Restore call state
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700999 if (AudioSystem.setPhoneState(mMode) == AudioSystem.AUDIO_STATUS_OK) {
1000 mModeLogger.log(new AudioEventLogger.StringEvent(
1001 "onAudioServerDied causes setPhoneState(" + AudioSystem.modeToString(mMode) + ")"));
1002 }
Eric Laurent0867bed2015-05-20 14:49:08 -07001003
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001004 // Restore forced usage for communications and record
1005 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm,
1006 "onAudioServerDied"));
Eric Laurent0867bed2015-05-20 14:49:08 -07001007 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001008 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_RECORD, mForcedUseForComm,
1009 "onAudioServerDied"));
Eric Laurent0867bed2015-05-20 14:49:08 -07001010 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08001011 final int forSys;
1012 synchronized (mSettingsLock) {
1013 forSys = mCameraSoundForced ?
1014 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE;
1015 }
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001016 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_SYSTEM, forSys,
1017 "onAudioServerDied"));
1018 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, forSys);
Eric Laurent0867bed2015-05-20 14:49:08 -07001019
1020 // Restore stream volumes
1021 int numStreamTypes = AudioSystem.getNumStreamTypes();
1022 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
1023 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurente4381ec2015-10-29 17:52:48 -07001024 AudioSystem.initStreamVolume(
1025 streamType, streamState.mIndexMin / 10, streamState.mIndexMax / 10);
Eric Laurent0867bed2015-05-20 14:49:08 -07001026
1027 streamState.applyAllVolumes();
1028 }
1029
Andy Hungf04b84d2015-12-18 17:33:27 -08001030 // Restore mono mode
Andy Hung7b98e9a2016-02-25 18:34:50 -08001031 updateMasterMono(mContentResolver);
Andy Hungf04b84d2015-12-18 17:33:27 -08001032
Eric Laurent0867bed2015-05-20 14:49:08 -07001033 // Restore ringer mode
1034 setRingerModeInt(getRingerModeInternal(), false);
1035
Mikhail Naganovb668bc62018-02-13 13:46:38 -08001036 // Reset device rotation (if monitored for this device)
Eric Laurent0867bed2015-05-20 14:49:08 -07001037 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07001038 RotationHelper.updateOrientation();
Eric Laurent0867bed2015-05-20 14:49:08 -07001039 }
1040
Sungsoocf09fe62016-09-28 16:21:48 +09001041 synchronized (mBluetoothA2dpEnabledLock) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001042 final int forMed = mBluetoothA2dpEnabled ?
1043 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP;
1044 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_MEDIA, forMed,
1045 "onAudioServerDied"));
1046 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, forMed);
Sungsoocf09fe62016-09-28 16:21:48 +09001047 }
1048
Eric Laurent0867bed2015-05-20 14:49:08 -07001049 synchronized (mSettingsLock) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001050 final int forDock = mDockAudioMediaEnabled ?
1051 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE;
1052 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_DOCK, forDock,
1053 "onAudioServerDied"));
1054 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, forDock);
1055 sendEncodedSurroundMode(mContentResolver, "onAudioServerDied");
jiabin39940752018-04-02 18:18:45 -07001056 sendEnabledSurroundFormats(mContentResolver, true);
Eric Laurent0867bed2015-05-20 14:49:08 -07001057 }
1058 if (mHdmiManager != null) {
1059 synchronized (mHdmiManager) {
1060 if (mHdmiTvClient != null) {
1061 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
1062 }
1063 }
1064 }
1065
1066 synchronized (mAudioPolicies) {
1067 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
1068 policy.connectMixes();
1069 }
1070 }
1071
1072 onIndicateSystemReady();
1073 // indicate the end of reconfiguration phase to audio HAL
1074 AudioSystem.setParameters("restarting=false");
Eric Laurent1d3cdce2018-01-20 10:31:21 -08001075
1076 sendMsg(mAudioHandler, MSG_DISPATCH_AUDIO_SERVER_STATE,
1077 SENDMSG_QUEUE, 1, 0, null, 0);
1078 }
1079
1080 private void onDispatchAudioServerStateChange(boolean state) {
1081 synchronized (mAudioServerStateListeners) {
1082 for (AsdProxy asdp : mAudioServerStateListeners.values()) {
1083 try {
1084 asdp.callback().dispatchAudioServerStateChange(state);
1085 } catch (RemoteException e) {
1086 Log.w(TAG, "Could not call dispatchAudioServerStateChange()", e);
1087 }
1088 }
1089 }
Eric Laurent4a5eeb92014-05-06 10:49:04 -07001090 }
1091
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001092 private void createAudioSystemThread() {
1093 mAudioSystemThread = new AudioSystemThread();
1094 mAudioSystemThread.start();
1095 waitForAudioHandlerCreation();
1096 }
1097
1098 /** Waits for the volume handler to be created by the other thread. */
1099 private void waitForAudioHandlerCreation() {
1100 synchronized(this) {
1101 while (mAudioHandler == null) {
1102 try {
1103 // Wait for mAudioHandler to be set by the other thread
1104 wait();
1105 } catch (InterruptedException e) {
1106 Log.e(TAG, "Interrupted while waiting on volume handler.");
1107 }
1108 }
1109 }
1110 }
1111
Eric Laurent24482012012-05-10 09:41:17 -07001112 private void checkAllAliasStreamVolumes() {
Jean-Michel Trivi085346a2018-02-14 10:48:51 -08001113 synchronized (mSettingsLock) {
1114 synchronized (VolumeStreamState.class) {
1115 int numStreamTypes = AudioSystem.getNumStreamTypes();
1116 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
1117 mStreamStates[streamType]
1118 .setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], TAG);
1119 // apply stream volume
1120 if (!mStreamStates[streamType].mIsMuted) {
1121 mStreamStates[streamType].applyAllVolumes();
1122 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001123 }
Eric Laurent24482012012-05-10 09:41:17 -07001124 }
1125 }
1126 }
1127
Eric Laurent212532b2014-07-21 15:43:18 -07001128 private void checkAllFixedVolumeDevices()
1129 {
1130 int numStreamTypes = AudioSystem.getNumStreamTypes();
1131 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
1132 mStreamStates[streamType].checkFixedVolumeDevices();
1133 }
1134 }
1135
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07001136 private void checkAllFixedVolumeDevices(int streamType) {
1137 mStreamStates[streamType].checkFixedVolumeDevices();
1138 }
1139
John Spurlockb6e19e32015-03-10 21:33:44 -04001140 private void checkMuteAffectedStreams() {
1141 // any stream with a min level > 0 is not muteable by definition
Nadav Bar6b7751d2017-12-24 16:03:08 +02001142 // STREAM_VOICE_CALL can be muted by applications that has the the MODIFY_PHONE_STATE permission.
John Spurlockb6e19e32015-03-10 21:33:44 -04001143 for (int i = 0; i < mStreamStates.length; i++) {
1144 final VolumeStreamState vss = mStreamStates[i];
Nadav Bar6b7751d2017-12-24 16:03:08 +02001145 if (vss.mIndexMin > 0 &&
1146 vss.mStreamType != AudioSystem.STREAM_VOICE_CALL) {
John Spurlockb6e19e32015-03-10 21:33:44 -04001147 mMuteAffectedStreams &= ~(1 << vss.mStreamType);
1148 }
1149 }
1150 }
1151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001152 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153 int numStreamTypes = AudioSystem.getNumStreamTypes();
1154 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
1155
1156 for (int i = 0; i < numStreamTypes; i++) {
Jean-Michel Trivia53b7052017-04-12 18:27:01 -07001157 streams[i] =
1158 new VolumeStreamState(System.VOLUME_SETTINGS_INT[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -07001159 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001160
Eric Laurent212532b2014-07-21 15:43:18 -07001161 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07001162 checkAllAliasStreamVolumes();
John Spurlockb6e19e32015-03-10 21:33:44 -04001163 checkMuteAffectedStreams();
Eric Laurent403bd342017-07-11 16:21:44 -07001164 updateDefaultVolumes();
1165 }
1166
1167 // Update default indexes from aliased streams. Must be called after mStreamStates is created
1168 private void updateDefaultVolumes() {
1169 for (int stream = 0; stream < mStreamStates.length; stream++) {
1170 if (stream != mStreamVolumeAlias[stream]) {
1171 AudioSystem.DEFAULT_STREAM_VOLUME[stream] = rescaleIndex(
1172 AudioSystem.DEFAULT_STREAM_VOLUME[mStreamVolumeAlias[stream]],
1173 mStreamVolumeAlias[stream],
1174 stream);
1175 }
1176 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177 }
1178
Eric Laurentbffc3d12012-05-07 17:43:49 -07001179 private void dumpStreamStates(PrintWriter pw) {
1180 pw.println("\nStream volumes (device: index)");
1181 int numStreamTypes = AudioSystem.getNumStreamTypes();
1182 for (int i = 0; i < numStreamTypes; i++) {
John Spurlock61560172015-02-06 19:46:04 -05001183 pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":");
Eric Laurentbffc3d12012-05-07 17:43:49 -07001184 mStreamStates[i].dump(pw);
1185 pw.println("");
1186 }
Eric Laurentdd45d012012-10-08 09:04:34 -07001187 pw.print("\n- mute affected streams = 0x");
1188 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -07001189 }
1190
John Spurlock90874332015-03-10 16:00:54 -04001191 private void updateStreamVolumeAlias(boolean updateVolumes, String caller) {
Eric Laurent6d517662012-04-23 18:42:39 -07001192 int dtmfStreamAlias;
Jean-Michel Triviac487672016-11-11 10:05:18 -08001193 final int a11yStreamAlias = sIndependentA11yVolume ?
1194 AudioSystem.STREAM_ACCESSIBILITY : AudioSystem.STREAM_MUSIC;
Eric Laurent212532b2014-07-21 15:43:18 -07001195
Muyuan Li1ed6df62016-06-18 11:16:52 -07001196 if (mIsSingleVolume) {
Eric Laurent212532b2014-07-21 15:43:18 -07001197 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
1198 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
Muyuan Li1ed6df62016-06-18 11:16:52 -07001199 } else {
1200 switch (mPlatformType) {
1201 case AudioSystem.PLATFORM_VOICE:
1202 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
1203 dtmfStreamAlias = AudioSystem.STREAM_RING;
1204 break;
1205 default:
1206 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
1207 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
1208 }
Eric Laurent6d517662012-04-23 18:42:39 -07001209 }
Eric Laurent212532b2014-07-21 15:43:18 -07001210
Muyuan Li1ed6df62016-06-18 11:16:52 -07001211 if (mIsSingleVolume) {
Eric Laurent212532b2014-07-21 15:43:18 -07001212 mRingerModeAffectedStreams = 0;
Eric Laurent24e0d9b2013-10-03 18:15:07 -07001213 } else {
Eric Laurent212532b2014-07-21 15:43:18 -07001214 if (isInCommunication()) {
1215 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
1216 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
1217 } else {
1218 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
1219 }
Eric Laurent6d517662012-04-23 18:42:39 -07001220 }
Eric Laurent212532b2014-07-21 15:43:18 -07001221
Eric Laurent6d517662012-04-23 18:42:39 -07001222 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
Jean-Michel Trivi170a0ee2017-04-14 18:13:26 -07001223 mStreamVolumeAlias[AudioSystem.STREAM_ACCESSIBILITY] = a11yStreamAlias;
Jean-Michel Triviac487672016-11-11 10:05:18 -08001224
Eric Laurent403bd342017-07-11 16:21:44 -07001225 if (updateVolumes && mStreamStates != null) {
1226 updateDefaultVolumes();
1227
Jean-Michel Trivi085346a2018-02-14 10:48:51 -08001228 synchronized (mSettingsLock) {
1229 synchronized (VolumeStreamState.class) {
1230 mStreamStates[AudioSystem.STREAM_DTMF]
1231 .setAllIndexes(mStreamStates[dtmfStreamAlias], caller);
1232 mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].mVolumeIndexSettingName =
1233 System.VOLUME_SETTINGS_INT[a11yStreamAlias];
1234 mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setAllIndexes(
1235 mStreamStates[a11yStreamAlias], caller);
Jean-Michel Trivie05eef82018-03-08 18:56:34 -08001236 mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].refreshRange(
1237 mStreamVolumeAlias[AudioSystem.STREAM_ACCESSIBILITY]);
Jean-Michel Trivi085346a2018-02-14 10:48:51 -08001238 }
1239 }
Jean-Michel Trivi170a0ee2017-04-14 18:13:26 -07001240 if (sIndependentA11yVolume) {
1241 // restore the a11y values from the settings
1242 mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].readSettings();
1243 }
1244
Eric Laurent24e0d9b2013-10-03 18:15:07 -07001245 // apply stream mute states according to new value of mRingerModeAffectedStreams
John Spurlock661f2cf2014-11-17 10:29:10 -05001246 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent6d517662012-04-23 18:42:39 -07001247 sendMsg(mAudioHandler,
1248 MSG_SET_ALL_VOLUMES,
1249 SENDMSG_QUEUE,
1250 0,
1251 0,
1252 mStreamStates[AudioSystem.STREAM_DTMF], 0);
Jean-Michel Triviac487672016-11-11 10:05:18 -08001253 sendMsg(mAudioHandler,
1254 MSG_SET_ALL_VOLUMES,
1255 SENDMSG_QUEUE,
1256 0,
1257 0,
1258 mStreamStates[AudioSystem.STREAM_ACCESSIBILITY], 0);
Eric Laurent6d517662012-04-23 18:42:39 -07001259 }
1260 }
1261
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001262 private void readDockAudioSettings(ContentResolver cr)
1263 {
1264 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -07001265 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001266
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001267 sendMsg(mAudioHandler,
1268 MSG_SET_FORCE_USE,
1269 SENDMSG_QUEUE,
1270 AudioSystem.FOR_DOCK,
1271 mDockAudioMediaEnabled ?
1272 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001273 new String("readDockAudioSettings"),
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001274 0);
1275 }
1276
Phil Burkac0f7042016-02-24 12:19:08 -08001277
Andy Hung7b98e9a2016-02-25 18:34:50 -08001278 private void updateMasterMono(ContentResolver cr)
1279 {
1280 final boolean masterMono = System.getIntForUser(
1281 cr, System.MASTER_MONO, 0 /* default */, UserHandle.USER_CURRENT) == 1;
1282 if (DEBUG_VOL) {
1283 Log.d(TAG, String.format("Master mono %b", masterMono));
1284 }
1285 AudioSystem.setMasterMono(masterMono);
1286 }
1287
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001288 private void sendEncodedSurroundMode(ContentResolver cr, String eventSource)
Phil Burkac0f7042016-02-24 12:19:08 -08001289 {
1290 int encodedSurroundMode = Settings.Global.getInt(
1291 cr, Settings.Global.ENCODED_SURROUND_OUTPUT,
1292 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001293 sendEncodedSurroundMode(encodedSurroundMode, eventSource);
Phil Burkac0f7042016-02-24 12:19:08 -08001294 }
1295
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001296 private void sendEncodedSurroundMode(int encodedSurroundMode, String eventSource)
Phil Burkac0f7042016-02-24 12:19:08 -08001297 {
1298 // initialize to guaranteed bad value
1299 int forceSetting = AudioSystem.NUM_FORCE_CONFIG;
1300 switch (encodedSurroundMode) {
1301 case Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO:
1302 forceSetting = AudioSystem.FORCE_NONE;
1303 break;
1304 case Settings.Global.ENCODED_SURROUND_OUTPUT_NEVER:
1305 forceSetting = AudioSystem.FORCE_ENCODED_SURROUND_NEVER;
1306 break;
1307 case Settings.Global.ENCODED_SURROUND_OUTPUT_ALWAYS:
1308 forceSetting = AudioSystem.FORCE_ENCODED_SURROUND_ALWAYS;
1309 break;
jiabin39940752018-04-02 18:18:45 -07001310 case Settings.Global.ENCODED_SURROUND_OUTPUT_MANUAL:
1311 forceSetting = AudioSystem.FORCE_ENCODED_SURROUND_MANUAL;
1312 break;
Phil Burkac0f7042016-02-24 12:19:08 -08001313 default:
1314 Log.e(TAG, "updateSurroundSoundSettings: illegal value "
1315 + encodedSurroundMode);
1316 break;
1317 }
1318 if (forceSetting != AudioSystem.NUM_FORCE_CONFIG) {
1319 sendMsg(mAudioHandler,
1320 MSG_SET_FORCE_USE,
1321 SENDMSG_QUEUE,
1322 AudioSystem.FOR_ENCODED_SURROUND,
1323 forceSetting,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001324 eventSource,
Phil Burkac0f7042016-02-24 12:19:08 -08001325 0);
1326 }
1327 }
1328
jiabin39940752018-04-02 18:18:45 -07001329 private void sendEnabledSurroundFormats(ContentResolver cr, boolean forceUpdate) {
1330 if (mEncodedSurroundMode != Settings.Global.ENCODED_SURROUND_OUTPUT_MANUAL) {
1331 // Manually enable surround formats only when the setting is in manual mode.
1332 return;
1333 }
1334 String enabledSurroundFormats = Settings.Global.getString(
1335 cr, Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS);
jiabin6db5f862018-05-17 10:33:09 -07001336 if (enabledSurroundFormats == null) {
1337 // Never allow enabledSurroundFormats as a null, which could happen when
1338 // ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS is not appear in settings DB.
1339 enabledSurroundFormats = "";
1340 }
jiabin39940752018-04-02 18:18:45 -07001341 if (!forceUpdate && TextUtils.equals(enabledSurroundFormats, mEnabledSurroundFormats)) {
1342 // Update enabled surround formats to AudioPolicyManager only when forceUpdate
1343 // is true or enabled surround formats changed.
1344 return;
1345 }
1346
1347 mEnabledSurroundFormats = enabledSurroundFormats;
1348 String[] surroundFormats = TextUtils.split(enabledSurroundFormats, ",");
1349 ArrayList<Integer> formats = new ArrayList<>();
1350 for (String format : surroundFormats) {
1351 try {
1352 int audioFormat = Integer.valueOf(format);
1353 boolean isSurroundFormat = false;
1354 for (int sf : AudioFormat.SURROUND_SOUND_ENCODING) {
1355 if (sf == audioFormat) {
1356 isSurroundFormat = true;
1357 break;
1358 }
1359 }
1360 if (isSurroundFormat && !formats.contains(audioFormat)) {
1361 formats.add(audioFormat);
1362 }
1363 } catch (Exception e) {
1364 Log.e(TAG, "Invalid enabled surround format:" + format);
1365 }
1366 }
1367 // Set filtered surround formats to settings DB in case
1368 // there are invalid surround formats in original settings.
1369 Settings.Global.putString(mContext.getContentResolver(),
1370 Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS,
1371 TextUtils.join(",", formats));
1372 sendMsg(mAudioHandler, MSG_ENABLE_SURROUND_FORMATS, SENDMSG_QUEUE, 0, 0, formats, 0);
1373 }
1374
1375 private void onEnableSurroundFormats(ArrayList<Integer> enabledSurroundFormats) {
1376 // Set surround format enabled accordingly.
1377 for (int surroundFormat : AudioFormat.SURROUND_SOUND_ENCODING) {
1378 boolean enabled = enabledSurroundFormats.contains(surroundFormat);
1379 int ret = AudioSystem.setSurroundFormatEnabled(surroundFormat, enabled);
1380 Log.i(TAG, "enable surround format:" + surroundFormat + " " + enabled + " " + ret);
1381 }
1382 }
1383
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384 private void readPersistedSettings() {
1385 final ContentResolver cr = mContentResolver;
1386
Eric Laurentbffc3d12012-05-07 17:43:49 -07001387 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07001388 Settings.Global.getInt(
1389 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -07001390 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -07001391 // sanity check in case the settings are restored from a device with incompatible
1392 // ringer modes
John Spurlock97559372014-10-24 16:27:36 -04001393 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001394 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -07001395 }
1396 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1397 ringerMode = AudioManager.RINGER_MODE_SILENT;
1398 }
1399 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07001400 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -08001401 }
Muyuan Li1ed6df62016-06-18 11:16:52 -07001402 if (mUseFixedVolume || mIsSingleVolume) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001403 ringerMode = AudioManager.RINGER_MODE_NORMAL;
1404 }
Glenn Kastenba195eb2011-12-13 09:30:40 -08001405 synchronized(mSettingsLock) {
1406 mRingerMode = ringerMode;
John Spurlock661f2cf2014-11-17 10:29:10 -05001407 if (mRingerModeExternal == -1) {
1408 mRingerModeExternal = mRingerMode;
1409 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001410
Eric Laurentdd45d012012-10-08 09:04:34 -07001411 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
1412 // are still needed while setVibrateSetting() and getVibrateSetting() are being
1413 // deprecated.
John Spurlock61560172015-02-06 19:46:04 -05001414 mVibrateSetting = AudioSystem.getValueForVibrateSetting(0,
Eric Laurentdd45d012012-10-08 09:04:34 -07001415 AudioManager.VIBRATE_TYPE_NOTIFICATION,
1416 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
1417 : AudioManager.VIBRATE_SETTING_OFF);
John Spurlock61560172015-02-06 19:46:04 -05001418 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting,
Eric Laurentdd45d012012-10-08 09:04:34 -07001419 AudioManager.VIBRATE_TYPE_RINGER,
1420 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
1421 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422
Beverlyd6964762018-02-16 14:07:03 -05001423 updateRingerAndZenModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001424 readDockAudioSettings(cr);
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001425 sendEncodedSurroundMode(cr, "readPersistedSettings");
jiabin39940752018-04-02 18:18:45 -07001426 sendEnabledSurroundFormats(cr, true);
Eric Laurent402f7f22011-02-04 12:30:32 -08001427 }
Eric Laurentc1d41662011-07-19 11:21:13 -07001428
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001429 mMuteAffectedStreams = System.getIntForUser(cr,
John Spurlock61560172015-02-06 19:46:04 -05001430 System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
John Spurlock24c05182015-02-05 12:30:36 -05001431 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001432
Andy Hung7b98e9a2016-02-25 18:34:50 -08001433 updateMasterMono(cr);
Andy Hungf04b84d2015-12-18 17:33:27 -08001434
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001435 // Each stream will read its own persisted settings
1436
John Spurlockbcc10872014-11-28 15:29:21 -05001437 // Broadcast the sticky intents
1438 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
1439 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440
1441 // Broadcast vibrate settings
1442 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
1443 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07001444
John Spurlock33f4e042014-07-11 13:10:58 -04001445 // Load settings for the volume controller
1446 mVolumeController.loadSettings(cr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001447 }
1448
Eric Laurentc0232482016-03-15 18:19:23 -07001449 private void readUserRestrictions() {
1450 final int currentUser = getCurrentUserId();
1451
1452 // Check the current user restriction.
Tony Makc1205112016-07-22 16:02:59 +01001453 boolean masterMute =
1454 mUserManagerInternal.getUserRestriction(currentUser,
Esteban Talavera492b4722017-02-13 14:59:45 +00001455 UserManager.DISALLOW_UNMUTE_DEVICE)
Tony Makc1205112016-07-22 16:02:59 +01001456 || mUserManagerInternal.getUserRestriction(currentUser,
1457 UserManager.DISALLOW_ADJUST_VOLUME);
Eric Laurentc0232482016-03-15 18:19:23 -07001458 if (mUseFixedVolume) {
1459 masterMute = false;
1460 AudioSystem.setMasterVolume(1.0f);
1461 }
1462 if (DEBUG_VOL) {
1463 Log.d(TAG, String.format("Master mute %s, user=%d", masterMute, currentUser));
1464 }
1465 setSystemAudioMute(masterMute);
1466 AudioSystem.setMasterMute(masterMute);
1467 broadcastMasterMuteStatus(masterMute);
1468
1469 boolean microphoneMute = mUserManagerInternal.getUserRestriction(
1470 currentUser, UserManager.DISALLOW_UNMUTE_MICROPHONE);
1471 if (DEBUG_VOL) {
1472 Log.d(TAG, String.format("Mic mute %s, user=%d", microphoneMute, currentUser));
1473 }
1474 AudioSystem.muteMicrophone(microphoneMute);
1475 }
1476
Eric Laurenta553c252009-07-17 12:17:14 -07001477 private int rescaleIndex(int index, int srcStream, int dstStream) {
Jean-Michel Trivie05eef82018-03-08 18:56:34 -08001478 final int rescaled =
1479 (index * mStreamStates[dstStream].getMaxIndex()
1480 + mStreamStates[srcStream].getMaxIndex() / 2)
1481 / mStreamStates[srcStream].getMaxIndex();
1482 if (rescaled < mStreamStates[dstStream].getMinIndex()) {
1483 return mStreamStates[dstStream].getMinIndex();
1484 } else {
1485 return rescaled;
1486 }
Eric Laurenta553c252009-07-17 12:17:14 -07001487 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001488
1489 ///////////////////////////////////////////////////////////////////////////
1490 // IPC methods
1491 ///////////////////////////////////////////////////////////////////////////
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001492 /** @see AudioManager#adjustVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001493 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001494 String callingPackage, String caller) {
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -08001495 final IAudioPolicyCallback extVolCtlr;
1496 synchronized (mExtVolumeControllerLock) {
1497 extVolCtlr = mExtVolumeController;
1498 }
1499 if (extVolCtlr != null) {
Jean-Michel Trivi7ed71472018-02-02 16:52:09 -08001500 sendMsg(mAudioHandler, MSG_NOTIFY_VOL_EVENT, SENDMSG_QUEUE,
1501 direction, 0 /*ignored*/,
1502 extVolCtlr, 0 /*delay*/);
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -08001503 } else {
1504 adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
1505 caller, Binder.getCallingUid());
1506 }
RoboErik272e1612014-09-05 11:39:29 -07001507 }
1508
1509 private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001510 String callingPackage, String caller, int uid) {
1511 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001512 + ", flags=" + flags + ", caller=" + caller
1513 + ", volControlStream=" + mVolumeControlStream
1514 + ", userSelect=" + mUserSelectedVolumeControlStream);
Jean-Michel Trivicf170362017-08-24 17:24:57 -07001515 mVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_SUGG_VOL, suggestedStreamType,
1516 direction/*val1*/, flags/*val2*/, new StringBuilder(callingPackage)
1517 .append("/").append(caller).append(" uid:").append(uid).toString()));
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001518 final int streamType;
jiabin8fd5d5e2018-03-23 14:09:28 -07001519 synchronized (mForceControlStreamLock) {
1520 // Request lock in case mVolumeControlStream is changed by other thread.
1521 if (mUserSelectedVolumeControlStream) { // implies mVolumeControlStream != -1
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001522 streamType = mVolumeControlStream;
jiabin8fd5d5e2018-03-23 14:09:28 -07001523 } else {
1524 final int maybeActiveStreamType = getActiveStreamType(suggestedStreamType);
1525 final boolean activeForReal;
1526 if (maybeActiveStreamType == AudioSystem.STREAM_RING
1527 || maybeActiveStreamType == AudioSystem.STREAM_NOTIFICATION) {
1528 activeForReal = wasStreamActiveRecently(maybeActiveStreamType, 0);
1529 } else {
1530 activeForReal = AudioSystem.isStreamActive(maybeActiveStreamType, 0);
1531 }
1532 if (activeForReal || mVolumeControlStream == -1) {
1533 streamType = maybeActiveStreamType;
1534 } else {
1535 streamType = mVolumeControlStream;
1536 }
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001537 }
Eric Laurent402f7f22011-02-04 12:30:32 -08001538 }
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001539
1540 final boolean isMute = isMuteAdjust(direction);
1541
John Spurlock0a376af2015-03-26 16:24:12 -04001542 ensureValidStreamType(streamType);
John Spurlock33f4e042014-07-11 13:10:58 -04001543 final int resolvedStream = mStreamVolumeAlias[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001544
RoboErik2811dd32014-08-12 09:48:13 -07001545 // Play sounds on STREAM_RING only.
1546 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
John Spurlock33f4e042014-07-11 13:10:58 -04001547 resolvedStream != AudioSystem.STREAM_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001548 flags &= ~AudioManager.FLAG_PLAY_SOUND;
1549 }
1550
John Spurlock33f4e042014-07-11 13:10:58 -04001551 // For notifications/ring, show the ui before making any adjustments
RoboErik4197cb62015-01-21 15:45:32 -08001552 // Don't suppress mute/unmute requests
1553 if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
John Spurlock33f4e042014-07-11 13:10:58 -04001554 direction = 0;
1555 flags &= ~AudioManager.FLAG_PLAY_SOUND;
1556 flags &= ~AudioManager.FLAG_VIBRATE;
1557 if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
1558 }
1559
John Spurlock90874332015-03-10 16:00:54 -04001560 adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001561 }
1562
1563 /** @see AudioManager#adjustStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001564 public void adjustStreamVolume(int streamType, int direction, int flags,
1565 String callingPackage) {
Phil Weaverf1a9aff2017-03-23 17:21:29 -07001566 if ((streamType == AudioManager.STREAM_ACCESSIBILITY) && !canChangeAccessibilityVolume()) {
Jean-Michel Triviab2d9312017-03-13 15:33:39 -07001567 Log.w(TAG, "Trying to call adjustStreamVolume() for a11y without"
Phil Weaverf1a9aff2017-03-23 17:21:29 -07001568 + "CHANGE_ACCESSIBILITY_VOLUME / callingPackage=" + callingPackage);
Jean-Michel Triviab2d9312017-03-13 15:33:39 -07001569 return;
1570 }
Jean-Michel Trivicf170362017-08-24 17:24:57 -07001571 mVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_STREAM_VOL, streamType,
1572 direction/*val1*/, flags/*val2*/, callingPackage));
John Spurlock90874332015-03-10 16:00:54 -04001573 adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage,
1574 Binder.getCallingUid());
RoboErik0dac35a2014-08-12 15:48:49 -07001575 }
1576
Chinyue Chen6affe932018-01-24 14:51:43 +08001577 protected void adjustStreamVolume(int streamType, int direction, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001578 String callingPackage, String caller, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001579 if (mUseFixedVolume) {
1580 return;
1581 }
John Spurlock90874332015-03-10 16:00:54 -04001582 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream=" + streamType + ", dir=" + direction
1583 + ", flags=" + flags + ", caller=" + caller);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07001584
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001585 ensureValidDirection(direction);
1586 ensureValidStreamType(streamType);
1587
RoboErik4197cb62015-01-21 15:45:32 -08001588 boolean isMuteAdjust = isMuteAdjust(direction);
1589
John Spurlock3ce37252015-02-17 13:20:45 -05001590 if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
1591 return;
1592 }
1593
Nadav Bar6b7751d2017-12-24 16:03:08 +02001594 // If adjust is mute and the stream is STREAM_VOICE_CALL, make sure
1595 // that the calling app have the MODIFY_PHONE_STATE permission.
1596 if (isMuteAdjust &&
1597 streamType == AudioSystem.STREAM_VOICE_CALL &&
1598 mContext.checkCallingOrSelfPermission(
1599 android.Manifest.permission.MODIFY_PHONE_STATE)
1600 != PackageManager.PERMISSION_GRANTED) {
1601 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: adjustStreamVolume from pid="
1602 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
1603 return;
1604 }
1605
Eric Laurent96a33d12011-11-08 10:31:57 -08001606 // use stream type alias here so that streams with same alias have the same behavior,
1607 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
1608 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
Eric Laurent6d517662012-04-23 18:42:39 -07001609 int streamTypeAlias = mStreamVolumeAlias[streamType];
RoboErik4197cb62015-01-21 15:45:32 -08001610
Eric Laurentb024c302011-10-14 17:19:27 -07001611 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001612
1613 final int device = getDeviceForStream(streamTypeAlias);
Eric Laurent3ef75492012-11-28 12:12:23 -08001614
Eric Laurent42b041e2013-03-29 11:36:03 -07001615 int aliasIndex = streamState.getIndex(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001616 boolean adjustVolume = true;
Eric Laurent3ef75492012-11-28 12:12:23 -08001617 int step;
Eric Laurent24482012012-05-10 09:41:17 -07001618
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001619 // skip a2dp absolute volume control request when the device
1620 // is not an a2dp device
1621 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1622 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1623 return;
1624 }
1625
Kenny Guy70e0c582015-06-30 19:18:28 +01001626 // If we are being called by the system (e.g. hardware keys) check for current user
1627 // so we handle user restrictions correctly.
1628 if (uid == android.os.Process.SYSTEM_UID) {
1629 uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
1630 }
John Spurlock59dc9c12015-03-02 11:20:15 -05001631 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001632 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001633 return;
1634 }
1635
Eric Laurentfde16d52012-12-03 14:42:39 -08001636 // reset any pending volume command
1637 synchronized (mSafeMediaVolumeState) {
1638 mPendingVolumeCommand = null;
1639 }
1640
Eric Laurent3ef75492012-11-28 12:12:23 -08001641 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1642 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1643 ((device & mFixedVolumeDevices) != 0)) {
1644 flags |= AudioManager.FLAG_FIXED_VOLUME;
1645
1646 // Always toggle between max safe volume and 0 for fixed volume devices where safe
1647 // volume is enforced, and max and 0 for the others.
1648 // This is simulated by stepping by the full allowed volume range
1649 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1650 (device & mSafeMediaVolumeDevices) != 0) {
Eric Laurenteab40d12017-06-09 12:45:21 -07001651 step = safeMediaVolumeIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001652 } else {
1653 step = streamState.getMaxIndex();
1654 }
1655 if (aliasIndex != 0) {
1656 aliasIndex = step;
1657 }
1658 } else {
1659 // convert one UI step (+/-1) into a number of internal units on the stream alias
1660 step = rescaleIndex(10, streamType, streamTypeAlias);
1661 }
1662
Eric Laurent42b041e2013-03-29 11:36:03 -07001663 // If either the client forces allowing ringer modes for this adjustment,
1664 // or the stream type is one that is affected by ringer modes
1665 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlockee5ad722015-03-03 16:17:21 -05001666 (streamTypeAlias == getUiSoundsStreamType())) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001667 int ringerMode = getRingerModeInternal();
Eric Laurent42b041e2013-03-29 11:36:03 -07001668 // do not vibrate if already in vibrate mode
1669 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
1670 flags &= ~AudioManager.FLAG_VIBRATE;
Eric Laurent3ef75492012-11-28 12:12:23 -08001671 }
RoboErik5452e252015-02-06 15:33:53 -08001672 // Check if the ringer mode handles this adjustment. If it does we don't
1673 // need to adjust the volume further.
John Spurlock50ced3f2015-05-11 16:00:09 -04001674 final int result = checkForRingerModeChange(aliasIndex, direction, step,
Julia Reynoldsed783792016-04-08 15:27:35 -04001675 streamState.mIsMuted, callingPackage, flags);
John Spurlocka11b4af2014-06-01 11:52:23 -04001676 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
1677 // If suppressing a volume adjustment in silent mode, display the UI hint
1678 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
1679 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
1680 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001681 // If suppressing a volume down adjustment in vibrate mode, display the UI hint
1682 if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
1683 flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
1684 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001685 }
Beverlyd6964762018-02-16 14:07:03 -05001686
1687 // If the ringer mode or zen is muting the stream, do not change stream unless
1688 // it'll cause us to exit dnd
Julia Reynoldsed783792016-04-08 15:27:35 -04001689 if (!volumeAdjustmentAllowedByDnd(streamTypeAlias, flags)) {
John Spurlock50ced3f2015-05-11 16:00:09 -04001690 adjustVolume = false;
1691 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001692 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001693
Eric Laurent42b041e2013-03-29 11:36:03 -07001694 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
RoboErik5452e252015-02-06 15:33:53 -08001695 mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001696
RoboErik4197cb62015-01-21 15:45:32 -08001697 if (isMuteAdjust) {
1698 boolean state;
1699 if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
1700 state = !streamState.mIsMuted;
1701 } else {
1702 state = direction == AudioManager.ADJUST_MUTE;
1703 }
1704 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1705 setSystemAudioMute(state);
1706 }
1707 for (int stream = 0; stream < mStreamStates.length; stream++) {
1708 if (streamTypeAlias == mStreamVolumeAlias[stream]) {
Sungmin Choi841ed0a2015-07-26 23:09:49 -07001709 if (!(readCameraSoundForced()
1710 && (mStreamStates[stream].getStreamType()
1711 == AudioSystem.STREAM_SYSTEM_ENFORCED))) {
1712 mStreamStates[stream].mute(state);
1713 }
RoboErik4197cb62015-01-21 15:45:32 -08001714 }
1715 }
1716 } else if ((direction == AudioManager.ADJUST_RAISE) &&
Eric Laurent42b041e2013-03-29 11:36:03 -07001717 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
RoboErik4197cb62015-01-21 15:45:32 -08001718 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -04001719 mVolumeController.postDisplaySafeVolumeWarning(flags);
John Spurlock90874332015-03-10 16:00:54 -04001720 } else if (streamState.adjustIndex(direction * step, device, caller)
1721 || streamState.mIsMuted) {
RoboErik4197cb62015-01-21 15:45:32 -08001722 // Post message to set system volume (it in turn will post a
1723 // message to persist).
1724 if (streamState.mIsMuted) {
1725 // Unmute the stream if it was previously muted
RoboErik5452e252015-02-06 15:33:53 -08001726 if (direction == AudioManager.ADJUST_RAISE) {
1727 // unmute immediately for volume up
1728 streamState.mute(false);
1729 } else if (direction == AudioManager.ADJUST_LOWER) {
Muyuan Li1ed6df62016-06-18 11:16:52 -07001730 if (mIsSingleVolume) {
John Spurlocka48d7792015-03-03 17:35:57 -05001731 sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
1732 streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
1733 }
RoboErik5452e252015-02-06 15:33:53 -08001734 }
RoboErik4197cb62015-01-21 15:45:32 -08001735 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001736 sendMsg(mAudioHandler,
1737 MSG_SET_DEVICE_VOLUME,
1738 SENDMSG_QUEUE,
1739 device,
1740 0,
1741 streamState,
1742 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001743 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001744
Jungshik Jang41d97462014-06-30 22:26:29 +09001745 int newIndex = mStreamStates[streamType].getIndex(device);
Ajay Panickere3946c82018-02-26 16:04:15 -08001746
1747 // Check if volume update should be send to AVRCP
1748 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1749 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1750 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1751 synchronized (mA2dpAvrcpLock) {
1752 if (mA2dp != null && mAvrcpAbsVolSupported) {
1753 mA2dp.setAvrcpAbsoluteVolume(newIndex / 10);
1754 }
1755 }
1756 }
1757
Jakub Pawlowskif9570f32018-02-21 17:15:12 -08001758 // Check if volume update should be send to Hearing Aid
1759 if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
Jakub Pawlowski21b7f492018-03-22 12:31:21 -07001760 setHearingAidVolume(newIndex, streamType);
Jakub Pawlowskif9570f32018-02-21 17:15:12 -08001761 }
1762
Ajay Panickere3946c82018-02-26 16:04:15 -08001763 // Check if volume update should be sent to Hdmi system audio.
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001764 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1765 setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
1766 }
Eric Laurent212532b2014-07-21 15:43:18 -07001767 if (mHdmiManager != null) {
1768 synchronized (mHdmiManager) {
Eric Laurent212532b2014-07-21 15:43:18 -07001769 // mHdmiCecSink true => mHdmiPlaybackClient != null
1770 if (mHdmiCecSink &&
1771 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1772 oldIndex != newIndex) {
1773 synchronized (mHdmiPlaybackClient) {
1774 int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
RoboErik4197cb62015-01-21 15:45:32 -08001775 KeyEvent.KEYCODE_VOLUME_UP;
Donghyun Cho5f6d404e2016-03-17 20:39:25 +09001776 final long ident = Binder.clearCallingIdentity();
1777 try {
1778 mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1779 mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1780 } finally {
1781 Binder.restoreCallingIdentity(ident);
1782 }
Eric Laurent212532b2014-07-21 15:43:18 -07001783 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001784 }
1785 }
1786 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001787 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001788 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001789 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001790 }
1791
RoboErik5452e252015-02-06 15:33:53 -08001792 // Called after a delay when volume down is pressed while muted
1793 private void onUnmuteStream(int stream, int flags) {
1794 VolumeStreamState streamState = mStreamStates[stream];
1795 streamState.mute(false);
1796
1797 final int device = getDeviceForStream(stream);
1798 final int index = mStreamStates[stream].getIndex(device);
1799 sendVolumeUpdate(stream, index, index, flags);
1800 }
1801
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001802 private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
1803 if (mHdmiManager == null
1804 || mHdmiTvClient == null
1805 || oldVolume == newVolume
1806 || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
1807
1808 // Sets the audio volume of AVR when we are in system audio mode. The new volume info
1809 // is tranformed to HDMI-CEC commands and passed through CEC bus.
1810 synchronized (mHdmiManager) {
1811 if (!mHdmiSystemAudioSupported) return;
1812 synchronized (mHdmiTvClient) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001813 final long token = Binder.clearCallingIdentity();
1814 try {
Jinsuk Kim7a9ba422015-02-16 16:47:38 +09001815 mHdmiTvClient.setSystemAudioVolume(oldVolume, newVolume, maxVolume);
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001816 } finally {
1817 Binder.restoreCallingIdentity(token);
1818 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001819 }
1820 }
1821 }
1822
Eric Laurentfde16d52012-12-03 14:42:39 -08001823 // StreamVolumeCommand contains the information needed to defer the process of
1824 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1825 class StreamVolumeCommand {
1826 public final int mStreamType;
1827 public final int mIndex;
1828 public final int mFlags;
1829 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001830
Eric Laurentfde16d52012-12-03 14:42:39 -08001831 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1832 mStreamType = streamType;
1833 mIndex = index;
1834 mFlags = flags;
1835 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001836 }
John Spurlock35134602014-07-24 18:10:48 -04001837
1838 @Override
1839 public String toString() {
1840 return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1841 .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1842 .append(mDevice).append('}').toString();
1843 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001844 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001845
Julia Reynolds48034f82016-03-09 10:15:16 -05001846 private int getNewRingerMode(int stream, int index, int flags) {
Zak Cohen47798292017-11-30 12:34:20 -08001847 // setRingerMode does nothing if the device is single volume,so the value would be unchanged
1848 if (mIsSingleVolume) {
1849 return getRingerModeExternal();
1850 }
1851
John Spurlockee5ad722015-03-03 16:17:21 -05001852 // setting volume on ui sounds stream type also controls silent mode
Eric Laurent3ef75492012-11-28 12:12:23 -08001853 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlock75ae23c2015-06-02 16:26:43 -04001854 (stream == getUiSoundsStreamType())) {
Eric Laurent3ef75492012-11-28 12:12:23 -08001855 int newRingerMode;
1856 if (index == 0) {
1857 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlocka48d7792015-03-03 17:35:57 -05001858 : mVolumePolicy.volumeDownToEnterSilent ? AudioManager.RINGER_MODE_SILENT
Julia Reynolds48034f82016-03-09 10:15:16 -05001859 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001860 } else {
1861 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1862 }
Julia Reynolds48034f82016-03-09 10:15:16 -05001863 return newRingerMode;
1864 }
1865 return getRingerModeExternal();
1866 }
1867
1868 private boolean isAndroidNPlus(String caller) {
1869 try {
1870 final ApplicationInfo applicationInfo =
1871 mContext.getPackageManager().getApplicationInfoAsUser(
1872 caller, 0, UserHandle.getUserId(Binder.getCallingUid()));
1873 if (applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
1874 return true;
1875 }
1876 return false;
1877 } catch (PackageManager.NameNotFoundException e) {
1878 return true;
1879 }
1880 }
1881
1882 private boolean wouldToggleZenMode(int newMode) {
1883 if (getRingerModeExternal() == AudioManager.RINGER_MODE_SILENT
1884 && newMode != AudioManager.RINGER_MODE_SILENT) {
1885 return true;
1886 } else if (getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT
1887 && newMode == AudioManager.RINGER_MODE_SILENT) {
1888 return true;
1889 }
1890 return false;
1891 }
1892
1893 private void onSetStreamVolume(int streamType, int index, int flags, int device,
1894 String caller) {
1895 final int stream = mStreamVolumeAlias[streamType];
1896 setStreamVolumeInt(stream, index, device, false, caller);
1897 // setting volume on ui sounds stream type also controls silent mode
1898 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1899 (stream == getUiSoundsStreamType())) {
1900 setRingerMode(getNewRingerMode(stream, index, flags),
1901 TAG + ".onSetStreamVolume", false /*external*/);
Eric Laurent3ef75492012-11-28 12:12:23 -08001902 }
John Spurlock75ae23c2015-06-02 16:26:43 -04001903 // setting non-zero volume for a muted stream unmutes the stream and vice versa
1904 mStreamStates[stream].mute(index == 0);
Eric Laurentfde16d52012-12-03 14:42:39 -08001905 }
1906
1907 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001908 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
Phil Weaverf1a9aff2017-03-23 17:21:29 -07001909 if ((streamType == AudioManager.STREAM_ACCESSIBILITY) && !canChangeAccessibilityVolume()) {
Jean-Michel Triviab2d9312017-03-13 15:33:39 -07001910 Log.w(TAG, "Trying to call setStreamVolume() for a11y without"
Phil Weaverf1a9aff2017-03-23 17:21:29 -07001911 + " CHANGE_ACCESSIBILITY_VOLUME callingPackage=" + callingPackage);
Jean-Michel Triviab2d9312017-03-13 15:33:39 -07001912 return;
1913 }
Nadav Bar6b7751d2017-12-24 16:03:08 +02001914 if ((streamType == AudioManager.STREAM_VOICE_CALL) &&
1915 (index == 0) &&
1916 (mContext.checkCallingOrSelfPermission(
1917 android.Manifest.permission.MODIFY_PHONE_STATE)
1918 != PackageManager.PERMISSION_GRANTED)) {
1919 Log.w(TAG, "Trying to call setStreamVolume() for STREAM_VOICE_CALL and index 0 without"
1920 + " MODIFY_PHONE_STATE callingPackage=" + callingPackage);
1921 return;
1922 }
Jean-Michel Trivicf170362017-08-24 17:24:57 -07001923 mVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_SET_STREAM_VOL, streamType,
1924 index/*val1*/, flags/*val2*/, callingPackage));
John Spurlock90874332015-03-10 16:00:54 -04001925 setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
1926 Binder.getCallingUid());
RoboErik0dac35a2014-08-12 15:48:49 -07001927 }
1928
Phil Weaverf1a9aff2017-03-23 17:21:29 -07001929 private boolean canChangeAccessibilityVolume() {
1930 synchronized (mAccessibilityServiceUidsLock) {
1931 if (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
1932 android.Manifest.permission.CHANGE_ACCESSIBILITY_VOLUME)) {
1933 return true;
1934 }
1935 if (mAccessibilityServiceUids != null) {
1936 int callingUid = Binder.getCallingUid();
1937 for (int i = 0; i < mAccessibilityServiceUids.length; i++) {
1938 if (mAccessibilityServiceUids[i] == callingUid) {
1939 return true;
1940 }
1941 }
1942 }
1943 return false;
1944 }
1945 }
1946
RoboErik0dac35a2014-08-12 15:48:49 -07001947 private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
John Spurlock90874332015-03-10 16:00:54 -04001948 String caller, int uid) {
Jean-Michel Triviac487672016-11-11 10:05:18 -08001949 if (DEBUG_VOL) {
1950 Log.d(TAG, "setStreamVolume(stream=" + streamType+", index=" + index
1951 + ", calling=" + callingPackage + ")");
1952 }
Eric Laurent83a017b2013-03-19 18:15:31 -07001953 if (mUseFixedVolume) {
1954 return;
1955 }
1956
Eric Laurentfde16d52012-12-03 14:42:39 -08001957 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001958 int streamTypeAlias = mStreamVolumeAlias[streamType];
1959 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001960
1961 final int device = getDeviceForStream(streamType);
1962 int oldIndex;
1963
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001964 // skip a2dp absolute volume control request when the device
1965 // is not an a2dp device
1966 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1967 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1968 return;
1969 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001970 // If we are being called by the system (e.g. hardware keys) check for current user
1971 // so we handle user restrictions correctly.
1972 if (uid == android.os.Process.SYSTEM_UID) {
1973 uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
1974 }
John Spurlock59dc9c12015-03-02 11:20:15 -05001975 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001976 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001977 return;
1978 }
1979
Julia Reynolds48034f82016-03-09 10:15:16 -05001980 if (isAndroidNPlus(callingPackage)
1981 && wouldToggleZenMode(getNewRingerMode(streamTypeAlias, index, flags))
1982 && !mNm.isNotificationPolicyAccessGrantedForPackage(callingPackage)) {
1983 throw new SecurityException("Not allowed to change Do Not Disturb state");
1984 }
1985
Julia Reynoldsed783792016-04-08 15:27:35 -04001986 if (!volumeAdjustmentAllowedByDnd(streamTypeAlias, flags)) {
1987 return;
1988 }
1989
Eric Laurentfde16d52012-12-03 14:42:39 -08001990 synchronized (mSafeMediaVolumeState) {
1991 // reset any pending volume command
1992 mPendingVolumeCommand = null;
1993
Eric Laurent42b041e2013-03-29 11:36:03 -07001994 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001995
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001996 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001997
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001998 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1999 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
2000 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
2001 synchronized (mA2dpAvrcpLock) {
2002 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08002003 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07002004 }
John Du5a0cf7a2013-07-19 11:30:34 -07002005 }
2006 }
2007
Jakub Pawlowskif9570f32018-02-21 17:15:12 -08002008 if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
Jakub Pawlowski21b7f492018-03-22 12:31:21 -07002009 setHearingAidVolume(index, streamType);
Jakub Pawlowskif9570f32018-02-21 17:15:12 -08002010 }
2011
Jinsuk Kim336cdb42014-11-29 06:27:00 +09002012 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
2013 setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
Jungshik Jang41d97462014-06-30 22:26:29 +09002014 }
2015
Eric Laurentfde16d52012-12-03 14:42:39 -08002016 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07002017 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08002018 ((device & mFixedVolumeDevices) != 0)) {
2019 flags |= AudioManager.FLAG_FIXED_VOLUME;
2020
2021 // volume is either 0 or max allowed for fixed volume devices
2022 if (index != 0) {
2023 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
2024 (device & mSafeMediaVolumeDevices) != 0) {
Eric Laurenteab40d12017-06-09 12:45:21 -07002025 index = safeMediaVolumeIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08002026 } else {
2027 index = streamState.getMaxIndex();
2028 }
2029 }
2030 }
2031
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07002032 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04002033 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08002034 mPendingVolumeCommand = new StreamVolumeCommand(
2035 streamType, index, flags, device);
2036 } else {
John Spurlock90874332015-03-10 16:00:54 -04002037 onSetStreamVolume(streamType, index, flags, device, caller);
Eric Laurent42b041e2013-03-29 11:36:03 -07002038 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08002039 }
2040 }
Eric Laurent25101b02011-02-02 09:33:30 -08002041 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002042 }
2043
Beverlyd6964762018-02-16 14:07:03 -05002044 // No ringer or zen muted stream volumes can be changed unless it'll exit dnd
Julia Reynoldsed783792016-04-08 15:27:35 -04002045 private boolean volumeAdjustmentAllowedByDnd(int streamTypeAlias, int flags) {
Beverlyd6964762018-02-16 14:07:03 -05002046 switch (mNm.getZenMode()) {
2047 case Settings.Global.ZEN_MODE_OFF:
2048 return true;
2049 case Settings.Global.ZEN_MODE_NO_INTERRUPTIONS:
2050 case Settings.Global.ZEN_MODE_ALARMS:
2051 case Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
2052 return !isStreamMutedByRingerOrZenMode(streamTypeAlias)
2053 || streamTypeAlias == getUiSoundsStreamType()
2054 || (flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0;
Julia Reynoldsed783792016-04-08 15:27:35 -04002055 }
Beverlyd6964762018-02-16 14:07:03 -05002056
Julia Reynoldsed783792016-04-08 15:27:35 -04002057 return true;
2058 }
2059
Eric Laurent45c90ce2012-04-24 18:44:22 -07002060 /** @see AudioManager#forceVolumeControlStream(int) */
2061 public void forceVolumeControlStream(int streamType, IBinder cb) {
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07002062 if (DEBUG_VOL) { Log.d(TAG, String.format("forceVolumeControlStream(%d)", streamType)); }
Eric Laurent45c90ce2012-04-24 18:44:22 -07002063 synchronized(mForceControlStreamLock) {
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07002064 if (mVolumeControlStream != -1 && streamType != -1) {
2065 mUserSelectedVolumeControlStream = true;
2066 }
Eric Laurent45c90ce2012-04-24 18:44:22 -07002067 mVolumeControlStream = streamType;
2068 if (mVolumeControlStream == -1) {
2069 if (mForceControlStreamClient != null) {
2070 mForceControlStreamClient.release();
2071 mForceControlStreamClient = null;
2072 }
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07002073 mUserSelectedVolumeControlStream = false;
Eric Laurent45c90ce2012-04-24 18:44:22 -07002074 } else {
jianzhou21fb09f2018-02-28 14:03:15 +08002075 if (null == mForceControlStreamClient) {
2076 mForceControlStreamClient = new ForceControlStreamClient(cb);
2077 } else {
2078 if (mForceControlStreamClient.getBinder() == cb) {
2079 Log.d(TAG, "forceVolumeControlStream cb:" + cb + " is already linked.");
2080 } else {
2081 mForceControlStreamClient.release();
2082 mForceControlStreamClient = new ForceControlStreamClient(cb);
2083 }
2084 }
Eric Laurent45c90ce2012-04-24 18:44:22 -07002085 }
2086 }
2087 }
2088
2089 private class ForceControlStreamClient implements IBinder.DeathRecipient {
2090 private IBinder mCb; // To be notified of client's death
2091
2092 ForceControlStreamClient(IBinder cb) {
2093 if (cb != null) {
2094 try {
2095 cb.linkToDeath(this, 0);
2096 } catch (RemoteException e) {
2097 // Client has died!
2098 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
2099 cb = null;
2100 }
2101 }
2102 mCb = cb;
2103 }
2104
2105 public void binderDied() {
2106 synchronized(mForceControlStreamLock) {
2107 Log.w(TAG, "SCO client died");
2108 if (mForceControlStreamClient != this) {
2109 Log.w(TAG, "unregistered control stream client died");
2110 } else {
2111 mForceControlStreamClient = null;
2112 mVolumeControlStream = -1;
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07002113 mUserSelectedVolumeControlStream = false;
Eric Laurent45c90ce2012-04-24 18:44:22 -07002114 }
2115 }
2116 }
2117
2118 public void release() {
2119 if (mCb != null) {
2120 mCb.unlinkToDeath(this, 0);
2121 mCb = null;
2122 }
2123 }
jianzhou21fb09f2018-02-28 14:03:15 +08002124
2125 public IBinder getBinder() {
2126 return mCb;
2127 }
Eric Laurent45c90ce2012-04-24 18:44:22 -07002128 }
2129
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002130 private void sendBroadcastToAll(Intent intent) {
Christopher Tate267603f2015-01-20 14:21:21 -08002131 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
John Spurlock86490862015-02-25 11:22:52 -05002132 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002133 final long ident = Binder.clearCallingIdentity();
2134 try {
2135 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
2136 } finally {
2137 Binder.restoreCallingIdentity(ident);
2138 }
2139 }
2140
2141 private void sendStickyBroadcastToAll(Intent intent) {
John Spurlock86490862015-02-25 11:22:52 -05002142 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002143 final long ident = Binder.clearCallingIdentity();
2144 try {
2145 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
2146 } finally {
2147 Binder.restoreCallingIdentity(ident);
2148 }
2149 }
2150
Kenny Guy70e0c582015-06-30 19:18:28 +01002151 private int getCurrentUserId() {
2152 final long ident = Binder.clearCallingIdentity();
2153 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08002154 UserInfo currentUser = ActivityManager.getService().getCurrentUser();
Kenny Guy70e0c582015-06-30 19:18:28 +01002155 return currentUser.id;
2156 } catch (RemoteException e) {
2157 // Activity manager not running, nothing we can do assume user 0.
2158 } finally {
2159 Binder.restoreCallingIdentity(ident);
2160 }
Xiaohui Chen7c696362015-09-16 09:56:14 -07002161 return UserHandle.USER_SYSTEM;
Kenny Guy70e0c582015-06-30 19:18:28 +01002162 }
2163
Eric Laurent25101b02011-02-02 09:33:30 -08002164 // UI update and Broadcast Intent
Yue Li949865b2017-05-24 17:25:28 -07002165 protected void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
John Spurlock72966d62015-06-18 15:45:07 -04002166 streamType = mStreamVolumeAlias[streamType];
Eric Laurent25101b02011-02-02 09:33:30 -08002167
Jinsuk Kim336cdb42014-11-29 06:27:00 +09002168 if (streamType == AudioSystem.STREAM_MUSIC) {
2169 flags = updateFlagsForSystemAudio(flags);
Jungshik Jang1a6be6e2014-09-16 11:04:54 +09002170 }
John Spurlock3346a802014-05-20 16:25:37 -04002171 mVolumeController.postVolumeChanged(streamType, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002172 }
2173
Jinsuk Kim336cdb42014-11-29 06:27:00 +09002174 // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
2175 // receives volume notification from Audio Receiver.
2176 private int updateFlagsForSystemAudio(int flags) {
2177 if (mHdmiTvClient != null) {
2178 synchronized (mHdmiTvClient) {
2179 if (mHdmiSystemAudioSupported &&
2180 ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
2181 flags &= ~AudioManager.FLAG_SHOW_UI;
2182 }
2183 }
2184 }
2185 return flags;
2186 }
2187
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05002188 // UI update and Broadcast Intent
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05002189 private void sendMasterMuteUpdate(boolean muted, int flags) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09002190 mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
Justin Koh57978ed2012-04-03 17:37:58 -07002191 broadcastMasterMuteStatus(muted);
2192 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05002193
Justin Koh57978ed2012-04-03 17:37:58 -07002194 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05002195 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
2196 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07002197 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
2198 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002199 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05002200 }
2201
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002202 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002203 * Sets the stream state's index, and posts a message to set system volume.
2204 * This will not call out to the UI. Assumes a valid stream type.
2205 *
2206 * @param streamType Type of the stream
2207 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002208 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002209 * @param force If true, set the volume even if the desired volume is same
2210 * as the current volume.
2211 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002212 private void setStreamVolumeInt(int streamType,
2213 int index,
2214 int device,
John Spurlock90874332015-03-10 16:00:54 -04002215 boolean force,
2216 String caller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002217 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07002218
John Spurlock90874332015-03-10 16:00:54 -04002219 if (streamState.setIndex(index, device, caller) || force) {
Eric Laurent42b041e2013-03-29 11:36:03 -07002220 // Post message to set system volume (it in turn will post a message
2221 // to persist).
2222 sendMsg(mAudioHandler,
2223 MSG_SET_DEVICE_VOLUME,
2224 SENDMSG_QUEUE,
2225 device,
2226 0,
2227 streamState,
2228 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002229 }
2230 }
2231
Jinsuk Kim336cdb42014-11-29 06:27:00 +09002232 private void setSystemAudioMute(boolean state) {
2233 if (mHdmiManager == null || mHdmiTvClient == null) return;
2234 synchronized (mHdmiManager) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09002235 if (!mHdmiSystemAudioSupported) return;
2236 synchronized (mHdmiTvClient) {
2237 final long token = Binder.clearCallingIdentity();
2238 try {
2239 mHdmiTvClient.setSystemAudioMute(state);
2240 } finally {
2241 Binder.restoreCallingIdentity(token);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09002242 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09002243 }
2244 }
2245 }
2246
Eric Laurent25101b02011-02-02 09:33:30 -08002247 /** get stream mute state. */
2248 public boolean isStreamMute(int streamType) {
RoboErik7c82ced2014-12-04 17:39:08 -08002249 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
2250 streamType = getActiveStreamType(streamType);
2251 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002252 synchronized (VolumeStreamState.class) {
jiabin93d32ef2017-07-11 13:50:02 -07002253 ensureValidStreamType(streamType);
RoboErik4197cb62015-01-21 15:45:32 -08002254 return mStreamStates[streamType].mIsMuted;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002255 }
Eric Laurent25101b02011-02-02 09:33:30 -08002256 }
2257
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07002258 private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
2259 private IBinder mICallback; // To be notified of client's death
2260
2261 RmtSbmxFullVolDeathHandler(IBinder cb) {
2262 mICallback = cb;
2263 try {
2264 cb.linkToDeath(this, 0/*flags*/);
2265 } catch (RemoteException e) {
2266 Log.e(TAG, "can't link to death", e);
2267 }
2268 }
2269
2270 boolean isHandlerFor(IBinder cb) {
2271 return mICallback.equals(cb);
2272 }
2273
2274 void forget() {
2275 try {
2276 mICallback.unlinkToDeath(this, 0/*flags*/);
2277 } catch (NoSuchElementException e) {
2278 Log.e(TAG, "error unlinking to death", e);
2279 }
2280 }
2281
2282 public void binderDied() {
2283 Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
2284 forceRemoteSubmixFullVolume(false, mICallback);
2285 }
2286 }
2287
2288 /**
2289 * call must be synchronized on mRmtSbmxFullVolDeathHandlers
2290 * @return true if there is a registered death handler, false otherwise */
2291 private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
2292 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
2293 while (it.hasNext()) {
2294 final RmtSbmxFullVolDeathHandler handler = it.next();
2295 if (handler.isHandlerFor(cb)) {
2296 handler.forget();
2297 mRmtSbmxFullVolDeathHandlers.remove(handler);
2298 return true;
2299 }
2300 }
2301 return false;
2302 }
2303
2304 /** call synchronized on mRmtSbmxFullVolDeathHandlers */
2305 private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
2306 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
2307 while (it.hasNext()) {
2308 if (it.next().isHandlerFor(cb)) {
2309 return true;
2310 }
2311 }
2312 return false;
2313 }
2314
2315 private int mRmtSbmxFullVolRefCount = 0;
2316 private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
2317 new ArrayList<RmtSbmxFullVolDeathHandler>();
2318
2319 public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
2320 if (cb == null) {
2321 return;
2322 }
2323 if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
2324 android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
2325 Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
2326 return;
2327 }
2328 synchronized(mRmtSbmxFullVolDeathHandlers) {
2329 boolean applyRequired = false;
2330 if (startForcing) {
2331 if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
2332 mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
2333 if (mRmtSbmxFullVolRefCount == 0) {
2334 mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
2335 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
2336 applyRequired = true;
2337 }
2338 mRmtSbmxFullVolRefCount++;
2339 }
2340 } else {
2341 if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
2342 mRmtSbmxFullVolRefCount--;
2343 if (mRmtSbmxFullVolRefCount == 0) {
2344 mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
2345 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
2346 applyRequired = true;
2347 }
2348 }
2349 }
2350 if (applyRequired) {
2351 // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
2352 checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
2353 mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
2354 }
2355 }
2356 }
2357
Kenny Guy70e0c582015-06-30 19:18:28 +01002358 private void setMasterMuteInternal(boolean mute, int flags, String callingPackage, int uid,
2359 int userId) {
2360 // If we are being called by the system check for user we are going to change
2361 // so we handle user restrictions correctly.
2362 if (uid == android.os.Process.SYSTEM_UID) {
2363 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
2364 }
Makoto Onuki4f160732015-10-27 17:15:38 -07002365 // If OP_AUDIO_MASTER_VOLUME is set, disallow unmuting.
2366 if (!mute && mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
RoboErik7c82ced2014-12-04 17:39:08 -08002367 != AppOpsManager.MODE_ALLOWED) {
Julia Reynolds4a21b252014-06-04 11:11:43 -04002368 return;
2369 }
Kenny Guy70e0c582015-06-30 19:18:28 +01002370 if (userId != UserHandle.getCallingUserId() &&
2371 mContext.checkCallingOrSelfPermission(
2372 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
2373 != PackageManager.PERMISSION_GRANTED) {
2374 return;
2375 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08002376 setMasterMuteInternalNoCallerCheck(mute, flags, userId);
2377 }
2378
2379 private void setMasterMuteInternalNoCallerCheck(boolean mute, int flags, int userId) {
2380 if (DEBUG_VOL) {
2381 Log.d(TAG, String.format("Master mute %s, %d, user=%d", mute, flags, userId));
2382 }
Hongwei Wangdaba1242018-05-29 14:36:16 -07002383 if (!isPlatformAutomotive() && mUseFixedVolume) {
2384 // If using fixed volume, we don't mute.
2385 // TODO: remove the isPlatformAutomotive check here.
2386 // The isPlatformAutomotive check is added for safety but may not be necessary.
2387 return;
Makoto Onukid45a4a22015-11-02 17:17:38 -08002388 }
Kenny Guy70e0c582015-06-30 19:18:28 +01002389 if (getCurrentUserId() == userId) {
2390 if (mute != AudioSystem.getMasterMute()) {
2391 setSystemAudioMute(mute);
2392 AudioSystem.setMasterMute(mute);
Kenny Guy70e0c582015-06-30 19:18:28 +01002393 sendMasterMuteUpdate(mute, flags);
RoboErik7c82ced2014-12-04 17:39:08 -08002394
Kenny Guy70e0c582015-06-30 19:18:28 +01002395 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
2396 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute);
2397 sendBroadcastToAll(intent);
2398 }
Jason Simmons1ce5b262012-02-02 13:00:17 -08002399 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08002400 }
2401
2402 /** get master mute state. */
2403 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08002404 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08002405 }
2406
Kenny Guy70e0c582015-06-30 19:18:28 +01002407 public void setMasterMute(boolean mute, int flags, String callingPackage, int userId) {
2408 setMasterMuteInternal(mute, flags, callingPackage, Binder.getCallingUid(),
2409 userId);
John Spurlockee5ad722015-03-03 16:17:21 -05002410 }
2411
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002412 /** @see AudioManager#getStreamVolume(int) */
2413 public int getStreamVolume(int streamType) {
2414 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002415 int device = getDeviceForStream(streamType);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002416 synchronized (VolumeStreamState.class) {
2417 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07002418
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002419 // by convention getStreamVolume() returns 0 when a stream is muted.
RoboErik4197cb62015-01-21 15:45:32 -08002420 if (mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002421 index = 0;
2422 }
2423 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
2424 (device & mFixedVolumeDevices) != 0) {
2425 index = mStreamStates[streamType].getMaxIndex();
2426 }
2427 return (index + 5) / 10;
Eric Laurent42b041e2013-03-29 11:36:03 -07002428 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002429 }
2430
2431 /** @see AudioManager#getStreamMaxVolume(int) */
2432 public int getStreamMaxVolume(int streamType) {
2433 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07002434 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002435 }
2436
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08002437 /** @see AudioManager#getStreamMinVolumeInt(int) */
John Spurlockb6e19e32015-03-10 21:33:44 -04002438 public int getStreamMinVolume(int streamType) {
2439 ensureValidStreamType(streamType);
2440 return (mStreamStates[streamType].getMinIndex() + 5) / 10;
2441 }
2442
Eric Laurent25101b02011-02-02 09:33:30 -08002443 /** Get last audible volume before stream was muted. */
2444 public int getLastAudibleStreamVolume(int streamType) {
2445 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002446 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07002447 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08002448 }
2449
John Spurlockee5ad722015-03-03 16:17:21 -05002450 /** @see AudioManager#getUiSoundsStreamType() */
2451 public int getUiSoundsStreamType() {
John Spurlock4f0f1202014-08-05 13:28:33 -04002452 return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
Eric Laurent6d517662012-04-23 18:42:39 -07002453 }
2454
Makoto Onukid45a4a22015-11-02 17:17:38 -08002455 /** @see AudioManager#setMicrophoneMute(boolean) */
2456 @Override
Kenny Guy70e0c582015-06-30 19:18:28 +01002457 public void setMicrophoneMute(boolean on, String callingPackage, int userId) {
2458 // If we are being called by the system check for user we are going to change
2459 // so we handle user restrictions correctly.
2460 int uid = Binder.getCallingUid();
2461 if (uid == android.os.Process.SYSTEM_UID) {
2462 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
2463 }
Makoto Onuki4f160732015-10-27 17:15:38 -07002464 // If OP_MUTE_MICROPHONE is set, disallow unmuting.
2465 if (!on && mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, uid, callingPackage)
Kenny Guy70e0c582015-06-30 19:18:28 +01002466 != AppOpsManager.MODE_ALLOWED) {
Emily Bernier22c921a2014-05-28 11:01:32 -04002467 return;
2468 }
Jean-Michel Trivi4a4fea02014-08-29 18:14:09 -07002469 if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
2470 return;
2471 }
Kenny Guy70e0c582015-06-30 19:18:28 +01002472 if (userId != UserHandle.getCallingUserId() &&
2473 mContext.checkCallingOrSelfPermission(
2474 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
2475 != PackageManager.PERMISSION_GRANTED) {
2476 return;
2477 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08002478 setMicrophoneMuteNoCallerCheck(on, userId);
2479 }
Emily Bernier22c921a2014-05-28 11:01:32 -04002480
Makoto Onukid45a4a22015-11-02 17:17:38 -08002481 private void setMicrophoneMuteNoCallerCheck(boolean on, int userId) {
2482 if (DEBUG_VOL) {
2483 Log.d(TAG, String.format("Mic mute %s, user=%d", on, userId));
2484 }
Jean-Michel Trivi7be17d22017-12-21 18:09:21 -08002485 // only mute for the current user
Kenny Guy70e0c582015-06-30 19:18:28 +01002486 if (getCurrentUserId() == userId) {
Jean-Michel Trivi7be17d22017-12-21 18:09:21 -08002487 final boolean currentMute = AudioSystem.isMicrophoneMuted();
Eric Laurent66b69672018-01-26 18:30:51 -08002488 final long identity = Binder.clearCallingIdentity();
Kenny Guy70e0c582015-06-30 19:18:28 +01002489 AudioSystem.muteMicrophone(on);
Eric Laurent66b69672018-01-26 18:30:51 -08002490 Binder.restoreCallingIdentity(identity);
Jean-Michel Trivi7be17d22017-12-21 18:09:21 -08002491 if (on != currentMute) {
2492 mContext.sendBroadcast(new Intent(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED)
2493 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY));
2494 }
Kenny Guy70e0c582015-06-30 19:18:28 +01002495 }
Emily Bernier22c921a2014-05-28 11:01:32 -04002496 }
2497
John Spurlock661f2cf2014-11-17 10:29:10 -05002498 @Override
2499 public int getRingerModeExternal() {
2500 synchronized(mSettingsLock) {
2501 return mRingerModeExternal;
2502 }
2503 }
2504
2505 @Override
2506 public int getRingerModeInternal() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08002507 synchronized(mSettingsLock) {
2508 return mRingerMode;
2509 }
2510 }
2511
2512 private void ensureValidRingerMode(int ringerMode) {
John Spurlock97559372014-10-24 16:27:36 -04002513 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08002514 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
2515 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002516 }
2517
John Spurlock97559372014-10-24 16:27:36 -04002518 /** @see AudioManager#isValidRingerMode(int) */
2519 public boolean isValidRingerMode(int ringerMode) {
2520 return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
2521 }
2522
John Spurlock661f2cf2014-11-17 10:29:10 -05002523 public void setRingerModeExternal(int ringerMode, String caller) {
Julia Reynolds48034f82016-03-09 10:15:16 -05002524 if (isAndroidNPlus(caller) && wouldToggleZenMode(ringerMode)
2525 && !mNm.isNotificationPolicyAccessGrantedForPackage(caller)) {
2526 throw new SecurityException("Not allowed to change Do Not Disturb state");
2527 }
2528
John Spurlockaf88a192014-12-23 16:14:44 -05002529 setRingerMode(ringerMode, caller, true /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05002530 }
2531
2532 public void setRingerModeInternal(int ringerMode, String caller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05002533 enforceVolumeController("setRingerModeInternal");
John Spurlockaf88a192014-12-23 16:14:44 -05002534 setRingerMode(ringerMode, caller, false /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05002535 }
2536
Mike Digman55272862018-02-20 14:35:17 -08002537 public void silenceRingerModeInternal(String reason) {
2538 VibrationEffect effect = null;
2539 int ringerMode = AudioManager.RINGER_MODE_SILENT;
2540 int toastText = 0;
2541
2542 int silenceRingerSetting = Settings.Secure.VOLUME_HUSH_OFF;
2543 if (mContext.getResources()
2544 .getBoolean(com.android.internal.R.bool.config_volumeHushGestureEnabled)) {
2545 silenceRingerSetting = Settings.Secure.getIntForUser(mContentResolver,
2546 Settings.Secure.VOLUME_HUSH_GESTURE, VOLUME_HUSH_OFF,
2547 UserHandle.USER_CURRENT);
2548 }
2549
2550 switch(silenceRingerSetting) {
2551 case VOLUME_HUSH_MUTE:
2552 effect = VibrationEffect.get(VibrationEffect.EFFECT_DOUBLE_CLICK);
2553 ringerMode = AudioManager.RINGER_MODE_SILENT;
2554 toastText = com.android.internal.R.string.volume_dialog_ringer_guidance_silent;
2555 break;
2556 case VOLUME_HUSH_VIBRATE:
2557 effect = VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK);
2558 ringerMode = AudioManager.RINGER_MODE_VIBRATE;
2559 toastText = com.android.internal.R.string.volume_dialog_ringer_guidance_vibrate;
2560 break;
2561 }
2562 maybeVibrate(effect);
2563 setRingerModeInternal(ringerMode, reason);
2564 Toast.makeText(mContext, toastText, Toast.LENGTH_SHORT).show();
2565 }
2566
2567 private boolean maybeVibrate(VibrationEffect effect) {
2568 if (!mHasVibrator) {
2569 return false;
2570 }
2571 final boolean hapticsDisabled = Settings.System.getIntForUser(mContext.getContentResolver(),
2572 Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 0;
2573 if (hapticsDisabled) {
2574 return false;
2575 }
2576
2577 if (effect == null) {
2578 return false;
2579 }
2580 mVibrator.vibrate(
2581 Binder.getCallingUid(), mContext.getOpPackageName(), effect, VIBRATION_ATTRIBUTES);
2582 return true;
2583 }
2584
John Spurlock661f2cf2014-11-17 10:29:10 -05002585 private void setRingerMode(int ringerMode, String caller, boolean external) {
Muyuan Li1ed6df62016-06-18 11:16:52 -07002586 if (mUseFixedVolume || mIsSingleVolume) {
Eric Laurent83a017b2013-03-19 18:15:31 -07002587 return;
2588 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002589 if (caller == null || caller.length() == 0) {
2590 throw new IllegalArgumentException("Bad caller: " + caller);
2591 }
John Spurlock97559372014-10-24 16:27:36 -04002592 ensureValidRingerMode(ringerMode);
Eric Laurent24482012012-05-10 09:41:17 -07002593 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
2594 ringerMode = AudioManager.RINGER_MODE_SILENT;
2595 }
John Spurlockaf88a192014-12-23 16:14:44 -05002596 final long identity = Binder.clearCallingIdentity();
2597 try {
2598 synchronized (mSettingsLock) {
2599 final int ringerModeInternal = getRingerModeInternal();
2600 final int ringerModeExternal = getRingerModeExternal();
2601 if (external) {
2602 setRingerModeExt(ringerMode);
2603 if (mRingerModeDelegate != null) {
2604 ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
John Spurlocka48d7792015-03-03 17:35:57 -05002605 ringerMode, caller, ringerModeInternal, mVolumePolicy);
John Spurlockaf88a192014-12-23 16:14:44 -05002606 }
2607 if (ringerMode != ringerModeInternal) {
2608 setRingerModeInt(ringerMode, true /*persist*/);
2609 }
2610 } else /*internal*/ {
2611 if (ringerMode != ringerModeInternal) {
2612 setRingerModeInt(ringerMode, true /*persist*/);
2613 }
2614 if (mRingerModeDelegate != null) {
2615 ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
John Spurlocka48d7792015-03-03 17:35:57 -05002616 ringerMode, caller, ringerModeExternal, mVolumePolicy);
John Spurlockaf88a192014-12-23 16:14:44 -05002617 }
2618 setRingerModeExt(ringerMode);
John Spurlock57627792014-12-11 11:29:54 -05002619 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002620 }
John Spurlockaf88a192014-12-23 16:14:44 -05002621 } finally {
2622 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002623 }
2624 }
2625
John Spurlock661f2cf2014-11-17 10:29:10 -05002626 private void setRingerModeExt(int ringerMode) {
2627 synchronized(mSettingsLock) {
2628 if (ringerMode == mRingerModeExternal) return;
2629 mRingerModeExternal = ringerMode;
John Spurlocke5b42d92014-10-15 12:03:48 -04002630 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002631 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05002632 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
John Spurlocke5b42d92014-10-15 12:03:48 -04002633 }
2634
Jean-Michel Trivic106d9f2018-06-07 12:28:27 -07002635 @GuardedBy("mSettingsLock")
John Spurlock50ced3f2015-05-11 16:00:09 -04002636 private void muteRingerModeStreams() {
Beverlyd6964762018-02-16 14:07:03 -05002637 // Mute stream if not previously muted by ringer mode and (ringer mode
2638 // is not RINGER_MODE_NORMAL OR stream is zen muted) and stream is affected by ringer mode.
2639 // Unmute stream if previously muted by ringer/zen mode and ringer mode
Eric Laurent5b4e6542010-03-19 20:02:21 -07002640 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07002641 int numStreamTypes = AudioSystem.getNumStreamTypes();
Beverly925cde82018-01-23 09:31:23 -05002642
2643 if (mNm == null) {
2644 mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
2645 }
2646
Jack He6dd78c12018-02-12 21:00:24 -08002647 final int ringerMode = mRingerMode; // Read ringer mode as reading primitives is atomic
2648 final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE
2649 || ringerMode == AudioManager.RINGER_MODE_SILENT;
2650 final boolean shouldRingSco = ringerMode == AudioManager.RINGER_MODE_VIBRATE
2651 && isBluetoothScoOn();
2652 // Ask audio policy engine to force use Bluetooth SCO channel if needed
2653 final String eventSource = "muteRingerModeStreams() from u/pid:" + Binder.getCallingUid()
2654 + "/" + Binder.getCallingPid();
2655 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, AudioSystem.FOR_VIBRATE_RINGING,
2656 shouldRingSco ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE, eventSource, 0);
Beverly925cde82018-01-23 09:31:23 -05002657
Eric Laurent5b4e6542010-03-19 20:02:21 -07002658 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
Beverlyd6964762018-02-16 14:07:03 -05002659 final boolean isMuted = isStreamMutedByRingerOrZenMode(streamType);
Jack He6dd78c12018-02-12 21:00:24 -08002660 final boolean muteAllowedBySco =
2661 !(shouldRingSco && streamType == AudioSystem.STREAM_RING);
Beverlyd6964762018-02-16 14:07:03 -05002662 final boolean shouldZenMute = shouldZenMuteStream(streamType);
2663 final boolean shouldMute = shouldZenMute || (ringerModeMute
Jack He6dd78c12018-02-12 21:00:24 -08002664 && isStreamAffectedByRingerMode(streamType) && muteAllowedBySco);
John Spurlock661f2cf2014-11-17 10:29:10 -05002665 if (isMuted == shouldMute) continue;
2666 if (!shouldMute) {
2667 // unmute
2668 // ring and notifications volume should never be 0 when not silenced
John Spurlockd9c75db2015-04-28 11:19:13 -04002669 if (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002670 synchronized (VolumeStreamState.class) {
John Spurlocka48d7792015-03-03 17:35:57 -05002671 final VolumeStreamState vss = mStreamStates[streamType];
2672 for (int i = 0; i < vss.mIndexMap.size(); i++) {
2673 int device = vss.mIndexMap.keyAt(i);
2674 int value = vss.mIndexMap.valueAt(i);
John Spurlock2bb02ec2015-03-02 13:13:06 -05002675 if (value == 0) {
John Spurlocka48d7792015-03-03 17:35:57 -05002676 vss.setIndex(10, device, TAG);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002677 }
2678 }
Eric Laurent9e0d25f2015-02-12 17:28:53 -08002679 // Persist volume for stream ring when it is changed here
2680 final int device = getDeviceForStream(streamType);
2681 sendMsg(mAudioHandler,
2682 MSG_PERSIST_VOLUME,
2683 SENDMSG_QUEUE,
2684 device,
2685 0,
2686 mStreamStates[streamType],
2687 PERSIST_DELAY);
Eric Laurentb024c302011-10-14 17:19:27 -07002688 }
Eric Laurent9bcf4012009-06-12 06:09:28 -07002689 }
RoboErik4197cb62015-01-21 15:45:32 -08002690 mStreamStates[streamType].mute(false);
Beverlyd6964762018-02-16 14:07:03 -05002691 mRingerAndZenModeMutedStreams &= ~(1 << streamType);
Eric Laurent5b4e6542010-03-19 20:02:21 -07002692 } else {
John Spurlock661f2cf2014-11-17 10:29:10 -05002693 // mute
RoboErik4197cb62015-01-21 15:45:32 -08002694 mStreamStates[streamType].mute(true);
Beverlyd6964762018-02-16 14:07:03 -05002695 mRingerAndZenModeMutedStreams |= (1 << streamType);
Jason Parekhb1096152009-03-24 17:48:25 -07002696 }
2697 }
John Spurlock50ced3f2015-05-11 16:00:09 -04002698 }
2699
Beverly925cde82018-01-23 09:31:23 -05002700 private boolean isAlarm(int streamType) {
2701 return streamType == AudioSystem.STREAM_ALARM;
2702 }
2703
2704 private boolean isNotificationOrRinger(int streamType) {
2705 return streamType == AudioSystem.STREAM_NOTIFICATION
2706 || streamType == AudioSystem.STREAM_RING;
2707 }
2708
2709 private boolean isMedia(int streamType) {
Beverlyd6964762018-02-16 14:07:03 -05002710 return streamType == AudioSystem.STREAM_MUSIC;
2711 }
2712
2713
2714 private boolean isSystem(int streamType) {
2715 return streamType == AudioSystem.STREAM_SYSTEM;
Beverly925cde82018-01-23 09:31:23 -05002716 }
2717
John Spurlock50ced3f2015-05-11 16:00:09 -04002718 private void setRingerModeInt(int ringerMode, boolean persist) {
2719 final boolean change;
2720 synchronized(mSettingsLock) {
2721 change = mRingerMode != ringerMode;
2722 mRingerMode = ringerMode;
Jean-Michel Trivic106d9f2018-06-07 12:28:27 -07002723 muteRingerModeStreams();
John Spurlock50ced3f2015-05-11 16:00:09 -04002724 }
2725
Jason Parekhb1096152009-03-24 17:48:25 -07002726 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07002727 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002728 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07002729 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
2730 }
John Spurlockbcc10872014-11-28 15:29:21 -05002731 if (change) {
2732 // Send sticky broadcast
2733 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
2734 }
Jason Parekhb1096152009-03-24 17:48:25 -07002735 }
2736
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002737 /** @see AudioManager#shouldVibrate(int) */
2738 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002739 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002740
2741 switch (getVibrateSetting(vibrateType)) {
2742
2743 case AudioManager.VIBRATE_SETTING_ON:
John Spurlock57627792014-12-11 11:29:54 -05002744 return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002745
2746 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
John Spurlock57627792014-12-11 11:29:54 -05002747 return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002748
2749 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04002750 // return false, even for incoming calls
2751 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002752
2753 default:
2754 return false;
2755 }
2756 }
2757
2758 /** @see AudioManager#getVibrateSetting(int) */
2759 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002760 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002761 return (mVibrateSetting >> (vibrateType * 2)) & 3;
2762 }
2763
2764 /** @see AudioManager#setVibrateSetting(int, int) */
2765 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
2766
Eric Laurentbffc3d12012-05-07 17:43:49 -07002767 if (!mHasVibrator) return;
2768
John Spurlock61560172015-02-06 19:46:04 -05002769 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
2770 vibrateSetting);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002771
2772 // Broadcast change
2773 broadcastVibrateSetting(vibrateType);
2774
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002775 }
2776
Eric Laurent9272b4b2010-01-23 17:12:59 -08002777 private class SetModeDeathHandler implements IBinder.DeathRecipient {
2778 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002779 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002780 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
2781
Eric Laurent9f103de2011-09-08 15:04:23 -07002782 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08002783 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07002784 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002785 }
2786
2787 public void binderDied() {
Jack He89f97982018-05-02 19:10:56 -07002788 int oldModeOwnerPid = 0;
Eric Laurentd7454be2011-09-14 08:45:58 -07002789 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002790 synchronized(mSetModeDeathHandlers) {
2791 Log.w(TAG, "setMode() client died");
Jack He89f97982018-05-02 19:10:56 -07002792 if (!mSetModeDeathHandlers.isEmpty()) {
2793 oldModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2794 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08002795 int index = mSetModeDeathHandlers.indexOf(this);
2796 if (index < 0) {
2797 Log.w(TAG, "unregistered setMode() client died");
2798 } else {
John Spurlock90874332015-03-10 16:00:54 -04002799 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid, TAG);
Eric Laurent9272b4b2010-01-23 17:12:59 -08002800 }
2801 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002802 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
Jack He89f97982018-05-02 19:10:56 -07002803 // SCO connections not started by the application changing the mode when pid changes
2804 if ((newModeOwnerPid != oldModeOwnerPid) && (newModeOwnerPid != 0)) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07002805 final long ident = Binder.clearCallingIdentity();
2806 disconnectBluetoothSco(newModeOwnerPid);
2807 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07002808 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08002809 }
2810
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002811 public int getPid() {
2812 return mPid;
2813 }
2814
Eric Laurent9272b4b2010-01-23 17:12:59 -08002815 public void setMode(int mode) {
2816 mMode = mode;
2817 }
2818
2819 public int getMode() {
2820 return mMode;
2821 }
2822
2823 public IBinder getBinder() {
2824 return mCb;
2825 }
2826 }
2827
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002828 /** @see AudioManager#setMode(int) */
John Spurlock90874332015-03-10 16:00:54 -04002829 public void setMode(int mode, IBinder cb, String callingPackage) {
2830 if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ", callingPackage=" + callingPackage + ")"); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002831 if (!checkAudioSettingsPermission("setMode()")) {
2832 return;
2833 }
Eric Laurenta553c252009-07-17 12:17:14 -07002834
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07002835 if ( (mode == AudioSystem.MODE_IN_CALL) &&
2836 (mContext.checkCallingOrSelfPermission(
2837 android.Manifest.permission.MODIFY_PHONE_STATE)
2838 != PackageManager.PERMISSION_GRANTED)) {
2839 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
2840 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
2841 return;
2842 }
2843
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08002844 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07002845 return;
2846 }
2847
Jack He89f97982018-05-02 19:10:56 -07002848 int oldModeOwnerPid = 0;
Eric Laurentd7454be2011-09-14 08:45:58 -07002849 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002850 synchronized(mSetModeDeathHandlers) {
Jack He89f97982018-05-02 19:10:56 -07002851 if (!mSetModeDeathHandlers.isEmpty()) {
2852 oldModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2853 }
Eric Laurenta553c252009-07-17 12:17:14 -07002854 if (mode == AudioSystem.MODE_CURRENT) {
2855 mode = mMode;
2856 }
John Spurlock90874332015-03-10 16:00:54 -04002857 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid(), callingPackage);
Eric Laurent9f103de2011-09-08 15:04:23 -07002858 }
2859 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
Jack He89f97982018-05-02 19:10:56 -07002860 // SCO connections not started by the application changing the mode when pid changes
2861 if ((newModeOwnerPid != oldModeOwnerPid) && (newModeOwnerPid != 0)) {
2862 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07002863 }
2864 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002865
Eric Laurent9f103de2011-09-08 15:04:23 -07002866 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07002867 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07002868 // any mode other than NORMAL.
John Spurlock90874332015-03-10 16:00:54 -04002869 private int setModeInt(int mode, IBinder cb, int pid, String caller) {
2870 if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ", caller="
2871 + caller + ")"); }
Eric Laurentd7454be2011-09-14 08:45:58 -07002872 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002873 if (cb == null) {
2874 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07002875 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07002876 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002877
Eric Laurent9f103de2011-09-08 15:04:23 -07002878 SetModeDeathHandler hdlr = null;
2879 Iterator iter = mSetModeDeathHandlers.iterator();
2880 while (iter.hasNext()) {
2881 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
2882 if (h.getPid() == pid) {
2883 hdlr = h;
2884 // Remove from client list so that it is re-inserted at top of list
2885 iter.remove();
2886 hdlr.getBinder().unlinkToDeath(hdlr, 0);
2887 break;
2888 }
2889 }
2890 int status = AudioSystem.AUDIO_STATUS_OK;
Eric Laurent6afa6502017-09-28 15:18:19 -07002891 int actualMode;
Eric Laurent9f103de2011-09-08 15:04:23 -07002892 do {
Eric Laurent6afa6502017-09-28 15:18:19 -07002893 actualMode = mode;
Eric Laurent9f103de2011-09-08 15:04:23 -07002894 if (mode == AudioSystem.MODE_NORMAL) {
2895 // get new mode from client at top the list if any
2896 if (!mSetModeDeathHandlers.isEmpty()) {
2897 hdlr = mSetModeDeathHandlers.get(0);
2898 cb = hdlr.getBinder();
Eric Laurent6afa6502017-09-28 15:18:19 -07002899 actualMode = hdlr.getMode();
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002900 if (DEBUG_MODE) {
2901 Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
2902 + hdlr.mPid);
2903 }
Eric Laurentb9c9d262009-05-06 08:13:20 -07002904 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002905 } else {
2906 if (hdlr == null) {
2907 hdlr = new SetModeDeathHandler(cb, pid);
2908 }
2909 // Register for client death notification
2910 try {
2911 cb.linkToDeath(hdlr, 0);
2912 } catch (RemoteException e) {
2913 // Client has died!
2914 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
2915 }
2916
2917 // Last client to call setMode() is always at top of client list
2918 // as required by SetModeDeathHandler.binderDied()
2919 mSetModeDeathHandlers.add(0, hdlr);
2920 hdlr.setMode(mode);
2921 }
2922
Eric Laurent6afa6502017-09-28 15:18:19 -07002923 if (actualMode != mMode) {
Eric Laurent66b69672018-01-26 18:30:51 -08002924 final long identity = Binder.clearCallingIdentity();
Eric Laurent6afa6502017-09-28 15:18:19 -07002925 status = AudioSystem.setPhoneState(actualMode);
Eric Laurent66b69672018-01-26 18:30:51 -08002926 Binder.restoreCallingIdentity(identity);
Eric Laurent9f103de2011-09-08 15:04:23 -07002927 if (status == AudioSystem.AUDIO_STATUS_OK) {
Eric Laurent6afa6502017-09-28 15:18:19 -07002928 if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + actualMode); }
2929 mMode = actualMode;
Eric Laurent9f103de2011-09-08 15:04:23 -07002930 } else {
2931 if (hdlr != null) {
2932 mSetModeDeathHandlers.remove(hdlr);
2933 cb.unlinkToDeath(hdlr, 0);
2934 }
2935 // force reading new top of mSetModeDeathHandlers stack
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002936 if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002937 mode = AudioSystem.MODE_NORMAL;
2938 }
2939 } else {
2940 status = AudioSystem.AUDIO_STATUS_OK;
2941 }
2942 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
2943
2944 if (status == AudioSystem.AUDIO_STATUS_OK) {
Eric Laurent6afa6502017-09-28 15:18:19 -07002945 if (actualMode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002946 if (mSetModeDeathHandlers.isEmpty()) {
2947 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
2948 } else {
2949 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2950 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002951 }
Eric Laurent6afa6502017-09-28 15:18:19 -07002952 // Note: newModeOwnerPid is always 0 when actualMode is MODE_NORMAL
2953 mModeLogger.log(
2954 new PhoneStateEvent(caller, pid, mode, newModeOwnerPid, actualMode));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002955 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002956 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07002957 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
John Spurlock90874332015-03-10 16:00:54 -04002958 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, caller);
Eric Laurent6d517662012-04-23 18:42:39 -07002959
John Spurlock90874332015-03-10 16:00:54 -04002960 updateStreamVolumeAlias(true /*updateVolumes*/, caller);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002961 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002962 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002963 }
2964
2965 /** @see AudioManager#getMode() */
2966 public int getMode() {
2967 return mMode;
2968 }
2969
Eric Laurente78fced2013-03-15 16:03:47 -07002970 //==========================================================================================
2971 // Sound Effects
2972 //==========================================================================================
2973
2974 private static final String TAG_AUDIO_ASSETS = "audio_assets";
2975 private static final String ATTR_VERSION = "version";
2976 private static final String TAG_GROUP = "group";
2977 private static final String ATTR_GROUP_NAME = "name";
2978 private static final String TAG_ASSET = "asset";
2979 private static final String ATTR_ASSET_ID = "id";
2980 private static final String ATTR_ASSET_FILE = "file";
2981
2982 private static final String ASSET_FILE_VERSION = "1.0";
2983 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
2984
Glenn Kasten167d1a22013-07-23 16:24:41 -07002985 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002986
2987 class LoadSoundEffectReply {
2988 public int mStatus = 1;
2989 };
2990
Eric Laurente78fced2013-03-15 16:03:47 -07002991 private void loadTouchSoundAssetDefaults() {
2992 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
2993 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
2994 SOUND_EFFECT_FILES_MAP[i][0] = 0;
2995 SOUND_EFFECT_FILES_MAP[i][1] = -1;
2996 }
2997 }
2998
2999 private void loadTouchSoundAssets() {
3000 XmlResourceParser parser = null;
3001
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003002 // only load assets once.
3003 if (!SOUND_EFFECT_FILES.isEmpty()) {
3004 return;
3005 }
3006
Eric Laurente78fced2013-03-15 16:03:47 -07003007 loadTouchSoundAssetDefaults();
3008
3009 try {
3010 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
3011
3012 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
3013 String version = parser.getAttributeValue(null, ATTR_VERSION);
3014 boolean inTouchSoundsGroup = false;
3015
3016 if (ASSET_FILE_VERSION.equals(version)) {
3017 while (true) {
3018 XmlUtils.nextElement(parser);
3019 String element = parser.getName();
3020 if (element == null) {
3021 break;
3022 }
3023 if (element.equals(TAG_GROUP)) {
3024 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
3025 if (GROUP_TOUCH_SOUNDS.equals(name)) {
3026 inTouchSoundsGroup = true;
3027 break;
3028 }
3029 }
3030 }
3031 while (inTouchSoundsGroup) {
3032 XmlUtils.nextElement(parser);
3033 String element = parser.getName();
3034 if (element == null) {
3035 break;
3036 }
3037 if (element.equals(TAG_ASSET)) {
3038 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
3039 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
3040 int fx;
3041
3042 try {
3043 Field field = AudioManager.class.getField(id);
3044 fx = field.getInt(null);
3045 } catch (Exception e) {
3046 Log.w(TAG, "Invalid touch sound ID: "+id);
3047 continue;
3048 }
3049
3050 int i = SOUND_EFFECT_FILES.indexOf(file);
3051 if (i == -1) {
3052 i = SOUND_EFFECT_FILES.size();
3053 SOUND_EFFECT_FILES.add(file);
3054 }
3055 SOUND_EFFECT_FILES_MAP[fx][0] = i;
3056 } else {
3057 break;
3058 }
3059 }
3060 }
3061 } catch (Resources.NotFoundException e) {
3062 Log.w(TAG, "audio assets file not found", e);
3063 } catch (XmlPullParserException e) {
3064 Log.w(TAG, "XML parser exception reading touch sound assets", e);
3065 } catch (IOException e) {
3066 Log.w(TAG, "I/O exception reading touch sound assets", e);
3067 } finally {
3068 if (parser != null) {
3069 parser.close();
3070 }
3071 }
3072 }
3073
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003074 /** @see AudioManager#playSoundEffect(int) */
3075 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003076 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003077 }
3078
3079 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003080 public void playSoundEffectVolume(int effectType, float volume) {
Beverlyd6964762018-02-16 14:07:03 -05003081 // do not try to play the sound effect if the system stream is muted
3082 if (isStreamMutedByRingerOrZenMode(STREAM_SYSTEM)) {
3083 return;
3084 }
3085
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07003086 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
3087 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
3088 return;
3089 }
3090
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003091 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003092 effectType, (int) (volume * 1000), null, 0);
3093 }
3094
3095 /**
3096 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08003097 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003098 */
3099 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003100 int attempts = 3;
3101 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08003102
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003103 synchronized (reply) {
3104 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
3105 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08003106 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07003107 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003108 } catch (InterruptedException e) {
3109 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08003110 }
Eric Laurenta60e2122010-12-28 16:49:07 -08003111 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003112 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003113 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003114 }
3115
3116 /**
3117 * Unloads samples from the sound pool.
3118 * This method can be called to free some memory when
3119 * sound effects are disabled.
3120 */
3121 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003122 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003123 }
3124
Eric Laurenta60e2122010-12-28 16:49:07 -08003125 class SoundPoolListenerThread extends Thread {
3126 public SoundPoolListenerThread() {
3127 super("SoundPoolListenerThread");
3128 }
3129
3130 @Override
3131 public void run() {
3132
3133 Looper.prepare();
3134 mSoundPoolLooper = Looper.myLooper();
3135
3136 synchronized (mSoundEffectsLock) {
3137 if (mSoundPool != null) {
3138 mSoundPoolCallBack = new SoundPoolCallback();
3139 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
3140 }
3141 mSoundEffectsLock.notify();
3142 }
3143 Looper.loop();
3144 }
3145 }
3146
3147 private final class SoundPoolCallback implements
3148 android.media.SoundPool.OnLoadCompleteListener {
3149
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003150 int mStatus = 1; // 1 means neither error nor last sample loaded yet
3151 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08003152
3153 public int status() {
3154 return mStatus;
3155 }
3156
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003157 public void setSamples(int[] samples) {
3158 for (int i = 0; i < samples.length; i++) {
3159 // do not wait ack for samples rejected upfront by SoundPool
3160 if (samples[i] > 0) {
3161 mSamples.add(samples[i]);
3162 }
3163 }
Eric Laurenta60e2122010-12-28 16:49:07 -08003164 }
3165
3166 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
3167 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003168 int i = mSamples.indexOf(sampleId);
3169 if (i >= 0) {
3170 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08003171 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003172 if ((status != 0) || mSamples. isEmpty()) {
3173 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08003174 mSoundEffectsLock.notify();
3175 }
3176 }
3177 }
3178 }
3179
Eric Laurent4050c932009-07-08 02:52:14 -07003180 /** @see AudioManager#reloadAudioSettings() */
3181 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07003182 readAudioSettings(false /*userSwitch*/);
3183 }
3184
3185 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07003186 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
3187 readPersistedSettings();
Eric Laurentc0232482016-03-15 18:19:23 -07003188 readUserRestrictions();
Eric Laurent4050c932009-07-08 02:52:14 -07003189
3190 // restore volume settings
3191 int numStreamTypes = AudioSystem.getNumStreamTypes();
3192 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
3193 VolumeStreamState streamState = mStreamStates[streamType];
3194
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07003195 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
3196 continue;
3197 }
3198
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003199 streamState.readSettings();
3200 synchronized (VolumeStreamState.class) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07003201 // unmute stream that was muted but is not affect by mute anymore
RoboErik4197cb62015-01-21 15:45:32 -08003202 if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
Beverlyd6964762018-02-16 14:07:03 -05003203 !isStreamMutedByRingerOrZenMode(streamType)) || mUseFixedVolume)) {
RoboErik4197cb62015-01-21 15:45:32 -08003204 streamState.mIsMuted = false;
Eric Laurent4050c932009-07-08 02:52:14 -07003205 }
Eric Laurent4050c932009-07-08 02:52:14 -07003206 }
3207 }
3208
Eric Laurent33902db2012-10-07 16:15:07 -07003209 // apply new ringer mode before checking volume for alias streams so that streams
3210 // muted by ringer mode have the correct volume
John Spurlock661f2cf2014-11-17 10:29:10 -05003211 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent33902db2012-10-07 16:15:07 -07003212
Eric Laurent212532b2014-07-21 15:43:18 -07003213 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07003214 checkAllAliasStreamVolumes();
John Spurlockb6e19e32015-03-10 21:33:44 -04003215 checkMuteAffectedStreams();
Eric Laurent24482012012-05-10 09:41:17 -07003216
Eric Laurentd640bd32012-09-28 18:01:48 -07003217 synchronized (mSafeMediaVolumeState) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003218 mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
3219 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
3220 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
Eric Laurentd640bd32012-09-28 18:01:48 -07003221 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
John Spurlock90874332015-03-10 16:00:54 -04003222 enforceSafeMediaVolume(TAG);
Eric Laurentf1a457d2012-09-20 16:27:23 -07003223 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07003224 }
Eric Laurent4050c932009-07-08 02:52:14 -07003225 }
3226
Dianne Hackborn961cae92013-03-20 14:59:43 -07003227 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003228 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07003229 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
3230 return;
3231 }
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07003232 // for logging only
3233 final String eventSource = new StringBuilder("setSpeakerphoneOn(").append(on)
3234 .append(") from u/pid:").append(Binder.getCallingUid()).append("/")
3235 .append(Binder.getCallingPid()).toString();
Johan Gustavsson7337bee2013-03-01 15:53:30 +01003236
3237 if (on) {
3238 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
3239 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07003240 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE,
3241 eventSource, 0);
Johan Gustavsson7337bee2013-03-01 15:53:30 +01003242 }
3243 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
3244 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
3245 mForcedUseForComm = AudioSystem.FORCE_NONE;
3246 }
Eric Laurentfa640152011-03-12 15:59:51 -08003247
Sharad Sangle1d188442017-05-09 16:05:40 +05303248 mForcedUseForCommExt = mForcedUseForComm;
Eric Laurentafbb0472011-12-15 09:04:23 -08003249 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07003250 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003251 }
3252
3253 /** @see AudioManager#isSpeakerphoneOn() */
3254 public boolean isSpeakerphoneOn() {
Sharad Sangle1d188442017-05-09 16:05:40 +05303255 return (mForcedUseForCommExt == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003256 }
3257
Dianne Hackborn961cae92013-03-20 14:59:43 -07003258 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurent48221252015-09-24 18:41:48 -07003259 public void setBluetoothScoOn(boolean on) {
Eric Laurentdc1d17a2009-09-10 00:48:21 -07003260 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
3261 return;
3262 }
Sharad Sangle1d188442017-05-09 16:05:40 +05303263
3264 // Only enable calls from system components
Vitor Albuquerquec3bb48c2018-03-07 10:39:59 -03003265 if (UserHandle.getCallingAppId() >= FIRST_APPLICATION_UID) {
Sharad Sangle1d188442017-05-09 16:05:40 +05303266 mForcedUseForCommExt = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE;
3267 return;
3268 }
3269
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07003270 // for logging only
3271 final String eventSource = new StringBuilder("setBluetoothScoOn(").append(on)
3272 .append(") from u/pid:").append(Binder.getCallingUid()).append("/")
3273 .append(Binder.getCallingPid()).toString();
3274 setBluetoothScoOnInt(on, eventSource);
Eric Laurent48221252015-09-24 18:41:48 -07003275 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01003276
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07003277 public void setBluetoothScoOnInt(boolean on, String eventSource) {
Jack He89f97982018-05-02 19:10:56 -07003278 Log.i(TAG, "setBluetoothScoOnInt: " + on + " " + eventSource);
Johan Gustavsson7337bee2013-03-01 15:53:30 +01003279 if (on) {
Sharad Sangle1d188442017-05-09 16:05:40 +05303280 // do not accept SCO ON if SCO audio is not connected
Jack He8dd33942018-01-17 15:45:12 -08003281 synchronized (mScoClients) {
Jack He89f97982018-05-02 19:10:56 -07003282 if ((mBluetoothHeadset != null)
3283 && (mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
3284 != BluetoothHeadset.STATE_AUDIO_CONNECTED)) {
3285 mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO;
3286 Log.w(TAG, "setBluetoothScoOnInt(true) failed because "
3287 + mBluetoothHeadsetDevice + " is not in audio connected mode");
3288 return;
Sharad Sangle1d188442017-05-09 16:05:40 +05303289 }
3290 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01003291 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
3292 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
3293 mForcedUseForComm = AudioSystem.FORCE_NONE;
3294 }
Sharad Sangle1d188442017-05-09 16:05:40 +05303295 mForcedUseForCommExt = mForcedUseForComm;
3296 AudioSystem.setParameters("BT_SCO="+ (on ? "on" : "off"));
Eric Laurentafbb0472011-12-15 09:04:23 -08003297 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07003298 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08003299 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07003300 AudioSystem.FOR_RECORD, mForcedUseForComm, eventSource, 0);
Jack He6dd78c12018-02-12 21:00:24 -08003301 // Un-mute ringtone stream volume
3302 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003303 }
3304
3305 /** @see AudioManager#isBluetoothScoOn() */
3306 public boolean isBluetoothScoOn() {
Sharad Sangle1d188442017-05-09 16:05:40 +05303307 return (mForcedUseForCommExt == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003308 }
3309
Sungsoocf09fe62016-09-28 16:21:48 +09003310 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07003311 public void setBluetoothA2dpOn(boolean on) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07003312 // for logging only
3313 final String eventSource = new StringBuilder("setBluetoothA2dpOn(").append(on)
3314 .append(") from u/pid:").append(Binder.getCallingUid()).append("/")
3315 .append(Binder.getCallingPid()).toString();
3316
Sungsoocf09fe62016-09-28 16:21:48 +09003317 synchronized (mBluetoothA2dpEnabledLock) {
zengjing452da332018-05-25 11:15:20 +08003318 if (mBluetoothA2dpEnabled == on) {
3319 return;
3320 }
Sungsoocf09fe62016-09-28 16:21:48 +09003321 mBluetoothA2dpEnabled = on;
3322 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
3323 AudioSystem.FOR_MEDIA,
3324 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07003325 eventSource, 0);
Sungsoocf09fe62016-09-28 16:21:48 +09003326 }
Eric Laurent78472112012-05-21 08:57:21 -07003327 }
3328
Sungsoocf09fe62016-09-28 16:21:48 +09003329 /** @see AudioManager#isBluetoothA2dpOn() */
Eric Laurent78472112012-05-21 08:57:21 -07003330 public boolean isBluetoothA2dpOn() {
Sungsoocf09fe62016-09-28 16:21:48 +09003331 synchronized (mBluetoothA2dpEnabledLock) {
3332 return mBluetoothA2dpEnabled;
3333 }
Eric Laurent78472112012-05-21 08:57:21 -07003334 }
3335
Eric Laurent3def1ee2010-03-17 23:26:26 -07003336 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07003337 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
3338 int scoAudioMode =
3339 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
Liejun Taof4e51d82014-07-16 11:18:29 -07003340 SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
Eric Laurent83900752014-05-15 15:14:22 -07003341 startBluetoothScoInt(cb, scoAudioMode);
3342 }
3343
3344 /** @see AudioManager#startBluetoothScoVirtualCall() */
3345 public void startBluetoothScoVirtualCall(IBinder cb) {
3346 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
3347 }
3348
3349 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07003350 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07003351 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07003352 return;
3353 }
Eric Laurent854938a2011-02-22 12:05:20 -08003354 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07003355 // The calling identity must be cleared before calling ScoClient.incCount().
3356 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
3357 // and this must be done on behalf of system server to make sure permissions are granted.
3358 // The caller identity must be cleared after getScoClient() because it is needed if a new
3359 // client is created.
3360 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07003361 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08003362 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003363 }
3364
3365 /** @see AudioManager#stopBluetoothSco() */
3366 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07003367 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07003368 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07003369 return;
3370 }
Eric Laurent854938a2011-02-22 12:05:20 -08003371 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07003372 // The calling identity must be cleared before calling ScoClient.decCount().
3373 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
3374 // and this must be done on behalf of system server to make sure permissions are granted.
3375 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08003376 if (client != null) {
3377 client.decCount();
3378 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08003379 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003380 }
3381
Eric Laurent78472112012-05-21 08:57:21 -07003382
Eric Laurent3def1ee2010-03-17 23:26:26 -07003383 private class ScoClient implements IBinder.DeathRecipient {
3384 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07003385 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003386 private int mStartcount; // number of SCO connections started by this client
3387
3388 ScoClient(IBinder cb) {
3389 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07003390 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07003391 mStartcount = 0;
3392 }
3393
3394 public void binderDied() {
3395 synchronized(mScoClients) {
3396 Log.w(TAG, "SCO client died");
3397 int index = mScoClients.indexOf(this);
3398 if (index < 0) {
3399 Log.w(TAG, "unregistered SCO client died");
3400 } else {
3401 clearCount(true);
3402 mScoClients.remove(this);
3403 }
3404 }
3405 }
3406
Eric Laurent83900752014-05-15 15:14:22 -07003407 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07003408 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07003409 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003410 if (mStartcount == 0) {
3411 try {
3412 mCb.linkToDeath(this, 0);
3413 } catch (RemoteException e) {
3414 // client has already died!
3415 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
3416 }
3417 }
3418 mStartcount++;
3419 }
3420 }
3421
3422 public void decCount() {
3423 synchronized(mScoClients) {
3424 if (mStartcount == 0) {
3425 Log.w(TAG, "ScoClient.decCount() already 0");
3426 } else {
3427 mStartcount--;
3428 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07003429 try {
3430 mCb.unlinkToDeath(this, 0);
3431 } catch (NoSuchElementException e) {
3432 Log.w(TAG, "decCount() going to 0 but not registered to binder");
3433 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07003434 }
Eric Laurentc18c9132013-04-12 17:24:56 -07003435 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003436 }
3437 }
3438 }
3439
3440 public void clearCount(boolean stopSco) {
3441 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07003442 if (mStartcount != 0) {
3443 try {
3444 mCb.unlinkToDeath(this, 0);
3445 } catch (NoSuchElementException e) {
3446 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
3447 }
3448 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07003449 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003450 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003451 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003452 }
3453 }
3454 }
3455
3456 public int getCount() {
3457 return mStartcount;
3458 }
3459
3460 public IBinder getBinder() {
3461 return mCb;
3462 }
3463
Eric Laurentd7454be2011-09-14 08:45:58 -07003464 public int getPid() {
3465 return mCreatorPid;
3466 }
3467
Eric Laurent3def1ee2010-03-17 23:26:26 -07003468 public int totalCount() {
3469 synchronized(mScoClients) {
3470 int count = 0;
Jack He89f97982018-05-02 19:10:56 -07003471 for (ScoClient mScoClient : mScoClients) {
3472 count += mScoClient.getCount();
Eric Laurent3def1ee2010-03-17 23:26:26 -07003473 }
3474 return count;
3475 }
3476 }
3477
Eric Laurent83900752014-05-15 15:14:22 -07003478 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08003479 checkScoAudioState();
Jack He89f97982018-05-02 19:10:56 -07003480 int clientCount = totalCount();
3481 if (clientCount != 0) {
3482 Log.i(TAG, "requestScoState: state=" + state + ", scoAudioMode=" + scoAudioMode
3483 + ", clientCount=" + clientCount);
3484 return;
3485 }
3486 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
3487 // Make sure that the state transitions to CONNECTING even if we cannot initiate
3488 // the connection.
3489 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
3490 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
3491 // currently controlled by the same client process.
3492 synchronized(mSetModeDeathHandlers) {
3493 int modeOwnerPid = mSetModeDeathHandlers.isEmpty()
3494 ? 0 : mSetModeDeathHandlers.get(0).getPid();
3495 if (modeOwnerPid != 0 && (modeOwnerPid != mCreatorPid)) {
3496 Log.w(TAG, "requestScoState: audio mode is not NORMAL and modeOwnerPid "
3497 + modeOwnerPid + " != creatorPid " + mCreatorPid);
3498 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3499 return;
Eric Laurentdc03c612011-04-01 10:59:41 -07003500 }
Jack He89f97982018-05-02 19:10:56 -07003501 switch (mScoAudioState) {
3502 case SCO_STATE_INACTIVE:
3503 mScoAudioMode = scoAudioMode;
3504 if (scoAudioMode == SCO_MODE_UNDEFINED) {
3505 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
3506 if (mBluetoothHeadsetDevice != null) {
3507 mScoAudioMode = Settings.Global.getInt(mContentResolver,
3508 "bluetooth_sco_channel_"
3509 + mBluetoothHeadsetDevice.getAddress(),
3510 SCO_MODE_VIRTUAL_CALL);
3511 if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
3512 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
3513 }
3514 }
Eric Laurentc18c9132013-04-12 17:24:56 -07003515 }
Jack He89f97982018-05-02 19:10:56 -07003516 if (mBluetoothHeadset == null) {
3517 if (getBluetoothHeadset()) {
3518 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
3519 } else {
3520 Log.w(TAG, "requestScoState: getBluetoothHeadset failed during"
3521 + " connection, mScoAudioMode=" + mScoAudioMode);
3522 broadcastScoConnectionState(
3523 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3524 }
3525 break;
3526 }
3527 if (mBluetoothHeadsetDevice == null) {
3528 Log.w(TAG, "requestScoState: no active device while connecting,"
3529 + " mScoAudioMode=" + mScoAudioMode);
3530 broadcastScoConnectionState(
3531 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3532 break;
3533 }
3534 if (connectBluetoothScoAudioHelper(mBluetoothHeadset,
3535 mBluetoothHeadsetDevice, mScoAudioMode)) {
3536 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
3537 } else {
3538 Log.w(TAG, "requestScoState: connect to " + mBluetoothHeadsetDevice
3539 + " failed, mScoAudioMode=" + mScoAudioMode);
3540 broadcastScoConnectionState(
3541 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3542 }
3543 break;
3544 case SCO_STATE_DEACTIVATING:
3545 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
3546 break;
3547 case SCO_STATE_DEACTIVATE_REQ:
3548 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
3549 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
3550 break;
3551 default:
3552 Log.w(TAG, "requestScoState: failed to connect in state "
3553 + mScoAudioState + ", scoAudioMode=" + scoAudioMode);
3554 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3555 break;
Liejun Taof4e51d82014-07-16 11:18:29 -07003556
Jack He89f97982018-05-02 19:10:56 -07003557 }
3558 }
3559 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
3560 switch (mScoAudioState) {
3561 case SCO_STATE_ACTIVE_INTERNAL:
3562 if (mBluetoothHeadset == null) {
3563 if (getBluetoothHeadset()) {
3564 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
3565 } else {
3566 Log.w(TAG, "requestScoState: getBluetoothHeadset failed during"
3567 + " disconnection, mScoAudioMode=" + mScoAudioMode);
Eric Laurentdc03c612011-04-01 10:59:41 -07003568 mScoAudioState = SCO_STATE_INACTIVE;
3569 broadcastScoConnectionState(
3570 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3571 }
Jack He89f97982018-05-02 19:10:56 -07003572 break;
Eric Laurentdc03c612011-04-01 10:59:41 -07003573 }
Jack He89f97982018-05-02 19:10:56 -07003574 if (mBluetoothHeadsetDevice == null) {
3575 mScoAudioState = SCO_STATE_INACTIVE;
3576 broadcastScoConnectionState(
3577 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3578 break;
3579 }
3580 if (disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
3581 mBluetoothHeadsetDevice, mScoAudioMode)) {
3582 mScoAudioState = SCO_STATE_DEACTIVATING;
3583 } else {
3584 mScoAudioState = SCO_STATE_INACTIVE;
3585 broadcastScoConnectionState(
3586 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3587 }
3588 break;
3589 case SCO_STATE_ACTIVATE_REQ:
Eric Laurentdc03c612011-04-01 10:59:41 -07003590 mScoAudioState = SCO_STATE_INACTIVE;
3591 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Jack He89f97982018-05-02 19:10:56 -07003592 break;
3593 default:
3594 Log.w(TAG, "requestScoState: failed to disconnect in state "
3595 + mScoAudioState + ", scoAudioMode=" + scoAudioMode);
3596 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3597 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003598 }
3599 }
3600 }
3601 }
3602
Eric Laurent62ef7672010-11-24 10:58:32 -08003603 private void checkScoAudioState() {
Jack He89f97982018-05-02 19:10:56 -07003604 synchronized (mScoClients) {
3605 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
3606 mScoAudioState == SCO_STATE_INACTIVE &&
3607 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
3608 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
3609 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
3610 }
Eric Laurent62ef7672010-11-24 10:58:32 -08003611 }
3612 }
3613
Jack He89f97982018-05-02 19:10:56 -07003614
Eric Laurent854938a2011-02-22 12:05:20 -08003615 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07003616 synchronized(mScoClients) {
Jack He89f97982018-05-02 19:10:56 -07003617 for (ScoClient existingClient : mScoClients) {
3618 if (existingClient.getBinder() == cb) {
3619 return existingClient;
3620 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07003621 }
Eric Laurent854938a2011-02-22 12:05:20 -08003622 if (create) {
Jack He89f97982018-05-02 19:10:56 -07003623 ScoClient newClient = new ScoClient(cb);
3624 mScoClients.add(newClient);
3625 return newClient;
Eric Laurent854938a2011-02-22 12:05:20 -08003626 }
Jack He89f97982018-05-02 19:10:56 -07003627 return null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003628 }
3629 }
3630
Eric Laurentd7454be2011-09-14 08:45:58 -07003631 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07003632 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08003633 ScoClient savedClient = null;
Jack He89f97982018-05-02 19:10:56 -07003634 for (ScoClient cl : mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07003635 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08003636 cl.clearCount(stopSco);
3637 } else {
3638 savedClient = cl;
3639 }
3640 }
3641 mScoClients.clear();
3642 if (savedClient != null) {
3643 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003644 }
3645 }
3646 }
3647
Eric Laurentdc03c612011-04-01 10:59:41 -07003648 private boolean getBluetoothHeadset() {
3649 boolean result = false;
3650 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
3651 if (adapter != null) {
3652 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
3653 BluetoothProfile.HEADSET);
3654 }
3655 // If we could not get a bluetooth headset proxy, send a failure message
3656 // without delay to reset the SCO audio state and clear SCO clients.
3657 // If we could get a proxy, send a delayed failure message that will reset our state
3658 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08003659 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07003660 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
3661 return result;
3662 }
3663
Jack He33c3a172018-05-08 14:51:07 -07003664 /**
3665 * Disconnect all SCO connections started by {@link AudioManager} except those started by
3666 * {@param exceptPid}
3667 *
3668 * @param exceptPid pid whose SCO connections through {@link AudioManager} should be kept
3669 */
Eric Laurentd7454be2011-09-14 08:45:58 -07003670 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07003671 synchronized(mScoClients) {
3672 checkScoAudioState();
Jack He33c3a172018-05-08 14:51:07 -07003673 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL) {
3674 return;
Eric Laurentdc03c612011-04-01 10:59:41 -07003675 }
Jack He33c3a172018-05-08 14:51:07 -07003676 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07003677 }
3678 }
3679
Jack He89f97982018-05-02 19:10:56 -07003680 private static boolean disconnectBluetoothScoAudioHelper(BluetoothHeadset bluetoothHeadset,
3681 BluetoothDevice device, int scoAudioMode) {
3682 switch (scoAudioMode) {
3683 case SCO_MODE_RAW:
3684 return bluetoothHeadset.disconnectAudio();
3685 case SCO_MODE_VIRTUAL_CALL:
3686 return bluetoothHeadset.stopScoUsingVirtualVoiceCall();
3687 case SCO_MODE_VR:
3688 return bluetoothHeadset.stopVoiceRecognition(device);
3689 default:
3690 return false;
3691 }
3692 }
3693
3694 private static boolean connectBluetoothScoAudioHelper(BluetoothHeadset bluetoothHeadset,
3695 BluetoothDevice device, int scoAudioMode) {
3696 switch (scoAudioMode) {
3697 case SCO_MODE_RAW:
3698 return bluetoothHeadset.connectAudio();
3699 case SCO_MODE_VIRTUAL_CALL:
3700 return bluetoothHeadset.startScoUsingVirtualVoiceCall();
3701 case SCO_MODE_VR:
3702 return bluetoothHeadset.startVoiceRecognition(device);
3703 default:
3704 return false;
3705 }
3706 }
3707
Eric Laurentdc03c612011-04-01 10:59:41 -07003708 private void resetBluetoothSco() {
3709 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07003710 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07003711 mScoAudioState = SCO_STATE_INACTIVE;
3712 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3713 }
Eric Laurent48221252015-09-24 18:41:48 -07003714 AudioSystem.setParameters("A2dpSuspended=false");
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07003715 setBluetoothScoOnInt(false, "resetBluetoothSco");
Eric Laurentdc03c612011-04-01 10:59:41 -07003716 }
3717
3718 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08003719 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
3720 SENDMSG_QUEUE, state, 0, null, 0);
3721 }
3722
3723 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07003724 if (state != mScoConnectionState) {
3725 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
3726 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
3727 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
3728 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003729 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07003730 mScoConnectionState = state;
3731 }
3732 }
3733
Jack He8dd33942018-01-17 15:45:12 -08003734 private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) {
Eric Laurent98859b22015-06-12 14:35:59 -07003735 if (btDevice == null) {
Jack He8dd33942018-01-17 15:45:12 -08003736 return true;
Eric Laurent98859b22015-06-12 14:35:59 -07003737 }
Eric Laurent98859b22015-06-12 14:35:59 -07003738 String address = btDevice.getAddress();
3739 BluetoothClass btClass = btDevice.getBluetoothClass();
Eric Laurent98859b22015-06-12 14:35:59 -07003740 int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
Ugo Yu8f8ee842018-05-14 19:30:32 +08003741 int[] outDeviceTypes = {
3742 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
3743 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET,
3744 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT
3745 };
Eric Laurent98859b22015-06-12 14:35:59 -07003746 if (btClass != null) {
3747 switch (btClass.getDeviceClass()) {
Jack He8dd33942018-01-17 15:45:12 -08003748 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
3749 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
Ugo Yu8f8ee842018-05-14 19:30:32 +08003750 outDeviceTypes = new int[] { AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET };
Jack He8dd33942018-01-17 15:45:12 -08003751 break;
3752 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
Ugo Yu8f8ee842018-05-14 19:30:32 +08003753 outDeviceTypes = new int[] { AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT };
Jack He8dd33942018-01-17 15:45:12 -08003754 break;
Eric Laurent98859b22015-06-12 14:35:59 -07003755 }
3756 }
Eric Laurent98859b22015-06-12 14:35:59 -07003757 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
3758 address = "";
3759 }
Eric Laurent98859b22015-06-12 14:35:59 -07003760 String btDeviceName = btDevice.getName();
Ugo Yu8f8ee842018-05-14 19:30:32 +08003761 boolean result = false;
3762 if (isActive) {
3763 result |= handleDeviceConnection(isActive, outDeviceTypes[0], address, btDeviceName);
3764 } else {
3765 for (int outDeviceType : outDeviceTypes) {
3766 result |= handleDeviceConnection(isActive, outDeviceType, address, btDeviceName);
3767 }
3768 }
Jack He8dd33942018-01-17 15:45:12 -08003769 // handleDeviceConnection() && result to make sure the method get executed
3770 result = handleDeviceConnection(isActive, inDevice, address, btDeviceName) && result;
3771 return result;
3772 }
Satish Kodishala29809802016-01-18 14:23:12 +05303773
Jack He89f97982018-05-02 19:10:56 -07003774 private void setBtScoActiveDevice(BluetoothDevice btDevice) {
Satish Kodishala29809802016-01-18 14:23:12 +05303775 synchronized (mScoClients) {
Jack He89f97982018-05-02 19:10:56 -07003776 Log.i(TAG, "setBtScoActiveDevice: " + mBluetoothHeadsetDevice + " -> " + btDevice);
Jack He8dd33942018-01-17 15:45:12 -08003777 final BluetoothDevice previousActiveDevice = mBluetoothHeadsetDevice;
3778 if (!Objects.equals(btDevice, previousActiveDevice)) {
3779 if (!handleBtScoActiveDeviceChange(previousActiveDevice, false)) {
3780 Log.w(TAG, "setBtScoActiveDevice() failed to remove previous device "
3781 + previousActiveDevice);
3782 }
3783 if (!handleBtScoActiveDeviceChange(btDevice, true)) {
3784 Log.e(TAG, "setBtScoActiveDevice() failed to add new device " + btDevice);
3785 // set mBluetoothHeadsetDevice to null when failing to add new device
3786 btDevice = null;
3787 }
Satish Kodishala29809802016-01-18 14:23:12 +05303788 mBluetoothHeadsetDevice = btDevice;
Jack He8dd33942018-01-17 15:45:12 -08003789 if (mBluetoothHeadsetDevice == null) {
3790 resetBluetoothSco();
3791 }
Eric Laurent98859b22015-06-12 14:35:59 -07003792 }
3793 }
3794 }
3795
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07003796 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
3797 new BluetoothProfile.ServiceListener() {
3798 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003799 BluetoothDevice btDevice;
3800 List<BluetoothDevice> deviceList;
3801 switch(profile) {
3802 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09003803 synchronized (mConnectedDevices) {
3804 synchronized (mA2dpAvrcpLock) {
3805 mA2dp = (BluetoothA2dp) proxy;
3806 deviceList = mA2dp.getConnectedDevices();
3807 if (deviceList.size() > 0) {
3808 btDevice = deviceList.get(0);
John Du5a0cf7a2013-07-19 11:30:34 -07003809 int state = mA2dp.getConnectionState(btDevice);
Eric Laurentcdae4762017-04-28 18:00:04 -07003810 int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
John Du5a0cf7a2013-07-19 11:30:34 -07003811 int delay = checkSendBecomingNoisyIntent(
Eric Laurentcdae4762017-04-28 18:00:04 -07003812 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, intState,
3813 AudioSystem.DEVICE_NONE);
Jean-Michel Trivi3bf75782018-07-02 10:48:04 -07003814 final String addr = btDevice == null ? "null" : btDevice.getAddress();
3815 mDeviceLogger.log(new AudioEventLogger.StringEvent(
3816 "A2DP service connected: device addr=" + addr
3817 + " state=" + state));
John Du5a0cf7a2013-07-19 11:30:34 -07003818 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003819 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07003820 state,
Eric Laurent3e6fb632018-05-21 09:28:46 -07003821 -1,
John Du5a0cf7a2013-07-19 11:30:34 -07003822 btDevice,
3823 delay);
3824 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003825 }
Eric Laurent62ef7672010-11-24 10:58:32 -08003826 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003827 break;
3828
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003829 case BluetoothProfile.A2DP_SINK:
3830 deviceList = proxy.getConnectedDevices();
3831 if (deviceList.size() > 0) {
3832 btDevice = deviceList.get(0);
3833 synchronized (mConnectedDevices) {
3834 int state = proxy.getConnectionState(btDevice);
3835 queueMsgUnderWakeLock(mAudioHandler,
3836 MSG_SET_A2DP_SRC_CONNECTION_STATE,
3837 state,
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08003838 0 /* arg2 unused */,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003839 btDevice,
3840 0 /* delay */);
3841 }
3842 }
3843 break;
3844
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003845 case BluetoothProfile.HEADSET:
3846 synchronized (mScoClients) {
3847 // Discard timeout message
3848 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
3849 mBluetoothHeadset = (BluetoothHeadset) proxy;
Jack He8dd33942018-01-17 15:45:12 -08003850 setBtScoActiveDevice(mBluetoothHeadset.getActiveDevice());
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003851 // Refresh SCO audio state
3852 checkScoAudioState();
3853 // Continue pending action if any
3854 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
Jack He33c3a172018-05-08 14:51:07 -07003855 mScoAudioState == SCO_STATE_DEACTIVATE_REQ) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003856 boolean status = false;
3857 if (mBluetoothHeadsetDevice != null) {
3858 switch (mScoAudioState) {
Jack He89f97982018-05-02 19:10:56 -07003859 case SCO_STATE_ACTIVATE_REQ:
3860 status = connectBluetoothScoAudioHelper(mBluetoothHeadset,
3861 mBluetoothHeadsetDevice, mScoAudioMode);
3862 if (status) {
3863 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
3864 }
3865 break;
3866 case SCO_STATE_DEACTIVATE_REQ:
3867 status = disconnectBluetoothScoAudioHelper(mBluetoothHeadset,
3868 mBluetoothHeadsetDevice, mScoAudioMode);
3869 if (status) {
3870 mScoAudioState = SCO_STATE_DEACTIVATING;
3871 }
3872 break;
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003873 }
3874 }
3875 if (!status) {
Jack He89f97982018-05-02 19:10:56 -07003876 mScoAudioState = SCO_STATE_INACTIVE;
3877 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07003878 }
3879 }
Eric Laurentdc03c612011-04-01 10:59:41 -07003880 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003881 break;
3882
Jakub Pawlowskif9570f32018-02-21 17:15:12 -08003883 case BluetoothProfile.HEARING_AID:
3884 synchronized (mConnectedDevices) {
3885 synchronized (mHearingAidLock) {
3886 mHearingAid = (BluetoothHearingAid) proxy;
3887 deviceList = mHearingAid.getConnectedDevices();
3888 if (deviceList.size() > 0) {
3889 btDevice = deviceList.get(0);
3890 int state = mHearingAid.getConnectionState(btDevice);
3891 int intState = (state == BluetoothHearingAid.STATE_CONNECTED) ? 1 : 0;
3892 int delay = checkSendBecomingNoisyIntent(
3893 AudioSystem.DEVICE_OUT_HEARING_AID, intState,
3894 AudioSystem.DEVICE_NONE);
3895 queueMsgUnderWakeLock(mAudioHandler,
3896 MSG_SET_HEARING_AID_CONNECTION_STATE,
3897 state,
3898 0 /* arg2 unused */,
3899 btDevice,
3900 delay);
3901 }
3902 }
3903 }
3904
3905 break;
3906
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003907 default:
3908 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003909 }
3910 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07003911 public void onServiceDisconnected(int profile) {
Eric Laurentb70b78a2016-01-13 19:16:04 -08003912
Paul McLean394a8e12015-03-03 10:29:19 -07003913 switch (profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003914 case BluetoothProfile.A2DP:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003915 disconnectA2dp();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003916 break;
3917
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003918 case BluetoothProfile.A2DP_SINK:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003919 disconnectA2dpSink();
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003920 break;
3921
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003922 case BluetoothProfile.HEADSET:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003923 disconnectHeadset();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003924 break;
3925
Jakub Pawlowskif9570f32018-02-21 17:15:12 -08003926 case BluetoothProfile.HEARING_AID:
3927 disconnectHearingAid();
3928 break;
3929
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003930 default:
3931 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003932 }
3933 }
3934 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003935
Eric Laurentb70b78a2016-01-13 19:16:04 -08003936 void disconnectAllBluetoothProfiles() {
3937 disconnectA2dp();
3938 disconnectA2dpSink();
3939 disconnectHeadset();
Jakub Pawlowskif9570f32018-02-21 17:15:12 -08003940 disconnectHearingAid();
Eric Laurentb70b78a2016-01-13 19:16:04 -08003941 }
3942
3943 void disconnectA2dp() {
3944 synchronized (mConnectedDevices) {
3945 synchronized (mA2dpAvrcpLock) {
3946 ArraySet<String> toRemove = null;
3947 // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
3948 for (int i = 0; i < mConnectedDevices.size(); i++) {
3949 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
3950 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
3951 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
3952 toRemove.add(deviceSpec.mDeviceAddress);
3953 }
3954 }
3955 if (toRemove != null) {
Eric Laurentcdae4762017-04-28 18:00:04 -07003956 int delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3957 0, AudioSystem.DEVICE_NONE);
Eric Laurentb70b78a2016-01-13 19:16:04 -08003958 for (int i = 0; i < toRemove.size(); i++) {
3959 makeA2dpDeviceUnavailableLater(toRemove.valueAt(i), delay);
3960 }
3961 }
3962 }
3963 }
3964 }
3965
3966 void disconnectA2dpSink() {
3967 synchronized (mConnectedDevices) {
3968 ArraySet<String> toRemove = null;
3969 // Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
3970 for(int i = 0; i < mConnectedDevices.size(); i++) {
3971 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
3972 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) {
3973 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
3974 toRemove.add(deviceSpec.mDeviceAddress);
3975 }
3976 }
3977 if (toRemove != null) {
3978 for (int i = 0; i < toRemove.size(); i++) {
3979 makeA2dpSrcUnavailable(toRemove.valueAt(i));
3980 }
3981 }
3982 }
3983 }
3984
3985 void disconnectHeadset() {
3986 synchronized (mScoClients) {
Jack He8dd33942018-01-17 15:45:12 -08003987 setBtScoActiveDevice(null);
Eric Laurentb70b78a2016-01-13 19:16:04 -08003988 mBluetoothHeadset = null;
3989 }
3990 }
3991
Jakub Pawlowskif9570f32018-02-21 17:15:12 -08003992 void disconnectHearingAid() {
3993 synchronized (mConnectedDevices) {
3994 synchronized (mHearingAidLock) {
3995 ArraySet<String> toRemove = null;
3996 // Disconnect ALL DEVICE_OUT_HEARING_AID devices
3997 for (int i = 0; i < mConnectedDevices.size(); i++) {
3998 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
3999 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_HEARING_AID) {
4000 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
4001 toRemove.add(deviceSpec.mDeviceAddress);
4002 }
4003 }
4004 if (toRemove != null) {
4005 int delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_HEARING_AID,
4006 0, AudioSystem.DEVICE_NONE);
4007 for (int i = 0; i < toRemove.size(); i++) {
4008 makeHearingAidDeviceUnavailable(toRemove.valueAt(i) /*, delay*/);
4009 }
4010 }
4011 }
4012 }
4013 }
4014
John Spurlock90874332015-03-10 16:00:54 -04004015 private void onCheckMusicActive(String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07004016 synchronized (mSafeMediaVolumeState) {
4017 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07004018 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
4019
4020 if ((device & mSafeMediaVolumeDevices) != 0) {
4021 sendMsg(mAudioHandler,
4022 MSG_CHECK_MUSIC_ACTIVE,
4023 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07004024 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07004025 0,
John Spurlock90874332015-03-10 16:00:54 -04004026 caller,
Eric Laurentc34dcc12012-09-10 13:51:52 -07004027 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07004028 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07004029 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
Eric Laurenteab40d12017-06-09 12:45:21 -07004030 (index > safeMediaVolumeIndex(device))) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07004031 // Approximate cumulative active music time
4032 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
4033 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
John Spurlock90874332015-03-10 16:00:54 -04004034 setSafeMediaVolumeEnabled(true, caller);
Eric Laurentc34dcc12012-09-10 13:51:52 -07004035 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07004036 }
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004037 saveMusicActiveMs();
Eric Laurentc34dcc12012-09-10 13:51:52 -07004038 }
4039 }
4040 }
4041 }
4042 }
4043
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004044 private void saveMusicActiveMs() {
4045 mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
4046 }
4047
Eric Laurenteab40d12017-06-09 12:45:21 -07004048 private int getSafeUsbMediaVolumeIndex()
4049 {
4050 // determine UI volume index corresponding to the wanted safe gain in dBFS
4051 int min = MIN_STREAM_VOLUME[AudioSystem.STREAM_MUSIC];
4052 int max = MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC];
4053
John Muir8b8bddd2018-02-16 14:29:14 -08004054 mSafeUsbMediaVolumeDbfs = mContext.getResources().getInteger(
4055 com.android.internal.R.integer.config_safe_media_volume_usb_mB) / 100.0f;
4056
Eric Laurenteab40d12017-06-09 12:45:21 -07004057 while (Math.abs(max-min) > 1) {
4058 int index = (max + min) / 2;
4059 float gainDB = AudioSystem.getStreamVolumeDB(
4060 AudioSystem.STREAM_MUSIC, index, AudioSystem.DEVICE_OUT_USB_HEADSET);
Eric Laurentb378a13a2017-07-11 14:08:11 -07004061 if (Float.isNaN(gainDB)) {
Eric Laurenteab40d12017-06-09 12:45:21 -07004062 //keep last min in case of read error
4063 break;
John Muir8b8bddd2018-02-16 14:29:14 -08004064 } else if (gainDB == mSafeUsbMediaVolumeDbfs) {
Eric Laurenteab40d12017-06-09 12:45:21 -07004065 min = index;
4066 break;
John Muir8b8bddd2018-02-16 14:29:14 -08004067 } else if (gainDB < mSafeUsbMediaVolumeDbfs) {
Eric Laurenteab40d12017-06-09 12:45:21 -07004068 min = index;
4069 } else {
4070 max = index;
4071 }
4072 }
4073 return min * 10;
4074 }
4075
John Spurlock90874332015-03-10 16:00:54 -04004076 private void onConfigureSafeVolume(boolean force, String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07004077 synchronized (mSafeMediaVolumeState) {
4078 int mcc = mContext.getResources().getConfiguration().mcc;
4079 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
4080 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
4081 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
Eric Laurenteab40d12017-06-09 12:45:21 -07004082
4083 mSafeUsbMediaVolumeIndex = getSafeUsbMediaVolumeIndex();
4084
John Spurlock35134602014-07-24 18:10:48 -04004085 boolean safeMediaVolumeEnabled =
4086 SystemProperties.getBoolean("audio.safemedia.force", false)
4087 || mContext.getResources().getBoolean(
4088 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08004089
Ricardo Garcia3a30a762015-06-23 15:54:45 -07004090 boolean safeMediaVolumeBypass =
4091 SystemProperties.getBoolean("audio.safemedia.bypass", false);
4092
Eric Laurent05274f32012-11-29 12:48:18 -08004093 // The persisted state is either "disabled" or "active": this is the state applied
4094 // next time we boot and cannot be "inactive"
4095 int persistedState;
Ricardo Garcia3a30a762015-06-23 15:54:45 -07004096 if (safeMediaVolumeEnabled && !safeMediaVolumeBypass) {
Eric Laurent05274f32012-11-29 12:48:18 -08004097 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
4098 // The state can already be "inactive" here if the user has forced it before
4099 // the 30 seconds timeout for forced configuration. In this case we don't reset
4100 // it to "active".
4101 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004102 if (mMusicActiveMs == 0) {
4103 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
John Spurlock90874332015-03-10 16:00:54 -04004104 enforceSafeMediaVolume(caller);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004105 } else {
4106 // We have existing playback time recorded, already confirmed.
4107 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
4108 }
Eric Laurent05274f32012-11-29 12:48:18 -08004109 }
Eric Laurentd640bd32012-09-28 18:01:48 -07004110 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08004111 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07004112 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
4113 }
4114 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08004115 sendMsg(mAudioHandler,
4116 MSG_PERSIST_SAFE_VOLUME_STATE,
4117 SENDMSG_QUEUE,
4118 persistedState,
4119 0,
4120 null,
4121 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07004122 }
4123 }
4124 }
4125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004126 ///////////////////////////////////////////////////////////////////////////
4127 // Internal methods
4128 ///////////////////////////////////////////////////////////////////////////
4129
4130 /**
4131 * Checks if the adjustment should change ringer mode instead of just
4132 * adjusting volume. If so, this will set the proper ringer mode and volume
4133 * indices on the stream states.
4134 */
Julia Reynoldsed783792016-04-08 15:27:35 -04004135 private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted,
4136 String caller, int flags) {
John Spurlocka11b4af2014-06-01 11:52:23 -04004137 int result = FLAG_ADJUST_VOLUME;
Zak Cohen47798292017-11-30 12:34:20 -08004138 if (isPlatformTelevision() || mIsSingleVolume) {
Hank Freund21003f62015-12-08 09:05:46 -08004139 return result;
4140 }
4141
John Spurlock661f2cf2014-11-17 10:29:10 -05004142 int ringerMode = getRingerModeInternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004143
Eric Laurentbffc3d12012-05-07 17:43:49 -07004144 switch (ringerMode) {
4145 case RINGER_MODE_NORMAL:
4146 if (direction == AudioManager.ADJUST_LOWER) {
4147 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07004148 // "step" is the delta in internal index units corresponding to a
4149 // change of 1 in UI index units.
4150 // Because of rounding when rescaling from one stream index range to its alias
4151 // index range, we cannot simply test oldIndex == step:
4152 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
4153 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07004154 ringerMode = RINGER_MODE_VIBRATE;
John Spurlock07e72432015-03-13 11:46:52 -04004155 mLoweredFromNormalToVibrateTime = SystemClock.uptimeMillis();
Eric Laurentbffc3d12012-05-07 17:43:49 -07004156 }
4157 } else {
John Spurlockd9c75db2015-04-28 11:19:13 -04004158 if (oldIndex == step && mVolumePolicy.volumeDownToEnterSilent) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07004159 ringerMode = RINGER_MODE_SILENT;
4160 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07004161 }
Muyuan Li1ed6df62016-06-18 11:16:52 -07004162 } else if (mIsSingleVolume && (direction == AudioManager.ADJUST_TOGGLE_MUTE
John Spurlocka48d7792015-03-03 17:35:57 -05004163 || direction == AudioManager.ADJUST_MUTE)) {
RoboErik5452e252015-02-06 15:33:53 -08004164 if (mHasVibrator) {
4165 ringerMode = RINGER_MODE_VIBRATE;
4166 } else {
4167 ringerMode = RINGER_MODE_SILENT;
4168 }
4169 // Setting the ringer mode will toggle mute
4170 result &= ~FLAG_ADJUST_VOLUME;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004171 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07004172 break;
4173 case RINGER_MODE_VIBRATE:
4174 if (!mHasVibrator) {
4175 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
4176 "but no vibrator is present");
4177 break;
4178 }
Amith Yamasanic696a532011-10-28 17:02:37 -07004179 if ((direction == AudioManager.ADJUST_LOWER)) {
RoboErik5452e252015-02-06 15:33:53 -08004180 // This is the case we were muted with the volume turned up
Muyuan Li1ed6df62016-06-18 11:16:52 -07004181 if (mIsSingleVolume && oldIndex >= 2 * step && isMuted) {
RoboErik5452e252015-02-06 15:33:53 -08004182 ringerMode = RINGER_MODE_NORMAL;
4183 } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
John Spurlocka48d7792015-03-03 17:35:57 -05004184 if (mVolumePolicy.volumeDownToEnterSilent) {
John Spurlock07e72432015-03-13 11:46:52 -04004185 final long diff = SystemClock.uptimeMillis()
4186 - mLoweredFromNormalToVibrateTime;
John Spurlockd9c75db2015-04-28 11:19:13 -04004187 if (diff > mVolumePolicy.vibrateToSilentDebounce
4188 && mRingerModeDelegate.canVolumeDownEnterSilent()) {
John Spurlock07e72432015-03-13 11:46:52 -04004189 ringerMode = RINGER_MODE_SILENT;
4190 }
John Spurlock795a5142014-12-08 14:09:35 -05004191 } else {
4192 result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
4193 }
Amith Yamasanic696a532011-10-28 17:02:37 -07004194 }
RoboErik5452e252015-02-06 15:33:53 -08004195 } else if (direction == AudioManager.ADJUST_RAISE
4196 || direction == AudioManager.ADJUST_TOGGLE_MUTE
4197 || direction == AudioManager.ADJUST_UNMUTE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07004198 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07004199 }
John Spurlocka11b4af2014-06-01 11:52:23 -04004200 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07004201 break;
4202 case RINGER_MODE_SILENT:
Muyuan Li1ed6df62016-06-18 11:16:52 -07004203 if (mIsSingleVolume && direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
RoboErik5452e252015-02-06 15:33:53 -08004204 // This is the case we were muted with the volume turned up
4205 ringerMode = RINGER_MODE_NORMAL;
4206 } else if (direction == AudioManager.ADJUST_RAISE
4207 || direction == AudioManager.ADJUST_TOGGLE_MUTE
4208 || direction == AudioManager.ADJUST_UNMUTE) {
John Spurlocka48d7792015-03-03 17:35:57 -05004209 if (!mVolumePolicy.volumeUpToExitSilent) {
John Spurlocka11b4af2014-06-01 11:52:23 -04004210 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07004211 } else {
RoboErik5452e252015-02-06 15:33:53 -08004212 if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04004213 ringerMode = RINGER_MODE_VIBRATE;
4214 } else {
RoboErik5452e252015-02-06 15:33:53 -08004215 // If we don't have a vibrator or they were toggling mute
4216 // go straight back to normal.
John Spurlocka11b4af2014-06-01 11:52:23 -04004217 ringerMode = RINGER_MODE_NORMAL;
4218 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07004219 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05004220 }
John Spurlocka11b4af2014-06-01 11:52:23 -04004221 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07004222 break;
4223 default:
4224 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
4225 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004226 }
4227
Julia Reynoldsed783792016-04-08 15:27:35 -04004228 if (isAndroidNPlus(caller) && wouldToggleZenMode(ringerMode)
4229 && !mNm.isNotificationPolicyAccessGrantedForPackage(caller)
4230 && (flags & AudioManager.FLAG_FROM_KEY) == 0) {
4231 throw new SecurityException("Not allowed to change Do Not Disturb state");
4232 }
4233
John Spurlock661f2cf2014-11-17 10:29:10 -05004234 setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004235
Eric Laurent25101b02011-02-02 09:33:30 -08004236 mPrevVolDirection = direction;
4237
John Spurlocka11b4af2014-06-01 11:52:23 -04004238 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004239 }
4240
John Spurlock3346a802014-05-20 16:25:37 -04004241 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004242 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07004243 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004244 }
4245
Beverlyd6964762018-02-16 14:07:03 -05004246 private boolean shouldZenMuteStream(int streamType) {
4247 if (mNm.getZenMode() != Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
4248 return false;
4249 }
4250
4251 NotificationManager.Policy zenPolicy = mNm.getNotificationPolicy();
4252 final boolean muteAlarms = (zenPolicy.priorityCategories
4253 & NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS) == 0;
4254 final boolean muteMedia = (zenPolicy.priorityCategories
4255 & NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA) == 0;
4256 final boolean muteSystem = (zenPolicy.priorityCategories
4257 & NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM) == 0;
4258 final boolean muteNotificationAndRing = ZenModeConfig
4259 .areAllPriorityOnlyNotificationZenSoundsMuted(mNm.getNotificationPolicy());
4260 return muteAlarms && isAlarm(streamType)
4261 || muteMedia && isMedia(streamType)
4262 || muteSystem && isSystem(streamType)
4263 || muteNotificationAndRing && isNotificationOrRinger(streamType);
4264 }
4265
4266 private boolean isStreamMutedByRingerOrZenMode(int streamType) {
4267 return (mRingerAndZenModeMutedStreams & (1 << streamType)) != 0;
4268 }
4269
4270 /**
4271 * DND total silence: media and alarms streams are tied to the muted ringer
4272 * {@link ZenModeHelper.RingerModeDelegate#getRingerModeAffectedStreams(int)}
4273 * DND alarms only: notification, ringer + system muted (by default tied to muted ringer mode)
4274 * DND priority only: alarms, media, system streams can be muted separate from ringer based on
4275 * zenPolicy (this method determines which streams)
4276 * @return true if changed, else false
4277 */
4278 private boolean updateZenModeAffectedStreams() {
4279 int zenModeAffectedStreams = 0;
4280 if (mSystemReady && mNm.getZenMode() == Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
4281 NotificationManager.Policy zenPolicy = mNm.getNotificationPolicy();
4282 if ((zenPolicy.priorityCategories
4283 & NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS) == 0) {
4284 zenModeAffectedStreams |= 1 << AudioManager.STREAM_ALARM;
4285 }
4286
4287 if ((zenPolicy.priorityCategories
4288 & NotificationManager.Policy.PRIORITY_CATEGORY_MEDIA) == 0) {
4289 zenModeAffectedStreams |= 1 << AudioManager.STREAM_MUSIC;
4290 }
4291
4292 if ((zenPolicy.priorityCategories
4293 & NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM) == 0) {
4294 zenModeAffectedStreams |= 1 << AudioManager.STREAM_SYSTEM;
4295 }
4296 }
4297
4298 if (mZenModeAffectedStreams != zenModeAffectedStreams) {
4299 mZenModeAffectedStreams = zenModeAffectedStreams;
4300 return true;
4301 }
4302
4303 return false;
Eric Laurent5b4e6542010-03-19 20:02:21 -07004304 }
4305
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004306 @GuardedBy("mSettingsLock")
Beverlyd6964762018-02-16 14:07:03 -05004307 private boolean updateRingerAndZenModeAffectedStreams() {
4308 boolean updatedZenModeAffectedStreams = updateZenModeAffectedStreams();
John Spurlock50ced3f2015-05-11 16:00:09 -04004309 int ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004310 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
4311 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
4312 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
4313 UserHandle.USER_CURRENT);
4314
Muyuan Li1ed6df62016-06-18 11:16:52 -07004315 if (mIsSingleVolume) {
John Spurlock50ced3f2015-05-11 16:00:09 -04004316 ringerModeAffectedStreams = 0;
4317 } else if (mRingerModeDelegate != null) {
4318 ringerModeAffectedStreams = mRingerModeDelegate
4319 .getRingerModeAffectedStreams(ringerModeAffectedStreams);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004320 }
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004321 if (mCameraSoundForced) {
4322 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4323 } else {
4324 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004325 }
4326 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
4327 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
4328 } else {
4329 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
4330 }
4331
4332 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
4333 Settings.System.putIntForUser(mContentResolver,
4334 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
4335 ringerModeAffectedStreams,
4336 UserHandle.USER_CURRENT);
4337 mRingerModeAffectedStreams = ringerModeAffectedStreams;
4338 return true;
4339 }
Beverlyd6964762018-02-16 14:07:03 -05004340 return updatedZenModeAffectedStreams;
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004341 }
4342
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05004343 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004344 public boolean isStreamAffectedByMute(int streamType) {
4345 return (mMuteAffectedStreams & (1 << streamType)) != 0;
4346 }
4347
4348 private void ensureValidDirection(int direction) {
RoboErik4197cb62015-01-21 15:45:32 -08004349 switch (direction) {
4350 case AudioManager.ADJUST_LOWER:
4351 case AudioManager.ADJUST_RAISE:
4352 case AudioManager.ADJUST_SAME:
4353 case AudioManager.ADJUST_MUTE:
4354 case AudioManager.ADJUST_UNMUTE:
4355 case AudioManager.ADJUST_TOGGLE_MUTE:
4356 break;
4357 default:
4358 throw new IllegalArgumentException("Bad direction " + direction);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004359 }
4360 }
4361
4362 private void ensureValidStreamType(int streamType) {
4363 if (streamType < 0 || streamType >= mStreamStates.length) {
4364 throw new IllegalArgumentException("Bad stream type " + streamType);
4365 }
4366 }
4367
RoboErik4197cb62015-01-21 15:45:32 -08004368 private boolean isMuteAdjust(int adjust) {
4369 return adjust == AudioManager.ADJUST_MUTE || adjust == AudioManager.ADJUST_UNMUTE
4370 || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
4371 }
4372
Eric Laurent6d517662012-04-23 18:42:39 -07004373 private boolean isInCommunication() {
Nancy Chen0eb1e402014-08-21 22:52:29 -07004374 boolean IsInCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004375
Tyler Gunnef9f6f92014-09-12 22:16:17 -07004376 TelecomManager telecomManager =
4377 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
Eric Laurent38edfda2014-12-18 17:38:04 -08004378
4379 final long ident = Binder.clearCallingIdentity();
Tyler Gunnef9f6f92014-09-12 22:16:17 -07004380 IsInCall = telecomManager.isInCall();
Eric Laurent38edfda2014-12-18 17:38:04 -08004381 Binder.restoreCallingIdentity(ident);
Santos Cordon9eb45932014-06-27 12:28:43 -07004382
Eric Laurentda1af762017-12-15 16:54:35 -08004383 return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION ||
4384 getMode() == AudioManager.MODE_IN_CALL);
Eric Laurent6d517662012-04-23 18:42:39 -07004385 }
Eric Laurent25101b02011-02-02 09:33:30 -08004386
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07004387 /**
4388 * For code clarity for getActiveStreamType(int)
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05004389 * @param delay_ms max time since last stream activity to consider
4390 * @return true if stream is active in streams handled by AudioFlinger now or
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07004391 * in the last "delay_ms" ms.
4392 */
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05004393 private boolean wasStreamActiveRecently(int stream, int delay_ms) {
4394 return AudioSystem.isStreamActive(stream, delay_ms)
4395 || AudioSystem.isStreamActiveRemotely(stream, delay_ms);
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07004396 }
4397
Eric Laurent6d517662012-04-23 18:42:39 -07004398 private int getActiveStreamType(int suggestedStreamType) {
Muyuan Li1ed6df62016-06-18 11:16:52 -07004399 if (mIsSingleVolume
4400 && suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
4401 return AudioSystem.STREAM_MUSIC;
4402 }
4403
Eric Laurent212532b2014-07-21 15:43:18 -07004404 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05004405 case AudioSystem.PLATFORM_VOICE:
Eric Laurent6d517662012-04-23 18:42:39 -07004406 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08004407 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
4408 == AudioSystem.FORCE_BT_SCO) {
4409 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
4410 return AudioSystem.STREAM_BLUETOOTH_SCO;
4411 } else {
4412 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
4413 return AudioSystem.STREAM_VOICE_CALL;
4414 }
Eric Laurent25101b02011-02-02 09:33:30 -08004415 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05004416 if (wasStreamActiveRecently(AudioSystem.STREAM_RING, sStreamOverrideDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004417 if (DEBUG_VOL)
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05004418 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING stream active");
4419 return AudioSystem.STREAM_RING;
4420 } else if (wasStreamActiveRecently(
4421 AudioSystem.STREAM_NOTIFICATION, sStreamOverrideDelayMs)) {
4422 if (DEBUG_VOL)
4423 Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION stream active");
4424 return AudioSystem.STREAM_NOTIFICATION;
4425 } else {
Julia Reynoldseb0ce472018-05-04 15:34:55 -04004426 if (DEBUG_VOL) {
4427 Log.v(TAG, "getActiveStreamType: Forcing DEFAULT_VOL_STREAM_NO_PLAYBACK("
4428 + DEFAULT_VOL_STREAM_NO_PLAYBACK + ") b/c default");
4429 }
4430 return DEFAULT_VOL_STREAM_NO_PLAYBACK;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004431 }
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05004432 } else if (
4433 wasStreamActiveRecently(AudioSystem.STREAM_NOTIFICATION, sStreamOverrideDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004434 if (DEBUG_VOL)
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05004435 Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION stream active");
4436 return AudioSystem.STREAM_NOTIFICATION;
4437 } else if (wasStreamActiveRecently(AudioSystem.STREAM_RING, sStreamOverrideDelayMs)) {
4438 if (DEBUG_VOL)
4439 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING stream active");
4440 return AudioSystem.STREAM_RING;
Eric Laurent25101b02011-02-02 09:33:30 -08004441 }
Eric Laurent212532b2014-07-21 15:43:18 -07004442 default:
Eric Laurent6d517662012-04-23 18:42:39 -07004443 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08004444 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
4445 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004446 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08004447 return AudioSystem.STREAM_BLUETOOTH_SCO;
4448 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004449 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08004450 return AudioSystem.STREAM_VOICE_CALL;
4451 }
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05004452 } else if (AudioSystem.isStreamActive(
4453 AudioSystem.STREAM_NOTIFICATION, sStreamOverrideDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004454 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08004455 return AudioSystem.STREAM_NOTIFICATION;
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05004456 } else if (AudioSystem.isStreamActive(
4457 AudioSystem.STREAM_RING, sStreamOverrideDelayMs)) {
4458 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING");
4459 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004460 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05004461 if (AudioSystem.isStreamActive(
4462 AudioSystem.STREAM_NOTIFICATION, sStreamOverrideDelayMs)) {
4463 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
John Spurlockeb1d88d2014-07-19 14:49:19 -04004464 return AudioSystem.STREAM_NOTIFICATION;
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05004465 } else if (AudioSystem.isStreamActive(
4466 AudioSystem.STREAM_RING, sStreamOverrideDelayMs)) {
4467 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING");
4468 return AudioSystem.STREAM_RING;
4469 } else {
Julia Reynoldseb0ce472018-05-04 15:34:55 -04004470 if (DEBUG_VOL) {
4471 Log.v(TAG, "getActiveStreamType: Forcing DEFAULT_VOL_STREAM_NO_PLAYBACK("
4472 + DEFAULT_VOL_STREAM_NO_PLAYBACK + ") b/c default");
4473 }
4474 return DEFAULT_VOL_STREAM_NO_PLAYBACK;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004475 }
Joe Onoratoc7fcba42011-01-05 16:53:11 -08004476 }
Eric Laurent212532b2014-07-21 15:43:18 -07004477 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004478 }
Eric Laurent212532b2014-07-21 15:43:18 -07004479 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
4480 + suggestedStreamType);
4481 return suggestedStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004482 }
4483
John Spurlockbcc10872014-11-28 15:29:21 -05004484 private void broadcastRingerMode(String action, int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004485 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05004486 Intent broadcast = new Intent(action);
Glenn Kastenba195eb2011-12-13 09:30:40 -08004487 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08004488 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
4489 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004490 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004491 }
4492
4493 private void broadcastVibrateSetting(int vibrateType) {
4494 // Send broadcast
Sudheer Shankafc46e9b2016-10-21 17:55:27 -07004495 if (mActivityManagerInternal.isSystemReady()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004496 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
4497 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
4498 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004499 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004500 }
4501 }
4502
4503 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07004504 /**
4505 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
4506 * Note that the wake lock needs to be released after the message has been handled.
4507 */
4508 private void queueMsgUnderWakeLock(Handler handler, int msg,
4509 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07004510 final long ident = Binder.clearCallingIdentity();
4511 // Always acquire the wake lock as AudioService because it is released by the
4512 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004513 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07004514 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07004515 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
4516 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004517
Eric Laurentafbb0472011-12-15 09:04:23 -08004518 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004519 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004520
4521 if (existingMsgPolicy == SENDMSG_REPLACE) {
4522 handler.removeMessages(msg);
4523 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
4524 return;
4525 }
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004526 synchronized (mLastDeviceConnectMsgTime) {
4527 long time = SystemClock.uptimeMillis() + delay;
Eric Laurent3c4636c2018-06-13 19:36:42 -07004528
4529 if (msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
4530 msg == MSG_SET_A2DP_SINK_CONNECTION_STATE ||
4531 msg == MSG_SET_HEARING_AID_CONNECTION_STATE ||
4532 msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
4533 msg == MSG_A2DP_DEVICE_CONFIG_CHANGE ||
4534 msg == MSG_BTA2DP_DOCK_TIMEOUT) {
4535 if (mLastDeviceConnectMsgTime >= time) {
4536 // add a little delay to make sure messages are ordered as expected
4537 time = mLastDeviceConnectMsgTime + 30;
4538 }
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004539 mLastDeviceConnectMsgTime = time;
4540 }
Eric Laurent3c4636c2018-06-13 19:36:42 -07004541
4542 handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004543 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004544 }
4545
4546 boolean checkAudioSettingsPermission(String method) {
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07004547 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004548 == PackageManager.PERMISSION_GRANTED) {
4549 return true;
4550 }
4551 String msg = "Audio Settings Permission Denial: " + method + " from pid="
4552 + Binder.getCallingPid()
4553 + ", uid=" + Binder.getCallingUid();
4554 Log.w(TAG, msg);
4555 return false;
4556 }
4557
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004558 private int getDeviceForStream(int stream) {
John Spurlock8a52c442015-03-26 14:23:58 -04004559 int device = getDevicesForStream(stream);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004560 if ((device & (device - 1)) != 0) {
4561 // Multiple device selection is either:
4562 // - speaker + one other device: give priority to speaker in this case.
4563 // - one A2DP device + another device: happens with duplicated output. In this case
4564 // retain the device on the A2DP output as the other must not correspond to an active
4565 // selection if not the speaker.
Jungshik Jangc9ff9682014-09-15 17:41:06 +09004566 // - HDMI-CEC system audio mode only output: give priority to available item in order.
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004567 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
4568 device = AudioSystem.DEVICE_OUT_SPEAKER;
Jungshik Jangc9ff9682014-09-15 17:41:06 +09004569 } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
4570 device = AudioSystem.DEVICE_OUT_HDMI_ARC;
4571 } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
4572 device = AudioSystem.DEVICE_OUT_SPDIF;
4573 } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
4574 device = AudioSystem.DEVICE_OUT_AUX_LINE;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004575 } else {
4576 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
4577 }
4578 }
4579 return device;
4580 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004581
John Spurlock8a52c442015-03-26 14:23:58 -04004582 private int getDevicesForStream(int stream) {
4583 return getDevicesForStream(stream, true /*checkOthers*/);
4584 }
4585
4586 private int getDevicesForStream(int stream, boolean checkOthers) {
4587 ensureValidStreamType(stream);
4588 synchronized (VolumeStreamState.class) {
4589 return mStreamStates[stream].observeDevicesForStream_syncVSS(checkOthers);
4590 }
4591 }
4592
4593 private void observeDevicesForStreams(int skipStream) {
4594 synchronized (VolumeStreamState.class) {
4595 for (int stream = 0; stream < mStreamStates.length; stream++) {
4596 if (stream != skipStream) {
4597 mStreamStates[stream].observeDevicesForStream_syncVSS(false /*checkOthers*/);
4598 }
4599 }
4600 }
4601 }
4602
Paul McLean10804eb2015-01-28 11:16:35 -08004603 /*
4604 * A class just for packaging up a set of connection parameters.
4605 */
Jean-Michel Trivicf170362017-08-24 17:24:57 -07004606 class WiredDeviceConnectionState {
John Spurlock90874332015-03-10 16:00:54 -04004607 public final int mType;
4608 public final int mState;
4609 public final String mAddress;
4610 public final String mName;
4611 public final String mCaller;
Paul McLean10804eb2015-01-28 11:16:35 -08004612
John Spurlock90874332015-03-10 16:00:54 -04004613 public WiredDeviceConnectionState(int type, int state, String address, String name,
4614 String caller) {
Paul McLean10804eb2015-01-28 11:16:35 -08004615 mType = type;
4616 mState = state;
4617 mAddress = address;
4618 mName = name;
John Spurlock90874332015-03-10 16:00:54 -04004619 mCaller = caller;
Paul McLean10804eb2015-01-28 11:16:35 -08004620 }
4621 }
4622
John Spurlock90874332015-03-10 16:00:54 -04004623 public void setWiredDeviceConnectionState(int type, int state, String address, String name,
4624 String caller) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004625 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004626 if (DEBUG_DEVICES) {
4627 Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
4628 + address + ")");
4629 }
Eric Laurentcdae4762017-04-28 18:00:04 -07004630 int delay = checkSendBecomingNoisyIntent(type, state, AudioSystem.DEVICE_NONE);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07004631 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004632 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08004633 0 /* arg1 unused */,
4634 0 /* arg2 unused */,
John Spurlock90874332015-03-10 16:00:54 -04004635 new WiredDeviceConnectionState(type, state, address, name, caller),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004636 delay);
4637 }
4638 }
4639
Jakub Pawlowski10c90612018-02-21 13:28:46 -08004640 @Override
4641 public void setHearingAidDeviceConnectionState(BluetoothDevice device, int state)
4642 {
Jakub Pawlowskif9570f32018-02-21 17:15:12 -08004643 Log.i(TAG, "setBluetoothHearingAidDeviceConnectionState");
4644
4645 setBluetoothHearingAidDeviceConnectionState(
4646 device, state, false /* suppressNoisyIntent */, AudioSystem.DEVICE_NONE);
4647 }
4648
4649 public int setBluetoothHearingAidDeviceConnectionState(
4650 BluetoothDevice device, int state, boolean suppressNoisyIntent,
4651 int musicDevice)
4652 {
4653 int delay;
4654 synchronized (mConnectedDevices) {
4655 if (!suppressNoisyIntent) {
4656 int intState = (state == BluetoothHearingAid.STATE_CONNECTED) ? 1 : 0;
4657 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_HEARING_AID,
4658 intState, musicDevice);
4659 } else {
4660 delay = 0;
4661 }
4662 queueMsgUnderWakeLock(mAudioHandler,
4663 MSG_SET_HEARING_AID_CONNECTION_STATE,
4664 state,
4665 0 /* arg2 unused */,
4666 device,
4667 delay);
4668 }
4669 return delay;
Jakub Pawlowski10c90612018-02-21 13:28:46 -08004670 }
4671
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004672 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004673 {
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08004674 return setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
Eric Laurent3e6fb632018-05-21 09:28:46 -07004675 device, state, profile, false /* suppressNoisyIntent */, -1 /* a2dpVolume */);
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08004676 }
4677
4678 public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice device,
Eric Laurent3e6fb632018-05-21 09:28:46 -07004679 int state, int profile, boolean suppressNoisyIntent, int a2dpVolume)
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08004680 {
Jean-Michel Trivi3bf75782018-07-02 10:48:04 -07004681 mDeviceLogger.log(new AudioEventLogger.StringEvent(
4682 "setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent state=" + state
4683 // only querying address as this is the only readily available field on the device
4684 + " addr=" + device.getAddress()
4685 + " prof=" + profile + " supprNoisy=" + suppressNoisyIntent
4686 + " vol=" + a2dpVolume));
Eric Laurent4724ea72017-05-23 10:39:38 -07004687 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, device)) {
Jean-Michel Trivi3bf75782018-07-02 10:48:04 -07004688 mDeviceLogger.log(new AudioEventLogger.StringEvent("A2DP connection state ignored"));
Eric Laurentcdae4762017-04-28 18:00:04 -07004689 return 0;
4690 }
4691 return setBluetoothA2dpDeviceConnectionStateInt(
Eric Laurent3e6fb632018-05-21 09:28:46 -07004692 device, state, profile, suppressNoisyIntent, AudioSystem.DEVICE_NONE, a2dpVolume);
Eric Laurentcdae4762017-04-28 18:00:04 -07004693 }
4694
4695 public int setBluetoothA2dpDeviceConnectionStateInt(
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08004696 BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent,
Eric Laurent3e6fb632018-05-21 09:28:46 -07004697 int musicDevice, int a2dpVolume)
Eric Laurentcdae4762017-04-28 18:00:04 -07004698 {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004699 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004700 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
4701 throw new IllegalArgumentException("invalid profile " + profile);
4702 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004703 synchronized (mConnectedDevices) {
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08004704 if (profile == BluetoothProfile.A2DP && !suppressNoisyIntent) {
Eric Laurentcdae4762017-04-28 18:00:04 -07004705 int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004706 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Eric Laurentcdae4762017-04-28 18:00:04 -07004707 intState, musicDevice);
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004708 } else {
4709 delay = 0;
4710 }
Eric Laurent3c4636c2018-06-13 19:36:42 -07004711
4712 if (DEBUG_DEVICES) {
4713 Log.d(TAG, "setBluetoothA2dpDeviceConnectionStateInt device: " + device
4714 + " state: " + state + " delay(ms): " + delay
4715 + " suppressNoisyIntent: " + suppressNoisyIntent);
4716 }
4717
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07004718 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004719 (profile == BluetoothProfile.A2DP ?
4720 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004721 state,
Eric Laurent3e6fb632018-05-21 09:28:46 -07004722 a2dpVolume,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004723 device,
4724 delay);
4725 }
4726 return delay;
4727 }
4728
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08004729 public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device)
4730 {
4731 synchronized (mConnectedDevices) {
4732 queueMsgUnderWakeLock(mAudioHandler,
4733 MSG_A2DP_DEVICE_CONFIG_CHANGE,
4734 0 /* arg1 unused */,
4735 0 /* arg1 unused */,
4736 device,
4737 0 /* delay */);
4738 }
4739 }
4740
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07004741 private static final int DEVICE_MEDIA_UNMUTED_ON_PLUG =
4742 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
4743 AudioSystem.DEVICE_OUT_LINE |
4744 AudioSystem.DEVICE_OUT_ALL_A2DP |
4745 AudioSystem.DEVICE_OUT_ALL_USB |
4746 AudioSystem.DEVICE_OUT_HDMI;
4747
4748 private void onAccessoryPlugMediaUnmute(int newDevice) {
4749 if (DEBUG_VOL) {
4750 Log.i(TAG, String.format("onAccessoryPlugMediaUnmute newDevice=%d [%s]",
4751 newDevice, AudioSystem.getOutputDeviceName(newDevice)));
4752 }
4753 synchronized (mConnectedDevices) {
Eric Laurent7fb83d92017-09-28 09:36:36 -07004754 if (mNm.getZenMode() != Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
4755 && (newDevice & DEVICE_MEDIA_UNMUTED_ON_PLUG) != 0
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07004756 && mStreamStates[AudioSystem.STREAM_MUSIC].mIsMuted
4757 && mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(newDevice) != 0
4758 && (newDevice & AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC)) != 0)
4759 {
4760 if (DEBUG_VOL) {
4761 Log.i(TAG, String.format(" onAccessoryPlugMediaUnmute unmuting device=%d [%s]",
4762 newDevice, AudioSystem.getOutputDeviceName(newDevice)));
4763 }
4764 mStreamStates[AudioSystem.STREAM_MUSIC].mute(false);
4765 }
4766 }
4767 }
4768
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004769 ///////////////////////////////////////////////////////////////////////////
4770 // Inner classes
4771 ///////////////////////////////////////////////////////////////////////////
4772
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004773 // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
4774 // 1 mScoclient OR mSafeMediaVolumeState
4775 // 2 mSetModeDeathHandlers
4776 // 3 mSettingsLock
4777 // 4 VolumeStreamState.class
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004778 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004779 private final int mStreamType;
Jean-Michel Trivie05eef82018-03-08 18:56:34 -08004780 private int mIndexMin;
4781 private int mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004782
RoboErik4197cb62015-01-21 15:45:32 -08004783 private boolean mIsMuted;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07004784 private String mVolumeIndexSettingName;
John Spurlock8a52c442015-03-26 14:23:58 -04004785 private int mObservedDevices;
John Spurlockb6e19e32015-03-10 21:33:44 -04004786
John Spurlock2bb02ec2015-03-02 13:13:06 -05004787 private final SparseIntArray mIndexMap = new SparseIntArray(8);
John Spurlockf63860c2015-02-19 09:46:27 -05004788 private final Intent mVolumeChanged;
John Spurlock8a52c442015-03-26 14:23:58 -04004789 private final Intent mStreamDevicesChanged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004790
Eric Laurenta553c252009-07-17 12:17:14 -07004791 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004792
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004793 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004794
4795 mStreamType = streamType;
John Spurlockb6e19e32015-03-10 21:33:44 -04004796 mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;
4797 mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;
4798 AudioSystem.initStreamVolume(streamType, mIndexMin / 10, mIndexMax / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004799
Eric Laurent33902db2012-10-07 16:15:07 -07004800 readSettings();
John Spurlockf63860c2015-02-19 09:46:27 -05004801 mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
4802 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
John Spurlock8a52c442015-03-26 14:23:58 -04004803 mStreamDevicesChanged = new Intent(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
4804 mStreamDevicesChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
4805 }
4806
4807 public int observeDevicesForStream_syncVSS(boolean checkOthers) {
4808 final int devices = AudioSystem.getDevicesForStream(mStreamType);
4809 if (devices == mObservedDevices) {
4810 return devices;
4811 }
4812 final int prevDevices = mObservedDevices;
4813 mObservedDevices = devices;
4814 if (checkOthers) {
4815 // one stream's devices have changed, check the others
4816 observeDevicesForStreams(mStreamType);
4817 }
4818 // log base stream changes to the event log
4819 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
4820 EventLogTags.writeStreamDevicesChanged(mStreamType, prevDevices, devices);
4821 }
4822 sendBroadcastToAll(mStreamDevicesChanged
4823 .putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, prevDevices)
4824 .putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, devices));
4825 return devices;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004826 }
4827
Jean-Michel Trivia53b7052017-04-12 18:27:01 -07004828 public @Nullable String getSettingNameForDevice(int device) {
4829 if (!hasValidSettingsName()) {
4830 return null;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004831 }
Jean-Michel Trivia53b7052017-04-12 18:27:01 -07004832 final String suffix = AudioSystem.getOutputDeviceName(device);
4833 if (suffix.isEmpty()) {
4834 return mVolumeIndexSettingName;
4835 }
4836 return mVolumeIndexSettingName + "_" + suffix;
4837 }
4838
4839 private boolean hasValidSettingsName() {
4840 return (mVolumeIndexSettingName != null && !mVolumeIndexSettingName.isEmpty());
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07004841 }
4842
Eric Laurentfdbee862014-05-12 15:26:12 -07004843 public void readSettings() {
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004844 synchronized (mSettingsLock) {
4845 synchronized (VolumeStreamState.class) {
4846 // force maximum volume on all streams if fixed volume property is set
4847 if (mUseFixedVolume) {
4848 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
4849 return;
4850 }
4851 // do not read system stream volume from settings: this stream is always aliased
4852 // to another stream type and its volume is never persisted. Values in settings can
4853 // only be stale values
4854 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
4855 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
4856 int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
Eric Laurentfdbee862014-05-12 15:26:12 -07004857 if (mCameraSoundForced) {
4858 index = mIndexMax;
4859 }
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004860 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
4861 return;
Eric Laurentdd45d012012-10-08 09:04:34 -07004862 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004863 }
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004864 }
4865 synchronized (VolumeStreamState.class) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004866 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
4867
4868 for (int i = 0; remainingDevices != 0; i++) {
4869 int device = (1 << i);
4870 if ((device & remainingDevices) == 0) {
4871 continue;
4872 }
4873 remainingDevices &= ~device;
4874
4875 // retrieve current volume for device
Eric Laurentfdbee862014-05-12 15:26:12 -07004876 // if no volume stored for current stream and device, use default volume if default
4877 // device, continue otherwise
4878 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
John Spurlock61560172015-02-06 19:46:04 -05004879 AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
Jean-Michel Trivia53b7052017-04-12 18:27:01 -07004880 int index;
4881 if (!hasValidSettingsName()) {
4882 index = defaultIndex;
4883 } else {
4884 String name = getSettingNameForDevice(device);
4885 index = Settings.System.getIntForUser(
4886 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
4887 }
Eric Laurentfdbee862014-05-12 15:26:12 -07004888 if (index == -1) {
4889 continue;
4890 }
4891
John Spurlock2bb02ec2015-03-02 13:13:06 -05004892 mIndexMap.put(device, getValidIndex(10 * index));
Eric Laurentdd45d012012-10-08 09:04:34 -07004893 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004894 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004895 }
4896
Liejun Tao39fb5672016-03-09 15:52:13 -06004897 private int getAbsoluteVolumeIndex(int index) {
4898 /* Special handling for Bluetooth Absolute Volume scenario
4899 * If we send full audio gain, some accessories are too loud even at its lowest
4900 * volume. We are not able to enumerate all such accessories, so here is the
4901 * workaround from phone side.
4902 * Pre-scale volume at lowest volume steps 1 2 and 3.
4903 * For volume step 0, set audio gain to 0 as some accessories won't mute on their end.
4904 */
4905 if (index == 0) {
4906 // 0% for volume 0
4907 index = 0;
4908 } else if (index == 1) {
4909 // 50% for volume 1
4910 index = (int)(mIndexMax * 0.5) /10;
4911 } else if (index == 2) {
4912 // 70% for volume 2
4913 index = (int)(mIndexMax * 0.70) /10;
4914 } else if (index == 3) {
4915 // 85% for volume 3
4916 index = (int)(mIndexMax * 0.85) /10;
4917 } else {
4918 // otherwise, full gain
4919 index = (mIndexMax + 5)/10;
4920 }
4921 return index;
4922 }
4923
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004924 // must be called while synchronized VolumeStreamState.class
4925 public void applyDeviceVolume_syncVSS(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07004926 int index;
RoboErik4197cb62015-01-21 15:45:32 -08004927 if (mIsMuted) {
Eric Laurent42b041e2013-03-29 11:36:03 -07004928 index = 0;
Liejun Tao4565a472016-01-20 17:52:20 -06004929 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) {
Liejun Tao39fb5672016-03-09 15:52:13 -06004930 index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
Liejun Tao4565a472016-01-20 17:52:20 -06004931 } else if ((device & mFullVolumeDevices) != 0) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004932 index = (mIndexMax + 5)/10;
Jakub Pawlowskic274fb22018-04-04 10:15:12 -07004933 } else if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
4934 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07004935 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07004936 index = (getIndex(device) + 5)/10;
4937 }
4938 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004939 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004940
Eric Laurentfdbee862014-05-12 15:26:12 -07004941 public void applyAllVolumes() {
4942 synchronized (VolumeStreamState.class) {
Eric Laurentd9ac2be2016-04-07 14:04:23 -07004943 // apply device specific volumes first
Eric Laurentfdbee862014-05-12 15:26:12 -07004944 int index;
John Spurlock2bb02ec2015-03-02 13:13:06 -05004945 for (int i = 0; i < mIndexMap.size(); i++) {
Eric Laurentd9ac2be2016-04-07 14:04:23 -07004946 final int device = mIndexMap.keyAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07004947 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
RoboErik4197cb62015-01-21 15:45:32 -08004948 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004949 index = 0;
Liejun Tao39fb5672016-03-09 15:52:13 -06004950 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
4951 mAvrcpAbsVolSupported) {
4952 index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
4953 } else if ((device & mFullVolumeDevices) != 0) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004954 index = (mIndexMax + 5)/10;
Jakub Pawlowskic274fb22018-04-04 10:15:12 -07004955 } else if ((device & AudioSystem.DEVICE_OUT_HEARING_AID) != 0) {
4956 index = (mIndexMax + 5)/10;
Eric Laurentfdbee862014-05-12 15:26:12 -07004957 } else {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004958 index = (mIndexMap.valueAt(i) + 5)/10;
Eric Laurentfdbee862014-05-12 15:26:12 -07004959 }
4960 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07004961 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004962 }
Eric Laurentd9ac2be2016-04-07 14:04:23 -07004963 // apply default volume last: by convention , default device volume will be used
4964 // by audio policy manager if no explicit volume is present for a given device type
4965 if (mIsMuted) {
4966 index = 0;
4967 } else {
4968 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
4969 }
4970 AudioSystem.setStreamVolumeIndex(
4971 mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004972 }
4973 }
4974
John Spurlock90874332015-03-10 16:00:54 -04004975 public boolean adjustIndex(int deltaIndex, int device, String caller) {
4976 return setIndex(getIndex(device) + deltaIndex, device, caller);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004977 }
4978
John Spurlock90874332015-03-10 16:00:54 -04004979 public boolean setIndex(int index, int device, String caller) {
Jack He6dd78c12018-02-12 21:00:24 -08004980 boolean changed;
John Spurlockf63860c2015-02-19 09:46:27 -05004981 int oldIndex;
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004982 synchronized (mSettingsLock) {
4983 synchronized (VolumeStreamState.class) {
4984 oldIndex = getIndex(device);
4985 index = getValidIndex(index);
Eric Laurentfdbee862014-05-12 15:26:12 -07004986 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
4987 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07004988 }
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004989 mIndexMap.put(device, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07004990
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004991 changed = oldIndex != index;
4992 // Apply change to all streams using this one as alias if:
4993 // - the index actually changed OR
4994 // - there is no volume index stored for this device on alias stream.
4995 // If changing volume of current device, also change volume of current
4996 // device on aliased stream
Jack He6dd78c12018-02-12 21:00:24 -08004997 final boolean isCurrentDevice = (device == getDeviceForStream(mStreamType));
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004998 final int numStreamTypes = AudioSystem.getNumStreamTypes();
4999 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
5000 final VolumeStreamState aliasStreamState = mStreamStates[streamType];
5001 if (streamType != mStreamType &&
5002 mStreamVolumeAlias[streamType] == mStreamType &&
5003 (changed || !aliasStreamState.hasIndexForDevice(device))) {
5004 final int scaledIndex = rescaleIndex(index, mStreamType, streamType);
5005 aliasStreamState.setIndex(scaledIndex, device, caller);
Jack He6dd78c12018-02-12 21:00:24 -08005006 if (isCurrentDevice) {
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08005007 aliasStreamState.setIndex(scaledIndex,
5008 getDeviceForStream(streamType), caller);
5009 }
Eric Laurentfdbee862014-05-12 15:26:12 -07005010 }
5011 }
Jack He6dd78c12018-02-12 21:00:24 -08005012 // Mirror changes in SPEAKER ringtone volume on SCO when
5013 if (changed && mStreamType == AudioSystem.STREAM_RING
5014 && device == AudioSystem.DEVICE_OUT_SPEAKER) {
5015 for (int i = 0; i < mIndexMap.size(); i++) {
5016 int otherDevice = mIndexMap.keyAt(i);
5017 if ((otherDevice & AudioSystem.DEVICE_OUT_ALL_SCO) != 0) {
5018 mIndexMap.put(otherDevice, index);
5019 }
5020 }
5021 }
Eric Laurentfdbee862014-05-12 15:26:12 -07005022 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005023 }
John Spurlockf63860c2015-02-19 09:46:27 -05005024 if (changed) {
5025 oldIndex = (oldIndex + 5) / 10;
5026 index = (index + 5) / 10;
John Spurlock90874332015-03-10 16:00:54 -04005027 // log base stream changes to the event log
5028 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
5029 if (caller == null) {
5030 Log.w(TAG, "No caller for volume_changed event", new Throwable());
5031 }
5032 EventLogTags.writeVolumeChanged(mStreamType, oldIndex, index, mIndexMax / 10,
5033 caller);
5034 }
5035 // fire changed intents for all streams
John Spurlockf63860c2015-02-19 09:46:27 -05005036 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
5037 mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
Jean-Michel Trivi560877d2015-06-25 17:38:35 -07005038 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
5039 mStreamVolumeAlias[mStreamType]);
John Spurlockf63860c2015-02-19 09:46:27 -05005040 sendBroadcastToAll(mVolumeChanged);
5041 }
5042 return changed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005043 }
5044
Eric Laurentfdbee862014-05-12 15:26:12 -07005045 public int getIndex(int device) {
5046 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05005047 int index = mIndexMap.get(device, -1);
5048 if (index == -1) {
Eric Laurentfdbee862014-05-12 15:26:12 -07005049 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
John Spurlock2bb02ec2015-03-02 13:13:06 -05005050 index = mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurentfdbee862014-05-12 15:26:12 -07005051 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05005052 return index;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08005053 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07005054 }
5055
Eric Laurent3fb608e2016-11-03 16:27:40 -07005056 public boolean hasIndexForDevice(int device) {
5057 synchronized (VolumeStreamState.class) {
5058 return (mIndexMap.get(device, -1) != -1);
5059 }
5060 }
5061
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005062 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07005063 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005064 }
5065
John Spurlockb6e19e32015-03-10 21:33:44 -04005066 public int getMinIndex() {
5067 return mIndexMin;
5068 }
5069
Jean-Michel Trivi170a0ee2017-04-14 18:13:26 -07005070 /**
Jean-Michel Trivie05eef82018-03-08 18:56:34 -08005071 * Updates the min/max index values from another stream. Use this when changing the alias
5072 * for the current stream type.
5073 * @param sourceStreamType
5074 */
5075 // must be sync'd on mSettingsLock before VolumeStreamState.class
5076 @GuardedBy("VolumeStreamState.class")
5077 public void refreshRange(int sourceStreamType) {
5078 mIndexMin = MIN_STREAM_VOLUME[sourceStreamType] * 10;
5079 mIndexMax = MAX_STREAM_VOLUME[sourceStreamType] * 10;
5080 // verify all current volumes are within bounds
5081 for (int i = 0 ; i < mIndexMap.size(); i++) {
5082 final int device = mIndexMap.keyAt(i);
5083 final int index = mIndexMap.valueAt(i);
5084 mIndexMap.put(device, getValidIndex(index));
5085 }
5086 }
5087
5088 /**
Jean-Michel Trivi170a0ee2017-04-14 18:13:26 -07005089 * Copies all device/index pairs from the given VolumeStreamState after initializing
5090 * them with the volume for DEVICE_OUT_DEFAULT. No-op if the source VolumeStreamState
5091 * has the same stream type as this instance.
5092 * @param srcStream
5093 * @param caller
5094 */
Jean-Michel Trivi085346a2018-02-14 10:48:51 -08005095 // must be sync'd on mSettingsLock before VolumeStreamState.class
5096 @GuardedBy("VolumeStreamState.class")
John Spurlock90874332015-03-10 16:00:54 -04005097 public void setAllIndexes(VolumeStreamState srcStream, String caller) {
Jean-Michel Trivi170a0ee2017-04-14 18:13:26 -07005098 if (mStreamType == srcStream.mStreamType) {
5099 return;
5100 }
Jean-Michel Trivi085346a2018-02-14 10:48:51 -08005101 int srcStreamType = srcStream.getStreamType();
5102 // apply default device volume from source stream to all devices first in case
5103 // some devices are present in this stream state but not in source stream state
5104 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
5105 index = rescaleIndex(index, srcStreamType, mStreamType);
5106 for (int i = 0; i < mIndexMap.size(); i++) {
5107 mIndexMap.put(mIndexMap.keyAt(i), index);
5108 }
5109 // Now apply actual volume for devices in source stream state
5110 SparseIntArray srcMap = srcStream.mIndexMap;
5111 for (int i = 0; i < srcMap.size(); i++) {
5112 int device = srcMap.keyAt(i);
5113 index = srcMap.valueAt(i);
5114 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07005115
Jean-Michel Trivi085346a2018-02-14 10:48:51 -08005116 setIndex(index, device, caller);
Eric Laurent6d517662012-04-23 18:42:39 -07005117 }
5118 }
5119
Jean-Michel Trivi085346a2018-02-14 10:48:51 -08005120 // must be sync'd on mSettingsLock before VolumeStreamState.class
5121 @GuardedBy("VolumeStreamState.class")
Eric Laurentfdbee862014-05-12 15:26:12 -07005122 public void setAllIndexesToMax() {
Jean-Michel Trivi085346a2018-02-14 10:48:51 -08005123 for (int i = 0; i < mIndexMap.size(); i++) {
5124 mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
Eric Laurentdd45d012012-10-08 09:04:34 -07005125 }
Eric Laurentdd45d012012-10-08 09:04:34 -07005126 }
5127
RoboErik4197cb62015-01-21 15:45:32 -08005128 public void mute(boolean state) {
John Spurlock22b9ee12015-02-18 22:51:44 -05005129 boolean changed = false;
Eric Laurentfdbee862014-05-12 15:26:12 -07005130 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08005131 if (state != mIsMuted) {
John Spurlock22b9ee12015-02-18 22:51:44 -05005132 changed = true;
RoboErik4197cb62015-01-21 15:45:32 -08005133 mIsMuted = state;
John Spurlock22b9ee12015-02-18 22:51:44 -05005134
RoboErik4197cb62015-01-21 15:45:32 -08005135 // Set the new mute volume. This propagates the values to
5136 // the audio system, otherwise the volume won't be changed
5137 // at the lower level.
5138 sendMsg(mAudioHandler,
5139 MSG_SET_ALL_VOLUMES,
5140 SENDMSG_QUEUE,
5141 0,
5142 0,
5143 this, 0);
Eric Laurentfdbee862014-05-12 15:26:12 -07005144 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005145 }
John Spurlock22b9ee12015-02-18 22:51:44 -05005146 if (changed) {
5147 // Stream mute changed, fire the intent.
5148 Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
5149 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
5150 intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
5151 sendBroadcastToAll(intent);
5152 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005153 }
5154
Eric Laurent6d517662012-04-23 18:42:39 -07005155 public int getStreamType() {
5156 return mStreamType;
5157 }
5158
Eric Laurent212532b2014-07-21 15:43:18 -07005159 public void checkFixedVolumeDevices() {
5160 synchronized (VolumeStreamState.class) {
5161 // ignore settings for fixed volume devices: volume should always be at max or 0
5162 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05005163 for (int i = 0; i < mIndexMap.size(); i++) {
5164 int device = mIndexMap.keyAt(i);
5165 int index = mIndexMap.valueAt(i);
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07005166 if (((device & mFullVolumeDevices) != 0)
5167 || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05005168 mIndexMap.put(device, mIndexMax);
Eric Laurent212532b2014-07-21 15:43:18 -07005169 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005170 applyDeviceVolume_syncVSS(device);
Eric Laurent212532b2014-07-21 15:43:18 -07005171 }
5172 }
5173 }
5174 }
5175
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005176 private int getValidIndex(int index) {
John Spurlockb6e19e32015-03-10 21:33:44 -04005177 if (index < mIndexMin) {
5178 return mIndexMin;
John Spurlockee5ad722015-03-03 16:17:21 -05005179 } else if (mUseFixedVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07005180 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005181 }
5182
5183 return index;
5184 }
5185
Eric Laurentbffc3d12012-05-07 17:43:49 -07005186 private void dump(PrintWriter pw) {
RoboErik4197cb62015-01-21 15:45:32 -08005187 pw.print(" Muted: ");
5188 pw.println(mIsMuted);
John Spurlockb6e19e32015-03-10 21:33:44 -04005189 pw.print(" Min: ");
5190 pw.println((mIndexMin + 5) / 10);
John Spurlock2b29bc42014-08-26 16:40:35 -04005191 pw.print(" Max: ");
5192 pw.println((mIndexMax + 5) / 10);
Eric Laurentbffc3d12012-05-07 17:43:49 -07005193 pw.print(" Current: ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05005194 for (int i = 0; i < mIndexMap.size(); i++) {
5195 if (i > 0) {
5196 pw.print(", ");
5197 }
5198 final int device = mIndexMap.keyAt(i);
John Spurlock2b29bc42014-08-26 16:40:35 -04005199 pw.print(Integer.toHexString(device));
5200 final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
5201 : AudioSystem.getOutputDeviceName(device);
5202 if (!deviceName.isEmpty()) {
5203 pw.print(" (");
5204 pw.print(deviceName);
5205 pw.print(")");
5206 }
5207 pw.print(": ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05005208 final int index = (mIndexMap.valueAt(i) + 5) / 10;
John Spurlock2b29bc42014-08-26 16:40:35 -04005209 pw.print(index);
Eric Laurentbffc3d12012-05-07 17:43:49 -07005210 }
John Spurlockb32fc972015-03-05 13:58:00 -05005211 pw.println();
5212 pw.print(" Devices: ");
John Spurlock8a52c442015-03-26 14:23:58 -04005213 final int devices = getDevicesForStream(mStreamType);
John Spurlockb32fc972015-03-05 13:58:00 -05005214 int device, i = 0, n = 0;
John Spurlock1ff1e6e2015-03-09 14:21:20 -04005215 // iterate all devices from 1 to DEVICE_OUT_DEFAULT exclusive
5216 // (the default device is not returned by getDevicesForStream)
5217 while ((device = 1 << i) != AudioSystem.DEVICE_OUT_DEFAULT) {
John Spurlockb32fc972015-03-05 13:58:00 -05005218 if ((devices & device) != 0) {
5219 if (n++ > 0) {
5220 pw.print(", ");
5221 }
5222 pw.print(AudioSystem.getOutputDeviceName(device));
5223 }
5224 i++;
5225 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07005226 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005227 }
5228
5229 /** Thread that handles native AudioSystem control. */
5230 private class AudioSystemThread extends Thread {
5231 AudioSystemThread() {
5232 super("AudioService");
5233 }
5234
5235 @Override
5236 public void run() {
5237 // Set this thread up so the handler will work on it
5238 Looper.prepare();
5239
5240 synchronized(AudioService.this) {
5241 mAudioHandler = new AudioHandler();
5242
5243 // Notify that the handler has been created
5244 AudioService.this.notify();
5245 }
5246
5247 // Listen for volume change requests that are set by VolumePanel
5248 Looper.loop();
5249 }
5250 }
5251
Eric Laurent3e6fb632018-05-21 09:28:46 -07005252 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005253
Eric Laurent3e6fb632018-05-21 09:28:46 -07005254 synchronized (VolumeStreamState.class) {
5255 // Apply volume
5256 streamState.applyDeviceVolume_syncVSS(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005257
Eric Laurent3e6fb632018-05-21 09:28:46 -07005258 // Apply change to all streams using this one as alias
5259 int numStreamTypes = AudioSystem.getNumStreamTypes();
5260 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
5261 if (streamType != streamState.mStreamType &&
5262 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
5263 // Make sure volume is also maxed out on A2DP device for aliased stream
5264 // that may have a different device selected
5265 int streamDevice = getDeviceForStream(streamType);
5266 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
5267 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
5268 mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
Eric Laurentcd772d02013-10-30 18:31:07 -07005269 }
Eric Laurent3e6fb632018-05-21 09:28:46 -07005270 mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
Eric Laurenta553c252009-07-17 12:17:14 -07005271 }
5272 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005273 }
Eric Laurent3e6fb632018-05-21 09:28:46 -07005274 // Post a persist volume msg
5275 sendMsg(mAudioHandler,
5276 MSG_PERSIST_VOLUME,
5277 SENDMSG_QUEUE,
5278 device,
5279 0,
5280 streamState,
5281 PERSIST_DELAY);
5282
5283 }
5284
5285 /** Handles internal volume messages in separate volume thread. */
5286 private class AudioHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005287
Eric Laurent9bc8358d2011-11-18 16:43:31 -08005288 private void setAllVolumes(VolumeStreamState streamState) {
5289
5290 // Apply volume
5291 streamState.applyAllVolumes();
5292
5293 // Apply change to all streams using this one as alias
5294 int numStreamTypes = AudioSystem.getNumStreamTypes();
5295 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
5296 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07005297 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08005298 mStreamStates[streamType].applyAllVolumes();
5299 }
5300 }
5301 }
5302
Eric Laurent42b041e2013-03-29 11:36:03 -07005303 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07005304 if (mUseFixedVolume) {
5305 return;
5306 }
Muyuan Li1ed6df62016-06-18 11:16:52 -07005307 if (mIsSingleVolume && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
Eric Laurent212532b2014-07-21 15:43:18 -07005308 return;
5309 }
Jean-Michel Trivia53b7052017-04-12 18:27:01 -07005310 if (streamState.hasValidSettingsName()) {
5311 System.putIntForUser(mContentResolver,
5312 streamState.getSettingNameForDevice(device),
5313 (streamState.getIndex(device) + 5)/ 10,
5314 UserHandle.USER_CURRENT);
5315 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005316 }
5317
Glenn Kastenba195eb2011-12-13 09:30:40 -08005318 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07005319 if (mUseFixedVolume) {
5320 return;
5321 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07005322 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005323 }
5324
Jaekyun Seokc31033f2018-01-15 14:53:17 +09005325 private String getSoundEffectFilePath(int effectType) {
5326 String filePath = Environment.getProductDirectory() + SOUND_EFFECTS_PATH
5327 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
5328 if (!new File(filePath).isFile()) {
5329 filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH
5330 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
5331 }
5332 return filePath;
5333 }
5334
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07005335 private boolean onLoadSoundEffects() {
5336 int status;
5337
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005338 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07005339 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07005340 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
5341 return false;
5342 }
5343
5344 if (mSoundPool != null) {
5345 return true;
5346 }
5347
5348 loadTouchSoundAssets();
5349
Jean-Michel Trivi55a30c42014-07-20 17:56:11 -07005350 mSoundPool = new SoundPool.Builder()
5351 .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
5352 .setAudioAttributes(new AudioAttributes.Builder()
5353 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
5354 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
5355 .build())
5356 .build();
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07005357 mSoundPoolCallBack = null;
5358 mSoundPoolListenerThread = new SoundPoolListenerThread();
5359 mSoundPoolListenerThread.start();
5360 int attempts = 3;
5361 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
5362 try {
5363 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07005364 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07005365 } catch (InterruptedException e) {
5366 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
5367 }
5368 }
5369
5370 if (mSoundPoolCallBack == null) {
5371 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
5372 if (mSoundPoolLooper != null) {
5373 mSoundPoolLooper.quit();
5374 mSoundPoolLooper = null;
5375 }
5376 mSoundPoolListenerThread = null;
5377 mSoundPool.release();
5378 mSoundPool = null;
5379 return false;
5380 }
5381 /*
5382 * poolId table: The value -1 in this table indicates that corresponding
5383 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
5384 * Once loaded, the value in poolId is the sample ID and the same
5385 * sample can be reused for another effect using the same file.
5386 */
5387 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
5388 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
5389 poolId[fileIdx] = -1;
5390 }
5391 /*
5392 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
5393 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
5394 * this indicates we have a valid sample loaded for this effect.
5395 */
5396
5397 int numSamples = 0;
5398 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
5399 // Do not load sample if this effect uses the MediaPlayer
5400 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
5401 continue;
5402 }
5403 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
Jaekyun Seokc31033f2018-01-15 14:53:17 +09005404 String filePath = getSoundEffectFilePath(effect);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07005405 int sampleId = mSoundPool.load(filePath, 0);
5406 if (sampleId <= 0) {
5407 Log.w(TAG, "Soundpool could not load file: "+filePath);
5408 } else {
5409 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
5410 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
5411 numSamples++;
5412 }
5413 } else {
5414 SOUND_EFFECT_FILES_MAP[effect][1] =
5415 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
5416 }
5417 }
5418 // wait for all samples to be loaded
5419 if (numSamples > 0) {
5420 mSoundPoolCallBack.setSamples(poolId);
5421
5422 attempts = 3;
5423 status = 1;
5424 while ((status == 1) && (attempts-- > 0)) {
5425 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07005426 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07005427 status = mSoundPoolCallBack.status();
5428 } catch (InterruptedException e) {
5429 Log.w(TAG, "Interrupted while waiting sound pool callback.");
5430 }
5431 }
5432 } else {
5433 status = -1;
5434 }
5435
5436 if (mSoundPoolLooper != null) {
5437 mSoundPoolLooper.quit();
5438 mSoundPoolLooper = null;
5439 }
5440 mSoundPoolListenerThread = null;
5441 if (status != 0) {
5442 Log.w(TAG,
5443 "onLoadSoundEffects(), Error "+status+ " while loading samples");
5444 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
5445 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
5446 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
5447 }
5448 }
5449
5450 mSoundPool.release();
5451 mSoundPool = null;
5452 }
5453 }
5454 return (status == 0);
5455 }
5456
5457 /**
5458 * Unloads samples from the sound pool.
5459 * This method can be called to free some memory when
5460 * sound effects are disabled.
5461 */
5462 private void onUnloadSoundEffects() {
5463 synchronized (mSoundEffectsLock) {
5464 if (mSoundPool == null) {
5465 return;
5466 }
5467
5468 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
5469 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
5470 poolId[fileIdx] = 0;
5471 }
5472
5473 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
5474 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
5475 continue;
5476 }
5477 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
5478 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
5479 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
5480 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
5481 }
5482 }
5483 mSoundPool.release();
5484 mSoundPool = null;
5485 }
5486 }
5487
5488 private void onPlaySoundEffect(int effectType, int volume) {
5489 synchronized (mSoundEffectsLock) {
5490
5491 onLoadSoundEffects();
5492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005493 if (mSoundPool == null) {
5494 return;
5495 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07005496 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08005497 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07005498 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07005499 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07005500 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07005501 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07005502 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005503
5504 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07005505 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
5506 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005507 } else {
5508 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08005509 try {
Jaekyun Seokc31033f2018-01-15 14:53:17 +09005510 String filePath = getSoundEffectFilePath(effectType);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08005511 mediaPlayer.setDataSource(filePath);
5512 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
5513 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08005514 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08005515 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
5516 public void onCompletion(MediaPlayer mp) {
5517 cleanupPlayer(mp);
5518 }
5519 });
5520 mediaPlayer.setOnErrorListener(new OnErrorListener() {
5521 public boolean onError(MediaPlayer mp, int what, int extra) {
5522 cleanupPlayer(mp);
5523 return true;
5524 }
5525 });
5526 mediaPlayer.start();
5527 } catch (IOException ex) {
5528 Log.w(TAG, "MediaPlayer IOException: "+ex);
5529 } catch (IllegalArgumentException ex) {
5530 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
5531 } catch (IllegalStateException ex) {
5532 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005533 }
5534 }
5535 }
5536 }
5537
5538 private void cleanupPlayer(MediaPlayer mp) {
5539 if (mp != null) {
5540 try {
5541 mp.stop();
5542 mp.release();
5543 } catch (IllegalStateException ex) {
5544 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
5545 }
5546 }
5547 }
5548
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005549 private void setForceUse(int usage, int config, String eventSource) {
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005550 synchronized (mConnectedDevices) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005551 setForceUseInt_SyncDevices(usage, config, eventSource);
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005552 }
Eric Laurentfa640152011-03-12 15:59:51 -08005553 }
5554
Eric Laurent05274f32012-11-29 12:48:18 -08005555 private void onPersistSafeVolumeState(int state) {
5556 Settings.Global.putInt(mContentResolver,
5557 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
5558 state);
5559 }
5560
Jean-Michel Trivi7ed71472018-02-02 16:52:09 -08005561 private void onNotifyVolumeEvent(@NonNull IAudioPolicyCallback apc,
5562 @AudioManager.VolumeAdjustment int direction) {
5563 try {
5564 apc.notifyVolumeAdjust(direction);
5565 } catch(Exception e) {
5566 // nothing we can do about this. Do not log error, too much potential for spam
5567 }
5568 }
5569
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005570 @Override
5571 public void handleMessage(Message msg) {
Eric Laurentafbb0472011-12-15 09:04:23 -08005572 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005573
Eric Laurent9bc8358d2011-11-18 16:43:31 -08005574 case MSG_SET_DEVICE_VOLUME:
5575 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
5576 break;
5577
5578 case MSG_SET_ALL_VOLUMES:
5579 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005580 break;
5581
5582 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07005583 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005584 break;
5585
5586 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08005587 // note that the value persisted is the current ringer mode, not the
5588 // value of ringer mode as of the time the request was made to persist
John Spurlock661f2cf2014-11-17 10:29:10 -05005589 persistRingerMode(getRingerModeInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005590 break;
5591
Andy Hunged0ea402015-10-30 14:11:46 -07005592 case MSG_AUDIO_SERVER_DIED:
5593 onAudioServerDied();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005594 break;
5595
Eric Laurent1d3cdce2018-01-20 10:31:21 -08005596 case MSG_DISPATCH_AUDIO_SERVER_STATE:
5597 onDispatchAudioServerStateChange(msg.arg1 == 1);
5598 break;
5599
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07005600 case MSG_UNLOAD_SOUND_EFFECTS:
5601 onUnloadSoundEffects();
5602 break;
5603
Eric Laurent117b7bb2011-01-16 17:07:27 -08005604 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07005605 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
5606 // can take several dozens of milliseconds to complete
5607 boolean loaded = onLoadSoundEffects();
5608 if (msg.obj != null) {
5609 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
5610 synchronized (reply) {
5611 reply.mStatus = loaded ? 0 : -1;
5612 reply.notify();
5613 }
5614 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08005615 break;
5616
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005617 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07005618 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005619 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005620
5621 case MSG_BTA2DP_DOCK_TIMEOUT:
5622 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005623 synchronized (mConnectedDevices) {
5624 makeA2dpDeviceUnavailableNow( (String) msg.obj );
5625 }
Eric Laurent3c4636c2018-06-13 19:36:42 -07005626 mAudioEventWakeLock.release();
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005627 break;
Eric Laurentfa640152011-03-12 15:59:51 -08005628
5629 case MSG_SET_FORCE_USE:
Sungsoocf09fe62016-09-28 16:21:48 +09005630 case MSG_SET_FORCE_BT_A2DP_USE:
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005631 setForceUse(msg.arg1, msg.arg2, (String) msg.obj);
Eric Laurentfa640152011-03-12 15:59:51 -08005632 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07005633
Eric Laurentdc03c612011-04-01 10:59:41 -07005634 case MSG_BT_HEADSET_CNCT_FAILED:
5635 resetBluetoothSco();
5636 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005637
5638 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
Paul McLean10804eb2015-01-28 11:16:35 -08005639 { WiredDeviceConnectionState connectState =
5640 (WiredDeviceConnectionState)msg.obj;
Jean-Michel Trivi3bf75782018-07-02 10:48:04 -07005641 mDeviceLogger.log(new WiredDevConnectEvent(connectState));
Paul McLean10804eb2015-01-28 11:16:35 -08005642 onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
John Spurlock90874332015-03-10 16:00:54 -04005643 connectState.mAddress, connectState.mName, connectState.mCaller);
Paul McLean10804eb2015-01-28 11:16:35 -08005644 mAudioEventWakeLock.release();
5645 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005646 break;
5647
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005648 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
5649 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
5650 mAudioEventWakeLock.release();
5651 break;
5652
5653 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
Eric Laurent3e6fb632018-05-21 09:28:46 -07005654 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1, msg.arg2);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005655 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005656 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07005657
Jakub Pawlowskif9570f32018-02-21 17:15:12 -08005658 case MSG_SET_HEARING_AID_CONNECTION_STATE:
5659 onSetHearingAidConnectionState((BluetoothDevice)msg.obj, msg.arg1);
5660 mAudioEventWakeLock.release();
5661 break;
5662
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005663 case MSG_A2DP_DEVICE_CONFIG_CHANGE:
5664 onBluetoothA2dpDeviceConfigChange((BluetoothDevice)msg.obj);
5665 mAudioEventWakeLock.release();
5666 break;
5667
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -07005668 case MSG_DISABLE_AUDIO_FOR_UID:
5669 mPlaybackMonitor.disableAudioForUid( msg.arg1 == 1 /* disable */,
5670 msg.arg2 /* uid */);
5671 mAudioEventWakeLock.release();
5672 break;
5673
Dianne Hackborn632ca412012-06-14 19:34:10 -07005674 case MSG_REPORT_NEW_ROUTES: {
5675 int N = mRoutesObservers.beginBroadcast();
5676 if (N > 0) {
5677 AudioRoutesInfo routes;
5678 synchronized (mCurAudioRoutes) {
5679 routes = new AudioRoutesInfo(mCurAudioRoutes);
5680 }
5681 while (N > 0) {
5682 N--;
5683 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
5684 try {
5685 obs.dispatchAudioRoutesChanged(routes);
5686 } catch (RemoteException e) {
5687 }
5688 }
5689 }
5690 mRoutesObservers.finishBroadcast();
John Spurlock8a52c442015-03-26 14:23:58 -04005691 observeDevicesForStreams(-1);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005692 break;
5693 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005694
Eric Laurentc34dcc12012-09-10 13:51:52 -07005695 case MSG_CHECK_MUSIC_ACTIVE:
John Spurlock90874332015-03-10 16:00:54 -04005696 onCheckMusicActive((String) msg.obj);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005697 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07005698
5699 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
5700 onSendBecomingNoisyIntent();
5701 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07005702
5703 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
5704 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
John Spurlock90874332015-03-10 16:00:54 -04005705 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED),
5706 (String) msg.obj);
Eric Laurentd640bd32012-09-28 18:01:48 -07005707 break;
Eric Laurent05274f32012-11-29 12:48:18 -08005708 case MSG_PERSIST_SAFE_VOLUME_STATE:
5709 onPersistSafeVolumeState(msg.arg1);
5710 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08005711
Eric Laurent2a57ca92013-03-07 17:29:27 -08005712 case MSG_BROADCAST_BT_CONNECTION_STATE:
5713 onBroadcastScoConnectionState(msg.arg1);
5714 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07005715
5716 case MSG_SYSTEM_READY:
5717 onSystemReady();
5718 break;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005719
Eric Laurent0867bed2015-05-20 14:49:08 -07005720 case MSG_INDICATE_SYSTEM_READY:
5721 onIndicateSystemReady();
5722 break;
5723
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07005724 case MSG_ACCESSORY_PLUG_MEDIA_UNMUTE:
5725 onAccessoryPlugMediaUnmute(msg.arg1);
5726 break;
5727
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005728 case MSG_PERSIST_MUSIC_ACTIVE_MS:
5729 final int musicActiveMs = msg.arg1;
5730 Settings.Secure.putIntForUser(mContentResolver,
5731 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
5732 UserHandle.USER_CURRENT);
5733 break;
Eric Laurentc0232482016-03-15 18:19:23 -07005734
RoboErik5452e252015-02-06 15:33:53 -08005735 case MSG_UNMUTE_STREAM:
5736 onUnmuteStream(msg.arg1, msg.arg2);
5737 break;
Eric Laurentc0232482016-03-15 18:19:23 -07005738
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07005739 case MSG_DYN_POLICY_MIX_STATE_UPDATE:
5740 onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1);
5741 break;
Jean-Michel Trivi7ed71472018-02-02 16:52:09 -08005742
5743 case MSG_NOTIFY_VOL_EVENT:
5744 onNotifyVolumeEvent((IAudioPolicyCallback) msg.obj, msg.arg1);
5745 break;
jiabin39940752018-04-02 18:18:45 -07005746
5747 case MSG_ENABLE_SURROUND_FORMATS:
5748 onEnableSurroundFormats((ArrayList<Integer>) msg.obj);
5749 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005750 }
5751 }
5752 }
5753
Jason Parekhb1096152009-03-24 17:48:25 -07005754 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07005755
Jason Parekhb1096152009-03-24 17:48:25 -07005756 SettingsObserver() {
5757 super(new Handler());
Beverlyd6964762018-02-16 14:07:03 -05005758 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
5759 Settings.Global.ZEN_MODE), false, this);
5760 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
5761 Settings.Global.ZEN_MODE_CONFIG_ETAG), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07005762 mContentResolver.registerContentObserver(Settings.System.getUriFor(
5763 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07005764 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
5765 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Andy Hung7b98e9a2016-02-25 18:34:50 -08005766 mContentResolver.registerContentObserver(Settings.System.getUriFor(
5767 Settings.System.MASTER_MONO), false, this);
Phil Burked43bf52016-03-01 17:01:35 -08005768
5769 mEncodedSurroundMode = Settings.Global.getInt(
5770 mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT,
5771 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
5772 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
5773 Settings.Global.ENCODED_SURROUND_OUTPUT), false, this);
jiabin39940752018-04-02 18:18:45 -07005774
5775 mEnabledSurroundFormats = Settings.Global.getString(
5776 mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS);
5777 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
5778 Settings.Global.ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07005779 }
5780
5781 @Override
5782 public void onChange(boolean selfChange) {
5783 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08005784 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
Beverlyd6964762018-02-16 14:07:03 -05005785 // However there appear to be some missing locks around mRingerAndZenModeMutedStreams
Glenn Kastenba195eb2011-12-13 09:30:40 -08005786 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
Beverlyd6964762018-02-16 14:07:03 -05005787 // mRingerAndZenModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07005788 synchronized (mSettingsLock) {
Beverlyd6964762018-02-16 14:07:03 -05005789 if (updateRingerAndZenModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07005790 /*
5791 * Ensure all stream types that should be affected by ringer mode
5792 * are in the proper state.
5793 */
John Spurlock661f2cf2014-11-17 10:29:10 -05005794 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurenta553c252009-07-17 12:17:14 -07005795 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07005796 readDockAudioSettings(mContentResolver);
Andy Hung7b98e9a2016-02-25 18:34:50 -08005797 updateMasterMono(mContentResolver);
Phil Burked43bf52016-03-01 17:01:35 -08005798 updateEncodedSurroundOutput();
jiabin39940752018-04-02 18:18:45 -07005799 sendEnabledSurroundFormats(mContentResolver, mSurroundModeChanged);
Phil Burked43bf52016-03-01 17:01:35 -08005800 }
5801 }
5802
5803 private void updateEncodedSurroundOutput() {
5804 int newSurroundMode = Settings.Global.getInt(
5805 mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT,
5806 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
5807 // Did it change?
5808 if (mEncodedSurroundMode != newSurroundMode) {
5809 // Send to AudioPolicyManager
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005810 sendEncodedSurroundMode(newSurroundMode, "SettingsObserver");
Phil Burked43bf52016-03-01 17:01:35 -08005811 synchronized(mConnectedDevices) {
5812 // Is HDMI connected?
5813 String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_HDMI, "");
5814 DeviceListSpec deviceSpec = mConnectedDevices.get(key);
5815 if (deviceSpec != null) {
5816 // Toggle HDMI to retrigger broadcast with proper formats.
5817 setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
5818 AudioSystem.DEVICE_STATE_UNAVAILABLE, "", "",
5819 "android"); // disconnect
5820 setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
5821 AudioSystem.DEVICE_STATE_AVAILABLE, "", "",
5822 "android"); // reconnect
5823 }
5824 }
5825 mEncodedSurroundMode = newSurroundMode;
jiabin39940752018-04-02 18:18:45 -07005826 mSurroundModeChanged = true;
5827 } else {
5828 mSurroundModeChanged = false;
Eric Laurenta553c252009-07-17 12:17:14 -07005829 }
Jason Parekhb1096152009-03-24 17:48:25 -07005830 }
Jason Parekhb1096152009-03-24 17:48:25 -07005831 }
Eric Laurenta553c252009-07-17 12:17:14 -07005832
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005833 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005834 private void makeA2dpDeviceAvailable(String address, String name, String eventSource) {
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07005835 // enable A2DP before notifying A2DP connection to avoid unnecessary processing in
Eric Laurent78472112012-05-21 08:57:21 -07005836 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07005837 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005838 setBluetoothA2dpOnInt(true, eventSource);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005839 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07005840 AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005841 // Reset A2DP suspend state each time a new sink is connected
5842 AudioSystem.setParameters("A2dpSuspended=false");
Paul McLean394a8e12015-03-03 10:29:19 -07005843 mConnectedDevices.put(
5844 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
Paul McLean20eec5b2015-05-09 13:02:18 -07005845 new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
Paul McLean394a8e12015-03-03 10:29:19 -07005846 address));
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07005847 sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
5848 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, null, 0);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005849 }
5850
Eric Laurent5bfaeae2012-09-21 18:44:48 -07005851 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005852 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07005853 }
5854
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005855 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005856 private void makeA2dpDeviceUnavailableNow(String address) {
Eric Laurent3c4636c2018-06-13 19:36:42 -07005857 if (address == null) {
5858 return;
5859 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07005860 synchronized (mA2dpAvrcpLock) {
5861 mAvrcpAbsVolSupported = false;
5862 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005863 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07005864 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07005865 mConnectedDevices.remove(
5866 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
Jakub Pawlowskif9570f32018-02-21 17:15:12 -08005867 // Remove A2DP routes as well
5868 setCurrentAudioRouteName(null);
Eric Laurent3c4636c2018-06-13 19:36:42 -07005869 if (mDockAddress == address) {
5870 mDockAddress = null;
5871 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005872 }
5873
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005874 // must be called synchronized on mConnectedDevices
Eric Laurentd138e4e2015-05-15 16:41:15 -07005875 private void makeA2dpDeviceUnavailableLater(String address, int delayMs) {
Eric Laurent3b591262010-04-20 07:01:00 -07005876 // prevent any activity on the A2DP audio output to avoid unwanted
5877 // reconnection of the sink.
5878 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005879 // the device will be made unavailable later, so consider it disconnected right away
Paul McLean394a8e12015-03-03 10:29:19 -07005880 mConnectedDevices.remove(
5881 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005882 // send the delayed message to make the device unavailable later
Eric Laurent3c4636c2018-06-13 19:36:42 -07005883 queueMsgUnderWakeLock(mAudioHandler,
5884 MSG_BTA2DP_DOCK_TIMEOUT,
5885 0,
5886 0,
5887 address,
5888 delayMs);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005889 }
5890
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005891 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005892 private void makeA2dpSrcAvailable(String address) {
5893 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07005894 AudioSystem.DEVICE_STATE_AVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07005895 mConnectedDevices.put(
5896 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
Paul McLean20eec5b2015-05-09 13:02:18 -07005897 new DeviceListSpec(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "",
Paul McLean394a8e12015-03-03 10:29:19 -07005898 address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005899 }
5900
5901 // must be called synchronized on mConnectedDevices
5902 private void makeA2dpSrcUnavailable(String address) {
5903 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07005904 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07005905 mConnectedDevices.remove(
5906 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005907 }
5908
Jakub Pawlowski21b7f492018-03-22 12:31:21 -07005909 private void setHearingAidVolume(int index, int streamType) {
Jakub Pawlowski09592d52018-03-19 12:23:59 -07005910 synchronized (mHearingAidLock) {
5911 if (mHearingAid != null) {
5912 //hearing aid expect volume value in range -128dB to 0dB
Jakub Pawlowski21b7f492018-03-22 12:31:21 -07005913 int gainDB = (int)AudioSystem.getStreamVolumeDB(streamType, index/10,
Jakub Pawlowski09592d52018-03-19 12:23:59 -07005914 AudioSystem.DEVICE_OUT_HEARING_AID);
5915 if (gainDB < BT_HEARING_AID_GAIN_MIN)
5916 gainDB = BT_HEARING_AID_GAIN_MIN;
5917 mHearingAid.setVolume(gainDB);
5918 }
5919 }
5920 }
5921
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005922 // must be called synchronized on mConnectedDevices
Jakub Pawlowskif9570f32018-02-21 17:15:12 -08005923 private void makeHearingAidDeviceAvailable(String address, String name, String eventSource) {
Jakub Pawlowski09592d52018-03-19 12:23:59 -07005924 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(AudioSystem.DEVICE_OUT_HEARING_AID);
Jakub Pawlowski21b7f492018-03-22 12:31:21 -07005925 setHearingAidVolume(index, AudioSystem.STREAM_MUSIC);
Jakub Pawlowski09592d52018-03-19 12:23:59 -07005926
Jakub Pawlowskif9570f32018-02-21 17:15:12 -08005927 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
5928 AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
5929 mConnectedDevices.put(
5930 makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address),
5931 new DeviceListSpec(AudioSystem.DEVICE_OUT_HEARING_AID, name,
5932 address));
5933 sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
5934 AudioSystem.DEVICE_OUT_HEARING_AID, 0, null, 0);
5935 }
5936
5937 // must be called synchronized on mConnectedDevices
5938 private void makeHearingAidDeviceUnavailable(String address) {
5939 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
5940 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
5941 mConnectedDevices.remove(
5942 makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID, address));
5943 // Remove Hearing Aid routes as well
5944 setCurrentAudioRouteName(null);
5945 }
5946
5947 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07005948 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005949 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
5950 }
5951
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005952 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07005953 private boolean hasScheduledA2dpDockTimeout() {
5954 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
5955 }
5956
Eric Laurent3e6fb632018-05-21 09:28:46 -07005957 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state, int a2dpVolume)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005958 {
Eric Laurent4724ea72017-05-23 10:39:38 -07005959 if (DEBUG_DEVICES) {
Eric Laurent3c4636c2018-06-13 19:36:42 -07005960 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice= " + btDevice+" state= " + state
5961 + " is dock: "+btDevice.isBluetoothDock());
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005962 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005963 if (btDevice == null) {
5964 return;
5965 }
5966 String address = btDevice.getAddress();
5967 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
5968 address = "";
5969 }
John Du5a0cf7a2013-07-19 11:30:34 -07005970
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005971 synchronized (mConnectedDevices) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005972 final String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
5973 btDevice.getAddress());
5974 final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
Paul McLean394a8e12015-03-03 10:29:19 -07005975 boolean isConnected = deviceSpec != null;
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005976
5977 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
5978 if (btDevice.isBluetoothDock()) {
5979 if (state == BluetoothProfile.STATE_DISCONNECTED) {
5980 // introduction of a delay for transient disconnections of docks when
5981 // power is rapidly turned off/on, this message will be canceled if
5982 // we reconnect the dock under a preset delay
Eric Laurentd138e4e2015-05-15 16:41:15 -07005983 makeA2dpDeviceUnavailableLater(address, BTA2DP_DOCK_TIMEOUT_MILLIS);
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005984 // the next time isConnected is evaluated, it will be false for the dock
5985 }
5986 } else {
5987 makeA2dpDeviceUnavailableNow(address);
5988 }
Jakub Pawlowskif9570f32018-02-21 17:15:12 -08005989 setCurrentAudioRouteName(null);
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005990 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
5991 if (btDevice.isBluetoothDock()) {
5992 // this could be a reconnection after a transient disconnection
5993 cancelA2dpDeviceTimeout();
5994 mDockAddress = address;
5995 } else {
5996 // this could be a connection of another A2DP device before the timeout of
5997 // a dock: cancel the dock timeout, and make the dock unavailable now
Eric Laurent3c4636c2018-06-13 19:36:42 -07005998 if (hasScheduledA2dpDockTimeout() && mDockAddress != null) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005999 cancelA2dpDeviceTimeout();
6000 makeA2dpDeviceUnavailableNow(mDockAddress);
6001 }
6002 }
Eric Laurent3e6fb632018-05-21 09:28:46 -07006003 if (a2dpVolume != -1) {
6004 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
6005 // Convert index to internal representation in VolumeStreamState
6006 a2dpVolume = a2dpVolume * 10;
6007 streamState.setIndex(a2dpVolume, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
6008 "onSetA2dpSinkConnectionState");
6009 setDeviceVolume(streamState, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
6010 }
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006011 makeA2dpDeviceAvailable(address, btDevice.getName(),
6012 "onSetA2dpSinkConnectionState");
Jakub Pawlowskif9570f32018-02-21 17:15:12 -08006013 setCurrentAudioRouteName(btDevice.getAliasName());
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08006014 }
6015 }
6016 }
6017
Mike Lockwood0a40ec22014-05-21 10:08:50 -07006018 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
6019 {
6020 if (DEBUG_VOL) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08006021 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice=" + btDevice + " state=" + state);
Mike Lockwood0a40ec22014-05-21 10:08:50 -07006022 }
6023 if (btDevice == null) {
6024 return;
6025 }
6026 String address = btDevice.getAddress();
6027 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
6028 address = "";
6029 }
6030
6031 synchronized (mConnectedDevices) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08006032 final String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
6033 final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
Paul McLean394a8e12015-03-03 10:29:19 -07006034 boolean isConnected = deviceSpec != null;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07006035
6036 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
6037 makeA2dpSrcUnavailable(address);
6038 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
6039 makeA2dpSrcAvailable(address);
6040 }
6041 }
6042 }
6043
Jakub Pawlowskif9570f32018-02-21 17:15:12 -08006044 private void onSetHearingAidConnectionState(BluetoothDevice btDevice, int state)
6045 {
6046 if (DEBUG_DEVICES) {
6047 Log.d(TAG, "onSetHearingAidConnectionState btDevice=" + btDevice+", state=" + state);
6048 }
6049 if (btDevice == null) {
6050 return;
6051 }
6052 String address = btDevice.getAddress();
6053 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
6054 address = "";
6055 }
6056
6057 synchronized (mConnectedDevices) {
6058 final String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_HEARING_AID,
6059 btDevice.getAddress());
6060 final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
6061 boolean isConnected = deviceSpec != null;
6062
6063 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
6064 makeHearingAidDeviceUnavailable(address);
6065 setCurrentAudioRouteName(null);
6066 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
6067 makeHearingAidDeviceAvailable(address, btDevice.getName(),
6068 "onSetHearingAidConnectionState");
6069 setCurrentAudioRouteName(btDevice.getAliasName());
6070 }
6071 }
6072 }
6073
6074 private void setCurrentAudioRouteName(String name){
6075 synchronized (mCurAudioRoutes) {
6076 if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
6077 mCurAudioRoutes.bluetoothName = name;
6078 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
6079 SENDMSG_NOOP, 0, 0, null, 0);
6080 }
6081 }
6082 }
6083
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08006084 private void onBluetoothA2dpDeviceConfigChange(BluetoothDevice btDevice)
6085 {
Eric Laurent5205a352017-04-27 18:31:22 -07006086 if (DEBUG_DEVICES) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08006087 Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice);
6088 }
6089 if (btDevice == null) {
6090 return;
6091 }
6092 String address = btDevice.getAddress();
6093 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
6094 address = "";
6095 }
Jean-Michel Trivi3bf75782018-07-02 10:48:04 -07006096 mDeviceLogger.log(new AudioEventLogger.StringEvent(
6097 "onBluetoothA2dpDeviceConfigChange addr=" + address));
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08006098
6099 int device = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
6100 synchronized (mConnectedDevices) {
Eric Laurent4724ea72017-05-23 10:39:38 -07006101 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, btDevice)) {
Jean-Michel Trivi3bf75782018-07-02 10:48:04 -07006102 mDeviceLogger.log(new AudioEventLogger.StringEvent(
6103 "A2dp config change ignored"));
Eric Laurentcdae4762017-04-28 18:00:04 -07006104 return;
6105 }
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08006106 final String key = makeDeviceListKey(device, address);
6107 final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
6108 if (deviceSpec != null) {
6109 // Device is connected
Eric Laurentcdae4762017-04-28 18:00:04 -07006110 int musicDevice = getDeviceForStream(AudioSystem.STREAM_MUSIC);
Eric Laurent5205a352017-04-27 18:31:22 -07006111 if (AudioSystem.handleDeviceConfigChange(device, address,
6112 btDevice.getName()) != AudioSystem.AUDIO_STATUS_OK) {
6113 // force A2DP device disconnection in case of error so that AudioService state is
6114 // consistent with audio policy manager state
Eric Laurentcdae4762017-04-28 18:00:04 -07006115 setBluetoothA2dpDeviceConnectionStateInt(
6116 btDevice, BluetoothA2dp.STATE_DISCONNECTED, BluetoothProfile.A2DP,
Eric Laurent3e6fb632018-05-21 09:28:46 -07006117 false /* suppressNoisyIntent */, musicDevice, -1 /* a2dpVolume */);
Eric Laurent5205a352017-04-27 18:31:22 -07006118 }
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08006119 }
6120 }
6121 }
6122
John Du5a0cf7a2013-07-19 11:30:34 -07006123 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
6124 // address is not used for now, but may be used when multiple a2dp devices are supported
6125 synchronized (mA2dpAvrcpLock) {
6126 mAvrcpAbsVolSupported = support;
Eric Laurent3e6fb632018-05-21 09:28:46 -07006127 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
6128 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
6129 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07006130 }
6131 }
6132
Paul McLean394a8e12015-03-03 10:29:19 -07006133 private boolean handleDeviceConnection(boolean connect, int device, String address,
6134 String deviceName) {
6135 if (DEBUG_DEVICES) {
6136 Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device)
6137 + " address:" + address + " name:" + deviceName + ")");
6138 }
Eric Laurent59f48272012-04-05 19:42:21 -07006139 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07006140 String deviceKey = makeDeviceListKey(device, address);
6141 if (DEBUG_DEVICES) {
6142 Slog.i(TAG, "deviceKey:" + deviceKey);
6143 }
6144 DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
6145 boolean isConnected = deviceSpec != null;
6146 if (DEBUG_DEVICES) {
6147 Slog.i(TAG, "deviceSpec:" + deviceSpec + " is(already)Connected:" + isConnected);
6148 }
6149 if (connect && !isConnected) {
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07006150 final int res = AudioSystem.setDeviceConnectionState(device,
6151 AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);
6152 if (res != AudioSystem.AUDIO_STATUS_OK) {
6153 Slog.e(TAG, "not connecting device 0x" + Integer.toHexString(device) +
6154 " due to command error " + res );
6155 return false;
6156 }
Paul McLean394a8e12015-03-03 10:29:19 -07006157 mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07006158 sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
6159 device, 0, null, 0);
Paul McLean394a8e12015-03-03 10:29:19 -07006160 return true;
6161 } else if (!connect && isConnected) {
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07006162 AudioSystem.setDeviceConnectionState(device,
6163 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName);
6164 // always remove even if disconnection failed
Paul McLean394a8e12015-03-03 10:29:19 -07006165 mConnectedDevices.remove(deviceKey);
6166 return true;
Eric Laurent59f48272012-04-05 19:42:21 -07006167 }
Jack Hef05e5162018-04-19 15:03:43 -07006168 Log.w(TAG, "handleDeviceConnection() failed, deviceKey=" + deviceKey + ", deviceSpec="
6169 + deviceSpec + ", connect=" + connect);
Eric Laurent59f48272012-04-05 19:42:21 -07006170 }
6171 return false;
6172 }
6173
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006174 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
Eric Laurent9a5b2622017-04-18 18:20:56 -07006175 // sent if:
6176 // - none of these devices are connected anymore after one is disconnected AND
6177 // - the device being disconnected is actually used for music.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08006178 // Access synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006179 int mBecomingNoisyIntentDevices =
6180 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07006181 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07006182 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Jakub Pawlowski26fac412018-03-22 15:00:34 -07006183 AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE |
6184 AudioSystem.DEVICE_OUT_HEARING_AID;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006185
6186 // must be called before removing the device from mConnectedDevices
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08006187 // Called synchronized on mConnectedDevices
Eric Laurentcdae4762017-04-28 18:00:04 -07006188 // musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying
6189 // from AudioSystem
6190 private int checkSendBecomingNoisyIntent(int device, int state, int musicDevice) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006191 int delay = 0;
6192 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
6193 int devices = 0;
John Spurlock8c3dc852015-04-23 21:32:37 -04006194 for (int i = 0; i < mConnectedDevices.size(); i++) {
6195 int dev = mConnectedDevices.valueAt(i).mDeviceType;
Paul McLean394a8e12015-03-03 10:29:19 -07006196 if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
6197 && ((dev & mBecomingNoisyIntentDevices) != 0)) {
6198 devices |= dev;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006199 }
6200 }
Eric Laurentcdae4762017-04-28 18:00:04 -07006201 if (musicDevice == AudioSystem.DEVICE_NONE) {
6202 musicDevice = getDeviceForStream(AudioSystem.STREAM_MUSIC);
6203 }
6204 // ignore condition on device being actually used for music when in communication
6205 // because music routing is altered in this case.
Jean-Michel Trivi7db2d8f2018-03-06 10:30:59 -08006206 // also checks whether media routing if affected by a dynamic policy
6207 if (((device == musicDevice) || isInCommunication()) && (device == devices)
6208 && !hasMediaDynamicPolicy()) {
Eric Laurentcdae4762017-04-28 18:00:04 -07006209 mAudioHandler.removeMessages(MSG_BROADCAST_AUDIO_BECOMING_NOISY);
Eric Laurent5bfaeae2012-09-21 18:44:48 -07006210 sendMsg(mAudioHandler,
6211 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
6212 SENDMSG_REPLACE,
6213 0,
6214 0,
6215 null,
6216 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006217 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006218 }
6219 }
6220
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006221 return delay;
6222 }
6223
Jean-Michel Trivi7db2d8f2018-03-06 10:30:59 -08006224 /**
6225 * @return true if there is currently a registered dynamic mixing policy that affects media
6226 */
6227 private boolean hasMediaDynamicPolicy() {
6228 synchronized (mAudioPolicies) {
6229 if (mAudioPolicies.isEmpty()) {
6230 return false;
6231 }
6232 final Collection<AudioPolicyProxy> appColl = mAudioPolicies.values();
6233 for (AudioPolicyProxy app : appColl) {
6234 if (app.hasMixAffectingUsage(AudioAttributes.USAGE_MEDIA)) {
6235 return true;
6236 }
6237 }
6238 return false;
6239 }
6240 }
6241
Eric Laurenteab40d12017-06-09 12:45:21 -07006242 private void updateAudioRoutes(int device, int state)
6243 {
Dianne Hackborn632ca412012-06-14 19:34:10 -07006244 int connType = 0;
6245
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006246 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07006247 connType = AudioRoutesInfo.MAIN_HEADSET;
Jon Eklund43cc8bb2014-07-28 16:07:24 -05006248 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
6249 device == AudioSystem.DEVICE_OUT_LINE) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07006250 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurent6fa42452015-01-09 15:09:40 -08006251 } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
6252 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07006253 connType = AudioRoutesInfo.MAIN_HDMI;
Eric Laurenteab40d12017-06-09 12:45:21 -07006254 } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE||
6255 device == AudioSystem.DEVICE_OUT_USB_HEADSET) {
Paul McLean10804eb2015-01-28 11:16:35 -08006256 connType = AudioRoutesInfo.MAIN_USB;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006257 }
6258
Dianne Hackborn632ca412012-06-14 19:34:10 -07006259 synchronized (mCurAudioRoutes) {
6260 if (connType != 0) {
John Spurlock61560172015-02-06 19:46:04 -05006261 int newConn = mCurAudioRoutes.mainType;
Dianne Hackborn632ca412012-06-14 19:34:10 -07006262 if (state != 0) {
6263 newConn |= connType;
6264 } else {
6265 newConn &= ~connType;
6266 }
John Spurlock61560172015-02-06 19:46:04 -05006267 if (newConn != mCurAudioRoutes.mainType) {
6268 mCurAudioRoutes.mainType = newConn;
Dianne Hackborn632ca412012-06-14 19:34:10 -07006269 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
6270 SENDMSG_NOOP, 0, 0, null, 0);
6271 }
6272 }
6273 }
Eric Laurenteab40d12017-06-09 12:45:21 -07006274 }
6275
6276 private void sendDeviceConnectionIntent(int device, int state, String address,
6277 String deviceName) {
6278 if (DEBUG_DEVICES) {
6279 Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
6280 " state:0x" + Integer.toHexString(state) + " address:" + address +
6281 " name:" + deviceName + ");");
6282 }
6283 Intent intent = new Intent();
6284
6285 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
6286 intent.setAction(Intent.ACTION_HEADSET_PLUG);
6287 intent.putExtra("microphone", 1);
6288 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
6289 device == AudioSystem.DEVICE_OUT_LINE) {
6290 intent.setAction(Intent.ACTION_HEADSET_PLUG);
Jean-Michel Trivi87d31ec2017-08-11 18:28:20 -07006291 intent.putExtra("microphone", 0);
Paul McLean145c9532017-08-04 11:12:19 -06006292 } else if (device == AudioSystem.DEVICE_OUT_USB_HEADSET) {
6293 intent.setAction(Intent.ACTION_HEADSET_PLUG);
Jean-Michel Trivi87d31ec2017-08-11 18:28:20 -07006294 intent.putExtra("microphone",
6295 AudioSystem.getDeviceConnectionState(AudioSystem.DEVICE_IN_USB_HEADSET, "")
6296 == AudioSystem.DEVICE_STATE_AVAILABLE ? 1 : 0);
6297 } else if (device == AudioSystem.DEVICE_IN_USB_HEADSET) {
6298 if (AudioSystem.getDeviceConnectionState(AudioSystem.DEVICE_OUT_USB_HEADSET, "")
6299 == AudioSystem.DEVICE_STATE_AVAILABLE) {
6300 intent.setAction(Intent.ACTION_HEADSET_PLUG);
6301 intent.putExtra("microphone", 1);
6302 } else {
6303 // do not send ACTION_HEADSET_PLUG when only the input side is seen as changing
6304 return;
6305 }
Eric Laurenteab40d12017-06-09 12:45:21 -07006306 } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
6307 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
6308 configureHdmiPlugIntent(intent, state);
6309 }
6310
Jean-Michel Trivi87a264d2017-08-15 17:52:22 -07006311 if (intent.getAction() == null) {
6312 return;
6313 }
6314
Eric Laurenteab40d12017-06-09 12:45:21 -07006315 intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
6316 intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
6317 intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
6318
6319 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
Dianne Hackborn632ca412012-06-14 19:34:10 -07006320
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07006321 final long ident = Binder.clearCallingIdentity();
6322 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08006323 ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07006324 } finally {
6325 Binder.restoreCallingIdentity(ident);
6326 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006327 }
6328
Eric Laurentbbe3e742017-04-28 18:11:50 -07006329 private static final int DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG =
6330 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
6331 AudioSystem.DEVICE_OUT_LINE |
6332 AudioSystem.DEVICE_OUT_ALL_USB;
6333
Paul McLean10804eb2015-01-28 11:16:35 -08006334 private void onSetWiredDeviceConnectionState(int device, int state, String address,
John Spurlock90874332015-03-10 16:00:54 -04006335 String deviceName, String caller) {
Paul McLean394a8e12015-03-03 10:29:19 -07006336 if (DEBUG_DEVICES) {
John Spurlock90874332015-03-10 16:00:54 -04006337 Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
6338 + " state:" + Integer.toHexString(state)
6339 + " address:" + address
6340 + " deviceName:" + deviceName
6341 + " caller: " + caller + ");");
Paul McLean394a8e12015-03-03 10:29:19 -07006342 }
Paul McLean10804eb2015-01-28 11:16:35 -08006343
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006344 synchronized (mConnectedDevices) {
Eric Laurentbbe3e742017-04-28 18:11:50 -07006345 if ((state == 0) && ((device & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0)) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006346 setBluetoothA2dpOnInt(true, "onSetWiredDeviceConnectionState state 0");
Sungsoocf09fe62016-09-28 16:21:48 +09006347 }
Paul McLean145c9532017-08-04 11:12:19 -06006348
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07006349 if (!handleDeviceConnection(state == 1, device, address, deviceName)) {
6350 // change of connection state failed, bailout
6351 return;
6352 }
Eric Laurentf1a457d2012-09-20 16:27:23 -07006353 if (state != 0) {
Eric Laurentbbe3e742017-04-28 18:11:50 -07006354 if ((device & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006355 setBluetoothA2dpOnInt(false, "onSetWiredDeviceConnectionState state not 0");
Sungsoocf09fe62016-09-28 16:21:48 +09006356 }
Eric Laurentf1a457d2012-09-20 16:27:23 -07006357 if ((device & mSafeMediaVolumeDevices) != 0) {
6358 sendMsg(mAudioHandler,
6359 MSG_CHECK_MUSIC_ACTIVE,
6360 SENDMSG_REPLACE,
6361 0,
6362 0,
John Spurlock90874332015-03-10 16:00:54 -04006363 caller,
Eric Laurentf1a457d2012-09-20 16:27:23 -07006364 MUSIC_ACTIVE_POLL_PERIOD_MS);
6365 }
Eric Laurent212532b2014-07-21 15:43:18 -07006366 // Television devices without CEC service apply software volume on HDMI output
6367 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
6368 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
6369 checkAllFixedVolumeDevices();
6370 if (mHdmiManager != null) {
6371 synchronized (mHdmiManager) {
6372 if (mHdmiPlaybackClient != null) {
6373 mHdmiCecSink = false;
6374 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
6375 }
6376 }
6377 }
6378 }
jiabin39940752018-04-02 18:18:45 -07006379 if ((device & AudioSystem.DEVICE_OUT_HDMI) != 0) {
6380 sendEnabledSurroundFormats(mContentResolver, true);
6381 }
Eric Laurent212532b2014-07-21 15:43:18 -07006382 } else {
6383 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
6384 if (mHdmiManager != null) {
6385 synchronized (mHdmiManager) {
6386 mHdmiCecSink = false;
6387 }
6388 }
6389 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006390 }
Jean-Michel Trivi87a264d2017-08-15 17:52:22 -07006391 sendDeviceConnectionIntent(device, state, address, deviceName);
Eric Laurenteab40d12017-06-09 12:45:21 -07006392 updateAudioRoutes(device, state);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07006393 }
6394 }
6395
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07006396 private void configureHdmiPlugIntent(Intent intent, int state) {
Jean-Michel Trivic5258432014-08-27 15:46:54 -07006397 intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
6398 intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07006399 if (state == 1) {
6400 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
6401 int[] portGeneration = new int[1];
6402 int status = AudioSystem.listAudioPorts(ports, portGeneration);
6403 if (status == AudioManager.SUCCESS) {
6404 for (AudioPort port : ports) {
6405 if (port instanceof AudioDevicePort) {
6406 final AudioDevicePort devicePort = (AudioDevicePort) port;
Eric Laurent6fa42452015-01-09 15:09:40 -08006407 if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
6408 devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07006409 // format the list of supported encodings
Eric Laurentcae34662015-05-19 16:46:52 -07006410 int[] formats = AudioFormat.filterPublicFormats(devicePort.formats());
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07006411 if (formats.length > 0) {
6412 ArrayList<Integer> encodingList = new ArrayList(1);
6413 for (int format : formats) {
6414 // a format in the list can be 0, skip it
6415 if (format != AudioFormat.ENCODING_INVALID) {
6416 encodingList.add(format);
6417 }
6418 }
6419 int[] encodingArray = new int[encodingList.size()];
6420 for (int i = 0 ; i < encodingArray.length ; i++) {
6421 encodingArray[i] = encodingList.get(i);
6422 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07006423 intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07006424 }
6425 // find the maximum supported number of channels
6426 int maxChannels = 0;
6427 for (int mask : devicePort.channelMasks()) {
6428 int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
6429 if (channelCount > maxChannels) {
6430 maxChannels = channelCount;
6431 }
6432 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07006433 intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07006434 }
6435 }
6436 }
6437 }
6438 }
6439 }
6440
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07006441 /* cache of the address of the last dock the device was connected to */
6442 private String mDockAddress;
6443
Eric Laurenta553c252009-07-17 12:17:14 -07006444 /**
6445 * Receiver for misc intent broadcasts the Phone app cares about.
6446 */
6447 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
6448 @Override
6449 public void onReceive(Context context, Intent intent) {
6450 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07006451 int outDevice;
6452 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07006453 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07006454
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08006455 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
6456 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
6457 Intent.EXTRA_DOCK_STATE_UNDOCKED);
6458 int config;
6459 switch (dockState) {
6460 case Intent.EXTRA_DOCK_STATE_DESK:
6461 config = AudioSystem.FORCE_BT_DESK_DOCK;
6462 break;
6463 case Intent.EXTRA_DOCK_STATE_CAR:
6464 config = AudioSystem.FORCE_BT_CAR_DOCK;
6465 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05006466 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08006467 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05006468 break;
6469 case Intent.EXTRA_DOCK_STATE_HE_DESK:
6470 config = AudioSystem.FORCE_DIGITAL_DOCK;
6471 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08006472 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
6473 default:
6474 config = AudioSystem.FORCE_NONE;
6475 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08006476 // Low end docks have a menu to enable or disable audio
6477 // (see mDockAudioMediaEnabled)
6478 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
6479 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
6480 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006481 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_DOCK, config,
6482 "ACTION_DOCK_EVENT intent"));
Eric Laurent08ed1b92012-11-05 14:54:12 -08006483 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
6484 }
6485 mDockState = dockState;
Jack He8dd33942018-01-17 15:45:12 -08006486 } else if (action.equals(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED)) {
Eric Laurentdca56b92011-09-02 14:20:56 -07006487 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Jack He8dd33942018-01-17 15:45:12 -08006488 setBtScoActiveDevice(btDevice);
Paul McLeandf361462014-04-10 16:02:55 -07006489 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08006490 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07006491 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07006492 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08006493 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07006494 // broadcast intent if the connection was initated by AudioService
6495 if (!mScoClients.isEmpty() &&
6496 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
6497 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
Jack He89f97982018-05-02 19:10:56 -07006498 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
6499 mScoAudioState == SCO_STATE_DEACTIVATING)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08006500 broadcast = true;
6501 }
6502 switch (btState) {
Jack He89f97982018-05-02 19:10:56 -07006503 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
6504 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
6505 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
Jack He33c3a172018-05-08 14:51:07 -07006506 mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
Jack He89f97982018-05-02 19:10:56 -07006507 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
6508 }
6509 setBluetoothScoOn(true);
6510 break;
6511 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
6512 setBluetoothScoOn(false);
6513 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
6514 // startBluetoothSco called after stopBluetoothSco
6515 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ) {
6516 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null
6517 && connectBluetoothScoAudioHelper(mBluetoothHeadset,
6518 mBluetoothHeadsetDevice, mScoAudioMode)) {
6519 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
6520 broadcast = false;
6521 break;
6522 }
6523 }
6524 // Tear down SCO if disconnected from external
6525 clearAllScoClients(0, mScoAudioState == SCO_STATE_ACTIVE_INTERNAL);
6526 mScoAudioState = SCO_STATE_INACTIVE;
6527 break;
6528 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
6529 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
Jack He33c3a172018-05-08 14:51:07 -07006530 mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
Jack He89f97982018-05-02 19:10:56 -07006531 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
6532 }
6533 default:
6534 // do not broadcast CONNECTING or invalid state
6535 broadcast = false;
6536 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07006537 }
6538 }
Eric Laurent62ef7672010-11-24 10:58:32 -08006539 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07006540 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07006541 //FIXME: this is to maintain compatibility with deprecated intent
6542 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08006543 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07006544 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07006545 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08006546 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07006547 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06006548 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07006549 RotationHelper.enable();
Jon Eklund318f0fe2014-01-23 17:53:48 -06006550 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07006551 AudioSystem.setParameters("screen_state=on");
6552 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06006553 if (mMonitorRotation) {
6554 //reduce wakeups (save current) by only listening when display is on
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07006555 RotationHelper.disable();
Jon Eklund318f0fe2014-01-23 17:53:48 -06006556 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07006557 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07006558 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07006559 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07006560 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Yasuhiro Matsuda4ced7192015-07-10 22:08:44 +09006561 if (mUserSwitchedReceived) {
6562 // attempt to stop music playback for background user except on first user
6563 // switch (i.e. first boot)
6564 sendMsg(mAudioHandler,
6565 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
6566 SENDMSG_REPLACE,
6567 0,
6568 0,
6569 null,
6570 0);
6571 }
6572 mUserSwitchedReceived = true;
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07006573 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07006574 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07006575
Eric Laurent5bfaeae2012-09-21 18:44:48 -07006576 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07006577 readAudioSettings(true /*userSwitch*/);
6578 // preserve STREAM_MUSIC volume from one user to the next.
6579 sendMsg(mAudioHandler,
6580 MSG_SET_ALL_VOLUMES,
6581 SENDMSG_QUEUE,
6582 0,
6583 0,
6584 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Fyodor Kupolovb5013302015-04-17 17:59:14 -07006585 } else if (action.equals(Intent.ACTION_USER_BACKGROUND)) {
6586 // Disable audio recording for the background user/profile
6587 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
6588 if (userId >= 0) {
6589 // TODO Kill recording streams instead of killing processes holding permission
6590 UserInfo userInfo = UserManagerService.getInstance().getUserInfo(userId);
6591 killBackgroundUserProcessesWithRecordAudioPermission(userInfo);
6592 }
Makoto Onukiac65e1e2015-11-20 15:33:17 -08006593 UserManagerService.getInstance().setUserRestriction(
Fyodor Kupolovb5013302015-04-17 17:59:14 -07006594 UserManager.DISALLOW_RECORD_AUDIO, true, userId);
6595 } else if (action.equals(Intent.ACTION_USER_FOREGROUND)) {
6596 // Enable audio recording for foreground user/profile
6597 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Makoto Onukiac65e1e2015-11-20 15:33:17 -08006598 UserManagerService.getInstance().setUserRestriction(
Fyodor Kupolovb5013302015-04-17 17:59:14 -07006599 UserManager.DISALLOW_RECORD_AUDIO, false, userId);
Eric Laurentb70b78a2016-01-13 19:16:04 -08006600 } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
6601 state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
6602 if (state == BluetoothAdapter.STATE_OFF ||
6603 state == BluetoothAdapter.STATE_TURNING_OFF) {
6604 disconnectAllBluetoothProfiles();
6605 }
Marco Nelissenfb6df0b2017-02-15 15:25:24 -08006606 } else if (action.equals(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION) ||
6607 action.equals(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION)) {
6608 handleAudioEffectBroadcast(context, intent);
Eric Laurenta553c252009-07-17 12:17:14 -07006609 }
6610 }
Paul McLeanc837a452014-04-09 09:04:43 -07006611 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08006612
Makoto Onukid45a4a22015-11-02 17:17:38 -08006613 private class AudioServiceUserRestrictionsListener implements UserRestrictionsListener {
6614
6615 @Override
6616 public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
6617 Bundle prevRestrictions) {
6618 // Update mic mute state.
6619 {
6620 final boolean wasRestricted =
6621 prevRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
6622 final boolean isRestricted =
6623 newRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
6624 if (wasRestricted != isRestricted) {
6625 setMicrophoneMuteNoCallerCheck(isRestricted, userId);
6626 }
6627 }
6628
6629 // Update speaker mute state.
6630 {
6631 final boolean wasRestricted =
Tony Makc1205112016-07-22 16:02:59 +01006632 prevRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)
Esteban Talavera492b4722017-02-13 14:59:45 +00006633 || prevRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_DEVICE);
Makoto Onukid45a4a22015-11-02 17:17:38 -08006634 final boolean isRestricted =
Tony Makc1205112016-07-22 16:02:59 +01006635 newRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)
Esteban Talavera492b4722017-02-13 14:59:45 +00006636 || newRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_DEVICE);
Makoto Onukid45a4a22015-11-02 17:17:38 -08006637 if (wasRestricted != isRestricted) {
6638 setMasterMuteInternalNoCallerCheck(isRestricted, /* flags =*/ 0, userId);
6639 }
6640 }
6641 }
6642 } // end class AudioServiceUserRestrictionsListener
6643
Marco Nelissenfb6df0b2017-02-15 15:25:24 -08006644 private void handleAudioEffectBroadcast(Context context, Intent intent) {
6645 String target = intent.getPackage();
6646 if (target != null) {
6647 Log.w(TAG, "effect broadcast already targeted to " + target);
6648 return;
6649 }
6650 intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
6651 // TODO this should target a user-selected panel
6652 List<ResolveInfo> ril = context.getPackageManager().queryBroadcastReceivers(
6653 intent, 0 /* flags */);
6654 if (ril != null && ril.size() != 0) {
6655 ResolveInfo ri = ril.get(0);
6656 if (ri != null && ri.activityInfo != null && ri.activityInfo.packageName != null) {
6657 intent.setPackage(ri.activityInfo.packageName);
6658 context.sendBroadcastAsUser(intent, UserHandle.ALL);
6659 return;
6660 }
6661 }
6662 Log.w(TAG, "couldn't find receiver package for effect intent");
6663 }
6664
Fyodor Kupolovb5013302015-04-17 17:59:14 -07006665 private void killBackgroundUserProcessesWithRecordAudioPermission(UserInfo oldUser) {
6666 PackageManager pm = mContext.getPackageManager();
6667 // Find the home activity of the user. It should not be killed to avoid expensive restart,
6668 // when the user switches back. For managed profiles, we should kill all recording apps
6669 ComponentName homeActivityName = null;
6670 if (!oldUser.isManagedProfile()) {
Sudheer Shankafc46e9b2016-10-21 17:55:27 -07006671 homeActivityName = mActivityManagerInternal.getHomeActivityForUser(oldUser.id);
Fyodor Kupolovb5013302015-04-17 17:59:14 -07006672 }
6673 final String[] permissions = { Manifest.permission.RECORD_AUDIO };
6674 List<PackageInfo> packages;
6675 try {
6676 packages = AppGlobals.getPackageManager()
6677 .getPackagesHoldingPermissions(permissions, 0, oldUser.id).getList();
6678 } catch (RemoteException e) {
6679 throw new AndroidRuntimeException(e);
6680 }
6681 for (int j = packages.size() - 1; j >= 0; j--) {
6682 PackageInfo pkg = packages.get(j);
Fyodor Kupolovbcb6c1e2015-05-11 12:05:15 -07006683 // Skip system processes
6684 if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
6685 continue;
6686 }
Amith Yamasanic1cbaab2015-07-21 11:46:14 -07006687 // Skip packages that have permission to interact across users
6688 if (pm.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS, pkg.packageName)
6689 == PackageManager.PERMISSION_GRANTED) {
6690 continue;
6691 }
Fyodor Kupolovb5013302015-04-17 17:59:14 -07006692 if (homeActivityName != null
6693 && pkg.packageName.equals(homeActivityName.getPackageName())
6694 && pkg.applicationInfo.isSystemApp()) {
6695 continue;
6696 }
6697 try {
Svetoslavaa41add2015-08-06 15:03:55 -07006698 final int uid = pkg.applicationInfo.uid;
Sudheer Shankadc589ac2016-11-10 15:30:17 -08006699 ActivityManager.getService().killUid(UserHandle.getAppId(uid),
Svetoslavaa41add2015-08-06 15:03:55 -07006700 UserHandle.getUserId(uid),
Fyodor Kupolovb5013302015-04-17 17:59:14 -07006701 "killBackgroundUserProcessesWithAudioRecordPermission");
6702 } catch (RemoteException e) {
6703 Log.w(TAG, "Error calling killUid", e);
6704 }
6705 }
6706 }
6707
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07006708
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07006709 //==========================================================================================
6710 // Audio Focus
6711 //==========================================================================================
Jean-Michel Trivi9228af62018-01-05 17:06:17 -08006712 /**
6713 * Returns whether a focus request is eligible to force ducking.
6714 * Will return true if:
6715 * - the AudioAttributes have a usage of USAGE_ASSISTANCE_ACCESSIBILITY,
6716 * - the focus request is AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
6717 * - the associated Bundle has KEY_ACCESSIBILITY_FORCE_FOCUS_DUCKING set to true,
6718 * - the uid of the requester is a known accessibility service or root.
6719 * @param aa AudioAttributes of the focus request
6720 * @param uid uid of the focus requester
6721 * @return true if ducking is to be forced
6722 */
6723 private boolean forceFocusDuckingForAccessibility(@Nullable AudioAttributes aa,
6724 int request, int uid) {
6725 if (aa == null || aa.getUsage() != AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY
6726 || request != AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK) {
6727 return false;
6728 }
6729 final Bundle extraInfo = aa.getBundle();
6730 if (extraInfo == null ||
6731 !extraInfo.getBoolean(AudioFocusRequest.KEY_ACCESSIBILITY_FORCE_FOCUS_DUCKING)) {
6732 return false;
6733 }
6734 if (uid == 0) {
6735 return true;
6736 }
6737 synchronized (mAccessibilityServiceUidsLock) {
6738 if (mAccessibilityServiceUids != null) {
6739 int callingUid = Binder.getCallingUid();
6740 for (int i = 0; i < mAccessibilityServiceUids.length; i++) {
6741 if (mAccessibilityServiceUids[i] == callingUid) {
6742 return true;
6743 }
6744 }
6745 }
6746 }
6747 return false;
6748 }
6749
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08006750 public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006751 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07006752 IAudioPolicyCallback pcb, int sdk) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006753 // permission checks
6754 if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
John Spurlock61560172015-02-06 19:46:04 -05006755 if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006756 if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
6757 android.Manifest.permission.MODIFY_PHONE_STATE)) {
6758 Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
6759 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
6760 }
6761 } else {
6762 // only a registered audio policy can be used to lock focus
6763 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006764 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
6765 Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006766 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
6767 }
6768 }
6769 }
6770 }
6771
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08006772 return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
Jean-Michel Trivi9228af62018-01-05 17:06:17 -08006773 clientId, callingPackageName, flags, sdk,
6774 forceFocusDuckingForAccessibility(aa, durationHint, Binder.getCallingUid()));
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07006775 }
6776
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07006777 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa,
6778 String callingPackageName) {
6779 return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa, callingPackageName);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07006780 }
6781
6782 public void unregisterAudioFocusClient(String clientId) {
6783 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07006784 }
6785
Jean-Michel Trivi23805662013-07-31 14:19:18 -07006786 public int getCurrentAudioFocus() {
6787 return mMediaFocusControl.getCurrentAudioFocus();
6788 }
6789
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08006790 public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) {
6791 return mMediaFocusControl.getFocusRampTimeMs(focusGain, attr);
6792 }
6793
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07006794 //==========================================================================================
John Spurlock5e783732015-02-19 10:28:59 -05006795 private boolean readCameraSoundForced() {
6796 return SystemProperties.getBoolean("audio.camerasound.force", false) ||
6797 mContext.getResources().getBoolean(
6798 com.android.internal.R.bool.config_camera_sound_forced);
6799 }
6800
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07006801 //==========================================================================================
6802 // Device orientation
6803 //==========================================================================================
6804 /**
Mikhail Naganovb668bc62018-02-13 13:46:38 -08006805 * Handles device configuration changes that may map to a change in rotation.
6806 * Monitoring rotation is optional, and is defined by the definition and value
6807 * of the "ro.audio.monitorRotation" system property.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07006808 */
6809 private void handleConfigurationChanged(Context context) {
6810 try {
Mikhail Naganovb668bc62018-02-13 13:46:38 -08006811 // reading new configuration "safely" (i.e. under try catch) in case anything
6812 // goes wrong.
Eric Laurentd640bd32012-09-28 18:01:48 -07006813 Configuration config = context.getResources().getConfiguration();
Eric Laurentd640bd32012-09-28 18:01:48 -07006814 sendMsg(mAudioHandler,
6815 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
6816 SENDMSG_REPLACE,
6817 0,
6818 0,
John Spurlock90874332015-03-10 16:00:54 -04006819 TAG,
Eric Laurentd640bd32012-09-28 18:01:48 -07006820 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07006821
John Spurlock5e783732015-02-19 10:28:59 -05006822 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -07006823 synchronized (mSettingsLock) {
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08006824 final boolean cameraSoundForcedChanged = (cameraSoundForced != mCameraSoundForced);
6825 mCameraSoundForced = cameraSoundForced;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07006826 if (cameraSoundForcedChanged) {
Muyuan Li1ed6df62016-06-18 11:16:52 -07006827 if (!mIsSingleVolume) {
Jean-Michel Trivi085346a2018-02-14 10:48:51 -08006828 synchronized (VolumeStreamState.class) {
6829 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
6830 if (cameraSoundForced) {
6831 s.setAllIndexesToMax();
6832 mRingerModeAffectedStreams &=
6833 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
6834 } else {
6835 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG);
6836 mRingerModeAffectedStreams |=
6837 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
6838 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07006839 }
6840 // take new state into account for streams muted by ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05006841 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07006842 }
6843
6844 sendMsg(mAudioHandler,
6845 MSG_SET_FORCE_USE,
6846 SENDMSG_QUEUE,
6847 AudioSystem.FOR_SYSTEM,
6848 cameraSoundForced ?
6849 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006850 new String("handleConfigurationChanged"),
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07006851 0);
6852
6853 sendMsg(mAudioHandler,
6854 MSG_SET_ALL_VOLUMES,
6855 SENDMSG_QUEUE,
6856 0,
6857 0,
6858 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
6859 }
Eric Laurentdd45d012012-10-08 09:04:34 -07006860 }
John Spurlock3346a802014-05-20 16:25:37 -04006861 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07006862 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07006863 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07006864 }
6865 }
6866
Sungsoocf09fe62016-09-28 16:21:48 +09006867 // Handles request to override default use of A2DP for media.
6868 // Must be called synchronized on mConnectedDevices
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006869 public void setBluetoothA2dpOnInt(boolean on, String eventSource) {
Sungsoocf09fe62016-09-28 16:21:48 +09006870 synchronized (mBluetoothA2dpEnabledLock) {
6871 mBluetoothA2dpEnabled = on;
6872 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
6873 setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006874 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
6875 eventSource);
Sungsoocf09fe62016-09-28 16:21:48 +09006876 }
6877 }
6878
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08006879 // Must be called synchronized on mConnectedDevices
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006880 private void setForceUseInt_SyncDevices(int usage, int config, String eventSource) {
Eric Laurent9a5b2622017-04-18 18:20:56 -07006881 if (usage == AudioSystem.FOR_MEDIA) {
6882 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
6883 SENDMSG_NOOP, 0, 0, null, 0);
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08006884 }
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006885 mForceUseLogger.log(new ForceUseEvent(usage, config, eventSource));
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08006886 AudioSystem.setForceUse(usage, config);
6887 }
6888
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08006889 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07006890 public void setRingtonePlayer(IRingtonePlayer player) {
6891 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
6892 mRingtonePlayer = player;
6893 }
6894
6895 @Override
6896 public IRingtonePlayer getRingtonePlayer() {
6897 return mRingtonePlayer;
6898 }
6899
6900 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07006901 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
6902 synchronized (mCurAudioRoutes) {
6903 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
6904 mRoutesObservers.register(observer);
6905 return routes;
6906 }
6907 }
6908
Eric Laurentc34dcc12012-09-10 13:51:52 -07006909
6910 //==========================================================================================
6911 // Safe media volume management.
6912 // MUSIC stream volume level is limited when headphones are connected according to safety
6913 // regulation. When the user attempts to raise the volume above the limit, a warning is
6914 // displayed and the user has to acknowlegde before the volume is actually changed.
6915 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
6916 // property. Platforms with a different limit must set this property accordingly in their
6917 // overlay.
6918 //==========================================================================================
6919
Eric Laurentd640bd32012-09-28 18:01:48 -07006920 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
6921 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
6922 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
6923 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
6924 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
6925 // (when user opts out).
John Spurlock35134602014-07-24 18:10:48 -04006926 private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
6927 private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
6928 private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed
6929 private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
Eric Laurentd640bd32012-09-28 18:01:48 -07006930 private Integer mSafeMediaVolumeState;
6931
6932 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07006933 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07006934 private int mSafeMediaVolumeIndex;
John Muir8b8bddd2018-02-16 14:29:14 -08006935 // mSafeUsbMediaVolumeDbfs is the cached value of the config_safe_media_volume_usb_mB
6936 // property, divided by 100.0.
6937 private float mSafeUsbMediaVolumeDbfs;
Eric Laurentb378a13a2017-07-11 14:08:11 -07006938 // mSafeUsbMediaVolumeIndex is used for USB Headsets and is the music volume UI index
John Muir8b8bddd2018-02-16 14:29:14 -08006939 // corresponding to a gain of mSafeUsbMediaVolumeDbfs (defaulting to -37dB) in audio
6940 // flinger mixer.
Eric Laurent0e5deb32017-09-01 15:12:42 -07006941 // We remove -22 dBs from the theoretical -15dB to account for the EQ + bass boost
6942 // amplification when both effects are on with all band gains at maximum.
Eric Laurentb378a13a2017-07-11 14:08:11 -07006943 // This level corresponds to a loudness of 85 dB SPL for the warning to be displayed when
6944 // the headset is compliant to EN 60950 with a max loudness of 100dB SPL.
Eric Laurenteab40d12017-06-09 12:45:21 -07006945 private int mSafeUsbMediaVolumeIndex;
Eric Laurentc34dcc12012-09-10 13:51:52 -07006946 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
6947 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
Eric Laurenteab40d12017-06-09 12:45:21 -07006948 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
6949 AudioSystem.DEVICE_OUT_USB_HEADSET;
Eric Laurentc34dcc12012-09-10 13:51:52 -07006950 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
6951 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
6952 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
6953 private int mMusicActiveMs;
6954 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
6955 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07006956 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07006957
Eric Laurenteab40d12017-06-09 12:45:21 -07006958 private int safeMediaVolumeIndex(int device) {
6959 if ((device & mSafeMediaVolumeDevices) == 0) {
6960 return MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC];
6961 }
6962 if (device == AudioSystem.DEVICE_OUT_USB_HEADSET) {
6963 return mSafeUsbMediaVolumeIndex;
6964 } else {
6965 return mSafeMediaVolumeIndex;
6966 }
6967 }
6968
John Spurlock90874332015-03-10 16:00:54 -04006969 private void setSafeMediaVolumeEnabled(boolean on, String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07006970 synchronized (mSafeMediaVolumeState) {
6971 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
6972 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
6973 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
6974 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
John Spurlock90874332015-03-10 16:00:54 -04006975 enforceSafeMediaVolume(caller);
Eric Laurentd640bd32012-09-28 18:01:48 -07006976 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
6977 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04006978 mMusicActiveMs = 1; // nonzero = confirmed
6979 saveMusicActiveMs();
Eric Laurentd640bd32012-09-28 18:01:48 -07006980 sendMsg(mAudioHandler,
6981 MSG_CHECK_MUSIC_ACTIVE,
6982 SENDMSG_REPLACE,
6983 0,
6984 0,
John Spurlock90874332015-03-10 16:00:54 -04006985 caller,
Eric Laurentd640bd32012-09-28 18:01:48 -07006986 MUSIC_ACTIVE_POLL_PERIOD_MS);
6987 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07006988 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07006989 }
6990 }
6991
John Spurlock90874332015-03-10 16:00:54 -04006992 private void enforceSafeMediaVolume(String caller) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07006993 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07006994 int devices = mSafeMediaVolumeDevices;
6995 int i = 0;
6996
6997 while (devices != 0) {
6998 int device = 1 << i++;
6999 if ((device & devices) == 0) {
7000 continue;
7001 }
Eric Laurent42b041e2013-03-29 11:36:03 -07007002 int index = streamState.getIndex(device);
Eric Laurenteab40d12017-06-09 12:45:21 -07007003 if (index > safeMediaVolumeIndex(device)) {
7004 streamState.setIndex(safeMediaVolumeIndex(device), device, caller);
Eric Laurent42b041e2013-03-29 11:36:03 -07007005 sendMsg(mAudioHandler,
7006 MSG_SET_DEVICE_VOLUME,
7007 SENDMSG_QUEUE,
7008 device,
7009 0,
7010 streamState,
7011 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07007012 }
7013 devices &= ~device;
7014 }
7015 }
7016
7017 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07007018 synchronized (mSafeMediaVolumeState) {
7019 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07007020 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
7021 ((device & mSafeMediaVolumeDevices) != 0) &&
Eric Laurenteab40d12017-06-09 12:45:21 -07007022 (index > safeMediaVolumeIndex(device))) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07007023 return false;
7024 }
7025 return true;
7026 }
7027 }
7028
John Spurlock3346a802014-05-20 16:25:37 -04007029 @Override
John Spurlock90874332015-03-10 16:00:54 -04007030 public void disableSafeMediaVolume(String callingPackage) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05007031 enforceVolumeController("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07007032 synchronized (mSafeMediaVolumeState) {
John Spurlock90874332015-03-10 16:00:54 -04007033 setSafeMediaVolumeEnabled(false, callingPackage);
Eric Laurentfde16d52012-12-03 14:42:39 -08007034 if (mPendingVolumeCommand != null) {
7035 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
7036 mPendingVolumeCommand.mIndex,
7037 mPendingVolumeCommand.mFlags,
John Spurlock90874332015-03-10 16:00:54 -04007038 mPendingVolumeCommand.mDevice,
7039 callingPackage);
Eric Laurentfde16d52012-12-03 14:42:39 -08007040 mPendingVolumeCommand = null;
7041 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07007042 }
7043 }
7044
Jungshik Jang41d97462014-06-30 22:26:29 +09007045 //==========================================================================================
7046 // Hdmi Cec system audio mode.
John Spurlockbc82b122015-03-02 16:12:38 -05007047 // If Hdmi Cec's system audio mode is on, audio service should send the volume change
7048 // to HdmiControlService so that the audio receiver can handle it.
Jungshik Jang41d97462014-06-30 22:26:29 +09007049 //==========================================================================================
7050
Eric Laurent212532b2014-07-21 15:43:18 -07007051 private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
7052 public void onComplete(int status) {
7053 if (mHdmiManager != null) {
7054 synchronized (mHdmiManager) {
7055 mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
7056 // Television devices without CEC service apply software volume on HDMI output
7057 if (isPlatformTelevision() && !mHdmiCecSink) {
7058 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
7059 }
7060 checkAllFixedVolumeDevices();
7061 }
7062 }
7063 }
7064 };
7065
Jungshik Jang41d97462014-06-30 22:26:29 +09007066 // If HDMI-CEC system audio is supported
7067 private boolean mHdmiSystemAudioSupported = false;
7068 // Set only when device is tv.
7069 private HdmiTvClient mHdmiTvClient;
Eric Laurent0b03f992014-11-18 18:08:02 -08007070 // true if the device has system feature PackageManager.FEATURE_LEANBACK.
Eric Laurent212532b2014-07-21 15:43:18 -07007071 // cached HdmiControlManager interface
7072 private HdmiControlManager mHdmiManager;
7073 // Set only when device is a set-top box.
7074 private HdmiPlaybackClient mHdmiPlaybackClient;
7075 // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
7076 private boolean mHdmiCecSink;
7077
7078 private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
Jungshik Jang41d97462014-06-30 22:26:29 +09007079
7080 @Override
Jungshik Jang12307ca2014-07-15 19:27:56 +09007081 public int setHdmiSystemAudioSupported(boolean on) {
Eric Laurent212532b2014-07-21 15:43:18 -07007082 int device = AudioSystem.DEVICE_NONE;
7083 if (mHdmiManager != null) {
7084 synchronized (mHdmiManager) {
7085 if (mHdmiTvClient == null) {
7086 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
7087 return device;
7088 }
Jungshik Jang41d97462014-06-30 22:26:29 +09007089
Eric Laurent212532b2014-07-21 15:43:18 -07007090 synchronized (mHdmiTvClient) {
7091 if (mHdmiSystemAudioSupported != on) {
7092 mHdmiSystemAudioSupported = on;
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07007093 final int config = on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
7094 AudioSystem.FORCE_NONE;
7095 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
7096 config, "setHdmiSystemAudioSupported"));
7097 AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO, config);
Eric Laurent212532b2014-07-21 15:43:18 -07007098 }
John Spurlock8a52c442015-03-26 14:23:58 -04007099 device = getDevicesForStream(AudioSystem.STREAM_MUSIC);
Eric Laurent212532b2014-07-21 15:43:18 -07007100 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09007101 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09007102 }
Eric Laurent212532b2014-07-21 15:43:18 -07007103 return device;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09007104 }
Jungshik Jang41d97462014-06-30 22:26:29 +09007105
Terry Heoe7d6d972014-09-04 21:05:28 +09007106 @Override
7107 public boolean isHdmiSystemAudioSupported() {
7108 return mHdmiSystemAudioSupported;
7109 }
7110
Eric Laurentdd45d012012-10-08 09:04:34 -07007111 //==========================================================================================
Jean-Michel Triviac487672016-11-11 10:05:18 -08007112 // Accessibility
7113
Jean-Michel Trivicfa55532017-01-18 11:17:51 -08007114 private void initA11yMonitoring() {
7115 final AccessibilityManager accessibilityManager =
7116 (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
Jean-Michel Triviac487672016-11-11 10:05:18 -08007117 updateDefaultStreamOverrideDelay(accessibilityManager.isTouchExplorationEnabled());
Jean-Michel Trivi7592b982017-02-01 15:12:15 -08007118 updateA11yVolumeAlias(accessibilityManager.isAccessibilityVolumeStreamActive());
Phil Weaver26d709f2017-04-20 17:19:14 -07007119 accessibilityManager.addTouchExplorationStateChangeListener(this, null);
7120 accessibilityManager.addAccessibilityServicesStateChangeListener(this, null);
Jean-Michel Triviac487672016-11-11 10:05:18 -08007121 }
7122
7123 //---------------------------------------------------------------------------------
7124 // A11y: taking touch exploration into account for selecting the default
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07007125 // stream override timeout when adjusting volume
Jean-Michel Triviac487672016-11-11 10:05:18 -08007126 //---------------------------------------------------------------------------------
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07007127
Jean-Michel Triviac487672016-11-11 10:05:18 -08007128 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05007129 // - STREAM_RING on phones during this period after a notification stopped
7130 // - STREAM_MUSIC otherwise
7131
Jean-Michel Triviac487672016-11-11 10:05:18 -08007132 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 0;
7133 private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07007134
Jean-Michel Triviac487672016-11-11 10:05:18 -08007135 private static int sStreamOverrideDelayMs;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07007136
Jean-Michel Triviac487672016-11-11 10:05:18 -08007137 @Override
7138 public void onTouchExplorationStateChanged(boolean enabled) {
7139 updateDefaultStreamOverrideDelay(enabled);
7140 }
7141
7142 private void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
7143 if (touchExploreEnabled) {
7144 sStreamOverrideDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
7145 } else {
7146 sStreamOverrideDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07007147 }
Jean-Michel Triviac487672016-11-11 10:05:18 -08007148 if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
7149 + " stream override delay is now " + sStreamOverrideDelayMs + " ms");
7150 }
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07007151
Jean-Michel Triviac487672016-11-11 10:05:18 -08007152 //---------------------------------------------------------------------------------
7153 // A11y: taking a11y state into account for the handling of a11y prompts volume
7154 //---------------------------------------------------------------------------------
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07007155
Jean-Michel Triviac487672016-11-11 10:05:18 -08007156 private static boolean sIndependentA11yVolume = false;
7157
Jean-Michel Trivicfa55532017-01-18 11:17:51 -08007158 // implementation of AccessibilityServicesStateChangeListener
7159 @Override
Phil Weaver4cab9302017-03-30 15:27:39 -07007160 public void onAccessibilityServicesStateChanged(AccessibilityManager accessibilityManager) {
Jean-Michel Trivicfa55532017-01-18 11:17:51 -08007161 updateA11yVolumeAlias(accessibilityManager.isAccessibilityVolumeStreamActive());
7162 }
7163
7164 private void updateA11yVolumeAlias(boolean a11VolEnabled) {
7165 if (DEBUG_VOL) Log.d(TAG, "Accessibility volume enabled = " + a11VolEnabled);
7166 if (sIndependentA11yVolume != a11VolEnabled) {
7167 sIndependentA11yVolume = a11VolEnabled;
7168 // update the volume mapping scheme
7169 updateStreamVolumeAlias(true /*updateVolumes*/, TAG);
7170 // update the volume controller behavior
7171 mVolumeController.setA11yMode(sIndependentA11yVolume ?
7172 VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME :
7173 VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME);
Jean-Michel Trivia53b7052017-04-12 18:27:01 -07007174 mVolumeController.postVolumeChanged(AudioManager.STREAM_ACCESSIBILITY, 0);
Jean-Michel Trivicfa55532017-01-18 11:17:51 -08007175 }
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07007176 }
7177
7178 //==========================================================================================
Eric Laurentdd45d012012-10-08 09:04:34 -07007179 // Camera shutter sound policy.
7180 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
7181 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
7182 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
7183 //==========================================================================================
7184
7185 // cached value of com.android.internal.R.bool.config_camera_sound_forced
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08007186 @GuardedBy("mSettingsLock")
7187 private boolean mCameraSoundForced;
Eric Laurentdd45d012012-10-08 09:04:34 -07007188
7189 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
7190 public boolean isCameraSoundForced() {
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08007191 synchronized (mSettingsLock) {
Eric Laurentdd45d012012-10-08 09:04:34 -07007192 return mCameraSoundForced;
7193 }
7194 }
7195
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07007196 //==========================================================================================
7197 // AudioService logging and dumpsys
7198 //==========================================================================================
Jean-Michel Trivi3bf75782018-07-02 10:48:04 -07007199 static final int LOG_NB_EVENTS_PHONE_STATE = 20;
7200 static final int LOG_NB_EVENTS_DEVICE_CONNECTION = 30;
7201 static final int LOG_NB_EVENTS_FORCE_USE = 20;
7202 static final int LOG_NB_EVENTS_VOLUME = 40;
7203 static final int LOG_NB_EVENTS_DYN_POLICY = 10;
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07007204
7205 final private AudioEventLogger mModeLogger = new AudioEventLogger(LOG_NB_EVENTS_PHONE_STATE,
7206 "phone state (logged after successfull call to AudioSystem.setPhoneState(int))");
7207
Jean-Michel Trivi3bf75782018-07-02 10:48:04 -07007208 // logs for wired + A2DP device connections:
7209 // - wired: logged before onSetWiredDeviceConnectionState() is executed
7210 // - A2DP: logged at reception of method call
7211 final private AudioEventLogger mDeviceLogger = new AudioEventLogger(
7212 LOG_NB_EVENTS_DEVICE_CONNECTION, "wired/A2DP device connection");
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07007213
7214 final private AudioEventLogger mForceUseLogger = new AudioEventLogger(
7215 LOG_NB_EVENTS_FORCE_USE,
7216 "force use (logged before setForceUse() is executed)");
7217
Jean-Michel Trivicf170362017-08-24 17:24:57 -07007218 final private AudioEventLogger mVolumeLogger = new AudioEventLogger(LOG_NB_EVENTS_VOLUME,
7219 "volume changes (logged when command received by AudioService)");
7220
Jean-Michel Trivi12a86762018-04-24 16:57:49 -07007221 final private AudioEventLogger mDynPolicyLogger = new AudioEventLogger(LOG_NB_EVENTS_DYN_POLICY,
7222 "dynamic policy events (logged when command received by AudioService)");
7223
Eric Laurentdd45d012012-10-08 09:04:34 -07007224 private static final String[] RINGER_MODE_NAMES = new String[] {
7225 "SILENT",
7226 "VIBRATE",
7227 "NORMAL"
7228 };
7229
7230 private void dumpRingerMode(PrintWriter pw) {
7231 pw.println("\nRinger mode: ");
John Spurlock661f2cf2014-11-17 10:29:10 -05007232 pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
7233 pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
John Spurlock50ced3f2015-05-11 16:00:09 -04007234 dumpRingerModeStreams(pw, "affected", mRingerModeAffectedStreams);
Beverlyd6964762018-02-16 14:07:03 -05007235 dumpRingerModeStreams(pw, "muted", mRingerAndZenModeMutedStreams);
John Spurlock661f2cf2014-11-17 10:29:10 -05007236 pw.print("- delegate = "); pw.println(mRingerModeDelegate);
Eric Laurentdd45d012012-10-08 09:04:34 -07007237 }
7238
John Spurlock50ced3f2015-05-11 16:00:09 -04007239 private void dumpRingerModeStreams(PrintWriter pw, String type, int streams) {
7240 pw.print("- ringer mode "); pw.print(type); pw.print(" streams = 0x");
7241 pw.print(Integer.toHexString(streams));
7242 if (streams != 0) {
7243 pw.print(" (");
7244 boolean first = true;
7245 for (int i = 0; i < AudioSystem.STREAM_NAMES.length; i++) {
7246 final int stream = (1 << i);
7247 if ((streams & stream) != 0) {
7248 if (!first) pw.print(',');
7249 pw.print(AudioSystem.STREAM_NAMES[i]);
7250 streams &= ~stream;
7251 first = false;
7252 }
7253 }
7254 if (streams != 0) {
7255 if (!first) pw.print(',');
7256 pw.print(streams);
7257 }
7258 pw.print(')');
7259 }
7260 pw.println();
7261 }
7262
Dianne Hackborn632ca412012-06-14 19:34:10 -07007263 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08007264 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06007265 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07007266
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07007267 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07007268 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07007269 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07007270 pw.println("\nAudio routes:");
John Spurlock61560172015-02-06 19:46:04 -05007271 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
7272 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
John Spurlock35134602014-07-24 18:10:48 -04007273
7274 pw.println("\nOther state:");
John Spurlock3346a802014-05-20 16:25:37 -04007275 pw.print(" mVolumeController="); pw.println(mVolumeController);
John Spurlock35134602014-07-24 18:10:48 -04007276 pw.print(" mSafeMediaVolumeState=");
7277 pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
7278 pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
Eric Laurenteab40d12017-06-09 12:45:21 -07007279 pw.print(" mSafeUsbMediaVolumeIndex="); pw.println(mSafeUsbMediaVolumeIndex);
John Muir8b8bddd2018-02-16 14:29:14 -08007280 pw.print(" mSafeUsbMediaVolumeDbfs="); pw.println(mSafeUsbMediaVolumeDbfs);
Jean-Michel Trivi7592b982017-02-01 15:12:15 -08007281 pw.print(" sIndependentA11yVolume="); pw.println(sIndependentA11yVolume);
John Spurlock35134602014-07-24 18:10:48 -04007282 pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
7283 pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04007284 pw.print(" mMcc="); pw.println(mMcc);
John Spurlock5e783732015-02-19 10:28:59 -05007285 pw.print(" mCameraSoundForced="); pw.println(mCameraSoundForced);
John Spurlock661f2cf2014-11-17 10:29:10 -05007286 pw.print(" mHasVibrator="); pw.println(mHasVibrator);
John Spurlocka48d7792015-03-03 17:35:57 -05007287 pw.print(" mVolumePolicy="); pw.println(mVolumePolicy);
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07007288 pw.print(" mAvrcpAbsVolSupported="); pw.println(mAvrcpAbsVolSupported);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08007289
7290 dumpAudioPolicies(pw);
Jean-Michel Trivi12a86762018-04-24 16:57:49 -07007291 mDynPolicyLogger.dump(pw);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007292
7293 mPlaybackMonitor.dump(pw);
Jean-Michel Trivi66ffacf2017-02-04 17:25:31 -08007294
7295 mRecordMonitor.dump(pw);
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07007296
Jean-Michel Trivicf170362017-08-24 17:24:57 -07007297 pw.println("\n");
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07007298 pw.println("\nEvent logs:");
7299 mModeLogger.dump(pw);
7300 pw.println("\n");
Jean-Michel Trivi3bf75782018-07-02 10:48:04 -07007301 mDeviceLogger.dump(pw);
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07007302 pw.println("\n");
7303 mForceUseLogger.dump(pw);
Jean-Michel Trivicf170362017-08-24 17:24:57 -07007304 pw.println("\n");
7305 mVolumeLogger.dump(pw);
John Spurlock35134602014-07-24 18:10:48 -04007306 }
7307
7308 private static String safeMediaVolumeStateToString(Integer state) {
7309 switch(state) {
7310 case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
7311 case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
7312 case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
7313 case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
7314 }
7315 return null;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08007316 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07007317
7318 // Inform AudioFlinger of our device's low RAM attribute
7319 private static void readAndSetLowRamDevice()
7320 {
Andy Hung79583582018-01-23 13:58:02 -08007321 boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic();
7322 long totalMemory = 1024 * 1024 * 1024; // 1GB is the default if ActivityManager fails.
7323
7324 try {
7325 final ActivityManager.MemoryInfo info = new ActivityManager.MemoryInfo();
7326 ActivityManager.getService().getMemoryInfo(info);
7327 totalMemory = info.totalMem;
7328 } catch (RemoteException e) {
7329 Log.w(TAG, "Cannot obtain MemoryInfo from ActivityManager, assume low memory device");
7330 isLowRamDevice = true;
7331 }
7332
7333 final int status = AudioSystem.setLowRamDevice(isLowRamDevice, totalMemory);
Glenn Kastenfd116ad2013-07-12 17:10:39 -07007334 if (status != 0) {
7335 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
7336 }
7337 }
John Spurlock3346a802014-05-20 16:25:37 -04007338
John Spurlockcdb57ae2015-02-11 19:04:11 -05007339 private void enforceVolumeController(String action) {
John Spurlock3346a802014-05-20 16:25:37 -04007340 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
7341 "Only SystemUI can " + action);
7342 }
7343
7344 @Override
7345 public void setVolumeController(final IVolumeController controller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05007346 enforceVolumeController("set the volume controller");
John Spurlock3346a802014-05-20 16:25:37 -04007347
7348 // return early if things are not actually changing
7349 if (mVolumeController.isSameBinder(controller)) {
7350 return;
7351 }
7352
7353 // dismiss the old volume controller
7354 mVolumeController.postDismiss();
7355 if (controller != null) {
7356 // we are about to register a new controller, listen for its death
7357 try {
7358 controller.asBinder().linkToDeath(new DeathRecipient() {
7359 @Override
7360 public void binderDied() {
7361 if (mVolumeController.isSameBinder(controller)) {
7362 Log.w(TAG, "Current remote volume controller died, unregistering");
7363 setVolumeController(null);
7364 }
7365 }
7366 }, 0);
7367 } catch (RemoteException e) {
7368 // noop
7369 }
7370 }
7371 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04007372 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
7373 }
7374
7375 @Override
7376 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05007377 enforceVolumeController("notify about volume controller visibility");
John Spurlock33f4e042014-07-11 13:10:58 -04007378
7379 // return early if the controller is not current
7380 if (!mVolumeController.isSameBinder(controller)) {
7381 return;
7382 }
7383
7384 mVolumeController.setVisible(visible);
7385 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04007386 }
RoboErikd09bd0c2014-06-24 17:45:19 -07007387
John Spurlocka48d7792015-03-03 17:35:57 -05007388 @Override
7389 public void setVolumePolicy(VolumePolicy policy) {
7390 enforceVolumeController("set volume policy");
John Spurlockb02c7442015-04-14 09:32:25 -04007391 if (policy != null && !policy.equals(mVolumePolicy)) {
John Spurlocka48d7792015-03-03 17:35:57 -05007392 mVolumePolicy = policy;
John Spurlockb02c7442015-04-14 09:32:25 -04007393 if (DEBUG_VOL) Log.d(TAG, "Volume policy changed: " + mVolumePolicy);
John Spurlocka48d7792015-03-03 17:35:57 -05007394 }
7395 }
7396
RoboErikd09bd0c2014-06-24 17:45:19 -07007397 public static class VolumeController {
7398 private static final String TAG = "VolumeController";
7399
7400 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04007401 private boolean mVisible;
7402 private long mNextLongPress;
7403 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07007404
7405 public void setController(IVolumeController controller) {
7406 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04007407 mVisible = false;
7408 }
7409
7410 public void loadSettings(ContentResolver cr) {
7411 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
7412 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
7413 }
7414
RoboErik4197cb62015-01-21 15:45:32 -08007415 public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
7416 if (isMute) {
7417 return false;
7418 }
John Spurlock33f4e042014-07-11 13:10:58 -04007419 boolean suppress = false;
Julia Reynoldseb0ce472018-05-04 15:34:55 -04007420 if (resolvedStream == DEFAULT_VOL_STREAM_NO_PLAYBACK && mController != null) {
John Spurlock33f4e042014-07-11 13:10:58 -04007421 final long now = SystemClock.uptimeMillis();
7422 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
7423 // ui will become visible
7424 if (mNextLongPress < now) {
7425 mNextLongPress = now + mLongPressTimeout;
7426 }
7427 suppress = true;
7428 } else if (mNextLongPress > 0) { // in a long-press
7429 if (now > mNextLongPress) {
7430 // long press triggered, no more suppression
7431 mNextLongPress = 0;
7432 } else {
7433 // keep suppressing until the long press triggers
7434 suppress = true;
7435 }
7436 }
7437 }
7438 return suppress;
7439 }
7440
7441 public void setVisible(boolean visible) {
7442 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07007443 }
7444
7445 public boolean isSameBinder(IVolumeController controller) {
7446 return Objects.equals(asBinder(), binder(controller));
7447 }
7448
7449 public IBinder asBinder() {
7450 return binder(mController);
7451 }
7452
7453 private static IBinder binder(IVolumeController controller) {
7454 return controller == null ? null : controller.asBinder();
7455 }
7456
7457 @Override
7458 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04007459 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07007460 }
7461
7462 public void postDisplaySafeVolumeWarning(int flags) {
7463 if (mController == null)
7464 return;
7465 try {
7466 mController.displaySafeVolumeWarning(flags);
7467 } catch (RemoteException e) {
7468 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
7469 }
7470 }
7471
7472 public void postVolumeChanged(int streamType, int flags) {
7473 if (mController == null)
7474 return;
7475 try {
7476 mController.volumeChanged(streamType, flags);
7477 } catch (RemoteException e) {
7478 Log.w(TAG, "Error calling volumeChanged", e);
7479 }
7480 }
7481
RoboErikd09bd0c2014-06-24 17:45:19 -07007482 public void postMasterMuteChanged(int flags) {
7483 if (mController == null)
7484 return;
7485 try {
7486 mController.masterMuteChanged(flags);
7487 } catch (RemoteException e) {
7488 Log.w(TAG, "Error calling masterMuteChanged", e);
7489 }
7490 }
7491
7492 public void setLayoutDirection(int layoutDirection) {
7493 if (mController == null)
7494 return;
7495 try {
7496 mController.setLayoutDirection(layoutDirection);
7497 } catch (RemoteException e) {
7498 Log.w(TAG, "Error calling setLayoutDirection", e);
7499 }
7500 }
7501
7502 public void postDismiss() {
7503 if (mController == null)
7504 return;
7505 try {
7506 mController.dismiss();
7507 } catch (RemoteException e) {
7508 Log.w(TAG, "Error calling dismiss", e);
7509 }
7510 }
Jean-Michel Triviac487672016-11-11 10:05:18 -08007511
7512 public void setA11yMode(int a11yMode) {
7513 if (mController == null)
7514 return;
7515 try {
7516 mController.setA11yMode(a11yMode);
7517 } catch (RemoteException e) {
7518 Log.w(TAG, "Error calling setA11Mode", e);
7519 }
7520 }
RoboErikd09bd0c2014-06-24 17:45:19 -07007521 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007522
RoboErik0dac35a2014-08-12 15:48:49 -07007523 /**
7524 * Interface for system components to get some extra functionality through
7525 * LocalServices.
7526 */
7527 final class AudioServiceInternal extends AudioManagerInternal {
John Spurlock661f2cf2014-11-17 10:29:10 -05007528 @Override
7529 public void setRingerModeDelegate(RingerModeDelegate delegate) {
7530 mRingerModeDelegate = delegate;
7531 if (mRingerModeDelegate != null) {
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08007532 synchronized (mSettingsLock) {
Beverlyd6964762018-02-16 14:07:03 -05007533 updateRingerAndZenModeAffectedStreams();
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08007534 }
John Spurlock661f2cf2014-11-17 10:29:10 -05007535 setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
7536 }
7537 }
RoboErik272e1612014-09-05 11:39:29 -07007538
7539 @Override
7540 public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
7541 String callingPackage, int uid) {
7542 // direction and stream type swap here because the public
7543 // adjustSuggested has a different order than the other methods.
John Spurlock90874332015-03-10 16:00:54 -04007544 adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage,
7545 callingPackage, uid);
RoboErik272e1612014-09-05 11:39:29 -07007546 }
7547
RoboErik0dac35a2014-08-12 15:48:49 -07007548 @Override
7549 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
7550 String callingPackage, int uid) {
John Spurlock90874332015-03-10 16:00:54 -04007551 adjustStreamVolume(streamType, direction, flags, callingPackage,
7552 callingPackage, uid);
RoboErik0dac35a2014-08-12 15:48:49 -07007553 }
7554
7555 @Override
7556 public void setStreamVolumeForUid(int streamType, int direction, int flags,
7557 String callingPackage, int uid) {
John Spurlock90874332015-03-10 16:00:54 -04007558 setStreamVolume(streamType, direction, flags, callingPackage, callingPackage, uid);
RoboErik0dac35a2014-08-12 15:48:49 -07007559 }
RoboErik519c7742014-11-18 10:59:09 -08007560
7561 @Override
John Spurlock661f2cf2014-11-17 10:29:10 -05007562 public int getRingerModeInternal() {
7563 return AudioService.this.getRingerModeInternal();
7564 }
7565
7566 @Override
7567 public void setRingerModeInternal(int ringerMode, String caller) {
7568 AudioService.this.setRingerModeInternal(ringerMode, caller);
7569 }
John Spurlockcdb57ae2015-02-11 19:04:11 -05007570
7571 @Override
Mike Digman55272862018-02-20 14:35:17 -08007572 public void silenceRingerModeInternal(String caller) {
7573 AudioService.this.silenceRingerModeInternal(caller);
7574 }
7575
7576 @Override
John Spurlock50ced3f2015-05-11 16:00:09 -04007577 public void updateRingerModeAffectedStreamsInternal() {
7578 synchronized (mSettingsLock) {
Beverlyd6964762018-02-16 14:07:03 -05007579 if (updateRingerAndZenModeAffectedStreams()) {
John Spurlock50ced3f2015-05-11 16:00:09 -04007580 setRingerModeInt(getRingerModeInternal(), false);
7581 }
7582 }
7583 }
Phil Weaverf1a9aff2017-03-23 17:21:29 -07007584
7585 @Override
7586 public void setAccessibilityServiceUids(IntArray uids) {
7587 synchronized (mAccessibilityServiceUidsLock) {
7588 if (uids.size() == 0) {
7589 mAccessibilityServiceUids = null;
7590 } else {
7591 boolean changed = (mAccessibilityServiceUids == null)
7592 || (mAccessibilityServiceUids.length != uids.size());
7593 if (!changed) {
7594 for (int i = 0; i < mAccessibilityServiceUids.length; i++) {
7595 if (uids.get(i) != mAccessibilityServiceUids[i]) {
7596 changed = true;
7597 break;
7598 }
7599 }
7600 }
7601 if (changed) {
7602 mAccessibilityServiceUids = uids.toArray();
7603 }
7604 }
7605 }
7606 }
RoboErik0dac35a2014-08-12 15:48:49 -07007607 }
7608
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007609 //==========================================================================================
7610 // Audio policy management
7611 //==========================================================================================
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007612 public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -08007613 boolean hasFocusListener, boolean isFocusPolicy, boolean isVolumeController) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007614 AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
7615
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007616 String regId = null;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007617 // error handling
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007618 boolean hasPermissionForPolicy =
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007619 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007620 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
7621 if (!hasPermissionForPolicy) {
7622 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
7623 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007624 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007625 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007626
Jean-Michel Trivi12a86762018-04-24 16:57:49 -07007627 mDynPolicyLogger.log((new AudioEventLogger.StringEvent("registerAudioPolicy for "
7628 + pcb.asBinder() + " with config:" + policyConfig)).printLog(TAG));
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007629 synchronized (mAudioPolicies) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007630 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007631 if (mAudioPolicies.containsKey(pcb.asBinder())) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08007632 Slog.e(TAG, "Cannot re-register policy");
7633 return null;
7634 }
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07007635 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener,
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -08007636 isFocusPolicy, isVolumeController);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007637 pcb.asBinder().linkToDeath(app, 0/*flags*/);
7638 regId = app.getRegistrationId();
7639 mAudioPolicies.put(pcb.asBinder(), app);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007640 } catch (RemoteException e) {
7641 // audio policy owner has already died!
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007642 Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007643 " binder death", e);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007644 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007645 }
7646 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007647 return regId;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007648 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007649
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007650 public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
Jean-Michel Trivi12a86762018-04-24 16:57:49 -07007651 mDynPolicyLogger.log((new AudioEventLogger.StringEvent("unregisterAudioPolicyAsync for "
7652 + pcb.asBinder()).printLog(TAG)));
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007653 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007654 AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007655 if (app == null) {
7656 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
7657 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08007658 return;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007659 } else {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007660 pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007661 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007662 app.release();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007663 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007664 // TODO implement clearing mix attribute matching info in native audio policy
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007665 }
7666
Jean-Michel Triviaf576a02018-02-14 08:57:46 -08007667 /**
7668 * Checks whether caller has MODIFY_AUDIO_ROUTING permission, and the policy is registered.
7669 * @param errorMsg log warning if permission check failed.
7670 * @return null if the operation on the audio mixes should be cancelled.
7671 */
7672 @GuardedBy("mAudioPolicies")
7673 private AudioPolicyProxy checkUpdateForPolicy(IAudioPolicyCallback pcb, String errorMsg) {
7674 // permission check
7675 final boolean hasPermissionForPolicy =
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007676 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
7677 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
7678 if (!hasPermissionForPolicy) {
Jean-Michel Triviaf576a02018-02-14 08:57:46 -08007679 Slog.w(TAG, errorMsg + " for pid " +
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007680 + Binder.getCallingPid() + " / uid "
7681 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
Jean-Michel Triviaf576a02018-02-14 08:57:46 -08007682 return null;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007683 }
Jean-Michel Triviaf576a02018-02-14 08:57:46 -08007684 // policy registered?
7685 final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
7686 if (app == null) {
7687 Slog.w(TAG, errorMsg + " for pid " +
7688 + Binder.getCallingPid() + " / uid "
7689 + Binder.getCallingUid() + ", unregistered policy");
7690 return null;
7691 }
7692 return app;
7693 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007694
Jean-Michel Triviaf576a02018-02-14 08:57:46 -08007695 public int addMixForPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb) {
7696 if (DEBUG_AP) { Log.d(TAG, "addMixForPolicy for " + pcb.asBinder()
7697 + " with config:" + policyConfig); }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007698 synchronized (mAudioPolicies) {
Jean-Michel Triviaf576a02018-02-14 08:57:46 -08007699 final AudioPolicyProxy app =
7700 checkUpdateForPolicy(pcb, "Cannot add AudioMix in audio policy");
7701 if (app == null){
7702 return AudioManager.ERROR;
7703 }
7704 app.addMixes(policyConfig.getMixes());
7705 }
7706 return AudioManager.SUCCESS;
7707 }
7708
7709 public int removeMixForPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb) {
7710 if (DEBUG_AP) { Log.d(TAG, "removeMixForPolicy for " + pcb.asBinder()
7711 + " with config:" + policyConfig); }
7712 synchronized (mAudioPolicies) {
7713 final AudioPolicyProxy app =
7714 checkUpdateForPolicy(pcb, "Cannot add AudioMix in audio policy");
7715 if (app == null) {
7716 return AudioManager.ERROR;
7717 }
7718 app.removeMixes(policyConfig.getMixes());
7719 }
7720 return AudioManager.SUCCESS;
7721 }
7722
7723 public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
7724 if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
7725 + " policy " + pcb.asBinder());
7726 synchronized (mAudioPolicies) {
7727 final AudioPolicyProxy app =
7728 checkUpdateForPolicy(pcb, "Cannot change audio policy focus properties");
7729 if (app == null){
7730 return AudioManager.ERROR;
7731 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007732 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
7733 Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
7734 return AudioManager.ERROR;
7735 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007736 if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
7737 // is there already one policy managing ducking?
Eric Laurent0867bed2015-05-20 14:49:08 -07007738 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007739 if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
7740 Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
7741 return AudioManager.ERROR;
7742 }
7743 }
7744 }
7745 app.mFocusDuckBehavior = duckingBehavior;
7746 mMediaFocusControl.setDuckingInExtPolicyAvailable(
7747 duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
7748 }
7749 return AudioManager.SUCCESS;
7750 }
7751
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -08007752 private final Object mExtVolumeControllerLock = new Object();
7753 private IAudioPolicyCallback mExtVolumeController;
7754 private void setExtVolumeController(IAudioPolicyCallback apc) {
7755 if (!mContext.getResources().getBoolean(
7756 com.android.internal.R.bool.config_handleVolumeKeysInWindowManager)) {
7757 Log.e(TAG, "Cannot set external volume controller: device not set for volume keys" +
7758 " handled in PhoneWindowManager");
7759 return;
7760 }
7761 synchronized (mExtVolumeControllerLock) {
7762 if (mExtVolumeController != null && !mExtVolumeController.asBinder().pingBinder()) {
7763 Log.e(TAG, "Cannot set external volume controller: existing controller");
7764 }
7765 mExtVolumeController = apc;
7766 }
7767 }
7768
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08007769 private void dumpAudioPolicies(PrintWriter pw) {
7770 pw.println("\nAudio policies:");
7771 synchronized (mAudioPolicies) {
Eric Laurent0867bed2015-05-20 14:49:08 -07007772 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08007773 pw.println(policy.toLogFriendlyString());
7774 }
7775 }
7776 }
7777
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08007778 //======================
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08007779 // Audio policy callbacks from AudioSystem for dynamic policies
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007780 //======================
7781 private final AudioSystem.DynamicPolicyCallback mDynPolicyCallback =
7782 new AudioSystem.DynamicPolicyCallback() {
7783 public void onDynamicPolicyMixStateUpdate(String regId, int state) {
7784 if (!TextUtils.isEmpty(regId)) {
7785 sendMsg(mAudioHandler, MSG_DYN_POLICY_MIX_STATE_UPDATE, SENDMSG_QUEUE,
7786 state /*arg1*/, 0 /*arg2 ignored*/, regId /*obj*/, 0 /*delay*/);
7787 }
7788 }
7789 };
7790
7791 private void onDynPolicyMixStateUpdate(String regId, int state) {
7792 if (DEBUG_AP) Log.d(TAG, "onDynamicPolicyMixStateUpdate("+ regId + ", " + state +")");
7793 synchronized (mAudioPolicies) {
7794 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
7795 for (AudioMix mix : policy.getMixes()) {
7796 if (mix.getRegistration().equals(regId)) {
7797 try {
7798 policy.mPolicyCallback.notifyMixStateUpdate(regId, state);
7799 } catch (RemoteException e) {
7800 Log.e(TAG, "Can't call notifyMixStateUpdate() on IAudioPolicyCallback "
7801 + policy.mPolicyCallback.asBinder(), e);
7802 }
7803 return;
7804 }
7805 }
7806 }
7807 }
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08007808 }
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007809
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08007810 //======================
7811 // Audio policy callbacks from AudioSystem for recording configuration updates
7812 //======================
Jean-Michel Trivi66ffacf2017-02-04 17:25:31 -08007813 private final RecordingActivityMonitor mRecordMonitor;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08007814
7815 public void registerRecordingCallback(IRecordingConfigDispatcher rcdb) {
Jean-Michel Trivi66ffacf2017-02-04 17:25:31 -08007816 final boolean isPrivileged =
7817 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
7818 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
7819 mRecordMonitor.registerRecordingCallback(rcdb, isPrivileged);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08007820 }
7821
7822 public void unregisterRecordingCallback(IRecordingConfigDispatcher rcdb) {
7823 mRecordMonitor.unregisterRecordingCallback(rcdb);
7824 }
7825
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07007826 public List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
Jean-Michel Trivi66ffacf2017-02-04 17:25:31 -08007827 final boolean isPrivileged =
7828 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
7829 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
7830 return mRecordMonitor.getActiveRecordingConfigurations(isPrivileged);
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007831 }
7832
Robin Lee7af9a742017-02-20 14:47:30 +00007833 public void disableRingtoneSync(final int userId) {
Andre Lago7bdc6d82016-09-22 18:00:41 +01007834 final int callingUserId = UserHandle.getCallingUserId();
Robin Lee7af9a742017-02-20 14:47:30 +00007835 if (callingUserId != userId) {
7836 mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
7837 "disable sound settings syncing for another profile");
7838 }
Andre Lago7bdc6d82016-09-22 18:00:41 +01007839 final long token = Binder.clearCallingIdentity();
7840 try {
Robin Lee7af9a742017-02-20 14:47:30 +00007841 // Disable the sync setting so the profile uses its own sound settings.
7842 Settings.Secure.putIntForUser(mContentResolver, Settings.Secure.SYNC_PARENT_SOUNDS,
7843 0 /* false */, userId);
Andre Lago7bdc6d82016-09-22 18:00:41 +01007844 } finally {
7845 Binder.restoreCallingIdentity(token);
7846 }
7847 }
7848
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007849 //======================
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -08007850 // Audio playback notification
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007851 //======================
Eric Laurente5a351c2017-09-27 20:11:51 -07007852 private final PlaybackActivityMonitor mPlaybackMonitor;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007853
7854 public void registerPlaybackCallback(IPlaybackConfigDispatcher pcdb) {
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -08007855 final boolean isPrivileged =
Jaewan Kim92dea332017-02-02 11:52:08 +09007856 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007857 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
7858 mPlaybackMonitor.registerPlaybackCallback(pcdb, isPrivileged);
7859 }
7860
7861 public void unregisterPlaybackCallback(IPlaybackConfigDispatcher pcdb) {
7862 mPlaybackMonitor.unregisterPlaybackCallback(pcdb);
7863 }
7864
7865 public List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() {
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -08007866 final boolean isPrivileged =
Jaewan Kim92dea332017-02-02 11:52:08 +09007867 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -08007868 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
7869 return mPlaybackMonitor.getActivePlaybackConfigurations(isPrivileged);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007870 }
7871
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -08007872 public int trackPlayer(PlayerBase.PlayerIdCard pic) {
7873 return mPlaybackMonitor.trackPlayer(pic);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007874 }
7875
7876 public void playerAttributes(int piid, AudioAttributes attr) {
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -08007877 mPlaybackMonitor.playerAttributes(piid, attr, Binder.getCallingUid());
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007878 }
7879
7880 public void playerEvent(int piid, int event) {
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -08007881 mPlaybackMonitor.playerEvent(piid, event, Binder.getCallingUid());
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007882 }
7883
Jean-Michel Trivi3120059d2017-08-28 12:40:55 -07007884 public void playerHasOpPlayAudio(int piid, boolean hasOpPlayAudio) {
7885 mPlaybackMonitor.playerHasOpPlayAudio(piid, hasOpPlayAudio, Binder.getCallingUid());
7886 }
7887
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007888 public void releasePlayer(int piid) {
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -08007889 mPlaybackMonitor.releasePlayer(piid, Binder.getCallingUid());
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007890 }
7891
7892 //======================
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08007893 // Audio policy proxy
7894 //======================
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007895 /**
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08007896 * This internal class inherits from AudioPolicyConfig, each instance contains all the
7897 * mixes of an AudioPolicy and their configurations.
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007898 */
7899 public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007900 private static final String TAG = "AudioPolicyProxy";
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -08007901 final IAudioPolicyCallback mPolicyCallback;
7902 final boolean mHasFocusListener;
7903 final boolean mIsVolumeController;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007904 /**
7905 * Audio focus ducking behavior for an audio policy.
7906 * This variable reflects the value that was successfully set in
7907 * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
7908 * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
7909 * is handling ducking for audio focus.
7910 */
7911 int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07007912 boolean mIsFocusPolicy = false;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007913
7914 AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -08007915 boolean hasFocusListener, boolean isFocusPolicy, boolean isVolumeController) {
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007916 super(config);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08007917 setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007918 mPolicyCallback = token;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007919 mHasFocusListener = hasFocusListener;
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -08007920 mIsVolumeController = isVolumeController;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007921 if (mHasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007922 mMediaFocusControl.addFocusFollower(mPolicyCallback);
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07007923 // can only ever be true if there is a focus listener
7924 if (isFocusPolicy) {
7925 mIsFocusPolicy = true;
7926 mMediaFocusControl.setFocusPolicy(mPolicyCallback);
7927 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007928 }
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -08007929 if (mIsVolumeController) {
7930 setExtVolumeController(mPolicyCallback);
7931 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08007932 connectMixes();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007933 }
7934
7935 public void binderDied() {
7936 synchronized (mAudioPolicies) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007937 Log.i(TAG, "audio policy " + mPolicyCallback + " died");
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007938 release();
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007939 mAudioPolicies.remove(mPolicyCallback.asBinder());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007940 }
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -08007941 if (mIsVolumeController) {
7942 synchronized (mExtVolumeControllerLock) {
7943 mExtVolumeController = null;
7944 }
7945 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007946 }
7947
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007948 String getRegistrationId() {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08007949 return getRegistration();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007950 }
7951
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007952 void release() {
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07007953 if (mIsFocusPolicy) {
7954 mMediaFocusControl.unsetFocusPolicy(mPolicyCallback);
7955 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007956 if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
7957 mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
7958 }
7959 if (mHasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007960 mMediaFocusControl.removeFocusFollower(mPolicyCallback);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007961 }
Eric Laurent66b69672018-01-26 18:30:51 -08007962 final long identity = Binder.clearCallingIdentity();
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08007963 AudioSystem.registerPolicyMixes(mMixes, false);
Eric Laurent66b69672018-01-26 18:30:51 -08007964 Binder.restoreCallingIdentity(identity);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007965 }
7966
Jean-Michel Trivi7db2d8f2018-03-06 10:30:59 -08007967 boolean hasMixAffectingUsage(int usage) {
7968 for (AudioMix mix : mMixes) {
7969 if (mix.isAffectingUsage(usage)) {
7970 return true;
7971 }
7972 }
7973 return false;
7974 }
7975
Jean-Michel Triviaf576a02018-02-14 08:57:46 -08007976 void addMixes(@NonNull ArrayList<AudioMix> mixes) {
7977 // TODO optimize to not have to unregister the mixes already in place
7978 synchronized (mMixes) {
7979 AudioSystem.registerPolicyMixes(mMixes, false);
7980 this.add(mixes);
7981 AudioSystem.registerPolicyMixes(mMixes, true);
7982 }
7983 }
7984
7985 void removeMixes(@NonNull ArrayList<AudioMix> mixes) {
7986 // TODO optimize to not have to unregister the mixes already in place
7987 synchronized (mMixes) {
7988 AudioSystem.registerPolicyMixes(mMixes, false);
7989 this.remove(mixes);
7990 AudioSystem.registerPolicyMixes(mMixes, true);
7991 }
7992 }
7993
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08007994 void connectMixes() {
Eric Laurent66b69672018-01-26 18:30:51 -08007995 final long identity = Binder.clearCallingIdentity();
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08007996 AudioSystem.registerPolicyMixes(mMixes, true);
Eric Laurent66b69672018-01-26 18:30:51 -08007997 Binder.restoreCallingIdentity(identity);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007998 }
7999 };
8000
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07008001 //======================
8002 // Audio policy: focus
8003 //======================
8004 /** */
8005 public int dispatchFocusChange(AudioFocusInfo afi, int focusChange, IAudioPolicyCallback pcb) {
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08008006 if (afi == null) {
8007 throw new IllegalArgumentException("Illegal null AudioFocusInfo");
8008 }
8009 if (pcb == null) {
8010 throw new IllegalArgumentException("Illegal null AudioPolicy callback");
8011 }
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07008012 synchronized (mAudioPolicies) {
8013 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
8014 throw new IllegalStateException("Unregistered AudioPolicy for focus dispatch");
8015 }
8016 return mMediaFocusControl.dispatchFocusChange(afi, focusChange);
8017 }
8018 }
8019
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08008020 public void setFocusRequestResultFromExtPolicy(AudioFocusInfo afi, int requestResult,
8021 IAudioPolicyCallback pcb) {
8022 if (afi == null) {
8023 throw new IllegalArgumentException("Illegal null AudioFocusInfo");
8024 }
8025 if (pcb == null) {
8026 throw new IllegalArgumentException("Illegal null AudioPolicy callback");
8027 }
8028 synchronized (mAudioPolicies) {
8029 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
8030 throw new IllegalStateException("Unregistered AudioPolicy for external focus");
8031 }
8032 mMediaFocusControl.setFocusRequestResultFromExtPolicy(afi, requestResult);
8033 }
8034 }
8035
8036
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07008037 //======================
Eric Laurent1d3cdce2018-01-20 10:31:21 -08008038 // Audioserver state displatch
8039 //======================
8040 private class AsdProxy implements IBinder.DeathRecipient {
8041 private final IAudioServerStateDispatcher mAsd;
8042
8043 AsdProxy(IAudioServerStateDispatcher asd) {
8044 mAsd = asd;
8045 }
8046
8047 public void binderDied() {
8048 synchronized (mAudioServerStateListeners) {
8049 mAudioServerStateListeners.remove(mAsd.asBinder());
8050 }
8051 }
8052
8053 IAudioServerStateDispatcher callback() {
8054 return mAsd;
8055 }
8056 }
8057
8058 private HashMap<IBinder, AsdProxy> mAudioServerStateListeners =
8059 new HashMap<IBinder, AsdProxy>();
8060
8061 private void checkMonitorAudioServerStatePermission() {
8062 if (!(mContext.checkCallingOrSelfPermission(
8063 android.Manifest.permission.MODIFY_PHONE_STATE) ==
8064 PackageManager.PERMISSION_GRANTED ||
8065 mContext.checkCallingOrSelfPermission(
8066 android.Manifest.permission.MODIFY_AUDIO_ROUTING) ==
8067 PackageManager.PERMISSION_GRANTED)) {
8068 throw new SecurityException("Not allowed to monitor audioserver state");
8069 }
8070 }
8071
8072 public void registerAudioServerStateDispatcher(IAudioServerStateDispatcher asd) {
8073 checkMonitorAudioServerStatePermission();
8074 synchronized (mAudioServerStateListeners) {
8075 if (mAudioServerStateListeners.containsKey(asd.asBinder())) {
8076 Slog.w(TAG, "Cannot re-register audio server state dispatcher");
8077 return;
8078 }
8079 AsdProxy asdp = new AsdProxy(asd);
8080 try {
8081 asd.asBinder().linkToDeath(asdp, 0/*flags*/);
8082 } catch (RemoteException e) {
8083
8084 }
8085 mAudioServerStateListeners.put(asd.asBinder(), asdp);
8086 }
8087 }
8088
8089 public void unregisterAudioServerStateDispatcher(IAudioServerStateDispatcher asd) {
8090 checkMonitorAudioServerStatePermission();
8091 synchronized (mAudioServerStateListeners) {
8092 AsdProxy asdp = mAudioServerStateListeners.remove(asd.asBinder());
8093 if (asdp == null) {
8094 Slog.w(TAG, "Trying to unregister unknown audioserver state dispatcher for pid "
8095 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
8096 return;
8097 } else {
8098 asd.asBinder().unlinkToDeath(asdp, 0/*flags*/);
8099 }
8100 }
8101 }
8102
8103 public boolean isAudioServerRunning() {
8104 checkMonitorAudioServerStatePermission();
8105 return (AudioSystem.checkAudioFlinger() == AudioSystem.AUDIO_STATUS_OK);
8106 }
8107
8108 //======================
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07008109 // misc
8110 //======================
Jean-Michel Triviaf576a02018-02-14 08:57:46 -08008111 private final HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07008112 new HashMap<IBinder, AudioPolicyProxy>();
Jean-Michel Triviaf576a02018-02-14 08:57:46 -08008113 @GuardedBy("mAudioPolicies")
8114 private int mAudioPolicyCounter = 0;
Phil Burkac0f7042016-02-24 12:19:08 -08008115}