blob: bedf043147def41170823d6d73d95258f9482e86 [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
Jean-Michel Trivicf170362017-08-24 17:24:57 -070019import com.android.server.audio.AudioServiceEvents.ForceUseEvent;
20import com.android.server.audio.AudioServiceEvents.PhoneStateEvent;
21import com.android.server.audio.AudioServiceEvents.VolumeEvent;
22import com.android.server.audio.AudioServiceEvents.WiredDevConnectEvent;
23
Jeff Sharkey098d5802012-04-26 17:30:34 -070024import static android.Manifest.permission.REMOTE_AUDIO_PLAYBACK;
Amith Yamasanic696a532011-10-28 17:02:37 -070025import static android.media.AudioManager.RINGER_MODE_NORMAL;
26import static android.media.AudioManager.RINGER_MODE_SILENT;
27import static android.media.AudioManager.RINGER_MODE_VIBRATE;
Fyodor Kupolovbcb6c1e2015-05-11 12:05:15 -070028import static android.os.Process.FIRST_APPLICATION_UID;
Amith Yamasanic696a532011-10-28 17:02:37 -070029
Fyodor Kupolovb5013302015-04-17 17:59:14 -070030import android.Manifest;
Jean-Michel Trivia53b7052017-04-12 18:27:01 -070031import android.annotation.Nullable;
Glenn Kastenfd116ad2013-07-12 17:10:39 -070032import android.app.ActivityManager;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070033import android.app.ActivityManagerInternal;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070034import android.app.AppGlobals;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -070035import android.app.AppOpsManager;
Dianne Hackborn3e99f652017-07-05 16:33:56 -070036import android.app.IUidObserver;
Julia Reynolds48034f82016-03-09 10:15:16 -050037import android.app.NotificationManager;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070038import android.bluetooth.BluetoothA2dp;
39import android.bluetooth.BluetoothAdapter;
40import android.bluetooth.BluetoothClass;
41import android.bluetooth.BluetoothDevice;
42import android.bluetooth.BluetoothHeadset;
43import android.bluetooth.BluetoothProfile;
Nick Pellybd022f42009-08-14 18:33:38 -070044import android.content.BroadcastReceiver;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070045import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.content.ContentResolver;
47import android.content.Context;
48import android.content.Intent;
Eric Laurenta553c252009-07-17 12:17:14 -070049import android.content.IntentFilter;
Julia Reynolds48034f82016-03-09 10:15:16 -050050import android.content.pm.ApplicationInfo;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070051import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.content.pm.PackageManager;
Marco Nelissenfb6df0b2017-02-15 15:25:24 -080053import android.content.pm.ResolveInfo;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070054import android.content.pm.UserInfo;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -070055import android.content.res.Configuration;
Eric Laurente78fced2013-03-15 16:03:47 -070056import android.content.res.Resources;
57import android.content.res.XmlResourceParser;
Jason Parekhb1096152009-03-24 17:48:25 -070058import android.database.ContentObserver;
Jungshik Jang41d97462014-06-30 22:26:29 +090059import android.hardware.hdmi.HdmiControlManager;
Eric Laurent212532b2014-07-21 15:43:18 -070060import android.hardware.hdmi.HdmiPlaybackClient;
Jungshik Jang41d97462014-06-30 22:26:29 +090061import android.hardware.hdmi.HdmiTvClient;
Paul McLeanc837a452014-04-09 09:04:43 -070062import android.hardware.usb.UsbManager;
John Spurlock61560172015-02-06 19:46:04 -050063import android.media.AudioAttributes;
64import android.media.AudioDevicePort;
Jean-Michel Trivi126cf032017-04-02 23:19:02 -070065import android.media.AudioFocusInfo;
Jean-Michel Trivi9228af62018-01-05 17:06:17 -080066import android.media.AudioFocusRequest;
John Spurlock61560172015-02-06 19:46:04 -050067import android.media.AudioSystem;
68import android.media.AudioFormat;
69import android.media.AudioManager;
70import android.media.AudioManagerInternal;
71import android.media.AudioPort;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080072import android.media.AudioPlaybackConfiguration;
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -080073import android.media.AudioRecordingConfiguration;
John Spurlock61560172015-02-06 19:46:04 -050074import android.media.AudioRoutesInfo;
John Spurlock61560172015-02-06 19:46:04 -050075import android.media.IAudioFocusDispatcher;
76import android.media.IAudioRoutesObserver;
77import android.media.IAudioService;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080078import android.media.IPlaybackConfigDispatcher;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -080079import android.media.IRecordingConfigDispatcher;
John Spurlock61560172015-02-06 19:46:04 -050080import android.media.IRingtonePlayer;
81import android.media.IVolumeController;
82import android.media.MediaPlayer;
83import android.media.SoundPool;
John Spurlocka48d7792015-03-03 17:35:57 -050084import android.media.VolumePolicy;
Marco Nelissenfb6df0b2017-02-15 15:25:24 -080085import android.media.audiofx.AudioEffect;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086import android.media.MediaPlayer.OnCompletionListener;
87import android.media.MediaPlayer.OnErrorListener;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -080088import android.media.PlayerBase;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -070089import android.media.audiopolicy.AudioMix;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -080090import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070091import android.media.audiopolicy.AudioPolicyConfig;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -080092import android.media.audiopolicy.IAudioPolicyCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093import android.os.Binder;
Eric Laurentc18c9132013-04-12 17:24:56 -070094import android.os.Build;
Makoto Onukid45a4a22015-11-02 17:17:38 -080095import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096import android.os.Environment;
97import android.os.Handler;
98import android.os.IBinder;
99import android.os.Looper;
100import android.os.Message;
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700101import android.os.PowerManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -0700102import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103import android.os.RemoteException;
John Spurlock33f4e042014-07-11 13:10:58 -0400104import android.os.SystemClock;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700105import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700106import android.os.UserHandle;
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700107import android.os.UserManager;
Makoto Onukid45a4a22015-11-02 17:17:38 -0800108import android.os.UserManagerInternal;
109import android.os.UserManagerInternal.UserRestrictionsListener;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700110import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111import android.provider.Settings;
112import android.provider.Settings.System;
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700113import android.telecom.TelecomManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -0700114import android.text.TextUtils;
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700115import android.util.AndroidRuntimeException;
John Spurlock8c3dc852015-04-23 21:32:37 -0400116import android.util.ArrayMap;
117import android.util.ArraySet;
Phil Weaverf1a9aff2017-03-23 17:21:29 -0700118import android.util.IntArray;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119import android.util.Log;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400120import android.util.MathUtils;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -0700121import android.util.Slog;
John Spurlock2bb02ec2015-03-02 13:13:06 -0500122import android.util.SparseIntArray;
Jean-Michel Trivid327f212010-03-16 21:44:33 -0700123import android.view.KeyEvent;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700124import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -0800126import com.android.internal.annotations.GuardedBy;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600127import com.android.internal.util.DumpUtils;
Eric Laurente78fced2013-03-15 16:03:47 -0700128import com.android.internal.util.XmlUtils;
John Spurlock90874332015-03-10 16:00:54 -0400129import com.android.server.EventLogTags;
RoboErik0dac35a2014-08-12 15:48:49 -0700130import com.android.server.LocalServices;
Makoto Onukie1aef852015-10-15 17:28:35 -0700131import com.android.server.SystemService;
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700132import com.android.server.pm.UserManagerService;
Eric Laurente78fced2013-03-15 16:03:47 -0700133
134import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800136import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137import java.io.IOException;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800138import java.io.PrintWriter;
Eric Laurente78fced2013-03-15 16:03:47 -0700139import java.lang.reflect.Field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140import java.util.ArrayList;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700141import java.util.HashMap;
142import java.util.Iterator;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -0700143import java.util.List;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700144import java.util.NoSuchElementException;
RoboErikd09bd0c2014-06-24 17:45:19 -0700145import java.util.Objects;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146
147/**
148 * The implementation of the volume manager service.
149 * <p>
150 * This implementation focuses on delivering a responsive UI. Most methods are
151 * asynchronous to external calls. For example, the task of setting a volume
152 * will update our internal state, but in a separate thread will set the system
153 * volume and later persist to the database. Similarly, setting the ringer mode
154 * will update the state and broadcast a change and in a separate thread later
155 * persist the ringer mode.
156 *
157 * @hide
158 */
Jean-Michel Triviac487672016-11-11 10:05:18 -0800159public class AudioService extends IAudioService.Stub
160 implements AccessibilityManager.TouchExplorationStateChangeListener,
Jean-Michel Trivicfa55532017-01-18 11:17:51 -0800161 AccessibilityManager.AccessibilityServicesStateChangeListener {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162
163 private static final String TAG = "AudioService";
164
Jean-Michel Trivi339567d2014-07-29 09:53:34 -0700165 /** Debug audio mode */
166 protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -0700167
168 /** Debug audio policy feature */
169 protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);
170
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700171 /** Debug volumes */
John Spurlockae641c92014-06-30 18:11:40 -0400172 protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700173
Paul McLean394a8e12015-03-03 10:29:19 -0700174 /** debug calls to devices APIs */
175 protected static final boolean DEBUG_DEVICES = Log.isLoggable(TAG + ".DEVICES", Log.DEBUG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176 /** How long to delay before persisting a change in volume/ringer mode. */
RoboErik45edba12012-03-27 17:54:36 -0700177 private static final int PERSIST_DELAY = 500;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178
RoboErik5452e252015-02-06 15:33:53 -0800179 /** How long to delay after a volume down event before unmuting a stream */
180 private static final int UNMUTE_STREAM_DELAY = 350;
181
John Spurlock3346a802014-05-20 16:25:37 -0400182 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400183 * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
184 */
185 private static final int FLAG_ADJUST_VOLUME = 1;
186
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700187 private final Context mContext;
188 private final ContentResolver mContentResolver;
189 private final AppOpsManager mAppOps;
Eric Laurent212532b2014-07-21 15:43:18 -0700190
Eric Laurent212532b2014-07-21 15:43:18 -0700191 // the platform type affects volume and silent mode behavior
192 private final int mPlatformType;
193
Muyuan Li1ed6df62016-06-18 11:16:52 -0700194 // indicates whether the system maps all streams to a single stream.
195 private final boolean mIsSingleVolume;
196
Eric Laurent212532b2014-07-21 15:43:18 -0700197 private boolean isPlatformVoice() {
John Spurlock61560172015-02-06 19:46:04 -0500198 return mPlatformType == AudioSystem.PLATFORM_VOICE;
Eric Laurent212532b2014-07-21 15:43:18 -0700199 }
200
201 private boolean isPlatformTelevision() {
John Spurlock61560172015-02-06 19:46:04 -0500202 return mPlatformType == AudioSystem.PLATFORM_TELEVISION;
Eric Laurent212532b2014-07-21 15:43:18 -0700203 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800204
John Spurlock3346a802014-05-20 16:25:37 -0400205 /** The controller for the volume UI. */
206 private final VolumeController mVolumeController = new VolumeController();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207
208 // sendMsg() flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 /** If the msg is already queued, replace it with this one. */
210 private static final int SENDMSG_REPLACE = 0;
211 /** If the msg is already queued, ignore this one and leave the old. */
212 private static final int SENDMSG_NOOP = 1;
213 /** If the msg is already queued, queue this one and leave the old. */
214 private static final int SENDMSG_QUEUE = 2;
215
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700216 // AudioHandler messages
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800217 private static final int MSG_SET_DEVICE_VOLUME = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 private static final int MSG_PERSIST_VOLUME = 1;
219 private static final int MSG_PERSIST_RINGER_MODE = 3;
Andy Hunged0ea402015-10-30 14:11:46 -0700220 private static final int MSG_AUDIO_SERVER_DIED = 4;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700221 private static final int MSG_PLAY_SOUND_EFFECT = 5;
222 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
223 private static final int MSG_LOAD_SOUND_EFFECTS = 7;
224 private static final int MSG_SET_FORCE_USE = 8;
225 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
226 private static final int MSG_SET_ALL_VOLUMES = 10;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700227 private static final int MSG_REPORT_NEW_ROUTES = 12;
Sungsoocf09fe62016-09-28 16:21:48 +0900228 private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700229 private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
230 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
231 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
232 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
233 private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
234 private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
235 private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700236 private static final int MSG_SYSTEM_READY = 21;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400237 private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
RoboErik5452e252015-02-06 15:33:53 -0800238 private static final int MSG_UNMUTE_STREAM = 24;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -0700239 private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 25;
Eric Laurent0867bed2015-05-20 14:49:08 -0700240 private static final int MSG_INDICATE_SYSTEM_READY = 26;
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -0700241 private static final int MSG_ACCESSORY_PLUG_MEDIA_UNMUTE = 27;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700242 // start of messages handled under wakelock
243 // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
Jean-Michel Trivie12c39b2012-06-06 10:51:58 -0700244 // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700245 private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
Mike Lockwood0a40ec22014-05-21 10:08:50 -0700246 private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
247 private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800248 private static final int MSG_A2DP_DEVICE_CONFIG_CHANGE = 103;
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -0700249 private static final int MSG_DISABLE_AUDIO_FOR_UID = 104;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700250 // end of messages handled under wakelock
Eric Laurentafbb0472011-12-15 09:04:23 -0800251
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -0700252 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
Eric Laurentdc03c612011-04-01 10:59:41 -0700253 // Timeout for connection to bluetooth headset service
254 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
255
Eric Laurent0867bed2015-05-20 14:49:08 -0700256 // retry delay in case of failure to indicate system ready to AudioFlinger
257 private static final int INDICATE_SYSTEM_READY_RETRY_DELAY_MS = 1000;
258
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 /** @see AudioSystemThread */
260 private AudioSystemThread mAudioSystemThread;
261 /** @see AudioHandler */
262 private AudioHandler mAudioHandler;
263 /** @see VolumeStreamState */
264 private VolumeStreamState[] mStreamStates;
Jason Parekhb1096152009-03-24 17:48:25 -0700265 private SettingsObserver mSettingsObserver;
Eric Laurenta553c252009-07-17 12:17:14 -0700266
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700267 private int mMode = AudioSystem.MODE_NORMAL;
Glenn Kastenba195eb2011-12-13 09:30:40 -0800268 // protects mRingerMode
269 private final Object mSettingsLock = new Object();
Eric Laurent45c90ce2012-04-24 18:44:22 -0700270
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271 private SoundPool mSoundPool;
Glenn Kasten30c918c2011-11-10 17:56:41 -0800272 private final Object mSoundEffectsLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 private static final int NUM_SOUNDPOOL_CHANNELS = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274
275 /* Sound effect file names */
276 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
Eric Laurente78fced2013-03-15 16:03:47 -0700277 private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278
279 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
280 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
281 * uses soundpool (second column) */
Eric Laurente78fced2013-03-15 16:03:47 -0700282 private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283
John Spurlockb6e19e32015-03-10 21:33:44 -0400284 /** Maximum volume index values for audio streams */
Eric Laurent91377de2014-10-10 15:24:04 -0700285 private static int[] MAX_STREAM_VOLUME = new int[] {
Eric Laurent6ee99522009-08-25 06:30:59 -0700286 5, // STREAM_VOICE_CALL
287 7, // STREAM_SYSTEM
288 7, // STREAM_RING
289 15, // STREAM_MUSIC
290 7, // STREAM_ALARM
291 7, // STREAM_NOTIFICATION
292 15, // STREAM_BLUETOOTH_SCO
293 7, // STREAM_SYSTEM_ENFORCED
294 15, // STREAM_DTMF
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800295 15, // STREAM_TTS
296 15 // STREAM_ACCESSIBILITY
Jared Suttles59820132009-08-13 21:50:52 -0500297 };
Eric Laurent91377de2014-10-10 15:24:04 -0700298
John Spurlockb6e19e32015-03-10 21:33:44 -0400299 /** Minimum volume index values for audio streams */
300 private static int[] MIN_STREAM_VOLUME = new int[] {
301 1, // STREAM_VOICE_CALL
302 0, // STREAM_SYSTEM
303 0, // STREAM_RING
304 0, // STREAM_MUSIC
305 0, // STREAM_ALARM
306 0, // STREAM_NOTIFICATION
Eric Laurente4381ec2015-10-29 17:52:48 -0700307 0, // STREAM_BLUETOOTH_SCO
John Spurlockb6e19e32015-03-10 21:33:44 -0400308 0, // STREAM_SYSTEM_ENFORCED
309 0, // STREAM_DTMF
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800310 0, // STREAM_TTS
311 0 // STREAM_ACCESSIBILITY
John Spurlockb6e19e32015-03-10 21:33:44 -0400312 };
313
Eric Laurent6d517662012-04-23 18:42:39 -0700314 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
Eric Laurenta553c252009-07-17 12:17:14 -0700315 * of another stream: This avoids multiplying the volume settings for hidden
316 * stream types that follow other stream behavior for volume settings
Eric Laurent6d517662012-04-23 18:42:39 -0700317 * NOTE: do not create loops in aliases!
318 * Some streams alias to different streams according to device category (phone or tablet) or
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700319 * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
Eric Laurent212532b2014-07-21 15:43:18 -0700320 * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
321 * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
322 * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
323 private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700324 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
325 AudioSystem.STREAM_RING, // STREAM_SYSTEM
326 AudioSystem.STREAM_RING, // STREAM_RING
327 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
328 AudioSystem.STREAM_ALARM, // STREAM_ALARM
329 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
330 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
331 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
332 AudioSystem.STREAM_RING, // STREAM_DTMF
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800333 AudioSystem.STREAM_MUSIC, // STREAM_TTS
334 AudioSystem.STREAM_MUSIC // STREAM_ACCESSIBILITY
Eric Laurenta553c252009-07-17 12:17:14 -0700335 };
Eric Laurent212532b2014-07-21 15:43:18 -0700336 private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
337 AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL
338 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
339 AudioSystem.STREAM_MUSIC, // STREAM_RING
340 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
341 AudioSystem.STREAM_MUSIC, // STREAM_ALARM
342 AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
343 AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO
344 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
345 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800346 AudioSystem.STREAM_MUSIC, // STREAM_TTS
347 AudioSystem.STREAM_MUSIC // STREAM_ACCESSIBILITY
Eric Laurent212532b2014-07-21 15:43:18 -0700348 };
349 private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700350 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
John Spurlock4f0f1202014-08-05 13:28:33 -0400351 AudioSystem.STREAM_RING, // STREAM_SYSTEM
Eric Laurent6d517662012-04-23 18:42:39 -0700352 AudioSystem.STREAM_RING, // STREAM_RING
353 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
354 AudioSystem.STREAM_ALARM, // STREAM_ALARM
355 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
356 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
John Spurlock4f0f1202014-08-05 13:28:33 -0400357 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
358 AudioSystem.STREAM_RING, // STREAM_DTMF
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800359 AudioSystem.STREAM_MUSIC, // STREAM_TTS
360 AudioSystem.STREAM_MUSIC // STREAM_ACCESSIBILITY
Eric Laurent6d517662012-04-23 18:42:39 -0700361 };
Yue Li949865b2017-05-24 17:25:28 -0700362 protected static int[] mStreamVolumeAlias;
Eric Laurenta553c252009-07-17 12:17:14 -0700363
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700364 /**
365 * Map AudioSystem.STREAM_* constants to app ops. This should be used
366 * after mapping through mStreamVolumeAlias.
367 */
John Spurlock59dc9c12015-03-02 11:20:15 -0500368 private static final int[] STREAM_VOLUME_OPS = new int[] {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700369 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL
370 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM
371 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING
372 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC
373 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM
374 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION
375 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO
376 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED
377 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF
378 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800379 AppOpsManager.OP_AUDIO_ACCESSIBILITY_VOLUME, // STREAM_ACCESSIBILITY
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700380 };
381
Eric Laurent83a017b2013-03-19 18:15:31 -0700382 private final boolean mUseFixedVolume;
383
Glenn Kasten30c918c2011-11-10 17:56:41 -0800384 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 public void onError(int error) {
386 switch (error) {
387 case AudioSystem.AUDIO_STATUS_SERVER_DIED:
Andy Hunged0ea402015-10-30 14:11:46 -0700388 sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED,
Eric Laurentdfb881f2013-07-18 14:41:39 -0700389 SENDMSG_NOOP, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 break;
391 default:
392 break;
393 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700394 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 };
396
397 /**
398 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
399 * {@link AudioManager#RINGER_MODE_SILENT}, or
400 * {@link AudioManager#RINGER_MODE_VIBRATE}.
401 */
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -0800402 @GuardedBy("mSettingsLock")
John Spurlock661f2cf2014-11-17 10:29:10 -0500403 private int mRingerMode; // internal ringer mode, affects muting of underlying streams
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -0800404 @GuardedBy("mSettingsLock")
John Spurlock661f2cf2014-11-17 10:29:10 -0500405 private int mRingerModeExternal = -1; // reported ringer mode to outside clients (AudioManager)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406
Eric Laurent9bcf4012009-06-12 06:09:28 -0700407 /** @see System#MODE_RINGER_STREAMS_AFFECTED */
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700408 private int mRingerModeAffectedStreams = 0;
Eric Laurent9bcf4012009-06-12 06:09:28 -0700409
Eric Laurent5b4e6542010-03-19 20:02:21 -0700410 // Streams currently muted by ringer mode
411 private int mRingerModeMutedStreams;
412
John Spurlock3ce37252015-02-17 13:20:45 -0500413 /** Streams that can be muted. Do not resolve to aliases when checking.
414 * @see System#MUTE_STREAMS_AFFECTED */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 private int mMuteAffectedStreams;
416
417 /**
Eric Laurentbffc3d12012-05-07 17:43:49 -0700418 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
419 * mVibrateSetting is just maintained during deprecation period but vibration policy is
420 * now only controlled by mHasVibrator and mRingerMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 */
422 private int mVibrateSetting;
423
Eric Laurentbffc3d12012-05-07 17:43:49 -0700424 // Is there a vibrator
425 private final boolean mHasVibrator;
426
Eric Laurenta553c252009-07-17 12:17:14 -0700427 // Broadcast receiver for device connections intent broadcasts
428 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
429
Makoto Onukid45a4a22015-11-02 17:17:38 -0800430 /** Interface for UserManagerService. */
431 private final UserManagerInternal mUserManagerInternal;
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700432 private final ActivityManagerInternal mActivityManagerInternal;
Makoto Onukid45a4a22015-11-02 17:17:38 -0800433
434 private final UserRestrictionsListener mUserRestrictionsListener =
435 new AudioServiceUserRestrictionsListener();
436
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700437 // Devices currently connected
Paul McLean394a8e12015-03-03 10:29:19 -0700438 // Use makeDeviceListKey() to make a unique key for this list.
439 private class DeviceListSpec {
440 int mDeviceType;
441 String mDeviceName;
442 String mDeviceAddress;
443
444 public DeviceListSpec(int deviceType, String deviceName, String deviceAddress) {
445 mDeviceType = deviceType;
446 mDeviceName = deviceName;
447 mDeviceAddress = deviceAddress;
448 }
449
450 public String toString() {
451 return "[type:0x" + Integer.toHexString(mDeviceType) + " name:" + mDeviceName
452 + " address:" + mDeviceAddress + "]";
453 }
454 }
455
456 // Generate a unique key for the mConnectedDevices List by composing the device "type"
457 // and the "address" associated with a specific instance of that device type
458 private String makeDeviceListKey(int device, String deviceAddress) {
459 return "0x" + Integer.toHexString(device) + ":" + deviceAddress;
460 }
461
John Spurlock8c3dc852015-04-23 21:32:37 -0400462 private final ArrayMap<String, DeviceListSpec> mConnectedDevices = new ArrayMap<>();
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700463
464 // Forced device usage for communications
465 private int mForcedUseForComm;
Sharad Sangle1d188442017-05-09 16:05:40 +0530466 private int mForcedUseForCommExt; // External state returned by getters: always consistent
467 // with requests by setters
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700468
Eric Laurent9272b4b2010-01-23 17:12:59 -0800469 // List of binder death handlers for setMode() client processes.
470 // The last process to have called setMode() is at the top of the list.
Glenn Kasten30c918c2011-11-10 17:56:41 -0800471 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
Eric Laurenteb14a782009-12-17 03:12:59 -0800472
Eric Laurent3def1ee2010-03-17 23:26:26 -0700473 // List of clients having issued a SCO start request
Glenn Kasten30c918c2011-11-10 17:56:41 -0800474 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
Eric Laurent3def1ee2010-03-17 23:26:26 -0700475
476 // BluetoothHeadset API to control SCO connection
477 private BluetoothHeadset mBluetoothHeadset;
478
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700479 // Bluetooth headset device
480 private BluetoothDevice mBluetoothHeadsetDevice;
Eric Laurent3def1ee2010-03-17 23:26:26 -0700481
Eric Laurent62ef7672010-11-24 10:58:32 -0800482 // Indicate if SCO audio connection is currently active and if the initiator is
483 // audio service (internal) or bluetooth headset (external)
484 private int mScoAudioState;
485 // SCO audio state is not active
486 private static final int SCO_STATE_INACTIVE = 0;
Eric Laurentdc03c612011-04-01 10:59:41 -0700487 // SCO audio activation request waiting for headset service to connect
488 private static final int SCO_STATE_ACTIVATE_REQ = 1;
Eric Laurent25fc29b2013-04-05 12:13:54 -0700489 // SCO audio state is active or starting due to a request from AudioManager API
Eric Laurentdc03c612011-04-01 10:59:41 -0700490 private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
491 // SCO audio deactivation request waiting for headset service to connect
492 private static final int SCO_STATE_DEACTIVATE_REQ = 5;
493
Eric Laurent62ef7672010-11-24 10:58:32 -0800494 // SCO audio state is active due to an action in BT handsfree (either voice recognition or
495 // in call audio)
496 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
Eric Laurentdc03c612011-04-01 10:59:41 -0700497 // Deactivation request for all SCO connections (initiated by audio mode change)
498 // waiting for headset service to connect
499 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
500
Eric Laurentc18c9132013-04-12 17:24:56 -0700501 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
502 // originated from an app targeting an API version before JB MR2 and raw audio after that.
503 private int mScoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -0700504 // SCO audio mode is undefined
505 private static final int SCO_MODE_UNDEFINED = -1;
Eric Laurentc18c9132013-04-12 17:24:56 -0700506 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
507 private static final int SCO_MODE_VIRTUAL_CALL = 0;
508 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
509 private static final int SCO_MODE_RAW = 1;
Liejun Taof4e51d82014-07-16 11:18:29 -0700510 // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
511 private static final int SCO_MODE_VR = 2;
512
513 private static final int SCO_MODE_MAX = 2;
Eric Laurentc18c9132013-04-12 17:24:56 -0700514
Eric Laurentdc03c612011-04-01 10:59:41 -0700515 // Current connection state indicated by bluetooth headset
516 private int mScoConnectionState;
Eric Laurent62ef7672010-11-24 10:58:32 -0800517
Eric Laurenta60e2122010-12-28 16:49:07 -0800518 // true if boot sequence has been completed
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700519 private boolean mSystemReady;
Yasuhiro Matsuda4ced7192015-07-10 22:08:44 +0900520 // true if Intent.ACTION_USER_SWITCHED has ever been received
521 private boolean mUserSwitchedReceived;
Eric Laurenta60e2122010-12-28 16:49:07 -0800522 // listener for SoundPool sample load completion indication
523 private SoundPoolCallback mSoundPoolCallBack;
524 // thread for SoundPool listener
525 private SoundPoolListenerThread mSoundPoolListenerThread;
526 // message looper for SoundPool listener
527 private Looper mSoundPoolLooper = null;
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700528 // volume applied to sound played with playSoundEffect()
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700529 private static int sSoundEffectVolumeDb;
Eric Laurent25101b02011-02-02 09:33:30 -0800530 // previous volume adjustment direction received by checkForRingerModeChange()
531 private int mPrevVolDirection = AudioManager.ADJUST_SAME;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700532 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
533 // is controlled by Vol keys.
Jean-Michel Trivia7880d42017-04-15 12:41:05 -0700534 private int mVolumeControlStream = -1;
535 // interpretation of whether the volume stream has been selected by the user by clicking on a
536 // volume slider to change which volume is controlled by the volume keys. Is false
537 // when mVolumeControlStream is -1.
538 private boolean mUserSelectedVolumeControlStream = false;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700539 private final Object mForceControlStreamLock = new Object();
540 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
541 // server process so in theory it is not necessary to monitor the client death.
542 // However it is good to be ready for future evolutions.
543 private ForceControlStreamClient mForceControlStreamClient = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700544 // Used to play ringtones outside system_server
545 private volatile IRingtonePlayer mRingtonePlayer;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800546
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700547 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
548
Eric Laurent78472112012-05-21 08:57:21 -0700549 // Request to override default use of A2DP for media.
Sungsoo486f7d32016-09-28 16:20:52 +0900550 private boolean mBluetoothA2dpEnabled;
Eric Laurent78472112012-05-21 08:57:21 -0700551 private final Object mBluetoothA2dpEnabledLock = new Object();
552
Dianne Hackborn632ca412012-06-14 19:34:10 -0700553 // Monitoring of audio routes. Protected by mCurAudioRoutes.
554 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
555 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
556 = new RemoteCallbackList<IAudioRoutesObserver>();
557
Eric Laurent4bbcc652012-09-24 14:26:30 -0700558 // Devices for which the volume is fixed and VolumePanel slider should be disabled
Eric Laurent212532b2014-07-21 15:43:18 -0700559 int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700560 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Eric Laurent212532b2014-07-21 15:43:18 -0700561 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
562 AudioSystem.DEVICE_OUT_HDMI_ARC |
563 AudioSystem.DEVICE_OUT_SPDIF |
564 AudioSystem.DEVICE_OUT_AUX_LINE;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700565 int mFullVolumeDevices = 0;
Eric Laurent4bbcc652012-09-24 14:26:30 -0700566
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700567 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700568 private final boolean mMonitorOrientation;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700569 private final boolean mMonitorRotation;
Eric Laurentd640bd32012-09-28 18:01:48 -0700570
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700571 private boolean mDockAudioMediaEnabled = true;
572
Eric Laurent08ed1b92012-11-05 14:54:12 -0800573 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
574
Eric Laurentfde16d52012-12-03 14:42:39 -0800575 // Used when safe volume warning message display is requested by setStreamVolume(). In this
576 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
577 // and used later when/if disableSafeMediaVolume() is called.
578 private StreamVolumeCommand mPendingVolumeCommand;
579
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700580 private PowerManager.WakeLock mAudioEventWakeLock;
581
582 private final MediaFocusControl mMediaFocusControl;
583
John Du5a0cf7a2013-07-19 11:30:34 -0700584 // Reference to BluetoothA2dp to query for AbsoluteVolume.
585 private BluetoothA2dp mA2dp;
seunghwan.hong4fe77952014-10-29 17:43:20 +0900586 // lock always taken synchronized on mConnectedDevices
John Du5a0cf7a2013-07-19 11:30:34 -0700587 private final Object mA2dpAvrcpLock = new Object();
588 // If absolute volume is supported in AVRCP device
589 private boolean mAvrcpAbsVolSupported = false;
590
Eric Laurentadbe8bf2014-11-03 18:26:32 -0800591 private static Long mLastDeviceConnectMsgTime = new Long(0);
592
Julia Reynolds48034f82016-03-09 10:15:16 -0500593 private NotificationManager mNm;
John Spurlock661f2cf2014-11-17 10:29:10 -0500594 private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
John Spurlocka48d7792015-03-03 17:35:57 -0500595 private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
John Spurlock07e72432015-03-13 11:46:52 -0400596 private long mLoweredFromNormalToVibrateTime;
John Spurlock661f2cf2014-11-17 10:29:10 -0500597
Phil Weaverf1a9aff2017-03-23 17:21:29 -0700598 // Array of Uids of valid accessibility services to check if caller is one of them
599 private int[] mAccessibilityServiceUids;
600 private final Object mAccessibilityServiceUidsLock = new Object();
601
Paul McLean10804eb2015-01-28 11:16:35 -0800602 // Intent "extra" data keys.
603 public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName";
604 public static final String CONNECT_INTENT_KEY_STATE = "state";
605 public static final String CONNECT_INTENT_KEY_ADDRESS = "address";
606 public static final String CONNECT_INTENT_KEY_HAS_PLAYBACK = "hasPlayback";
607 public static final String CONNECT_INTENT_KEY_HAS_CAPTURE = "hasCapture";
608 public static final String CONNECT_INTENT_KEY_HAS_MIDI = "hasMIDI";
609 public static final String CONNECT_INTENT_KEY_DEVICE_CLASS = "class";
610
611 // Defines the format for the connection "address" for ALSA devices
612 public static String makeAlsaAddressString(int card, int device) {
613 return "card=" + card + ";device=" + device + ";";
614 }
615
Makoto Onukie1aef852015-10-15 17:28:35 -0700616 public static final class Lifecycle extends SystemService {
617 private AudioService mService;
618
619 public Lifecycle(Context context) {
620 super(context);
621 mService = new AudioService(context);
622 }
623
624 @Override
625 public void onStart() {
626 publishBinderService(Context.AUDIO_SERVICE, mService);
627 }
628
629 @Override
630 public void onBootPhase(int phase) {
631 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
632 mService.systemReady();
633 }
634 }
635 }
636
Dianne Hackborn3e99f652017-07-05 16:33:56 -0700637 final private IUidObserver mUidObserver = new IUidObserver.Stub() {
638 @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
639 }
640
641 @Override public void onUidGone(int uid, boolean disabled) {
642 // Once the uid is no longer running, no need to keep trying to disable its audio.
643 disableAudioForUid(false, uid);
644 }
645
646 @Override public void onUidActive(int uid) throws RemoteException {
647 }
648
649 @Override public void onUidIdle(int uid, boolean disabled) {
650 }
651
652 @Override public void onUidCachedChanged(int uid, boolean cached) {
653 disableAudioForUid(cached, uid);
654 }
655
656 private void disableAudioForUid(boolean disable, int uid) {
657 queueMsgUnderWakeLock(mAudioHandler, MSG_DISABLE_AUDIO_FOR_UID,
658 disable ? 1 : 0 /* arg1 */, uid /* arg2 */,
659 null /* obj */, 0 /* delay */);
660 }
661 };
662
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800663 ///////////////////////////////////////////////////////////////////////////
664 // Construction
665 ///////////////////////////////////////////////////////////////////////////
666
667 /** @hide */
668 public AudioService(Context context) {
669 mContext = context;
670 mContentResolver = context.getContentResolver();
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700671 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700672
John Spurlock61560172015-02-06 19:46:04 -0500673 mPlatformType = AudioSystem.getPlatformType(context);
Jared Suttles59820132009-08-13 21:50:52 -0500674
Muyuan Li1ed6df62016-06-18 11:16:52 -0700675 mIsSingleVolume = AudioSystem.isSingleVolume(context);
676
Makoto Onukid45a4a22015-11-02 17:17:38 -0800677 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700678 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
Makoto Onukid45a4a22015-11-02 17:17:38 -0800679
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700680 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700681 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700682
Eric Laurentbffc3d12012-05-07 17:43:49 -0700683 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
684 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
685
John Spurlockb6e19e32015-03-10 21:33:44 -0400686 // Initialize volume
Eric Laurent403bd342017-07-11 16:21:44 -0700687 int maxCallVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps", -1);
688 if (maxCallVolume != -1) {
689 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxCallVolume;
690 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] =
691 (maxCallVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700692 }
Eric Laurent403bd342017-07-11 16:21:44 -0700693
694 int maxMusicVolume = SystemProperties.getInt("ro.config.media_vol_steps", -1);
695 if (maxMusicVolume != -1) {
696 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxMusicVolume;
697 }
698
699 int defaultMusicVolume = SystemProperties.getInt("ro.config.media_vol_default", -1);
700 if (defaultMusicVolume != -1 &&
701 defaultMusicVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
702 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = defaultMusicVolume;
703 } else {
Hank Freund45926dc2015-12-11 10:50:45 -0800704 if (isPlatformTelevision()) {
Eric Laurent403bd342017-07-11 16:21:44 -0700705 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] =
706 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] / 4;
Hank Freund45926dc2015-12-11 10:50:45 -0800707 } else {
Eric Laurent403bd342017-07-11 16:21:44 -0700708 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] =
709 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] / 3;
Hank Freund45926dc2015-12-11 10:50:45 -0800710 }
Eric Laurent91377de2014-10-10 15:24:04 -0700711 }
Jared Suttles59820132009-08-13 21:50:52 -0500712
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700713 sSoundEffectVolumeDb = context.getResources().getInteger(
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700714 com.android.internal.R.integer.config_soundEffectVolumeDb);
Eric Laurent25101b02011-02-02 09:33:30 -0800715
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700716 mForcedUseForComm = AudioSystem.FORCE_NONE;
Eric Laurentdd45d012012-10-08 09:04:34 -0700717
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800718 createAudioSystemThread();
Eric Laurentdd45d012012-10-08 09:04:34 -0700719
Eric Laurentdfb881f2013-07-18 14:41:39 -0700720 AudioSystem.setErrorCallback(mAudioSystemCallback);
721
John Spurlock5e783732015-02-19 10:28:59 -0500722 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -0700723 mCameraSoundForced = new Boolean(cameraSoundForced);
724 sendMsg(mAudioHandler,
725 MSG_SET_FORCE_USE,
726 SENDMSG_QUEUE,
727 AudioSystem.FOR_SYSTEM,
728 cameraSoundForced ?
729 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700730 new String("AudioService ctor"),
Eric Laurentdd45d012012-10-08 09:04:34 -0700731 0);
732
Eric Laurent05274f32012-11-29 12:48:18 -0800733 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
734 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
735 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
736 // The default safe volume index read here will be replaced by the actual value when
737 // the mcc is read by onConfigureSafeVolume()
738 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
739 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
740
Eric Laurent83a017b2013-03-19 18:15:31 -0700741 mUseFixedVolume = mContext.getResources().getBoolean(
742 com.android.internal.R.bool.config_useFixedVolume);
743
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700744 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
745 // array initialized by updateStreamVolumeAlias()
John Spurlock90874332015-03-10 16:00:54 -0400746 updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 readPersistedSettings();
Eric Laurentc0232482016-03-15 18:19:23 -0700748 readUserRestrictions();
Eric Laurentc1d41662011-07-19 11:21:13 -0700749 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700750 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700751
Eric Laurentb378a13a2017-07-11 14:08:11 -0700752 // mSafeUsbMediaVolumeIndex must be initialized after createStreamStates() because it
753 // relies on audio policy having correct ranges for volume indexes.
754 mSafeUsbMediaVolumeIndex = getSafeUsbMediaVolumeIndex();
755
Eric Laurente5a351c2017-09-27 20:11:51 -0700756 mPlaybackMonitor =
757 new PlaybackActivityMonitor(context, MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM]);
758
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800759 mMediaFocusControl = new MediaFocusControl(mContext, mPlaybackMonitor);
John Spurlockb6e19e32015-03-10 21:33:44 -0400760
Jean-Michel Trivi66ffacf2017-02-04 17:25:31 -0800761 mRecordMonitor = new RecordingActivityMonitor(mContext);
762
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700763 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700764
765 // Call setRingerModeInt() to apply correct mute
766 // state on streams affected by ringer mode.
767 mRingerModeMutedStreams = 0;
John Spurlock661f2cf2014-11-17 10:29:10 -0500768 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3891c4c2010-04-20 09:40:57 -0700769
Eric Laurenta553c252009-07-17 12:17:14 -0700770 // Register for device connection intent broadcasts.
771 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700772 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jack He8dd33942018-01-17 15:45:12 -0800773 intentFilter.addAction(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700774 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700775 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
776 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700777 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700778 intentFilter.addAction(Intent.ACTION_USER_BACKGROUND);
779 intentFilter.addAction(Intent.ACTION_USER_FOREGROUND);
Paul McLeanc837a452014-04-09 09:04:43 -0700780 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Eric Laurentb70b78a2016-01-13 19:16:04 -0800781 intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700782
Eric Laurentd640bd32012-09-28 18:01:48 -0700783 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700784 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700785 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
786 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700787 Log.v(TAG, "monitoring device orientation");
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700788 // initialize orientation in AudioSystem
789 setOrientationForAudioSystem();
790 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700791 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
792 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -0700793 RotationHelper.init(mContext, mAudioHandler);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700794 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700795
Marco Nelissenfb6df0b2017-02-15 15:25:24 -0800796 intentFilter.addAction(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
797 intentFilter.addAction(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
798
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700799 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null);
Jared Suttles59820132009-08-13 21:50:52 -0500800
RoboErik0dac35a2014-08-12 15:48:49 -0700801 LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
Makoto Onukid45a4a22015-11-02 17:17:38 -0800802
803 mUserManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -0800804
805 mRecordMonitor.initMonitor();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806 }
807
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700808 public void systemReady() {
809 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
810 0, 0, null, 0);
Dianne Hackborn3e3600e2017-08-31 11:15:26 -0700811 if (false) {
812 // This is turned off for now, because it is racy and thus causes apps to break.
813 // Currently banning a uid means that if an app tries to start playing an audio
814 // stream, that will be preventing, and unbanning it will not allow that stream
815 // to resume. However these changes in uid state are racy with what the app is doing,
816 // so that after taking a process out of the cached state we can't guarantee that
817 // we will unban the uid before the app actually tries to start playing audio.
818 // (To do that, the activity manager would need to wait until it knows for sure
819 // that the ban has been removed, before telling the app to do whatever it is
820 // supposed to do that caused it to go out of the cached state.)
821 try {
822 ActivityManager.getService().registerUidObserver(mUidObserver,
823 ActivityManager.UID_OBSERVER_CACHED | ActivityManager.UID_OBSERVER_GONE,
824 ActivityManager.PROCESS_STATE_UNKNOWN, null);
825 } catch (RemoteException e) {
826 // ignored; both services live in system_server
827 }
Dianne Hackborn3e99f652017-07-05 16:33:56 -0700828 }
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700829 }
830
831 public void onSystemReady() {
832 mSystemReady = true;
833 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
834 0, 0, null, 0);
835
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700836 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
837 resetBluetoothSco();
838 getBluetoothHeadset();
839 //FIXME: this is to maintain compatibility with deprecated intent
840 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
841 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
842 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
843 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
844 sendStickyBroadcastToAll(newIntent);
845
846 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
847 if (adapter != null) {
848 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
849 BluetoothProfile.A2DP);
850 }
851
Jeff Sharkey73ea0ae2016-08-10 17:30:38 -0600852 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_HDMI_CEC)) {
853 mHdmiManager = mContext.getSystemService(HdmiControlManager.class);
Eric Laurent212532b2014-07-21 15:43:18 -0700854 synchronized (mHdmiManager) {
855 mHdmiTvClient = mHdmiManager.getTvClient();
Jungshik Jangc9ff9682014-09-15 17:41:06 +0900856 if (mHdmiTvClient != null) {
857 mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
858 }
Eric Laurent212532b2014-07-21 15:43:18 -0700859 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
860 mHdmiCecSink = false;
861 }
862 }
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900863
Julia Reynolds48034f82016-03-09 10:15:16 -0500864 mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
865
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700866 sendMsg(mAudioHandler,
867 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
868 SENDMSG_REPLACE,
869 0,
870 0,
John Spurlock90874332015-03-10 16:00:54 -0400871 TAG,
Eric Laurent03332ab2017-02-09 18:29:15 -0800872 SystemProperties.getBoolean("audio.safemedia.bypass", false) ?
873 0 : SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700874
Jean-Michel Trivicfa55532017-01-18 11:17:51 -0800875 initA11yMonitoring();
Eric Laurent0867bed2015-05-20 14:49:08 -0700876 onIndicateSystemReady();
877 }
878
879 void onIndicateSystemReady() {
880 if (AudioSystem.systemReady() == AudioSystem.SUCCESS) {
881 return;
882 }
883 sendMsg(mAudioHandler,
884 MSG_INDICATE_SYSTEM_READY,
885 SENDMSG_REPLACE,
886 0,
887 0,
888 null,
889 INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
890 }
891
Andy Hunged0ea402015-10-30 14:11:46 -0700892 public void onAudioServerDied() {
Eric Laurent0867bed2015-05-20 14:49:08 -0700893 if (!mSystemReady ||
894 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Andy Hunged0ea402015-10-30 14:11:46 -0700895 Log.e(TAG, "Audioserver died.");
896 sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent0867bed2015-05-20 14:49:08 -0700897 null, 500);
898 return;
899 }
Andy Hunged0ea402015-10-30 14:11:46 -0700900 Log.e(TAG, "Audioserver started.");
Eric Laurent0867bed2015-05-20 14:49:08 -0700901
902 // indicate to audio HAL that we start the reconfiguration phase after a media
903 // server crash
904 // Note that we only execute this when the media server
905 // process restarts after a crash, not the first time it is started.
906 AudioSystem.setParameters("restarting=true");
907
908 readAndSetLowRamDevice();
909
910 // Restore device connection states
911 synchronized (mConnectedDevices) {
912 for (int i = 0; i < mConnectedDevices.size(); i++) {
913 DeviceListSpec spec = mConnectedDevices.valueAt(i);
914 AudioSystem.setDeviceConnectionState(
915 spec.mDeviceType,
916 AudioSystem.DEVICE_STATE_AVAILABLE,
917 spec.mDeviceAddress,
918 spec.mDeviceName);
919 }
920 }
921 // Restore call state
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700922 if (AudioSystem.setPhoneState(mMode) == AudioSystem.AUDIO_STATUS_OK) {
923 mModeLogger.log(new AudioEventLogger.StringEvent(
924 "onAudioServerDied causes setPhoneState(" + AudioSystem.modeToString(mMode) + ")"));
925 }
Eric Laurent0867bed2015-05-20 14:49:08 -0700926
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700927 // Restore forced usage for communications and record
928 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm,
929 "onAudioServerDied"));
Eric Laurent0867bed2015-05-20 14:49:08 -0700930 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700931 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_RECORD, mForcedUseForComm,
932 "onAudioServerDied"));
Eric Laurent0867bed2015-05-20 14:49:08 -0700933 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -0800934 final int forSys;
935 synchronized (mSettingsLock) {
936 forSys = mCameraSoundForced ?
937 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE;
938 }
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700939 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_SYSTEM, forSys,
940 "onAudioServerDied"));
941 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, forSys);
Eric Laurent0867bed2015-05-20 14:49:08 -0700942
943 // Restore stream volumes
944 int numStreamTypes = AudioSystem.getNumStreamTypes();
945 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
946 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurente4381ec2015-10-29 17:52:48 -0700947 AudioSystem.initStreamVolume(
948 streamType, streamState.mIndexMin / 10, streamState.mIndexMax / 10);
Eric Laurent0867bed2015-05-20 14:49:08 -0700949
950 streamState.applyAllVolumes();
951 }
952
Andy Hungf04b84d2015-12-18 17:33:27 -0800953 // Restore mono mode
Andy Hung7b98e9a2016-02-25 18:34:50 -0800954 updateMasterMono(mContentResolver);
Andy Hungf04b84d2015-12-18 17:33:27 -0800955
Eric Laurent0867bed2015-05-20 14:49:08 -0700956 // Restore ringer mode
957 setRingerModeInt(getRingerModeInternal(), false);
958
959 // Reset device orientation (if monitored for this device)
960 if (mMonitorOrientation) {
961 setOrientationForAudioSystem();
962 }
963 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -0700964 RotationHelper.updateOrientation();
Eric Laurent0867bed2015-05-20 14:49:08 -0700965 }
966
Sungsoocf09fe62016-09-28 16:21:48 +0900967 synchronized (mBluetoothA2dpEnabledLock) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700968 final int forMed = mBluetoothA2dpEnabled ?
969 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP;
970 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_MEDIA, forMed,
971 "onAudioServerDied"));
972 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, forMed);
Sungsoocf09fe62016-09-28 16:21:48 +0900973 }
974
Eric Laurent0867bed2015-05-20 14:49:08 -0700975 synchronized (mSettingsLock) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700976 final int forDock = mDockAudioMediaEnabled ?
977 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE;
978 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_DOCK, forDock,
979 "onAudioServerDied"));
980 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, forDock);
981 sendEncodedSurroundMode(mContentResolver, "onAudioServerDied");
Eric Laurent0867bed2015-05-20 14:49:08 -0700982 }
983 if (mHdmiManager != null) {
984 synchronized (mHdmiManager) {
985 if (mHdmiTvClient != null) {
986 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
987 }
988 }
989 }
990
991 synchronized (mAudioPolicies) {
992 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
993 policy.connectMixes();
994 }
995 }
996
997 onIndicateSystemReady();
998 // indicate the end of reconfiguration phase to audio HAL
999 AudioSystem.setParameters("restarting=false");
Eric Laurent4a5eeb92014-05-06 10:49:04 -07001000 }
1001
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001002 private void createAudioSystemThread() {
1003 mAudioSystemThread = new AudioSystemThread();
1004 mAudioSystemThread.start();
1005 waitForAudioHandlerCreation();
1006 }
1007
1008 /** Waits for the volume handler to be created by the other thread. */
1009 private void waitForAudioHandlerCreation() {
1010 synchronized(this) {
1011 while (mAudioHandler == null) {
1012 try {
1013 // Wait for mAudioHandler to be set by the other thread
1014 wait();
1015 } catch (InterruptedException e) {
1016 Log.e(TAG, "Interrupted while waiting on volume handler.");
1017 }
1018 }
1019 }
1020 }
1021
Eric Laurent24482012012-05-10 09:41:17 -07001022 private void checkAllAliasStreamVolumes() {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001023 synchronized (VolumeStreamState.class) {
1024 int numStreamTypes = AudioSystem.getNumStreamTypes();
1025 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
Jean-Michel Trivi170a0ee2017-04-14 18:13:26 -07001026 mStreamStates[streamType]
1027 .setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], TAG);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001028 // apply stream volume
RoboErik4197cb62015-01-21 15:45:32 -08001029 if (!mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001030 mStreamStates[streamType].applyAllVolumes();
1031 }
Eric Laurent24482012012-05-10 09:41:17 -07001032 }
1033 }
1034 }
1035
Eric Laurent212532b2014-07-21 15:43:18 -07001036 private void checkAllFixedVolumeDevices()
1037 {
1038 int numStreamTypes = AudioSystem.getNumStreamTypes();
1039 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
1040 mStreamStates[streamType].checkFixedVolumeDevices();
1041 }
1042 }
1043
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07001044 private void checkAllFixedVolumeDevices(int streamType) {
1045 mStreamStates[streamType].checkFixedVolumeDevices();
1046 }
1047
John Spurlockb6e19e32015-03-10 21:33:44 -04001048 private void checkMuteAffectedStreams() {
1049 // any stream with a min level > 0 is not muteable by definition
Nadav Bar6b7751d2017-12-24 16:03:08 +02001050 // STREAM_VOICE_CALL can be muted by applications that has the the MODIFY_PHONE_STATE permission.
John Spurlockb6e19e32015-03-10 21:33:44 -04001051 for (int i = 0; i < mStreamStates.length; i++) {
1052 final VolumeStreamState vss = mStreamStates[i];
Nadav Bar6b7751d2017-12-24 16:03:08 +02001053 if (vss.mIndexMin > 0 &&
1054 vss.mStreamType != AudioSystem.STREAM_VOICE_CALL) {
John Spurlockb6e19e32015-03-10 21:33:44 -04001055 mMuteAffectedStreams &= ~(1 << vss.mStreamType);
1056 }
1057 }
1058 }
1059
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001060 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 int numStreamTypes = AudioSystem.getNumStreamTypes();
1062 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
1063
1064 for (int i = 0; i < numStreamTypes; i++) {
Jean-Michel Trivia53b7052017-04-12 18:27:01 -07001065 streams[i] =
1066 new VolumeStreamState(System.VOLUME_SETTINGS_INT[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -07001067 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001068
Eric Laurent212532b2014-07-21 15:43:18 -07001069 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07001070 checkAllAliasStreamVolumes();
John Spurlockb6e19e32015-03-10 21:33:44 -04001071 checkMuteAffectedStreams();
Eric Laurent403bd342017-07-11 16:21:44 -07001072 updateDefaultVolumes();
1073 }
1074
1075 // Update default indexes from aliased streams. Must be called after mStreamStates is created
1076 private void updateDefaultVolumes() {
1077 for (int stream = 0; stream < mStreamStates.length; stream++) {
1078 if (stream != mStreamVolumeAlias[stream]) {
1079 AudioSystem.DEFAULT_STREAM_VOLUME[stream] = rescaleIndex(
1080 AudioSystem.DEFAULT_STREAM_VOLUME[mStreamVolumeAlias[stream]],
1081 mStreamVolumeAlias[stream],
1082 stream);
1083 }
1084 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001085 }
1086
Eric Laurentbffc3d12012-05-07 17:43:49 -07001087 private void dumpStreamStates(PrintWriter pw) {
1088 pw.println("\nStream volumes (device: index)");
1089 int numStreamTypes = AudioSystem.getNumStreamTypes();
1090 for (int i = 0; i < numStreamTypes; i++) {
John Spurlock61560172015-02-06 19:46:04 -05001091 pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":");
Eric Laurentbffc3d12012-05-07 17:43:49 -07001092 mStreamStates[i].dump(pw);
1093 pw.println("");
1094 }
Eric Laurentdd45d012012-10-08 09:04:34 -07001095 pw.print("\n- mute affected streams = 0x");
1096 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -07001097 }
1098
John Spurlock90874332015-03-10 16:00:54 -04001099 private void updateStreamVolumeAlias(boolean updateVolumes, String caller) {
Eric Laurent6d517662012-04-23 18:42:39 -07001100 int dtmfStreamAlias;
Jean-Michel Triviac487672016-11-11 10:05:18 -08001101 final int a11yStreamAlias = sIndependentA11yVolume ?
1102 AudioSystem.STREAM_ACCESSIBILITY : AudioSystem.STREAM_MUSIC;
Eric Laurent212532b2014-07-21 15:43:18 -07001103
Muyuan Li1ed6df62016-06-18 11:16:52 -07001104 if (mIsSingleVolume) {
Eric Laurent212532b2014-07-21 15:43:18 -07001105 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
1106 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
Muyuan Li1ed6df62016-06-18 11:16:52 -07001107 } else {
1108 switch (mPlatformType) {
1109 case AudioSystem.PLATFORM_VOICE:
1110 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
1111 dtmfStreamAlias = AudioSystem.STREAM_RING;
1112 break;
1113 default:
1114 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
1115 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
1116 }
Eric Laurent6d517662012-04-23 18:42:39 -07001117 }
Eric Laurent212532b2014-07-21 15:43:18 -07001118
Muyuan Li1ed6df62016-06-18 11:16:52 -07001119 if (mIsSingleVolume) {
Eric Laurent212532b2014-07-21 15:43:18 -07001120 mRingerModeAffectedStreams = 0;
Eric Laurent24e0d9b2013-10-03 18:15:07 -07001121 } else {
Eric Laurent212532b2014-07-21 15:43:18 -07001122 if (isInCommunication()) {
1123 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
1124 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
1125 } else {
1126 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
1127 }
Eric Laurent6d517662012-04-23 18:42:39 -07001128 }
Eric Laurent212532b2014-07-21 15:43:18 -07001129
Eric Laurent6d517662012-04-23 18:42:39 -07001130 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
Jean-Michel Trivi170a0ee2017-04-14 18:13:26 -07001131 mStreamVolumeAlias[AudioSystem.STREAM_ACCESSIBILITY] = a11yStreamAlias;
Jean-Michel Triviac487672016-11-11 10:05:18 -08001132
Eric Laurent403bd342017-07-11 16:21:44 -07001133 if (updateVolumes && mStreamStates != null) {
1134 updateDefaultVolumes();
1135
John Spurlock90874332015-03-10 16:00:54 -04001136 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
1137 caller);
Jean-Michel Trivi170a0ee2017-04-14 18:13:26 -07001138
1139 mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].mVolumeIndexSettingName =
1140 System.VOLUME_SETTINGS_INT[a11yStreamAlias];
Jean-Michel Triviac487672016-11-11 10:05:18 -08001141 mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setAllIndexes(
1142 mStreamStates[a11yStreamAlias], caller);
Jean-Michel Trivi170a0ee2017-04-14 18:13:26 -07001143 if (sIndependentA11yVolume) {
1144 // restore the a11y values from the settings
1145 mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].readSettings();
1146 }
1147
Eric Laurent24e0d9b2013-10-03 18:15:07 -07001148 // apply stream mute states according to new value of mRingerModeAffectedStreams
John Spurlock661f2cf2014-11-17 10:29:10 -05001149 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent6d517662012-04-23 18:42:39 -07001150 sendMsg(mAudioHandler,
1151 MSG_SET_ALL_VOLUMES,
1152 SENDMSG_QUEUE,
1153 0,
1154 0,
1155 mStreamStates[AudioSystem.STREAM_DTMF], 0);
Jean-Michel Triviac487672016-11-11 10:05:18 -08001156 sendMsg(mAudioHandler,
1157 MSG_SET_ALL_VOLUMES,
1158 SENDMSG_QUEUE,
1159 0,
1160 0,
1161 mStreamStates[AudioSystem.STREAM_ACCESSIBILITY], 0);
Eric Laurent6d517662012-04-23 18:42:39 -07001162 }
1163 }
1164
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001165 private void readDockAudioSettings(ContentResolver cr)
1166 {
1167 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -07001168 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001169
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001170 sendMsg(mAudioHandler,
1171 MSG_SET_FORCE_USE,
1172 SENDMSG_QUEUE,
1173 AudioSystem.FOR_DOCK,
1174 mDockAudioMediaEnabled ?
1175 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001176 new String("readDockAudioSettings"),
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001177 0);
1178 }
1179
Phil Burkac0f7042016-02-24 12:19:08 -08001180
Andy Hung7b98e9a2016-02-25 18:34:50 -08001181 private void updateMasterMono(ContentResolver cr)
1182 {
1183 final boolean masterMono = System.getIntForUser(
1184 cr, System.MASTER_MONO, 0 /* default */, UserHandle.USER_CURRENT) == 1;
1185 if (DEBUG_VOL) {
1186 Log.d(TAG, String.format("Master mono %b", masterMono));
1187 }
1188 AudioSystem.setMasterMono(masterMono);
1189 }
1190
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001191 private void sendEncodedSurroundMode(ContentResolver cr, String eventSource)
Phil Burkac0f7042016-02-24 12:19:08 -08001192 {
1193 int encodedSurroundMode = Settings.Global.getInt(
1194 cr, Settings.Global.ENCODED_SURROUND_OUTPUT,
1195 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001196 sendEncodedSurroundMode(encodedSurroundMode, eventSource);
Phil Burkac0f7042016-02-24 12:19:08 -08001197 }
1198
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001199 private void sendEncodedSurroundMode(int encodedSurroundMode, String eventSource)
Phil Burkac0f7042016-02-24 12:19:08 -08001200 {
1201 // initialize to guaranteed bad value
1202 int forceSetting = AudioSystem.NUM_FORCE_CONFIG;
1203 switch (encodedSurroundMode) {
1204 case Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO:
1205 forceSetting = AudioSystem.FORCE_NONE;
1206 break;
1207 case Settings.Global.ENCODED_SURROUND_OUTPUT_NEVER:
1208 forceSetting = AudioSystem.FORCE_ENCODED_SURROUND_NEVER;
1209 break;
1210 case Settings.Global.ENCODED_SURROUND_OUTPUT_ALWAYS:
1211 forceSetting = AudioSystem.FORCE_ENCODED_SURROUND_ALWAYS;
1212 break;
1213 default:
1214 Log.e(TAG, "updateSurroundSoundSettings: illegal value "
1215 + encodedSurroundMode);
1216 break;
1217 }
1218 if (forceSetting != AudioSystem.NUM_FORCE_CONFIG) {
1219 sendMsg(mAudioHandler,
1220 MSG_SET_FORCE_USE,
1221 SENDMSG_QUEUE,
1222 AudioSystem.FOR_ENCODED_SURROUND,
1223 forceSetting,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001224 eventSource,
Phil Burkac0f7042016-02-24 12:19:08 -08001225 0);
1226 }
1227 }
1228
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001229 private void readPersistedSettings() {
1230 final ContentResolver cr = mContentResolver;
1231
Eric Laurentbffc3d12012-05-07 17:43:49 -07001232 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07001233 Settings.Global.getInt(
1234 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -07001235 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -07001236 // sanity check in case the settings are restored from a device with incompatible
1237 // ringer modes
John Spurlock97559372014-10-24 16:27:36 -04001238 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001239 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -07001240 }
1241 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1242 ringerMode = AudioManager.RINGER_MODE_SILENT;
1243 }
1244 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07001245 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -08001246 }
Muyuan Li1ed6df62016-06-18 11:16:52 -07001247 if (mUseFixedVolume || mIsSingleVolume) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001248 ringerMode = AudioManager.RINGER_MODE_NORMAL;
1249 }
Glenn Kastenba195eb2011-12-13 09:30:40 -08001250 synchronized(mSettingsLock) {
1251 mRingerMode = ringerMode;
John Spurlock661f2cf2014-11-17 10:29:10 -05001252 if (mRingerModeExternal == -1) {
1253 mRingerModeExternal = mRingerMode;
1254 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001255
Eric Laurentdd45d012012-10-08 09:04:34 -07001256 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
1257 // are still needed while setVibrateSetting() and getVibrateSetting() are being
1258 // deprecated.
John Spurlock61560172015-02-06 19:46:04 -05001259 mVibrateSetting = AudioSystem.getValueForVibrateSetting(0,
Eric Laurentdd45d012012-10-08 09:04:34 -07001260 AudioManager.VIBRATE_TYPE_NOTIFICATION,
1261 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
1262 : AudioManager.VIBRATE_SETTING_OFF);
John Spurlock61560172015-02-06 19:46:04 -05001263 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting,
Eric Laurentdd45d012012-10-08 09:04:34 -07001264 AudioManager.VIBRATE_TYPE_RINGER,
1265 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
1266 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001267
Eric Laurent24e0d9b2013-10-03 18:15:07 -07001268 updateRingerModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001269 readDockAudioSettings(cr);
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001270 sendEncodedSurroundMode(cr, "readPersistedSettings");
Eric Laurent402f7f22011-02-04 12:30:32 -08001271 }
Eric Laurentc1d41662011-07-19 11:21:13 -07001272
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001273 mMuteAffectedStreams = System.getIntForUser(cr,
John Spurlock61560172015-02-06 19:46:04 -05001274 System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
John Spurlock24c05182015-02-05 12:30:36 -05001275 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276
Andy Hung7b98e9a2016-02-25 18:34:50 -08001277 updateMasterMono(cr);
Andy Hungf04b84d2015-12-18 17:33:27 -08001278
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279 // Each stream will read its own persisted settings
1280
John Spurlockbcc10872014-11-28 15:29:21 -05001281 // Broadcast the sticky intents
1282 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
1283 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001284
1285 // Broadcast vibrate settings
1286 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
1287 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07001288
John Spurlock33f4e042014-07-11 13:10:58 -04001289 // Load settings for the volume controller
1290 mVolumeController.loadSettings(cr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 }
1292
Eric Laurentc0232482016-03-15 18:19:23 -07001293 private void readUserRestrictions() {
1294 final int currentUser = getCurrentUserId();
1295
1296 // Check the current user restriction.
Tony Makc1205112016-07-22 16:02:59 +01001297 boolean masterMute =
1298 mUserManagerInternal.getUserRestriction(currentUser,
Esteban Talavera492b4722017-02-13 14:59:45 +00001299 UserManager.DISALLOW_UNMUTE_DEVICE)
Tony Makc1205112016-07-22 16:02:59 +01001300 || mUserManagerInternal.getUserRestriction(currentUser,
1301 UserManager.DISALLOW_ADJUST_VOLUME);
Eric Laurentc0232482016-03-15 18:19:23 -07001302 if (mUseFixedVolume) {
1303 masterMute = false;
1304 AudioSystem.setMasterVolume(1.0f);
1305 }
1306 if (DEBUG_VOL) {
1307 Log.d(TAG, String.format("Master mute %s, user=%d", masterMute, currentUser));
1308 }
1309 setSystemAudioMute(masterMute);
1310 AudioSystem.setMasterMute(masterMute);
1311 broadcastMasterMuteStatus(masterMute);
1312
1313 boolean microphoneMute = mUserManagerInternal.getUserRestriction(
1314 currentUser, UserManager.DISALLOW_UNMUTE_MICROPHONE);
1315 if (DEBUG_VOL) {
1316 Log.d(TAG, String.format("Mic mute %s, user=%d", microphoneMute, currentUser));
1317 }
1318 AudioSystem.muteMicrophone(microphoneMute);
1319 }
1320
Eric Laurenta553c252009-07-17 12:17:14 -07001321 private int rescaleIndex(int index, int srcStream, int dstStream) {
1322 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
1323 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001324
1325 ///////////////////////////////////////////////////////////////////////////
1326 // IPC methods
1327 ///////////////////////////////////////////////////////////////////////////
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001328 /** @see AudioManager#adjustVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001329 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001330 String callingPackage, String caller) {
RoboErik272e1612014-09-05 11:39:29 -07001331 adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
John Spurlock90874332015-03-10 16:00:54 -04001332 caller, Binder.getCallingUid());
RoboErik272e1612014-09-05 11:39:29 -07001333 }
1334
1335 private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001336 String callingPackage, String caller, int uid) {
1337 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001338 + ", flags=" + flags + ", caller=" + caller
1339 + ", volControlStream=" + mVolumeControlStream
1340 + ", userSelect=" + mUserSelectedVolumeControlStream);
Jean-Michel Trivicf170362017-08-24 17:24:57 -07001341 mVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_SUGG_VOL, suggestedStreamType,
1342 direction/*val1*/, flags/*val2*/, new StringBuilder(callingPackage)
1343 .append("/").append(caller).append(" uid:").append(uid).toString()));
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001344 final int streamType;
1345 if (mUserSelectedVolumeControlStream) { // implies mVolumeControlStream != -1
Eric Laurent45c90ce2012-04-24 18:44:22 -07001346 streamType = mVolumeControlStream;
Eric Laurent402f7f22011-02-04 12:30:32 -08001347 } else {
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001348 final int maybeActiveStreamType = getActiveStreamType(suggestedStreamType);
1349 final boolean activeForReal;
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05001350 if (maybeActiveStreamType == AudioSystem.STREAM_RING
1351 || maybeActiveStreamType == AudioSystem.STREAM_NOTIFICATION) {
1352 activeForReal = wasStreamActiveRecently(maybeActiveStreamType, 0);
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001353 } else {
1354 activeForReal = AudioSystem.isStreamActive(maybeActiveStreamType, 0);
1355 }
1356 if (activeForReal || mVolumeControlStream == -1) {
1357 streamType = maybeActiveStreamType;
1358 } else {
1359 streamType = mVolumeControlStream;
1360 }
Eric Laurent402f7f22011-02-04 12:30:32 -08001361 }
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001362
1363 final boolean isMute = isMuteAdjust(direction);
1364
John Spurlock0a376af2015-03-26 16:24:12 -04001365 ensureValidStreamType(streamType);
John Spurlock33f4e042014-07-11 13:10:58 -04001366 final int resolvedStream = mStreamVolumeAlias[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001367
RoboErik2811dd32014-08-12 09:48:13 -07001368 // Play sounds on STREAM_RING only.
1369 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
John Spurlock33f4e042014-07-11 13:10:58 -04001370 resolvedStream != AudioSystem.STREAM_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371 flags &= ~AudioManager.FLAG_PLAY_SOUND;
1372 }
1373
John Spurlock33f4e042014-07-11 13:10:58 -04001374 // For notifications/ring, show the ui before making any adjustments
RoboErik4197cb62015-01-21 15:45:32 -08001375 // Don't suppress mute/unmute requests
1376 if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
John Spurlock33f4e042014-07-11 13:10:58 -04001377 direction = 0;
1378 flags &= ~AudioManager.FLAG_PLAY_SOUND;
1379 flags &= ~AudioManager.FLAG_VIBRATE;
1380 if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
1381 }
1382
John Spurlock90874332015-03-10 16:00:54 -04001383 adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384 }
1385
1386 /** @see AudioManager#adjustStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001387 public void adjustStreamVolume(int streamType, int direction, int flags,
1388 String callingPackage) {
Phil Weaverf1a9aff2017-03-23 17:21:29 -07001389 if ((streamType == AudioManager.STREAM_ACCESSIBILITY) && !canChangeAccessibilityVolume()) {
Jean-Michel Triviab2d9312017-03-13 15:33:39 -07001390 Log.w(TAG, "Trying to call adjustStreamVolume() for a11y without"
Phil Weaverf1a9aff2017-03-23 17:21:29 -07001391 + "CHANGE_ACCESSIBILITY_VOLUME / callingPackage=" + callingPackage);
Jean-Michel Triviab2d9312017-03-13 15:33:39 -07001392 return;
1393 }
Jean-Michel Trivicf170362017-08-24 17:24:57 -07001394 mVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_STREAM_VOL, streamType,
1395 direction/*val1*/, flags/*val2*/, callingPackage));
John Spurlock90874332015-03-10 16:00:54 -04001396 adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage,
1397 Binder.getCallingUid());
RoboErik0dac35a2014-08-12 15:48:49 -07001398 }
1399
1400 private void adjustStreamVolume(int streamType, int direction, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001401 String callingPackage, String caller, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001402 if (mUseFixedVolume) {
1403 return;
1404 }
John Spurlock90874332015-03-10 16:00:54 -04001405 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream=" + streamType + ", dir=" + direction
1406 + ", flags=" + flags + ", caller=" + caller);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07001407
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 ensureValidDirection(direction);
1409 ensureValidStreamType(streamType);
1410
RoboErik4197cb62015-01-21 15:45:32 -08001411 boolean isMuteAdjust = isMuteAdjust(direction);
1412
John Spurlock3ce37252015-02-17 13:20:45 -05001413 if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
1414 return;
1415 }
1416
Nadav Bar6b7751d2017-12-24 16:03:08 +02001417 // If adjust is mute and the stream is STREAM_VOICE_CALL, make sure
1418 // that the calling app have the MODIFY_PHONE_STATE permission.
1419 if (isMuteAdjust &&
1420 streamType == AudioSystem.STREAM_VOICE_CALL &&
1421 mContext.checkCallingOrSelfPermission(
1422 android.Manifest.permission.MODIFY_PHONE_STATE)
1423 != PackageManager.PERMISSION_GRANTED) {
1424 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: adjustStreamVolume from pid="
1425 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
1426 return;
1427 }
1428
Eric Laurent96a33d12011-11-08 10:31:57 -08001429 // use stream type alias here so that streams with same alias have the same behavior,
1430 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
1431 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
Eric Laurent6d517662012-04-23 18:42:39 -07001432 int streamTypeAlias = mStreamVolumeAlias[streamType];
RoboErik4197cb62015-01-21 15:45:32 -08001433
Eric Laurentb024c302011-10-14 17:19:27 -07001434 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001435
1436 final int device = getDeviceForStream(streamTypeAlias);
Eric Laurent3ef75492012-11-28 12:12:23 -08001437
Eric Laurent42b041e2013-03-29 11:36:03 -07001438 int aliasIndex = streamState.getIndex(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001439 boolean adjustVolume = true;
Eric Laurent3ef75492012-11-28 12:12:23 -08001440 int step;
Eric Laurent24482012012-05-10 09:41:17 -07001441
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001442 // skip a2dp absolute volume control request when the device
1443 // is not an a2dp device
1444 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1445 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1446 return;
1447 }
1448
Kenny Guy70e0c582015-06-30 19:18:28 +01001449 // If we are being called by the system (e.g. hardware keys) check for current user
1450 // so we handle user restrictions correctly.
1451 if (uid == android.os.Process.SYSTEM_UID) {
1452 uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
1453 }
John Spurlock59dc9c12015-03-02 11:20:15 -05001454 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001455 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001456 return;
1457 }
1458
Eric Laurentfde16d52012-12-03 14:42:39 -08001459 // reset any pending volume command
1460 synchronized (mSafeMediaVolumeState) {
1461 mPendingVolumeCommand = null;
1462 }
1463
Eric Laurent3ef75492012-11-28 12:12:23 -08001464 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1465 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1466 ((device & mFixedVolumeDevices) != 0)) {
1467 flags |= AudioManager.FLAG_FIXED_VOLUME;
1468
1469 // Always toggle between max safe volume and 0 for fixed volume devices where safe
1470 // volume is enforced, and max and 0 for the others.
1471 // This is simulated by stepping by the full allowed volume range
1472 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1473 (device & mSafeMediaVolumeDevices) != 0) {
Eric Laurenteab40d12017-06-09 12:45:21 -07001474 step = safeMediaVolumeIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001475 } else {
1476 step = streamState.getMaxIndex();
1477 }
1478 if (aliasIndex != 0) {
1479 aliasIndex = step;
1480 }
1481 } else {
1482 // convert one UI step (+/-1) into a number of internal units on the stream alias
1483 step = rescaleIndex(10, streamType, streamTypeAlias);
1484 }
1485
Eric Laurent42b041e2013-03-29 11:36:03 -07001486 // If either the client forces allowing ringer modes for this adjustment,
1487 // or the stream type is one that is affected by ringer modes
1488 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlockee5ad722015-03-03 16:17:21 -05001489 (streamTypeAlias == getUiSoundsStreamType())) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001490 int ringerMode = getRingerModeInternal();
Eric Laurent42b041e2013-03-29 11:36:03 -07001491 // do not vibrate if already in vibrate mode
1492 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
1493 flags &= ~AudioManager.FLAG_VIBRATE;
Eric Laurent3ef75492012-11-28 12:12:23 -08001494 }
RoboErik5452e252015-02-06 15:33:53 -08001495 // Check if the ringer mode handles this adjustment. If it does we don't
1496 // need to adjust the volume further.
John Spurlock50ced3f2015-05-11 16:00:09 -04001497 final int result = checkForRingerModeChange(aliasIndex, direction, step,
Julia Reynoldsed783792016-04-08 15:27:35 -04001498 streamState.mIsMuted, callingPackage, flags);
John Spurlocka11b4af2014-06-01 11:52:23 -04001499 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
1500 // If suppressing a volume adjustment in silent mode, display the UI hint
1501 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
1502 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
1503 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001504 // If suppressing a volume down adjustment in vibrate mode, display the UI hint
1505 if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
1506 flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
1507 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001508 }
John Spurlock50ced3f2015-05-11 16:00:09 -04001509 // If the ringermode is suppressing media, prevent changes
Julia Reynoldsed783792016-04-08 15:27:35 -04001510 if (!volumeAdjustmentAllowedByDnd(streamTypeAlias, flags)) {
John Spurlock50ced3f2015-05-11 16:00:09 -04001511 adjustVolume = false;
1512 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001513 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001514
Eric Laurent42b041e2013-03-29 11:36:03 -07001515 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
RoboErik5452e252015-02-06 15:33:53 -08001516 mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001517
John Du5a0cf7a2013-07-19 11:30:34 -07001518 // Check if volume update should be send to AVRCP
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001519 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1520 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1521 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1522 synchronized (mA2dpAvrcpLock) {
1523 if (mA2dp != null && mAvrcpAbsVolSupported) {
1524 mA2dp.adjustAvrcpAbsoluteVolume(direction);
1525 }
John Du5a0cf7a2013-07-19 11:30:34 -07001526 }
1527 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001528
RoboErik4197cb62015-01-21 15:45:32 -08001529 if (isMuteAdjust) {
1530 boolean state;
1531 if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
1532 state = !streamState.mIsMuted;
1533 } else {
1534 state = direction == AudioManager.ADJUST_MUTE;
1535 }
1536 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1537 setSystemAudioMute(state);
1538 }
1539 for (int stream = 0; stream < mStreamStates.length; stream++) {
1540 if (streamTypeAlias == mStreamVolumeAlias[stream]) {
Sungmin Choi841ed0a2015-07-26 23:09:49 -07001541 if (!(readCameraSoundForced()
1542 && (mStreamStates[stream].getStreamType()
1543 == AudioSystem.STREAM_SYSTEM_ENFORCED))) {
1544 mStreamStates[stream].mute(state);
1545 }
RoboErik4197cb62015-01-21 15:45:32 -08001546 }
1547 }
1548 } else if ((direction == AudioManager.ADJUST_RAISE) &&
Eric Laurent42b041e2013-03-29 11:36:03 -07001549 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
RoboErik4197cb62015-01-21 15:45:32 -08001550 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -04001551 mVolumeController.postDisplaySafeVolumeWarning(flags);
John Spurlock90874332015-03-10 16:00:54 -04001552 } else if (streamState.adjustIndex(direction * step, device, caller)
1553 || streamState.mIsMuted) {
RoboErik4197cb62015-01-21 15:45:32 -08001554 // Post message to set system volume (it in turn will post a
1555 // message to persist).
1556 if (streamState.mIsMuted) {
1557 // Unmute the stream if it was previously muted
RoboErik5452e252015-02-06 15:33:53 -08001558 if (direction == AudioManager.ADJUST_RAISE) {
1559 // unmute immediately for volume up
1560 streamState.mute(false);
1561 } else if (direction == AudioManager.ADJUST_LOWER) {
Muyuan Li1ed6df62016-06-18 11:16:52 -07001562 if (mIsSingleVolume) {
John Spurlocka48d7792015-03-03 17:35:57 -05001563 sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
1564 streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
1565 }
RoboErik5452e252015-02-06 15:33:53 -08001566 }
RoboErik4197cb62015-01-21 15:45:32 -08001567 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001568 sendMsg(mAudioHandler,
1569 MSG_SET_DEVICE_VOLUME,
1570 SENDMSG_QUEUE,
1571 device,
1572 0,
1573 streamState,
1574 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001575 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001576
RoboErik4197cb62015-01-21 15:45:32 -08001577 // Check if volume update should be sent to Hdmi system audio.
Jungshik Jang41d97462014-06-30 22:26:29 +09001578 int newIndex = mStreamStates[streamType].getIndex(device);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001579 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1580 setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
1581 }
Eric Laurent212532b2014-07-21 15:43:18 -07001582 if (mHdmiManager != null) {
1583 synchronized (mHdmiManager) {
Eric Laurent212532b2014-07-21 15:43:18 -07001584 // mHdmiCecSink true => mHdmiPlaybackClient != null
1585 if (mHdmiCecSink &&
1586 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1587 oldIndex != newIndex) {
1588 synchronized (mHdmiPlaybackClient) {
1589 int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
RoboErik4197cb62015-01-21 15:45:32 -08001590 KeyEvent.KEYCODE_VOLUME_UP;
Donghyun Cho5f6d404e2016-03-17 20:39:25 +09001591 final long ident = Binder.clearCallingIdentity();
1592 try {
1593 mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1594 mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1595 } finally {
1596 Binder.restoreCallingIdentity(ident);
1597 }
Eric Laurent212532b2014-07-21 15:43:18 -07001598 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001599 }
1600 }
1601 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001602 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001603 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001604 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001605 }
1606
RoboErik5452e252015-02-06 15:33:53 -08001607 // Called after a delay when volume down is pressed while muted
1608 private void onUnmuteStream(int stream, int flags) {
1609 VolumeStreamState streamState = mStreamStates[stream];
1610 streamState.mute(false);
1611
1612 final int device = getDeviceForStream(stream);
1613 final int index = mStreamStates[stream].getIndex(device);
1614 sendVolumeUpdate(stream, index, index, flags);
1615 }
1616
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001617 private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
1618 if (mHdmiManager == null
1619 || mHdmiTvClient == null
1620 || oldVolume == newVolume
1621 || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
1622
1623 // Sets the audio volume of AVR when we are in system audio mode. The new volume info
1624 // is tranformed to HDMI-CEC commands and passed through CEC bus.
1625 synchronized (mHdmiManager) {
1626 if (!mHdmiSystemAudioSupported) return;
1627 synchronized (mHdmiTvClient) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001628 final long token = Binder.clearCallingIdentity();
1629 try {
Jinsuk Kim7a9ba422015-02-16 16:47:38 +09001630 mHdmiTvClient.setSystemAudioVolume(oldVolume, newVolume, maxVolume);
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001631 } finally {
1632 Binder.restoreCallingIdentity(token);
1633 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001634 }
1635 }
1636 }
1637
Eric Laurentfde16d52012-12-03 14:42:39 -08001638 // StreamVolumeCommand contains the information needed to defer the process of
1639 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1640 class StreamVolumeCommand {
1641 public final int mStreamType;
1642 public final int mIndex;
1643 public final int mFlags;
1644 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001645
Eric Laurentfde16d52012-12-03 14:42:39 -08001646 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1647 mStreamType = streamType;
1648 mIndex = index;
1649 mFlags = flags;
1650 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001651 }
John Spurlock35134602014-07-24 18:10:48 -04001652
1653 @Override
1654 public String toString() {
1655 return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1656 .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1657 .append(mDevice).append('}').toString();
1658 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001659 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001660
Julia Reynolds48034f82016-03-09 10:15:16 -05001661 private int getNewRingerMode(int stream, int index, int flags) {
Zak Cohen47798292017-11-30 12:34:20 -08001662 // setRingerMode does nothing if the device is single volume,so the value would be unchanged
1663 if (mIsSingleVolume) {
1664 return getRingerModeExternal();
1665 }
1666
John Spurlockee5ad722015-03-03 16:17:21 -05001667 // setting volume on ui sounds stream type also controls silent mode
Eric Laurent3ef75492012-11-28 12:12:23 -08001668 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlock75ae23c2015-06-02 16:26:43 -04001669 (stream == getUiSoundsStreamType())) {
Eric Laurent3ef75492012-11-28 12:12:23 -08001670 int newRingerMode;
1671 if (index == 0) {
1672 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlocka48d7792015-03-03 17:35:57 -05001673 : mVolumePolicy.volumeDownToEnterSilent ? AudioManager.RINGER_MODE_SILENT
Julia Reynolds48034f82016-03-09 10:15:16 -05001674 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001675 } else {
1676 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1677 }
Julia Reynolds48034f82016-03-09 10:15:16 -05001678 return newRingerMode;
1679 }
1680 return getRingerModeExternal();
1681 }
1682
1683 private boolean isAndroidNPlus(String caller) {
1684 try {
1685 final ApplicationInfo applicationInfo =
1686 mContext.getPackageManager().getApplicationInfoAsUser(
1687 caller, 0, UserHandle.getUserId(Binder.getCallingUid()));
1688 if (applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
1689 return true;
1690 }
1691 return false;
1692 } catch (PackageManager.NameNotFoundException e) {
1693 return true;
1694 }
1695 }
1696
1697 private boolean wouldToggleZenMode(int newMode) {
1698 if (getRingerModeExternal() == AudioManager.RINGER_MODE_SILENT
1699 && newMode != AudioManager.RINGER_MODE_SILENT) {
1700 return true;
1701 } else if (getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT
1702 && newMode == AudioManager.RINGER_MODE_SILENT) {
1703 return true;
1704 }
1705 return false;
1706 }
1707
1708 private void onSetStreamVolume(int streamType, int index, int flags, int device,
1709 String caller) {
1710 final int stream = mStreamVolumeAlias[streamType];
1711 setStreamVolumeInt(stream, index, device, false, caller);
1712 // setting volume on ui sounds stream type also controls silent mode
1713 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1714 (stream == getUiSoundsStreamType())) {
1715 setRingerMode(getNewRingerMode(stream, index, flags),
1716 TAG + ".onSetStreamVolume", false /*external*/);
Eric Laurent3ef75492012-11-28 12:12:23 -08001717 }
John Spurlock75ae23c2015-06-02 16:26:43 -04001718 // setting non-zero volume for a muted stream unmutes the stream and vice versa
1719 mStreamStates[stream].mute(index == 0);
Eric Laurentfde16d52012-12-03 14:42:39 -08001720 }
1721
1722 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001723 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
Phil Weaverf1a9aff2017-03-23 17:21:29 -07001724 if ((streamType == AudioManager.STREAM_ACCESSIBILITY) && !canChangeAccessibilityVolume()) {
Jean-Michel Triviab2d9312017-03-13 15:33:39 -07001725 Log.w(TAG, "Trying to call setStreamVolume() for a11y without"
Phil Weaverf1a9aff2017-03-23 17:21:29 -07001726 + " CHANGE_ACCESSIBILITY_VOLUME callingPackage=" + callingPackage);
Jean-Michel Triviab2d9312017-03-13 15:33:39 -07001727 return;
1728 }
Nadav Bar6b7751d2017-12-24 16:03:08 +02001729 if ((streamType == AudioManager.STREAM_VOICE_CALL) &&
1730 (index == 0) &&
1731 (mContext.checkCallingOrSelfPermission(
1732 android.Manifest.permission.MODIFY_PHONE_STATE)
1733 != PackageManager.PERMISSION_GRANTED)) {
1734 Log.w(TAG, "Trying to call setStreamVolume() for STREAM_VOICE_CALL and index 0 without"
1735 + " MODIFY_PHONE_STATE callingPackage=" + callingPackage);
1736 return;
1737 }
Jean-Michel Trivicf170362017-08-24 17:24:57 -07001738 mVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_SET_STREAM_VOL, streamType,
1739 index/*val1*/, flags/*val2*/, callingPackage));
John Spurlock90874332015-03-10 16:00:54 -04001740 setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
1741 Binder.getCallingUid());
RoboErik0dac35a2014-08-12 15:48:49 -07001742 }
1743
Phil Weaverf1a9aff2017-03-23 17:21:29 -07001744 private boolean canChangeAccessibilityVolume() {
1745 synchronized (mAccessibilityServiceUidsLock) {
1746 if (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
1747 android.Manifest.permission.CHANGE_ACCESSIBILITY_VOLUME)) {
1748 return true;
1749 }
1750 if (mAccessibilityServiceUids != null) {
1751 int callingUid = Binder.getCallingUid();
1752 for (int i = 0; i < mAccessibilityServiceUids.length; i++) {
1753 if (mAccessibilityServiceUids[i] == callingUid) {
1754 return true;
1755 }
1756 }
1757 }
1758 return false;
1759 }
1760 }
1761
RoboErik0dac35a2014-08-12 15:48:49 -07001762 private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
John Spurlock90874332015-03-10 16:00:54 -04001763 String caller, int uid) {
Jean-Michel Triviac487672016-11-11 10:05:18 -08001764 if (DEBUG_VOL) {
1765 Log.d(TAG, "setStreamVolume(stream=" + streamType+", index=" + index
1766 + ", calling=" + callingPackage + ")");
1767 }
Eric Laurent83a017b2013-03-19 18:15:31 -07001768 if (mUseFixedVolume) {
1769 return;
1770 }
1771
Eric Laurentfde16d52012-12-03 14:42:39 -08001772 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001773 int streamTypeAlias = mStreamVolumeAlias[streamType];
1774 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001775
1776 final int device = getDeviceForStream(streamType);
1777 int oldIndex;
1778
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001779 // skip a2dp absolute volume control request when the device
1780 // is not an a2dp device
1781 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1782 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1783 return;
1784 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001785 // If we are being called by the system (e.g. hardware keys) check for current user
1786 // so we handle user restrictions correctly.
1787 if (uid == android.os.Process.SYSTEM_UID) {
1788 uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
1789 }
John Spurlock59dc9c12015-03-02 11:20:15 -05001790 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001791 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001792 return;
1793 }
1794
Julia Reynolds48034f82016-03-09 10:15:16 -05001795 if (isAndroidNPlus(callingPackage)
1796 && wouldToggleZenMode(getNewRingerMode(streamTypeAlias, index, flags))
1797 && !mNm.isNotificationPolicyAccessGrantedForPackage(callingPackage)) {
1798 throw new SecurityException("Not allowed to change Do Not Disturb state");
1799 }
1800
Julia Reynoldsed783792016-04-08 15:27:35 -04001801 if (!volumeAdjustmentAllowedByDnd(streamTypeAlias, flags)) {
1802 return;
1803 }
1804
Eric Laurentfde16d52012-12-03 14:42:39 -08001805 synchronized (mSafeMediaVolumeState) {
1806 // reset any pending volume command
1807 mPendingVolumeCommand = null;
1808
Eric Laurent42b041e2013-03-29 11:36:03 -07001809 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001810
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001811 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001812
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001813 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1814 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1815 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1816 synchronized (mA2dpAvrcpLock) {
1817 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001818 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001819 }
John Du5a0cf7a2013-07-19 11:30:34 -07001820 }
1821 }
1822
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001823 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1824 setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
Jungshik Jang41d97462014-06-30 22:26:29 +09001825 }
1826
Eric Laurentfde16d52012-12-03 14:42:39 -08001827 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001828 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001829 ((device & mFixedVolumeDevices) != 0)) {
1830 flags |= AudioManager.FLAG_FIXED_VOLUME;
1831
1832 // volume is either 0 or max allowed for fixed volume devices
1833 if (index != 0) {
1834 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1835 (device & mSafeMediaVolumeDevices) != 0) {
Eric Laurenteab40d12017-06-09 12:45:21 -07001836 index = safeMediaVolumeIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001837 } else {
1838 index = streamState.getMaxIndex();
1839 }
1840 }
1841 }
1842
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001843 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001844 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001845 mPendingVolumeCommand = new StreamVolumeCommand(
1846 streamType, index, flags, device);
1847 } else {
John Spurlock90874332015-03-10 16:00:54 -04001848 onSetStreamVolume(streamType, index, flags, device, caller);
Eric Laurent42b041e2013-03-29 11:36:03 -07001849 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001850 }
1851 }
Eric Laurent25101b02011-02-02 09:33:30 -08001852 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001853 }
1854
Julia Reynoldsed783792016-04-08 15:27:35 -04001855 // No ringer affected streams can be changed in total silence mode except those that
1856 // will cause the device to exit total silence mode.
1857 private boolean volumeAdjustmentAllowedByDnd(int streamTypeAlias, int flags) {
1858 if (mNm.getZenMode() == Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
1859 && isStreamMutedByRingerMode(streamTypeAlias)) {
1860 if (!(((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1861 (streamTypeAlias == getUiSoundsStreamType()))) {
1862 return false;
1863 }
1864 }
1865 return true;
1866 }
1867
Eric Laurent45c90ce2012-04-24 18:44:22 -07001868 /** @see AudioManager#forceVolumeControlStream(int) */
1869 public void forceVolumeControlStream(int streamType, IBinder cb) {
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001870 if (DEBUG_VOL) { Log.d(TAG, String.format("forceVolumeControlStream(%d)", streamType)); }
Eric Laurent45c90ce2012-04-24 18:44:22 -07001871 synchronized(mForceControlStreamLock) {
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001872 if (mVolumeControlStream != -1 && streamType != -1) {
1873 mUserSelectedVolumeControlStream = true;
1874 }
Eric Laurent45c90ce2012-04-24 18:44:22 -07001875 mVolumeControlStream = streamType;
1876 if (mVolumeControlStream == -1) {
1877 if (mForceControlStreamClient != null) {
1878 mForceControlStreamClient.release();
1879 mForceControlStreamClient = null;
1880 }
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001881 mUserSelectedVolumeControlStream = false;
Eric Laurent45c90ce2012-04-24 18:44:22 -07001882 } else {
1883 mForceControlStreamClient = new ForceControlStreamClient(cb);
1884 }
1885 }
1886 }
1887
1888 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1889 private IBinder mCb; // To be notified of client's death
1890
1891 ForceControlStreamClient(IBinder cb) {
1892 if (cb != null) {
1893 try {
1894 cb.linkToDeath(this, 0);
1895 } catch (RemoteException e) {
1896 // Client has died!
1897 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1898 cb = null;
1899 }
1900 }
1901 mCb = cb;
1902 }
1903
1904 public void binderDied() {
1905 synchronized(mForceControlStreamLock) {
1906 Log.w(TAG, "SCO client died");
1907 if (mForceControlStreamClient != this) {
1908 Log.w(TAG, "unregistered control stream client died");
1909 } else {
1910 mForceControlStreamClient = null;
1911 mVolumeControlStream = -1;
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001912 mUserSelectedVolumeControlStream = false;
Eric Laurent45c90ce2012-04-24 18:44:22 -07001913 }
1914 }
1915 }
1916
1917 public void release() {
1918 if (mCb != null) {
1919 mCb.unlinkToDeath(this, 0);
1920 mCb = null;
1921 }
1922 }
1923 }
1924
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001925 private void sendBroadcastToAll(Intent intent) {
Christopher Tate267603f2015-01-20 14:21:21 -08001926 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
John Spurlock86490862015-02-25 11:22:52 -05001927 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001928 final long ident = Binder.clearCallingIdentity();
1929 try {
1930 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1931 } finally {
1932 Binder.restoreCallingIdentity(ident);
1933 }
1934 }
1935
1936 private void sendStickyBroadcastToAll(Intent intent) {
John Spurlock86490862015-02-25 11:22:52 -05001937 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001938 final long ident = Binder.clearCallingIdentity();
1939 try {
1940 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1941 } finally {
1942 Binder.restoreCallingIdentity(ident);
1943 }
1944 }
1945
Kenny Guy70e0c582015-06-30 19:18:28 +01001946 private int getCurrentUserId() {
1947 final long ident = Binder.clearCallingIdentity();
1948 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001949 UserInfo currentUser = ActivityManager.getService().getCurrentUser();
Kenny Guy70e0c582015-06-30 19:18:28 +01001950 return currentUser.id;
1951 } catch (RemoteException e) {
1952 // Activity manager not running, nothing we can do assume user 0.
1953 } finally {
1954 Binder.restoreCallingIdentity(ident);
1955 }
Xiaohui Chen7c696362015-09-16 09:56:14 -07001956 return UserHandle.USER_SYSTEM;
Kenny Guy70e0c582015-06-30 19:18:28 +01001957 }
1958
Eric Laurent25101b02011-02-02 09:33:30 -08001959 // UI update and Broadcast Intent
Yue Li949865b2017-05-24 17:25:28 -07001960 protected void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
John Spurlock72966d62015-06-18 15:45:07 -04001961 streamType = mStreamVolumeAlias[streamType];
Eric Laurent25101b02011-02-02 09:33:30 -08001962
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001963 if (streamType == AudioSystem.STREAM_MUSIC) {
1964 flags = updateFlagsForSystemAudio(flags);
Jungshik Jang1a6be6e2014-09-16 11:04:54 +09001965 }
John Spurlock3346a802014-05-20 16:25:37 -04001966 mVolumeController.postVolumeChanged(streamType, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001967 }
1968
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001969 // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
1970 // receives volume notification from Audio Receiver.
1971 private int updateFlagsForSystemAudio(int flags) {
1972 if (mHdmiTvClient != null) {
1973 synchronized (mHdmiTvClient) {
1974 if (mHdmiSystemAudioSupported &&
1975 ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
1976 flags &= ~AudioManager.FLAG_SHOW_UI;
1977 }
1978 }
1979 }
1980 return flags;
1981 }
1982
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001983 // UI update and Broadcast Intent
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001984 private void sendMasterMuteUpdate(boolean muted, int flags) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001985 mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
Justin Koh57978ed2012-04-03 17:37:58 -07001986 broadcastMasterMuteStatus(muted);
1987 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001988
Justin Koh57978ed2012-04-03 17:37:58 -07001989 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001990 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1991 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001992 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1993 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001994 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001995 }
1996
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001997 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001998 * Sets the stream state's index, and posts a message to set system volume.
1999 * This will not call out to the UI. Assumes a valid stream type.
2000 *
2001 * @param streamType Type of the stream
2002 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002003 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002004 * @param force If true, set the volume even if the desired volume is same
2005 * as the current volume.
2006 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002007 private void setStreamVolumeInt(int streamType,
2008 int index,
2009 int device,
John Spurlock90874332015-03-10 16:00:54 -04002010 boolean force,
2011 String caller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002012 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07002013
John Spurlock90874332015-03-10 16:00:54 -04002014 if (streamState.setIndex(index, device, caller) || force) {
Eric Laurent42b041e2013-03-29 11:36:03 -07002015 // Post message to set system volume (it in turn will post a message
2016 // to persist).
2017 sendMsg(mAudioHandler,
2018 MSG_SET_DEVICE_VOLUME,
2019 SENDMSG_QUEUE,
2020 device,
2021 0,
2022 streamState,
2023 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002024 }
2025 }
2026
Jinsuk Kim336cdb42014-11-29 06:27:00 +09002027 private void setSystemAudioMute(boolean state) {
2028 if (mHdmiManager == null || mHdmiTvClient == null) return;
2029 synchronized (mHdmiManager) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09002030 if (!mHdmiSystemAudioSupported) return;
2031 synchronized (mHdmiTvClient) {
2032 final long token = Binder.clearCallingIdentity();
2033 try {
2034 mHdmiTvClient.setSystemAudioMute(state);
2035 } finally {
2036 Binder.restoreCallingIdentity(token);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09002037 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09002038 }
2039 }
2040 }
2041
Eric Laurent25101b02011-02-02 09:33:30 -08002042 /** get stream mute state. */
2043 public boolean isStreamMute(int streamType) {
RoboErik7c82ced2014-12-04 17:39:08 -08002044 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
2045 streamType = getActiveStreamType(streamType);
2046 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002047 synchronized (VolumeStreamState.class) {
jiabin93d32ef2017-07-11 13:50:02 -07002048 ensureValidStreamType(streamType);
RoboErik4197cb62015-01-21 15:45:32 -08002049 return mStreamStates[streamType].mIsMuted;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002050 }
Eric Laurent25101b02011-02-02 09:33:30 -08002051 }
2052
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07002053 private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
2054 private IBinder mICallback; // To be notified of client's death
2055
2056 RmtSbmxFullVolDeathHandler(IBinder cb) {
2057 mICallback = cb;
2058 try {
2059 cb.linkToDeath(this, 0/*flags*/);
2060 } catch (RemoteException e) {
2061 Log.e(TAG, "can't link to death", e);
2062 }
2063 }
2064
2065 boolean isHandlerFor(IBinder cb) {
2066 return mICallback.equals(cb);
2067 }
2068
2069 void forget() {
2070 try {
2071 mICallback.unlinkToDeath(this, 0/*flags*/);
2072 } catch (NoSuchElementException e) {
2073 Log.e(TAG, "error unlinking to death", e);
2074 }
2075 }
2076
2077 public void binderDied() {
2078 Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
2079 forceRemoteSubmixFullVolume(false, mICallback);
2080 }
2081 }
2082
2083 /**
2084 * call must be synchronized on mRmtSbmxFullVolDeathHandlers
2085 * @return true if there is a registered death handler, false otherwise */
2086 private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
2087 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
2088 while (it.hasNext()) {
2089 final RmtSbmxFullVolDeathHandler handler = it.next();
2090 if (handler.isHandlerFor(cb)) {
2091 handler.forget();
2092 mRmtSbmxFullVolDeathHandlers.remove(handler);
2093 return true;
2094 }
2095 }
2096 return false;
2097 }
2098
2099 /** call synchronized on mRmtSbmxFullVolDeathHandlers */
2100 private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
2101 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
2102 while (it.hasNext()) {
2103 if (it.next().isHandlerFor(cb)) {
2104 return true;
2105 }
2106 }
2107 return false;
2108 }
2109
2110 private int mRmtSbmxFullVolRefCount = 0;
2111 private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
2112 new ArrayList<RmtSbmxFullVolDeathHandler>();
2113
2114 public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
2115 if (cb == null) {
2116 return;
2117 }
2118 if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
2119 android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
2120 Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
2121 return;
2122 }
2123 synchronized(mRmtSbmxFullVolDeathHandlers) {
2124 boolean applyRequired = false;
2125 if (startForcing) {
2126 if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
2127 mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
2128 if (mRmtSbmxFullVolRefCount == 0) {
2129 mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
2130 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
2131 applyRequired = true;
2132 }
2133 mRmtSbmxFullVolRefCount++;
2134 }
2135 } else {
2136 if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
2137 mRmtSbmxFullVolRefCount--;
2138 if (mRmtSbmxFullVolRefCount == 0) {
2139 mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
2140 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
2141 applyRequired = true;
2142 }
2143 }
2144 }
2145 if (applyRequired) {
2146 // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
2147 checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
2148 mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
2149 }
2150 }
2151 }
2152
Kenny Guy70e0c582015-06-30 19:18:28 +01002153 private void setMasterMuteInternal(boolean mute, int flags, String callingPackage, int uid,
2154 int userId) {
2155 // If we are being called by the system check for user we are going to change
2156 // so we handle user restrictions correctly.
2157 if (uid == android.os.Process.SYSTEM_UID) {
2158 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
2159 }
Makoto Onuki4f160732015-10-27 17:15:38 -07002160 // If OP_AUDIO_MASTER_VOLUME is set, disallow unmuting.
2161 if (!mute && mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
RoboErik7c82ced2014-12-04 17:39:08 -08002162 != AppOpsManager.MODE_ALLOWED) {
Julia Reynolds4a21b252014-06-04 11:11:43 -04002163 return;
2164 }
Kenny Guy70e0c582015-06-30 19:18:28 +01002165 if (userId != UserHandle.getCallingUserId() &&
2166 mContext.checkCallingOrSelfPermission(
2167 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
2168 != PackageManager.PERMISSION_GRANTED) {
2169 return;
2170 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08002171 setMasterMuteInternalNoCallerCheck(mute, flags, userId);
2172 }
2173
2174 private void setMasterMuteInternalNoCallerCheck(boolean mute, int flags, int userId) {
2175 if (DEBUG_VOL) {
2176 Log.d(TAG, String.format("Master mute %s, %d, user=%d", mute, flags, userId));
2177 }
2178 if (mUseFixedVolume) {
2179 return; // If using fixed volume, we don't mute.
2180 }
Kenny Guy70e0c582015-06-30 19:18:28 +01002181 if (getCurrentUserId() == userId) {
2182 if (mute != AudioSystem.getMasterMute()) {
2183 setSystemAudioMute(mute);
2184 AudioSystem.setMasterMute(mute);
Kenny Guy70e0c582015-06-30 19:18:28 +01002185 sendMasterMuteUpdate(mute, flags);
RoboErik7c82ced2014-12-04 17:39:08 -08002186
Kenny Guy70e0c582015-06-30 19:18:28 +01002187 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
2188 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute);
2189 sendBroadcastToAll(intent);
2190 }
Jason Simmons1ce5b262012-02-02 13:00:17 -08002191 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08002192 }
2193
2194 /** get master mute state. */
2195 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08002196 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08002197 }
2198
Kenny Guy70e0c582015-06-30 19:18:28 +01002199 public void setMasterMute(boolean mute, int flags, String callingPackage, int userId) {
2200 setMasterMuteInternal(mute, flags, callingPackage, Binder.getCallingUid(),
2201 userId);
John Spurlockee5ad722015-03-03 16:17:21 -05002202 }
2203
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002204 /** @see AudioManager#getStreamVolume(int) */
2205 public int getStreamVolume(int streamType) {
2206 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002207 int device = getDeviceForStream(streamType);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002208 synchronized (VolumeStreamState.class) {
2209 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07002210
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002211 // by convention getStreamVolume() returns 0 when a stream is muted.
RoboErik4197cb62015-01-21 15:45:32 -08002212 if (mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002213 index = 0;
2214 }
2215 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
2216 (device & mFixedVolumeDevices) != 0) {
2217 index = mStreamStates[streamType].getMaxIndex();
2218 }
2219 return (index + 5) / 10;
Eric Laurent42b041e2013-03-29 11:36:03 -07002220 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002221 }
2222
2223 /** @see AudioManager#getStreamMaxVolume(int) */
2224 public int getStreamMaxVolume(int streamType) {
2225 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07002226 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002227 }
2228
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08002229 /** @see AudioManager#getStreamMinVolumeInt(int) */
John Spurlockb6e19e32015-03-10 21:33:44 -04002230 public int getStreamMinVolume(int streamType) {
2231 ensureValidStreamType(streamType);
2232 return (mStreamStates[streamType].getMinIndex() + 5) / 10;
2233 }
2234
Eric Laurent25101b02011-02-02 09:33:30 -08002235 /** Get last audible volume before stream was muted. */
2236 public int getLastAudibleStreamVolume(int streamType) {
2237 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002238 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07002239 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08002240 }
2241
John Spurlockee5ad722015-03-03 16:17:21 -05002242 /** @see AudioManager#getUiSoundsStreamType() */
2243 public int getUiSoundsStreamType() {
John Spurlock4f0f1202014-08-05 13:28:33 -04002244 return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
Eric Laurent6d517662012-04-23 18:42:39 -07002245 }
2246
Makoto Onukid45a4a22015-11-02 17:17:38 -08002247 /** @see AudioManager#setMicrophoneMute(boolean) */
2248 @Override
Kenny Guy70e0c582015-06-30 19:18:28 +01002249 public void setMicrophoneMute(boolean on, String callingPackage, int userId) {
2250 // If we are being called by the system check for user we are going to change
2251 // so we handle user restrictions correctly.
2252 int uid = Binder.getCallingUid();
2253 if (uid == android.os.Process.SYSTEM_UID) {
2254 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
2255 }
Makoto Onuki4f160732015-10-27 17:15:38 -07002256 // If OP_MUTE_MICROPHONE is set, disallow unmuting.
2257 if (!on && mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, uid, callingPackage)
Kenny Guy70e0c582015-06-30 19:18:28 +01002258 != AppOpsManager.MODE_ALLOWED) {
Emily Bernier22c921a2014-05-28 11:01:32 -04002259 return;
2260 }
Jean-Michel Trivi4a4fea02014-08-29 18:14:09 -07002261 if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
2262 return;
2263 }
Kenny Guy70e0c582015-06-30 19:18:28 +01002264 if (userId != UserHandle.getCallingUserId() &&
2265 mContext.checkCallingOrSelfPermission(
2266 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
2267 != PackageManager.PERMISSION_GRANTED) {
2268 return;
2269 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08002270 setMicrophoneMuteNoCallerCheck(on, userId);
2271 }
Emily Bernier22c921a2014-05-28 11:01:32 -04002272
Makoto Onukid45a4a22015-11-02 17:17:38 -08002273 private void setMicrophoneMuteNoCallerCheck(boolean on, int userId) {
2274 if (DEBUG_VOL) {
2275 Log.d(TAG, String.format("Mic mute %s, user=%d", on, userId));
2276 }
Jean-Michel Trivi7be17d22017-12-21 18:09:21 -08002277 // only mute for the current user
Kenny Guy70e0c582015-06-30 19:18:28 +01002278 if (getCurrentUserId() == userId) {
Jean-Michel Trivi7be17d22017-12-21 18:09:21 -08002279 final boolean currentMute = AudioSystem.isMicrophoneMuted();
Kenny Guy70e0c582015-06-30 19:18:28 +01002280 AudioSystem.muteMicrophone(on);
Jean-Michel Trivi7be17d22017-12-21 18:09:21 -08002281 if (on != currentMute) {
2282 mContext.sendBroadcast(new Intent(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED)
2283 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY));
2284 }
Kenny Guy70e0c582015-06-30 19:18:28 +01002285 }
Emily Bernier22c921a2014-05-28 11:01:32 -04002286 }
2287
John Spurlock661f2cf2014-11-17 10:29:10 -05002288 @Override
2289 public int getRingerModeExternal() {
2290 synchronized(mSettingsLock) {
2291 return mRingerModeExternal;
2292 }
2293 }
2294
2295 @Override
2296 public int getRingerModeInternal() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08002297 synchronized(mSettingsLock) {
2298 return mRingerMode;
2299 }
2300 }
2301
2302 private void ensureValidRingerMode(int ringerMode) {
John Spurlock97559372014-10-24 16:27:36 -04002303 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08002304 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
2305 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002306 }
2307
John Spurlock97559372014-10-24 16:27:36 -04002308 /** @see AudioManager#isValidRingerMode(int) */
2309 public boolean isValidRingerMode(int ringerMode) {
2310 return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
2311 }
2312
John Spurlock661f2cf2014-11-17 10:29:10 -05002313 public void setRingerModeExternal(int ringerMode, String caller) {
Julia Reynolds48034f82016-03-09 10:15:16 -05002314 if (isAndroidNPlus(caller) && wouldToggleZenMode(ringerMode)
2315 && !mNm.isNotificationPolicyAccessGrantedForPackage(caller)) {
2316 throw new SecurityException("Not allowed to change Do Not Disturb state");
2317 }
2318
John Spurlockaf88a192014-12-23 16:14:44 -05002319 setRingerMode(ringerMode, caller, true /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05002320 }
2321
2322 public void setRingerModeInternal(int ringerMode, String caller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05002323 enforceVolumeController("setRingerModeInternal");
John Spurlockaf88a192014-12-23 16:14:44 -05002324 setRingerMode(ringerMode, caller, false /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05002325 }
2326
2327 private void setRingerMode(int ringerMode, String caller, boolean external) {
Muyuan Li1ed6df62016-06-18 11:16:52 -07002328 if (mUseFixedVolume || mIsSingleVolume) {
Eric Laurent83a017b2013-03-19 18:15:31 -07002329 return;
2330 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002331 if (caller == null || caller.length() == 0) {
2332 throw new IllegalArgumentException("Bad caller: " + caller);
2333 }
John Spurlock97559372014-10-24 16:27:36 -04002334 ensureValidRingerMode(ringerMode);
Eric Laurent24482012012-05-10 09:41:17 -07002335 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
2336 ringerMode = AudioManager.RINGER_MODE_SILENT;
2337 }
John Spurlockaf88a192014-12-23 16:14:44 -05002338 final long identity = Binder.clearCallingIdentity();
2339 try {
2340 synchronized (mSettingsLock) {
2341 final int ringerModeInternal = getRingerModeInternal();
2342 final int ringerModeExternal = getRingerModeExternal();
2343 if (external) {
2344 setRingerModeExt(ringerMode);
2345 if (mRingerModeDelegate != null) {
2346 ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
John Spurlocka48d7792015-03-03 17:35:57 -05002347 ringerMode, caller, ringerModeInternal, mVolumePolicy);
John Spurlockaf88a192014-12-23 16:14:44 -05002348 }
2349 if (ringerMode != ringerModeInternal) {
2350 setRingerModeInt(ringerMode, true /*persist*/);
2351 }
2352 } else /*internal*/ {
2353 if (ringerMode != ringerModeInternal) {
2354 setRingerModeInt(ringerMode, true /*persist*/);
2355 }
2356 if (mRingerModeDelegate != null) {
2357 ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
John Spurlocka48d7792015-03-03 17:35:57 -05002358 ringerMode, caller, ringerModeExternal, mVolumePolicy);
John Spurlockaf88a192014-12-23 16:14:44 -05002359 }
2360 setRingerModeExt(ringerMode);
John Spurlock57627792014-12-11 11:29:54 -05002361 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002362 }
John Spurlockaf88a192014-12-23 16:14:44 -05002363 } finally {
2364 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002365 }
2366 }
2367
John Spurlock661f2cf2014-11-17 10:29:10 -05002368 private void setRingerModeExt(int ringerMode) {
2369 synchronized(mSettingsLock) {
2370 if (ringerMode == mRingerModeExternal) return;
2371 mRingerModeExternal = ringerMode;
John Spurlocke5b42d92014-10-15 12:03:48 -04002372 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002373 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05002374 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
John Spurlocke5b42d92014-10-15 12:03:48 -04002375 }
2376
John Spurlock50ced3f2015-05-11 16:00:09 -04002377 private void muteRingerModeStreams() {
Eric Laurent5b4e6542010-03-19 20:02:21 -07002378 // Mute stream if not previously muted by ringer mode and ringer mode
2379 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
2380 // Unmute stream if previously muted by ringer mode and ringer mode
2381 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07002382 int numStreamTypes = AudioSystem.getNumStreamTypes();
John Spurlock50ced3f2015-05-11 16:00:09 -04002383 final boolean ringerModeMute = mRingerMode == AudioManager.RINGER_MODE_VIBRATE
2384 || mRingerMode == AudioManager.RINGER_MODE_SILENT;
Eric Laurent5b4e6542010-03-19 20:02:21 -07002385 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002386 final boolean isMuted = isStreamMutedByRingerMode(streamType);
2387 final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
2388 if (isMuted == shouldMute) continue;
2389 if (!shouldMute) {
2390 // unmute
2391 // ring and notifications volume should never be 0 when not silenced
John Spurlockd9c75db2015-04-28 11:19:13 -04002392 if (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002393 synchronized (VolumeStreamState.class) {
John Spurlocka48d7792015-03-03 17:35:57 -05002394 final VolumeStreamState vss = mStreamStates[streamType];
2395 for (int i = 0; i < vss.mIndexMap.size(); i++) {
2396 int device = vss.mIndexMap.keyAt(i);
2397 int value = vss.mIndexMap.valueAt(i);
John Spurlock2bb02ec2015-03-02 13:13:06 -05002398 if (value == 0) {
John Spurlocka48d7792015-03-03 17:35:57 -05002399 vss.setIndex(10, device, TAG);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002400 }
2401 }
Eric Laurent9e0d25f2015-02-12 17:28:53 -08002402 // Persist volume for stream ring when it is changed here
2403 final int device = getDeviceForStream(streamType);
2404 sendMsg(mAudioHandler,
2405 MSG_PERSIST_VOLUME,
2406 SENDMSG_QUEUE,
2407 device,
2408 0,
2409 mStreamStates[streamType],
2410 PERSIST_DELAY);
Eric Laurentb024c302011-10-14 17:19:27 -07002411 }
Eric Laurent9bcf4012009-06-12 06:09:28 -07002412 }
RoboErik4197cb62015-01-21 15:45:32 -08002413 mStreamStates[streamType].mute(false);
John Spurlock661f2cf2014-11-17 10:29:10 -05002414 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent5b4e6542010-03-19 20:02:21 -07002415 } else {
John Spurlock661f2cf2014-11-17 10:29:10 -05002416 // mute
RoboErik4197cb62015-01-21 15:45:32 -08002417 mStreamStates[streamType].mute(true);
John Spurlock661f2cf2014-11-17 10:29:10 -05002418 mRingerModeMutedStreams |= (1 << streamType);
Jason Parekhb1096152009-03-24 17:48:25 -07002419 }
2420 }
John Spurlock50ced3f2015-05-11 16:00:09 -04002421 }
2422
2423 private void setRingerModeInt(int ringerMode, boolean persist) {
2424 final boolean change;
2425 synchronized(mSettingsLock) {
2426 change = mRingerMode != ringerMode;
2427 mRingerMode = ringerMode;
2428 }
2429
2430 muteRingerModeStreams();
Eric Laurenta553c252009-07-17 12:17:14 -07002431
Jason Parekhb1096152009-03-24 17:48:25 -07002432 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07002433 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002434 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07002435 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
2436 }
John Spurlockbcc10872014-11-28 15:29:21 -05002437 if (change) {
2438 // Send sticky broadcast
2439 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
2440 }
Jason Parekhb1096152009-03-24 17:48:25 -07002441 }
2442
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002443 /** @see AudioManager#shouldVibrate(int) */
2444 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002445 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002446
2447 switch (getVibrateSetting(vibrateType)) {
2448
2449 case AudioManager.VIBRATE_SETTING_ON:
John Spurlock57627792014-12-11 11:29:54 -05002450 return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002451
2452 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
John Spurlock57627792014-12-11 11:29:54 -05002453 return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002454
2455 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04002456 // return false, even for incoming calls
2457 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002458
2459 default:
2460 return false;
2461 }
2462 }
2463
2464 /** @see AudioManager#getVibrateSetting(int) */
2465 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002466 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002467 return (mVibrateSetting >> (vibrateType * 2)) & 3;
2468 }
2469
2470 /** @see AudioManager#setVibrateSetting(int, int) */
2471 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
2472
Eric Laurentbffc3d12012-05-07 17:43:49 -07002473 if (!mHasVibrator) return;
2474
John Spurlock61560172015-02-06 19:46:04 -05002475 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
2476 vibrateSetting);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002477
2478 // Broadcast change
2479 broadcastVibrateSetting(vibrateType);
2480
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002481 }
2482
Eric Laurent9272b4b2010-01-23 17:12:59 -08002483 private class SetModeDeathHandler implements IBinder.DeathRecipient {
2484 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002485 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002486 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
2487
Eric Laurent9f103de2011-09-08 15:04:23 -07002488 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08002489 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07002490 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002491 }
2492
2493 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07002494 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002495 synchronized(mSetModeDeathHandlers) {
2496 Log.w(TAG, "setMode() client died");
2497 int index = mSetModeDeathHandlers.indexOf(this);
2498 if (index < 0) {
2499 Log.w(TAG, "unregistered setMode() client died");
2500 } else {
John Spurlock90874332015-03-10 16:00:54 -04002501 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid, TAG);
Eric Laurent9272b4b2010-01-23 17:12:59 -08002502 }
2503 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002504 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2505 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002506 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07002507 final long ident = Binder.clearCallingIdentity();
2508 disconnectBluetoothSco(newModeOwnerPid);
2509 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07002510 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08002511 }
2512
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002513 public int getPid() {
2514 return mPid;
2515 }
2516
Eric Laurent9272b4b2010-01-23 17:12:59 -08002517 public void setMode(int mode) {
2518 mMode = mode;
2519 }
2520
2521 public int getMode() {
2522 return mMode;
2523 }
2524
2525 public IBinder getBinder() {
2526 return mCb;
2527 }
2528 }
2529
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002530 /** @see AudioManager#setMode(int) */
John Spurlock90874332015-03-10 16:00:54 -04002531 public void setMode(int mode, IBinder cb, String callingPackage) {
2532 if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ", callingPackage=" + callingPackage + ")"); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002533 if (!checkAudioSettingsPermission("setMode()")) {
2534 return;
2535 }
Eric Laurenta553c252009-07-17 12:17:14 -07002536
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07002537 if ( (mode == AudioSystem.MODE_IN_CALL) &&
2538 (mContext.checkCallingOrSelfPermission(
2539 android.Manifest.permission.MODIFY_PHONE_STATE)
2540 != PackageManager.PERMISSION_GRANTED)) {
2541 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
2542 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
2543 return;
2544 }
2545
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08002546 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07002547 return;
2548 }
2549
Eric Laurentd7454be2011-09-14 08:45:58 -07002550 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002551 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07002552 if (mode == AudioSystem.MODE_CURRENT) {
2553 mode = mMode;
2554 }
John Spurlock90874332015-03-10 16:00:54 -04002555 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid(), callingPackage);
Eric Laurent9f103de2011-09-08 15:04:23 -07002556 }
2557 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2558 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002559 if (newModeOwnerPid != 0) {
2560 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07002561 }
2562 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002563
Eric Laurent9f103de2011-09-08 15:04:23 -07002564 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07002565 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07002566 // any mode other than NORMAL.
John Spurlock90874332015-03-10 16:00:54 -04002567 private int setModeInt(int mode, IBinder cb, int pid, String caller) {
2568 if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ", caller="
2569 + caller + ")"); }
Eric Laurentd7454be2011-09-14 08:45:58 -07002570 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002571 if (cb == null) {
2572 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07002573 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07002574 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002575
Eric Laurent9f103de2011-09-08 15:04:23 -07002576 SetModeDeathHandler hdlr = null;
2577 Iterator iter = mSetModeDeathHandlers.iterator();
2578 while (iter.hasNext()) {
2579 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
2580 if (h.getPid() == pid) {
2581 hdlr = h;
2582 // Remove from client list so that it is re-inserted at top of list
2583 iter.remove();
2584 hdlr.getBinder().unlinkToDeath(hdlr, 0);
2585 break;
2586 }
2587 }
2588 int status = AudioSystem.AUDIO_STATUS_OK;
Eric Laurent6afa6502017-09-28 15:18:19 -07002589 int actualMode;
Eric Laurent9f103de2011-09-08 15:04:23 -07002590 do {
Eric Laurent6afa6502017-09-28 15:18:19 -07002591 actualMode = mode;
Eric Laurent9f103de2011-09-08 15:04:23 -07002592 if (mode == AudioSystem.MODE_NORMAL) {
2593 // get new mode from client at top the list if any
2594 if (!mSetModeDeathHandlers.isEmpty()) {
2595 hdlr = mSetModeDeathHandlers.get(0);
2596 cb = hdlr.getBinder();
Eric Laurent6afa6502017-09-28 15:18:19 -07002597 actualMode = hdlr.getMode();
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002598 if (DEBUG_MODE) {
2599 Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
2600 + hdlr.mPid);
2601 }
Eric Laurentb9c9d262009-05-06 08:13:20 -07002602 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002603 } else {
2604 if (hdlr == null) {
2605 hdlr = new SetModeDeathHandler(cb, pid);
2606 }
2607 // Register for client death notification
2608 try {
2609 cb.linkToDeath(hdlr, 0);
2610 } catch (RemoteException e) {
2611 // Client has died!
2612 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
2613 }
2614
2615 // Last client to call setMode() is always at top of client list
2616 // as required by SetModeDeathHandler.binderDied()
2617 mSetModeDeathHandlers.add(0, hdlr);
2618 hdlr.setMode(mode);
2619 }
2620
Eric Laurent6afa6502017-09-28 15:18:19 -07002621 if (actualMode != mMode) {
2622 status = AudioSystem.setPhoneState(actualMode);
Eric Laurent9f103de2011-09-08 15:04:23 -07002623 if (status == AudioSystem.AUDIO_STATUS_OK) {
Eric Laurent6afa6502017-09-28 15:18:19 -07002624 if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + actualMode); }
2625 mMode = actualMode;
Eric Laurent9f103de2011-09-08 15:04:23 -07002626 } else {
2627 if (hdlr != null) {
2628 mSetModeDeathHandlers.remove(hdlr);
2629 cb.unlinkToDeath(hdlr, 0);
2630 }
2631 // force reading new top of mSetModeDeathHandlers stack
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002632 if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002633 mode = AudioSystem.MODE_NORMAL;
2634 }
2635 } else {
2636 status = AudioSystem.AUDIO_STATUS_OK;
2637 }
2638 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
2639
2640 if (status == AudioSystem.AUDIO_STATUS_OK) {
Eric Laurent6afa6502017-09-28 15:18:19 -07002641 if (actualMode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002642 if (mSetModeDeathHandlers.isEmpty()) {
2643 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
2644 } else {
2645 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2646 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002647 }
Eric Laurent6afa6502017-09-28 15:18:19 -07002648 // Note: newModeOwnerPid is always 0 when actualMode is MODE_NORMAL
2649 mModeLogger.log(
2650 new PhoneStateEvent(caller, pid, mode, newModeOwnerPid, actualMode));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002651 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002652 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07002653 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
John Spurlock90874332015-03-10 16:00:54 -04002654 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, caller);
Eric Laurent6d517662012-04-23 18:42:39 -07002655
John Spurlock90874332015-03-10 16:00:54 -04002656 updateStreamVolumeAlias(true /*updateVolumes*/, caller);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002657 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002658 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002659 }
2660
2661 /** @see AudioManager#getMode() */
2662 public int getMode() {
2663 return mMode;
2664 }
2665
Eric Laurente78fced2013-03-15 16:03:47 -07002666 //==========================================================================================
2667 // Sound Effects
2668 //==========================================================================================
2669
2670 private static final String TAG_AUDIO_ASSETS = "audio_assets";
2671 private static final String ATTR_VERSION = "version";
2672 private static final String TAG_GROUP = "group";
2673 private static final String ATTR_GROUP_NAME = "name";
2674 private static final String TAG_ASSET = "asset";
2675 private static final String ATTR_ASSET_ID = "id";
2676 private static final String ATTR_ASSET_FILE = "file";
2677
2678 private static final String ASSET_FILE_VERSION = "1.0";
2679 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
2680
Glenn Kasten167d1a22013-07-23 16:24:41 -07002681 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002682
2683 class LoadSoundEffectReply {
2684 public int mStatus = 1;
2685 };
2686
Eric Laurente78fced2013-03-15 16:03:47 -07002687 private void loadTouchSoundAssetDefaults() {
2688 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
2689 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
2690 SOUND_EFFECT_FILES_MAP[i][0] = 0;
2691 SOUND_EFFECT_FILES_MAP[i][1] = -1;
2692 }
2693 }
2694
2695 private void loadTouchSoundAssets() {
2696 XmlResourceParser parser = null;
2697
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002698 // only load assets once.
2699 if (!SOUND_EFFECT_FILES.isEmpty()) {
2700 return;
2701 }
2702
Eric Laurente78fced2013-03-15 16:03:47 -07002703 loadTouchSoundAssetDefaults();
2704
2705 try {
2706 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
2707
2708 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
2709 String version = parser.getAttributeValue(null, ATTR_VERSION);
2710 boolean inTouchSoundsGroup = false;
2711
2712 if (ASSET_FILE_VERSION.equals(version)) {
2713 while (true) {
2714 XmlUtils.nextElement(parser);
2715 String element = parser.getName();
2716 if (element == null) {
2717 break;
2718 }
2719 if (element.equals(TAG_GROUP)) {
2720 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
2721 if (GROUP_TOUCH_SOUNDS.equals(name)) {
2722 inTouchSoundsGroup = true;
2723 break;
2724 }
2725 }
2726 }
2727 while (inTouchSoundsGroup) {
2728 XmlUtils.nextElement(parser);
2729 String element = parser.getName();
2730 if (element == null) {
2731 break;
2732 }
2733 if (element.equals(TAG_ASSET)) {
2734 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
2735 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
2736 int fx;
2737
2738 try {
2739 Field field = AudioManager.class.getField(id);
2740 fx = field.getInt(null);
2741 } catch (Exception e) {
2742 Log.w(TAG, "Invalid touch sound ID: "+id);
2743 continue;
2744 }
2745
2746 int i = SOUND_EFFECT_FILES.indexOf(file);
2747 if (i == -1) {
2748 i = SOUND_EFFECT_FILES.size();
2749 SOUND_EFFECT_FILES.add(file);
2750 }
2751 SOUND_EFFECT_FILES_MAP[fx][0] = i;
2752 } else {
2753 break;
2754 }
2755 }
2756 }
2757 } catch (Resources.NotFoundException e) {
2758 Log.w(TAG, "audio assets file not found", e);
2759 } catch (XmlPullParserException e) {
2760 Log.w(TAG, "XML parser exception reading touch sound assets", e);
2761 } catch (IOException e) {
2762 Log.w(TAG, "I/O exception reading touch sound assets", e);
2763 } finally {
2764 if (parser != null) {
2765 parser.close();
2766 }
2767 }
2768 }
2769
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002770 /** @see AudioManager#playSoundEffect(int) */
2771 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002772 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002773 }
2774
2775 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002776 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07002777 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
2778 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
2779 return;
2780 }
2781
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002782 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002783 effectType, (int) (volume * 1000), null, 0);
2784 }
2785
2786 /**
2787 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08002788 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002789 */
2790 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002791 int attempts = 3;
2792 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08002793
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002794 synchronized (reply) {
2795 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
2796 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08002797 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07002798 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002799 } catch (InterruptedException e) {
2800 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08002801 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002802 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002803 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002804 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002805 }
2806
2807 /**
2808 * Unloads samples from the sound pool.
2809 * This method can be called to free some memory when
2810 * sound effects are disabled.
2811 */
2812 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002813 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002814 }
2815
Eric Laurenta60e2122010-12-28 16:49:07 -08002816 class SoundPoolListenerThread extends Thread {
2817 public SoundPoolListenerThread() {
2818 super("SoundPoolListenerThread");
2819 }
2820
2821 @Override
2822 public void run() {
2823
2824 Looper.prepare();
2825 mSoundPoolLooper = Looper.myLooper();
2826
2827 synchronized (mSoundEffectsLock) {
2828 if (mSoundPool != null) {
2829 mSoundPoolCallBack = new SoundPoolCallback();
2830 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2831 }
2832 mSoundEffectsLock.notify();
2833 }
2834 Looper.loop();
2835 }
2836 }
2837
2838 private final class SoundPoolCallback implements
2839 android.media.SoundPool.OnLoadCompleteListener {
2840
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002841 int mStatus = 1; // 1 means neither error nor last sample loaded yet
2842 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08002843
2844 public int status() {
2845 return mStatus;
2846 }
2847
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002848 public void setSamples(int[] samples) {
2849 for (int i = 0; i < samples.length; i++) {
2850 // do not wait ack for samples rejected upfront by SoundPool
2851 if (samples[i] > 0) {
2852 mSamples.add(samples[i]);
2853 }
2854 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002855 }
2856
2857 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2858 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002859 int i = mSamples.indexOf(sampleId);
2860 if (i >= 0) {
2861 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08002862 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002863 if ((status != 0) || mSamples. isEmpty()) {
2864 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08002865 mSoundEffectsLock.notify();
2866 }
2867 }
2868 }
2869 }
2870
Eric Laurent4050c932009-07-08 02:52:14 -07002871 /** @see AudioManager#reloadAudioSettings() */
2872 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002873 readAudioSettings(false /*userSwitch*/);
2874 }
2875
2876 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07002877 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2878 readPersistedSettings();
Eric Laurentc0232482016-03-15 18:19:23 -07002879 readUserRestrictions();
Eric Laurent4050c932009-07-08 02:52:14 -07002880
2881 // restore volume settings
2882 int numStreamTypes = AudioSystem.getNumStreamTypes();
2883 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2884 VolumeStreamState streamState = mStreamStates[streamType];
2885
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002886 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2887 continue;
2888 }
2889
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002890 streamState.readSettings();
2891 synchronized (VolumeStreamState.class) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002892 // unmute stream that was muted but is not affect by mute anymore
RoboErik4197cb62015-01-21 15:45:32 -08002893 if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07002894 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
RoboErik4197cb62015-01-21 15:45:32 -08002895 streamState.mIsMuted = false;
Eric Laurent4050c932009-07-08 02:52:14 -07002896 }
Eric Laurent4050c932009-07-08 02:52:14 -07002897 }
2898 }
2899
Eric Laurent33902db2012-10-07 16:15:07 -07002900 // apply new ringer mode before checking volume for alias streams so that streams
2901 // muted by ringer mode have the correct volume
John Spurlock661f2cf2014-11-17 10:29:10 -05002902 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent33902db2012-10-07 16:15:07 -07002903
Eric Laurent212532b2014-07-21 15:43:18 -07002904 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07002905 checkAllAliasStreamVolumes();
John Spurlockb6e19e32015-03-10 21:33:44 -04002906 checkMuteAffectedStreams();
Eric Laurent24482012012-05-10 09:41:17 -07002907
Eric Laurentd640bd32012-09-28 18:01:48 -07002908 synchronized (mSafeMediaVolumeState) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002909 mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2910 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2911 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
Eric Laurentd640bd32012-09-28 18:01:48 -07002912 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
John Spurlock90874332015-03-10 16:00:54 -04002913 enforceSafeMediaVolume(TAG);
Eric Laurentf1a457d2012-09-20 16:27:23 -07002914 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07002915 }
Eric Laurent4050c932009-07-08 02:52:14 -07002916 }
2917
Dianne Hackborn961cae92013-03-20 14:59:43 -07002918 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002919 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002920 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2921 return;
2922 }
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07002923 // for logging only
2924 final String eventSource = new StringBuilder("setSpeakerphoneOn(").append(on)
2925 .append(") from u/pid:").append(Binder.getCallingUid()).append("/")
2926 .append(Binder.getCallingPid()).toString();
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002927
2928 if (on) {
2929 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2930 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07002931 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE,
2932 eventSource, 0);
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002933 }
2934 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2935 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2936 mForcedUseForComm = AudioSystem.FORCE_NONE;
2937 }
Eric Laurentfa640152011-03-12 15:59:51 -08002938
Sharad Sangle1d188442017-05-09 16:05:40 +05302939 mForcedUseForCommExt = mForcedUseForComm;
Eric Laurentafbb0472011-12-15 09:04:23 -08002940 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07002941 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002942 }
2943
2944 /** @see AudioManager#isSpeakerphoneOn() */
2945 public boolean isSpeakerphoneOn() {
Sharad Sangle1d188442017-05-09 16:05:40 +05302946 return (mForcedUseForCommExt == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002947 }
2948
Dianne Hackborn961cae92013-03-20 14:59:43 -07002949 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurent48221252015-09-24 18:41:48 -07002950 public void setBluetoothScoOn(boolean on) {
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002951 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2952 return;
2953 }
Sharad Sangle1d188442017-05-09 16:05:40 +05302954
2955 // Only enable calls from system components
2956 if (Binder.getCallingUid() >= FIRST_APPLICATION_UID) {
2957 mForcedUseForCommExt = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE;
2958 return;
2959 }
2960
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07002961 // for logging only
2962 final String eventSource = new StringBuilder("setBluetoothScoOn(").append(on)
2963 .append(") from u/pid:").append(Binder.getCallingUid()).append("/")
2964 .append(Binder.getCallingPid()).toString();
2965 setBluetoothScoOnInt(on, eventSource);
Eric Laurent48221252015-09-24 18:41:48 -07002966 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002967
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07002968 public void setBluetoothScoOnInt(boolean on, String eventSource) {
Jack He8dd33942018-01-17 15:45:12 -08002969 if (DEBUG_DEVICES) {
2970 Log.d(TAG, "setBluetoothScoOnInt: " + on + " " + eventSource);
2971 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002972 if (on) {
Sharad Sangle1d188442017-05-09 16:05:40 +05302973 // do not accept SCO ON if SCO audio is not connected
Jack He8dd33942018-01-17 15:45:12 -08002974 synchronized (mScoClients) {
2975 if (mBluetoothHeadset != null) {
2976 if (mBluetoothHeadsetDevice == null) {
2977 BluetoothDevice activeDevice = mBluetoothHeadset.getActiveDevice();
2978 if (activeDevice != null) {
2979 // setBtScoActiveDevice() might trigger resetBluetoothSco() which
2980 // will call setBluetoothScoOnInt(false, "resetBluetoothSco")
2981 setBtScoActiveDevice(activeDevice);
2982 }
2983 }
2984 if (mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2985 != BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2986 mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO;
2987 Log.w(TAG, "setBluetoothScoOnInt(true) failed because "
2988 + mBluetoothHeadsetDevice + " is not in audio connected mode");
2989 return;
2990 }
Sharad Sangle1d188442017-05-09 16:05:40 +05302991 }
2992 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002993 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2994 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2995 mForcedUseForComm = AudioSystem.FORCE_NONE;
2996 }
Sharad Sangle1d188442017-05-09 16:05:40 +05302997 mForcedUseForCommExt = mForcedUseForComm;
2998 AudioSystem.setParameters("BT_SCO="+ (on ? "on" : "off"));
Eric Laurentafbb0472011-12-15 09:04:23 -08002999 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07003000 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08003001 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07003002 AudioSystem.FOR_RECORD, mForcedUseForComm, eventSource, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003003 }
3004
3005 /** @see AudioManager#isBluetoothScoOn() */
3006 public boolean isBluetoothScoOn() {
Sharad Sangle1d188442017-05-09 16:05:40 +05303007 return (mForcedUseForCommExt == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07003008 }
3009
Sungsoocf09fe62016-09-28 16:21:48 +09003010 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07003011 public void setBluetoothA2dpOn(boolean on) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07003012 // for logging only
3013 final String eventSource = new StringBuilder("setBluetoothA2dpOn(").append(on)
3014 .append(") from u/pid:").append(Binder.getCallingUid()).append("/")
3015 .append(Binder.getCallingPid()).toString();
3016
Sungsoocf09fe62016-09-28 16:21:48 +09003017 synchronized (mBluetoothA2dpEnabledLock) {
3018 mBluetoothA2dpEnabled = on;
3019 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
3020 AudioSystem.FOR_MEDIA,
3021 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07003022 eventSource, 0);
Sungsoocf09fe62016-09-28 16:21:48 +09003023 }
Eric Laurent78472112012-05-21 08:57:21 -07003024 }
3025
Sungsoocf09fe62016-09-28 16:21:48 +09003026 /** @see AudioManager#isBluetoothA2dpOn() */
Eric Laurent78472112012-05-21 08:57:21 -07003027 public boolean isBluetoothA2dpOn() {
Sungsoocf09fe62016-09-28 16:21:48 +09003028 synchronized (mBluetoothA2dpEnabledLock) {
3029 return mBluetoothA2dpEnabled;
3030 }
Eric Laurent78472112012-05-21 08:57:21 -07003031 }
3032
Eric Laurent3def1ee2010-03-17 23:26:26 -07003033 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07003034 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
3035 int scoAudioMode =
3036 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
Liejun Taof4e51d82014-07-16 11:18:29 -07003037 SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
Eric Laurent83900752014-05-15 15:14:22 -07003038 startBluetoothScoInt(cb, scoAudioMode);
3039 }
3040
3041 /** @see AudioManager#startBluetoothScoVirtualCall() */
3042 public void startBluetoothScoVirtualCall(IBinder cb) {
3043 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
3044 }
3045
3046 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07003047 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07003048 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07003049 return;
3050 }
Eric Laurent854938a2011-02-22 12:05:20 -08003051 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07003052 // The calling identity must be cleared before calling ScoClient.incCount().
3053 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
3054 // and this must be done on behalf of system server to make sure permissions are granted.
3055 // The caller identity must be cleared after getScoClient() because it is needed if a new
3056 // client is created.
3057 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07003058 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08003059 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003060 }
3061
3062 /** @see AudioManager#stopBluetoothSco() */
3063 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07003064 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07003065 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07003066 return;
3067 }
Eric Laurent854938a2011-02-22 12:05:20 -08003068 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07003069 // The calling identity must be cleared before calling ScoClient.decCount().
3070 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
3071 // and this must be done on behalf of system server to make sure permissions are granted.
3072 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08003073 if (client != null) {
3074 client.decCount();
3075 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08003076 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003077 }
3078
Eric Laurent78472112012-05-21 08:57:21 -07003079
Eric Laurent3def1ee2010-03-17 23:26:26 -07003080 private class ScoClient implements IBinder.DeathRecipient {
3081 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07003082 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003083 private int mStartcount; // number of SCO connections started by this client
3084
3085 ScoClient(IBinder cb) {
3086 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07003087 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07003088 mStartcount = 0;
3089 }
3090
3091 public void binderDied() {
3092 synchronized(mScoClients) {
3093 Log.w(TAG, "SCO client died");
3094 int index = mScoClients.indexOf(this);
3095 if (index < 0) {
3096 Log.w(TAG, "unregistered SCO client died");
3097 } else {
3098 clearCount(true);
3099 mScoClients.remove(this);
3100 }
3101 }
3102 }
3103
Eric Laurent83900752014-05-15 15:14:22 -07003104 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07003105 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07003106 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003107 if (mStartcount == 0) {
3108 try {
3109 mCb.linkToDeath(this, 0);
3110 } catch (RemoteException e) {
3111 // client has already died!
3112 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
3113 }
3114 }
3115 mStartcount++;
3116 }
3117 }
3118
3119 public void decCount() {
3120 synchronized(mScoClients) {
3121 if (mStartcount == 0) {
3122 Log.w(TAG, "ScoClient.decCount() already 0");
3123 } else {
3124 mStartcount--;
3125 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07003126 try {
3127 mCb.unlinkToDeath(this, 0);
3128 } catch (NoSuchElementException e) {
3129 Log.w(TAG, "decCount() going to 0 but not registered to binder");
3130 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07003131 }
Eric Laurentc18c9132013-04-12 17:24:56 -07003132 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003133 }
3134 }
3135 }
3136
3137 public void clearCount(boolean stopSco) {
3138 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07003139 if (mStartcount != 0) {
3140 try {
3141 mCb.unlinkToDeath(this, 0);
3142 } catch (NoSuchElementException e) {
3143 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
3144 }
3145 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07003146 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003147 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003148 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003149 }
3150 }
3151 }
3152
3153 public int getCount() {
3154 return mStartcount;
3155 }
3156
3157 public IBinder getBinder() {
3158 return mCb;
3159 }
3160
Eric Laurentd7454be2011-09-14 08:45:58 -07003161 public int getPid() {
3162 return mCreatorPid;
3163 }
3164
Eric Laurent3def1ee2010-03-17 23:26:26 -07003165 public int totalCount() {
3166 synchronized(mScoClients) {
3167 int count = 0;
3168 int size = mScoClients.size();
3169 for (int i = 0; i < size; i++) {
3170 count += mScoClients.get(i).getCount();
3171 }
3172 return count;
3173 }
3174 }
3175
Eric Laurent83900752014-05-15 15:14:22 -07003176 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08003177 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07003178 if (totalCount() == 0) {
3179 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
3180 // Make sure that the state transitions to CONNECTING even if we cannot initiate
3181 // the connection.
3182 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
3183 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07003184 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07003185 synchronized(mSetModeDeathHandlers) {
3186 if ((mSetModeDeathHandlers.isEmpty() ||
3187 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
3188 (mScoAudioState == SCO_STATE_INACTIVE ||
3189 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
3190 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07003191 mScoAudioMode = scoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -07003192 if (scoAudioMode == SCO_MODE_UNDEFINED) {
Andre Eisenbach570cc532014-10-28 17:03:18 -07003193 if (mBluetoothHeadsetDevice != null) {
3194 mScoAudioMode = new Integer(Settings.Global.getInt(
3195 mContentResolver,
3196 "bluetooth_sco_channel_"+
3197 mBluetoothHeadsetDevice.getAddress(),
3198 SCO_MODE_VIRTUAL_CALL));
3199 if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
3200 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
3201 }
3202 } else {
3203 mScoAudioMode = SCO_MODE_RAW;
Liejun Taof4e51d82014-07-16 11:18:29 -07003204 }
3205 }
Eric Laurent9f103de2011-09-08 15:04:23 -07003206 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07003207 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07003208 if (mScoAudioMode == SCO_MODE_RAW) {
3209 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003210 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003211 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
3212 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003213 } else if (mScoAudioMode == SCO_MODE_VR) {
3214 status = mBluetoothHeadset.startVoiceRecognition(
3215 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003216 }
Liejun Taof4e51d82014-07-16 11:18:29 -07003217
Eric Laurentc18c9132013-04-12 17:24:56 -07003218 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07003219 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
3220 } else {
3221 broadcastScoConnectionState(
3222 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3223 }
3224 } else if (getBluetoothHeadset()) {
3225 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07003226 }
Eric Laurent9f103de2011-09-08 15:04:23 -07003227 } else {
3228 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
3229 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07003230 }
3231 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07003232 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07003233 }
Eric Laurentdc03c612011-04-01 10:59:41 -07003234 }
Eric Laurent62ef7672010-11-24 10:58:32 -08003235 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07003236 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
3237 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
3238 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07003239 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07003240 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07003241 if (mScoAudioMode == SCO_MODE_RAW) {
3242 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003243 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003244 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
3245 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003246 } else if (mScoAudioMode == SCO_MODE_VR) {
3247 status = mBluetoothHeadset.stopVoiceRecognition(
3248 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003249 }
Liejun Taof4e51d82014-07-16 11:18:29 -07003250
Eric Laurentc18c9132013-04-12 17:24:56 -07003251 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07003252 mScoAudioState = SCO_STATE_INACTIVE;
3253 broadcastScoConnectionState(
3254 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3255 }
3256 } else if (getBluetoothHeadset()) {
3257 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
3258 }
3259 } else {
3260 mScoAudioState = SCO_STATE_INACTIVE;
3261 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3262 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07003263 }
3264 }
3265 }
3266 }
3267
Eric Laurent62ef7672010-11-24 10:58:32 -08003268 private void checkScoAudioState() {
3269 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07003270 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08003271 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
3272 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
3273 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
3274 }
3275 }
3276
Eric Laurent854938a2011-02-22 12:05:20 -08003277 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07003278 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08003279 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003280 int size = mScoClients.size();
3281 for (int i = 0; i < size; i++) {
3282 client = mScoClients.get(i);
3283 if (client.getBinder() == cb)
3284 return client;
3285 }
Eric Laurent854938a2011-02-22 12:05:20 -08003286 if (create) {
3287 client = new ScoClient(cb);
3288 mScoClients.add(client);
3289 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07003290 return client;
3291 }
3292 }
3293
Eric Laurentd7454be2011-09-14 08:45:58 -07003294 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07003295 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08003296 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003297 int size = mScoClients.size();
3298 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08003299 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07003300 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08003301 cl.clearCount(stopSco);
3302 } else {
3303 savedClient = cl;
3304 }
3305 }
3306 mScoClients.clear();
3307 if (savedClient != null) {
3308 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003309 }
3310 }
3311 }
3312
Eric Laurentdc03c612011-04-01 10:59:41 -07003313 private boolean getBluetoothHeadset() {
3314 boolean result = false;
3315 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
3316 if (adapter != null) {
3317 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
3318 BluetoothProfile.HEADSET);
3319 }
3320 // If we could not get a bluetooth headset proxy, send a failure message
3321 // without delay to reset the SCO audio state and clear SCO clients.
3322 // If we could get a proxy, send a delayed failure message that will reset our state
3323 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08003324 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07003325 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
3326 return result;
3327 }
3328
Eric Laurentd7454be2011-09-14 08:45:58 -07003329 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07003330 synchronized(mScoClients) {
3331 checkScoAudioState();
3332 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
3333 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
3334 if (mBluetoothHeadsetDevice != null) {
3335 if (mBluetoothHeadset != null) {
3336 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07003337 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08003338 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07003339 SENDMSG_REPLACE, 0, 0, null, 0);
3340 }
3341 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
3342 getBluetoothHeadset()) {
3343 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
3344 }
3345 }
3346 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07003347 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07003348 }
3349 }
3350 }
3351
3352 private void resetBluetoothSco() {
3353 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07003354 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07003355 mScoAudioState = SCO_STATE_INACTIVE;
3356 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3357 }
Eric Laurent48221252015-09-24 18:41:48 -07003358 AudioSystem.setParameters("A2dpSuspended=false");
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07003359 setBluetoothScoOnInt(false, "resetBluetoothSco");
Eric Laurentdc03c612011-04-01 10:59:41 -07003360 }
3361
3362 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08003363 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
3364 SENDMSG_QUEUE, state, 0, null, 0);
3365 }
3366
3367 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07003368 if (state != mScoConnectionState) {
3369 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
3370 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
3371 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
3372 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003373 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07003374 mScoConnectionState = state;
3375 }
3376 }
3377
Jack He8dd33942018-01-17 15:45:12 -08003378 private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) {
Eric Laurent98859b22015-06-12 14:35:59 -07003379 if (btDevice == null) {
Jack He8dd33942018-01-17 15:45:12 -08003380 return true;
Eric Laurent98859b22015-06-12 14:35:59 -07003381 }
Eric Laurent98859b22015-06-12 14:35:59 -07003382 String address = btDevice.getAddress();
3383 BluetoothClass btClass = btDevice.getBluetoothClass();
3384 int outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
3385 int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
3386 if (btClass != null) {
3387 switch (btClass.getDeviceClass()) {
Jack He8dd33942018-01-17 15:45:12 -08003388 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
3389 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
3390 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
3391 break;
3392 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
3393 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
3394 break;
Eric Laurent98859b22015-06-12 14:35:59 -07003395 }
3396 }
3397
3398 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
3399 address = "";
3400 }
3401
Eric Laurent98859b22015-06-12 14:35:59 -07003402 String btDeviceName = btDevice.getName();
Jack He8dd33942018-01-17 15:45:12 -08003403 boolean result = handleDeviceConnection(isActive, outDevice, address, btDeviceName);
3404 // handleDeviceConnection() && result to make sure the method get executed
3405 result = handleDeviceConnection(isActive, inDevice, address, btDeviceName) && result;
3406 return result;
3407 }
Satish Kodishala29809802016-01-18 14:23:12 +05303408
Jack He8dd33942018-01-17 15:45:12 -08003409 void setBtScoActiveDevice(BluetoothDevice btDevice) {
3410 if (DEBUG_DEVICES) {
3411 Log.d(TAG, "setBtScoActiveDevice(" + btDevice + ")");
Satish Kodishala29809802016-01-18 14:23:12 +05303412 }
Satish Kodishala29809802016-01-18 14:23:12 +05303413 synchronized (mScoClients) {
Jack He8dd33942018-01-17 15:45:12 -08003414 final BluetoothDevice previousActiveDevice = mBluetoothHeadsetDevice;
3415 if (!Objects.equals(btDevice, previousActiveDevice)) {
3416 if (!handleBtScoActiveDeviceChange(previousActiveDevice, false)) {
3417 Log.w(TAG, "setBtScoActiveDevice() failed to remove previous device "
3418 + previousActiveDevice);
3419 }
3420 if (!handleBtScoActiveDeviceChange(btDevice, true)) {
3421 Log.e(TAG, "setBtScoActiveDevice() failed to add new device " + btDevice);
3422 // set mBluetoothHeadsetDevice to null when failing to add new device
3423 btDevice = null;
3424 }
Satish Kodishala29809802016-01-18 14:23:12 +05303425 mBluetoothHeadsetDevice = btDevice;
Jack He8dd33942018-01-17 15:45:12 -08003426 if (mBluetoothHeadsetDevice == null) {
3427 resetBluetoothSco();
3428 }
Eric Laurent98859b22015-06-12 14:35:59 -07003429 }
3430 }
3431 }
3432
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07003433 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
3434 new BluetoothProfile.ServiceListener() {
3435 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003436 BluetoothDevice btDevice;
3437 List<BluetoothDevice> deviceList;
3438 switch(profile) {
3439 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09003440 synchronized (mConnectedDevices) {
3441 synchronized (mA2dpAvrcpLock) {
3442 mA2dp = (BluetoothA2dp) proxy;
3443 deviceList = mA2dp.getConnectedDevices();
3444 if (deviceList.size() > 0) {
3445 btDevice = deviceList.get(0);
John Du5a0cf7a2013-07-19 11:30:34 -07003446 int state = mA2dp.getConnectionState(btDevice);
Eric Laurentcdae4762017-04-28 18:00:04 -07003447 int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
John Du5a0cf7a2013-07-19 11:30:34 -07003448 int delay = checkSendBecomingNoisyIntent(
Eric Laurentcdae4762017-04-28 18:00:04 -07003449 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, intState,
3450 AudioSystem.DEVICE_NONE);
John Du5a0cf7a2013-07-19 11:30:34 -07003451 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003452 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07003453 state,
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08003454 0 /* arg2 unused */,
John Du5a0cf7a2013-07-19 11:30:34 -07003455 btDevice,
3456 delay);
3457 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003458 }
Eric Laurent62ef7672010-11-24 10:58:32 -08003459 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003460 break;
3461
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003462 case BluetoothProfile.A2DP_SINK:
3463 deviceList = proxy.getConnectedDevices();
3464 if (deviceList.size() > 0) {
3465 btDevice = deviceList.get(0);
3466 synchronized (mConnectedDevices) {
3467 int state = proxy.getConnectionState(btDevice);
3468 queueMsgUnderWakeLock(mAudioHandler,
3469 MSG_SET_A2DP_SRC_CONNECTION_STATE,
3470 state,
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08003471 0 /* arg2 unused */,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003472 btDevice,
3473 0 /* delay */);
3474 }
3475 }
3476 break;
3477
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003478 case BluetoothProfile.HEADSET:
3479 synchronized (mScoClients) {
3480 // Discard timeout message
3481 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
3482 mBluetoothHeadset = (BluetoothHeadset) proxy;
Jack He8dd33942018-01-17 15:45:12 -08003483 setBtScoActiveDevice(mBluetoothHeadset.getActiveDevice());
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003484 // Refresh SCO audio state
3485 checkScoAudioState();
3486 // Continue pending action if any
3487 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
3488 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
3489 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
3490 boolean status = false;
3491 if (mBluetoothHeadsetDevice != null) {
3492 switch (mScoAudioState) {
3493 case SCO_STATE_ACTIVATE_REQ:
3494 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07003495 if (mScoAudioMode == SCO_MODE_RAW) {
3496 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003497 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003498 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
3499 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003500 } else if (mScoAudioMode == SCO_MODE_VR) {
3501 status = mBluetoothHeadset.startVoiceRecognition(
3502 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003503 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003504 break;
3505 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07003506 if (mScoAudioMode == SCO_MODE_RAW) {
3507 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003508 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003509 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
3510 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003511 } else if (mScoAudioMode == SCO_MODE_VR) {
3512 status = mBluetoothHeadset.stopVoiceRecognition(
3513 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003514 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003515 break;
3516 case SCO_STATE_DEACTIVATE_EXT_REQ:
3517 status = mBluetoothHeadset.stopVoiceRecognition(
3518 mBluetoothHeadsetDevice);
3519 }
3520 }
3521 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08003522 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003523 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07003524 }
3525 }
Eric Laurentdc03c612011-04-01 10:59:41 -07003526 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003527 break;
3528
3529 default:
3530 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003531 }
3532 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07003533 public void onServiceDisconnected(int profile) {
Eric Laurentb70b78a2016-01-13 19:16:04 -08003534
Paul McLean394a8e12015-03-03 10:29:19 -07003535 switch (profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003536 case BluetoothProfile.A2DP:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003537 disconnectA2dp();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003538 break;
3539
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003540 case BluetoothProfile.A2DP_SINK:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003541 disconnectA2dpSink();
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003542 break;
3543
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003544 case BluetoothProfile.HEADSET:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003545 disconnectHeadset();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003546 break;
3547
3548 default:
3549 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003550 }
3551 }
3552 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003553
Eric Laurentb70b78a2016-01-13 19:16:04 -08003554 void disconnectAllBluetoothProfiles() {
3555 disconnectA2dp();
3556 disconnectA2dpSink();
3557 disconnectHeadset();
3558 }
3559
3560 void disconnectA2dp() {
3561 synchronized (mConnectedDevices) {
3562 synchronized (mA2dpAvrcpLock) {
3563 ArraySet<String> toRemove = null;
3564 // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
3565 for (int i = 0; i < mConnectedDevices.size(); i++) {
3566 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
3567 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
3568 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
3569 toRemove.add(deviceSpec.mDeviceAddress);
3570 }
3571 }
3572 if (toRemove != null) {
Eric Laurentcdae4762017-04-28 18:00:04 -07003573 int delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3574 0, AudioSystem.DEVICE_NONE);
Eric Laurentb70b78a2016-01-13 19:16:04 -08003575 for (int i = 0; i < toRemove.size(); i++) {
3576 makeA2dpDeviceUnavailableLater(toRemove.valueAt(i), delay);
3577 }
3578 }
3579 }
3580 }
3581 }
3582
3583 void disconnectA2dpSink() {
3584 synchronized (mConnectedDevices) {
3585 ArraySet<String> toRemove = null;
3586 // Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
3587 for(int i = 0; i < mConnectedDevices.size(); i++) {
3588 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
3589 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) {
3590 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
3591 toRemove.add(deviceSpec.mDeviceAddress);
3592 }
3593 }
3594 if (toRemove != null) {
3595 for (int i = 0; i < toRemove.size(); i++) {
3596 makeA2dpSrcUnavailable(toRemove.valueAt(i));
3597 }
3598 }
3599 }
3600 }
3601
3602 void disconnectHeadset() {
3603 synchronized (mScoClients) {
Jack He8dd33942018-01-17 15:45:12 -08003604 setBtScoActiveDevice(null);
Eric Laurentb70b78a2016-01-13 19:16:04 -08003605 mBluetoothHeadset = null;
3606 }
3607 }
3608
John Spurlock90874332015-03-10 16:00:54 -04003609 private void onCheckMusicActive(String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07003610 synchronized (mSafeMediaVolumeState) {
3611 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07003612 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
3613
3614 if ((device & mSafeMediaVolumeDevices) != 0) {
3615 sendMsg(mAudioHandler,
3616 MSG_CHECK_MUSIC_ACTIVE,
3617 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07003618 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07003619 0,
John Spurlock90874332015-03-10 16:00:54 -04003620 caller,
Eric Laurentc34dcc12012-09-10 13:51:52 -07003621 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07003622 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07003623 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
Eric Laurenteab40d12017-06-09 12:45:21 -07003624 (index > safeMediaVolumeIndex(device))) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07003625 // Approximate cumulative active music time
3626 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
3627 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
John Spurlock90874332015-03-10 16:00:54 -04003628 setSafeMediaVolumeEnabled(true, caller);
Eric Laurentc34dcc12012-09-10 13:51:52 -07003629 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07003630 }
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003631 saveMusicActiveMs();
Eric Laurentc34dcc12012-09-10 13:51:52 -07003632 }
3633 }
3634 }
3635 }
3636 }
3637
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003638 private void saveMusicActiveMs() {
3639 mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
3640 }
3641
Eric Laurenteab40d12017-06-09 12:45:21 -07003642 private int getSafeUsbMediaVolumeIndex()
3643 {
3644 // determine UI volume index corresponding to the wanted safe gain in dBFS
3645 int min = MIN_STREAM_VOLUME[AudioSystem.STREAM_MUSIC];
3646 int max = MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC];
3647
3648 while (Math.abs(max-min) > 1) {
3649 int index = (max + min) / 2;
3650 float gainDB = AudioSystem.getStreamVolumeDB(
3651 AudioSystem.STREAM_MUSIC, index, AudioSystem.DEVICE_OUT_USB_HEADSET);
Eric Laurentb378a13a2017-07-11 14:08:11 -07003652 if (Float.isNaN(gainDB)) {
Eric Laurenteab40d12017-06-09 12:45:21 -07003653 //keep last min in case of read error
3654 break;
Eric Laurentb378a13a2017-07-11 14:08:11 -07003655 } else if (gainDB == SAFE_VOLUME_GAIN_DBFS) {
Eric Laurenteab40d12017-06-09 12:45:21 -07003656 min = index;
3657 break;
Eric Laurentb378a13a2017-07-11 14:08:11 -07003658 } else if (gainDB < SAFE_VOLUME_GAIN_DBFS) {
Eric Laurenteab40d12017-06-09 12:45:21 -07003659 min = index;
3660 } else {
3661 max = index;
3662 }
3663 }
3664 return min * 10;
3665 }
3666
John Spurlock90874332015-03-10 16:00:54 -04003667 private void onConfigureSafeVolume(boolean force, String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07003668 synchronized (mSafeMediaVolumeState) {
3669 int mcc = mContext.getResources().getConfiguration().mcc;
3670 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
3671 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
3672 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
Eric Laurenteab40d12017-06-09 12:45:21 -07003673
3674 mSafeUsbMediaVolumeIndex = getSafeUsbMediaVolumeIndex();
3675
John Spurlock35134602014-07-24 18:10:48 -04003676 boolean safeMediaVolumeEnabled =
3677 SystemProperties.getBoolean("audio.safemedia.force", false)
3678 || mContext.getResources().getBoolean(
3679 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08003680
Ricardo Garcia3a30a762015-06-23 15:54:45 -07003681 boolean safeMediaVolumeBypass =
3682 SystemProperties.getBoolean("audio.safemedia.bypass", false);
3683
Eric Laurent05274f32012-11-29 12:48:18 -08003684 // The persisted state is either "disabled" or "active": this is the state applied
3685 // next time we boot and cannot be "inactive"
3686 int persistedState;
Ricardo Garcia3a30a762015-06-23 15:54:45 -07003687 if (safeMediaVolumeEnabled && !safeMediaVolumeBypass) {
Eric Laurent05274f32012-11-29 12:48:18 -08003688 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
3689 // The state can already be "inactive" here if the user has forced it before
3690 // the 30 seconds timeout for forced configuration. In this case we don't reset
3691 // it to "active".
3692 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003693 if (mMusicActiveMs == 0) {
3694 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
John Spurlock90874332015-03-10 16:00:54 -04003695 enforceSafeMediaVolume(caller);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003696 } else {
3697 // We have existing playback time recorded, already confirmed.
3698 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
3699 }
Eric Laurent05274f32012-11-29 12:48:18 -08003700 }
Eric Laurentd640bd32012-09-28 18:01:48 -07003701 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08003702 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07003703 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
3704 }
3705 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08003706 sendMsg(mAudioHandler,
3707 MSG_PERSIST_SAFE_VOLUME_STATE,
3708 SENDMSG_QUEUE,
3709 persistedState,
3710 0,
3711 null,
3712 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07003713 }
3714 }
3715 }
3716
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003717 ///////////////////////////////////////////////////////////////////////////
3718 // Internal methods
3719 ///////////////////////////////////////////////////////////////////////////
3720
3721 /**
3722 * Checks if the adjustment should change ringer mode instead of just
3723 * adjusting volume. If so, this will set the proper ringer mode and volume
3724 * indices on the stream states.
3725 */
Julia Reynoldsed783792016-04-08 15:27:35 -04003726 private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted,
3727 String caller, int flags) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003728 int result = FLAG_ADJUST_VOLUME;
Zak Cohen47798292017-11-30 12:34:20 -08003729 if (isPlatformTelevision() || mIsSingleVolume) {
Hank Freund21003f62015-12-08 09:05:46 -08003730 return result;
3731 }
3732
John Spurlock661f2cf2014-11-17 10:29:10 -05003733 int ringerMode = getRingerModeInternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003734
Eric Laurentbffc3d12012-05-07 17:43:49 -07003735 switch (ringerMode) {
3736 case RINGER_MODE_NORMAL:
3737 if (direction == AudioManager.ADJUST_LOWER) {
3738 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07003739 // "step" is the delta in internal index units corresponding to a
3740 // change of 1 in UI index units.
3741 // Because of rounding when rescaling from one stream index range to its alias
3742 // index range, we cannot simply test oldIndex == step:
3743 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
3744 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003745 ringerMode = RINGER_MODE_VIBRATE;
John Spurlock07e72432015-03-13 11:46:52 -04003746 mLoweredFromNormalToVibrateTime = SystemClock.uptimeMillis();
Eric Laurentbffc3d12012-05-07 17:43:49 -07003747 }
3748 } else {
John Spurlockd9c75db2015-04-28 11:19:13 -04003749 if (oldIndex == step && mVolumePolicy.volumeDownToEnterSilent) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003750 ringerMode = RINGER_MODE_SILENT;
3751 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07003752 }
Muyuan Li1ed6df62016-06-18 11:16:52 -07003753 } else if (mIsSingleVolume && (direction == AudioManager.ADJUST_TOGGLE_MUTE
John Spurlocka48d7792015-03-03 17:35:57 -05003754 || direction == AudioManager.ADJUST_MUTE)) {
RoboErik5452e252015-02-06 15:33:53 -08003755 if (mHasVibrator) {
3756 ringerMode = RINGER_MODE_VIBRATE;
3757 } else {
3758 ringerMode = RINGER_MODE_SILENT;
3759 }
3760 // Setting the ringer mode will toggle mute
3761 result &= ~FLAG_ADJUST_VOLUME;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003762 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003763 break;
3764 case RINGER_MODE_VIBRATE:
3765 if (!mHasVibrator) {
3766 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
3767 "but no vibrator is present");
3768 break;
3769 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003770 if ((direction == AudioManager.ADJUST_LOWER)) {
RoboErik5452e252015-02-06 15:33:53 -08003771 // This is the case we were muted with the volume turned up
Muyuan Li1ed6df62016-06-18 11:16:52 -07003772 if (mIsSingleVolume && oldIndex >= 2 * step && isMuted) {
RoboErik5452e252015-02-06 15:33:53 -08003773 ringerMode = RINGER_MODE_NORMAL;
3774 } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
John Spurlocka48d7792015-03-03 17:35:57 -05003775 if (mVolumePolicy.volumeDownToEnterSilent) {
John Spurlock07e72432015-03-13 11:46:52 -04003776 final long diff = SystemClock.uptimeMillis()
3777 - mLoweredFromNormalToVibrateTime;
John Spurlockd9c75db2015-04-28 11:19:13 -04003778 if (diff > mVolumePolicy.vibrateToSilentDebounce
3779 && mRingerModeDelegate.canVolumeDownEnterSilent()) {
John Spurlock07e72432015-03-13 11:46:52 -04003780 ringerMode = RINGER_MODE_SILENT;
3781 }
John Spurlock795a5142014-12-08 14:09:35 -05003782 } else {
3783 result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
3784 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003785 }
RoboErik5452e252015-02-06 15:33:53 -08003786 } else if (direction == AudioManager.ADJUST_RAISE
3787 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3788 || direction == AudioManager.ADJUST_UNMUTE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003789 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07003790 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003791 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003792 break;
3793 case RINGER_MODE_SILENT:
Muyuan Li1ed6df62016-06-18 11:16:52 -07003794 if (mIsSingleVolume && direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
RoboErik5452e252015-02-06 15:33:53 -08003795 // This is the case we were muted with the volume turned up
3796 ringerMode = RINGER_MODE_NORMAL;
3797 } else if (direction == AudioManager.ADJUST_RAISE
3798 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3799 || direction == AudioManager.ADJUST_UNMUTE) {
John Spurlocka48d7792015-03-03 17:35:57 -05003800 if (!mVolumePolicy.volumeUpToExitSilent) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003801 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003802 } else {
RoboErik5452e252015-02-06 15:33:53 -08003803 if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003804 ringerMode = RINGER_MODE_VIBRATE;
3805 } else {
RoboErik5452e252015-02-06 15:33:53 -08003806 // If we don't have a vibrator or they were toggling mute
3807 // go straight back to normal.
John Spurlocka11b4af2014-06-01 11:52:23 -04003808 ringerMode = RINGER_MODE_NORMAL;
3809 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003810 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05003811 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003812 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003813 break;
3814 default:
3815 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
3816 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003817 }
3818
Julia Reynoldsed783792016-04-08 15:27:35 -04003819 if (isAndroidNPlus(caller) && wouldToggleZenMode(ringerMode)
3820 && !mNm.isNotificationPolicyAccessGrantedForPackage(caller)
3821 && (flags & AudioManager.FLAG_FROM_KEY) == 0) {
3822 throw new SecurityException("Not allowed to change Do Not Disturb state");
3823 }
3824
John Spurlock661f2cf2014-11-17 10:29:10 -05003825 setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003826
Eric Laurent25101b02011-02-02 09:33:30 -08003827 mPrevVolDirection = direction;
3828
John Spurlocka11b4af2014-06-01 11:52:23 -04003829 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003830 }
3831
John Spurlock3346a802014-05-20 16:25:37 -04003832 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003833 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07003834 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003835 }
3836
Eric Laurent5b4e6542010-03-19 20:02:21 -07003837 private boolean isStreamMutedByRingerMode(int streamType) {
3838 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
3839 }
3840
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08003841 @GuardedBy("mSettingsLock")
John Spurlock50ced3f2015-05-11 16:00:09 -04003842 private boolean updateRingerModeAffectedStreams() {
3843 int ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003844 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3845 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
3846 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
3847 UserHandle.USER_CURRENT);
3848
Muyuan Li1ed6df62016-06-18 11:16:52 -07003849 if (mIsSingleVolume) {
John Spurlock50ced3f2015-05-11 16:00:09 -04003850 ringerModeAffectedStreams = 0;
3851 } else if (mRingerModeDelegate != null) {
3852 ringerModeAffectedStreams = mRingerModeDelegate
3853 .getRingerModeAffectedStreams(ringerModeAffectedStreams);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003854 }
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08003855 if (mCameraSoundForced) {
3856 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3857 } else {
3858 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003859 }
3860 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
3861 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
3862 } else {
3863 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
3864 }
3865
3866 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3867 Settings.System.putIntForUser(mContentResolver,
3868 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3869 ringerModeAffectedStreams,
3870 UserHandle.USER_CURRENT);
3871 mRingerModeAffectedStreams = ringerModeAffectedStreams;
3872 return true;
3873 }
3874 return false;
3875 }
3876
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05003877 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003878 public boolean isStreamAffectedByMute(int streamType) {
3879 return (mMuteAffectedStreams & (1 << streamType)) != 0;
3880 }
3881
3882 private void ensureValidDirection(int direction) {
RoboErik4197cb62015-01-21 15:45:32 -08003883 switch (direction) {
3884 case AudioManager.ADJUST_LOWER:
3885 case AudioManager.ADJUST_RAISE:
3886 case AudioManager.ADJUST_SAME:
3887 case AudioManager.ADJUST_MUTE:
3888 case AudioManager.ADJUST_UNMUTE:
3889 case AudioManager.ADJUST_TOGGLE_MUTE:
3890 break;
3891 default:
3892 throw new IllegalArgumentException("Bad direction " + direction);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003893 }
3894 }
3895
3896 private void ensureValidStreamType(int streamType) {
3897 if (streamType < 0 || streamType >= mStreamStates.length) {
3898 throw new IllegalArgumentException("Bad stream type " + streamType);
3899 }
3900 }
3901
RoboErik4197cb62015-01-21 15:45:32 -08003902 private boolean isMuteAdjust(int adjust) {
3903 return adjust == AudioManager.ADJUST_MUTE || adjust == AudioManager.ADJUST_UNMUTE
3904 || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
3905 }
3906
Eric Laurent6d517662012-04-23 18:42:39 -07003907 private boolean isInCommunication() {
Nancy Chen0eb1e402014-08-21 22:52:29 -07003908 boolean IsInCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003909
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003910 TelecomManager telecomManager =
3911 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
Eric Laurent38edfda2014-12-18 17:38:04 -08003912
3913 final long ident = Binder.clearCallingIdentity();
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003914 IsInCall = telecomManager.isInCall();
Eric Laurent38edfda2014-12-18 17:38:04 -08003915 Binder.restoreCallingIdentity(ident);
Santos Cordon9eb45932014-06-27 12:28:43 -07003916
Eric Laurentda1af762017-12-15 16:54:35 -08003917 return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION ||
3918 getMode() == AudioManager.MODE_IN_CALL);
Eric Laurent6d517662012-04-23 18:42:39 -07003919 }
Eric Laurent25101b02011-02-02 09:33:30 -08003920
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003921 /**
3922 * For code clarity for getActiveStreamType(int)
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05003923 * @param delay_ms max time since last stream activity to consider
3924 * @return true if stream is active in streams handled by AudioFlinger now or
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003925 * in the last "delay_ms" ms.
3926 */
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05003927 private boolean wasStreamActiveRecently(int stream, int delay_ms) {
3928 return AudioSystem.isStreamActive(stream, delay_ms)
3929 || AudioSystem.isStreamActiveRemotely(stream, delay_ms);
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003930 }
3931
Eric Laurent6d517662012-04-23 18:42:39 -07003932 private int getActiveStreamType(int suggestedStreamType) {
Muyuan Li1ed6df62016-06-18 11:16:52 -07003933 if (mIsSingleVolume
3934 && suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
3935 return AudioSystem.STREAM_MUSIC;
3936 }
3937
Eric Laurent212532b2014-07-21 15:43:18 -07003938 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003939 case AudioSystem.PLATFORM_VOICE:
Eric Laurent6d517662012-04-23 18:42:39 -07003940 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003941 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3942 == AudioSystem.FORCE_BT_SCO) {
3943 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
3944 return AudioSystem.STREAM_BLUETOOTH_SCO;
3945 } else {
3946 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
3947 return AudioSystem.STREAM_VOICE_CALL;
3948 }
Eric Laurent25101b02011-02-02 09:33:30 -08003949 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05003950 if (wasStreamActiveRecently(AudioSystem.STREAM_RING, sStreamOverrideDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003951 if (DEBUG_VOL)
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05003952 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING stream active");
3953 return AudioSystem.STREAM_RING;
3954 } else if (wasStreamActiveRecently(
3955 AudioSystem.STREAM_NOTIFICATION, sStreamOverrideDelayMs)) {
3956 if (DEBUG_VOL)
3957 Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION stream active");
3958 return AudioSystem.STREAM_NOTIFICATION;
3959 } else {
3960 if (DEBUG_VOL)
3961 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC b/c default");
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003962 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003963 }
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05003964 } else if (
3965 wasStreamActiveRecently(AudioSystem.STREAM_NOTIFICATION, sStreamOverrideDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003966 if (DEBUG_VOL)
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05003967 Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION stream active");
3968 return AudioSystem.STREAM_NOTIFICATION;
3969 } else if (wasStreamActiveRecently(AudioSystem.STREAM_RING, sStreamOverrideDelayMs)) {
3970 if (DEBUG_VOL)
3971 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING stream active");
3972 return AudioSystem.STREAM_RING;
Eric Laurent25101b02011-02-02 09:33:30 -08003973 }
Eric Laurent212532b2014-07-21 15:43:18 -07003974 default:
Eric Laurent6d517662012-04-23 18:42:39 -07003975 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003976 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3977 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003978 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08003979 return AudioSystem.STREAM_BLUETOOTH_SCO;
3980 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003981 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08003982 return AudioSystem.STREAM_VOICE_CALL;
3983 }
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05003984 } else if (AudioSystem.isStreamActive(
3985 AudioSystem.STREAM_NOTIFICATION, sStreamOverrideDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003986 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08003987 return AudioSystem.STREAM_NOTIFICATION;
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05003988 } else if (AudioSystem.isStreamActive(
3989 AudioSystem.STREAM_RING, sStreamOverrideDelayMs)) {
3990 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING");
3991 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003992 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05003993 if (AudioSystem.isStreamActive(
3994 AudioSystem.STREAM_NOTIFICATION, sStreamOverrideDelayMs)) {
3995 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
John Spurlockeb1d88d2014-07-19 14:49:19 -04003996 return AudioSystem.STREAM_NOTIFICATION;
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05003997 } else if (AudioSystem.isStreamActive(
3998 AudioSystem.STREAM_RING, sStreamOverrideDelayMs)) {
3999 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING");
4000 return AudioSystem.STREAM_RING;
4001 } else {
4002 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default");
4003 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004004 }
Joe Onoratoc7fcba42011-01-05 16:53:11 -08004005 }
Eric Laurent212532b2014-07-21 15:43:18 -07004006 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004007 }
Eric Laurent212532b2014-07-21 15:43:18 -07004008 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
4009 + suggestedStreamType);
4010 return suggestedStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004011 }
4012
John Spurlockbcc10872014-11-28 15:29:21 -05004013 private void broadcastRingerMode(String action, int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004014 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05004015 Intent broadcast = new Intent(action);
Glenn Kastenba195eb2011-12-13 09:30:40 -08004016 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08004017 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
4018 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004019 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004020 }
4021
4022 private void broadcastVibrateSetting(int vibrateType) {
4023 // Send broadcast
Sudheer Shankafc46e9b2016-10-21 17:55:27 -07004024 if (mActivityManagerInternal.isSystemReady()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004025 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
4026 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
4027 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004028 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004029 }
4030 }
4031
4032 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07004033 /**
4034 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
4035 * Note that the wake lock needs to be released after the message has been handled.
4036 */
4037 private void queueMsgUnderWakeLock(Handler handler, int msg,
4038 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07004039 final long ident = Binder.clearCallingIdentity();
4040 // Always acquire the wake lock as AudioService because it is released by the
4041 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004042 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07004043 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07004044 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
4045 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004046
Eric Laurentafbb0472011-12-15 09:04:23 -08004047 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004048 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004049
4050 if (existingMsgPolicy == SENDMSG_REPLACE) {
4051 handler.removeMessages(msg);
4052 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
4053 return;
4054 }
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004055 synchronized (mLastDeviceConnectMsgTime) {
4056 long time = SystemClock.uptimeMillis() + delay;
4057 handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
4058 if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
4059 msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
4060 msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
4061 mLastDeviceConnectMsgTime = time;
4062 }
4063 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004064 }
4065
4066 boolean checkAudioSettingsPermission(String method) {
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07004067 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004068 == PackageManager.PERMISSION_GRANTED) {
4069 return true;
4070 }
4071 String msg = "Audio Settings Permission Denial: " + method + " from pid="
4072 + Binder.getCallingPid()
4073 + ", uid=" + Binder.getCallingUid();
4074 Log.w(TAG, msg);
4075 return false;
4076 }
4077
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004078 private int getDeviceForStream(int stream) {
John Spurlock8a52c442015-03-26 14:23:58 -04004079 int device = getDevicesForStream(stream);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004080 if ((device & (device - 1)) != 0) {
4081 // Multiple device selection is either:
4082 // - speaker + one other device: give priority to speaker in this case.
4083 // - one A2DP device + another device: happens with duplicated output. In this case
4084 // retain the device on the A2DP output as the other must not correspond to an active
4085 // selection if not the speaker.
Jungshik Jangc9ff9682014-09-15 17:41:06 +09004086 // - HDMI-CEC system audio mode only output: give priority to available item in order.
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004087 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
4088 device = AudioSystem.DEVICE_OUT_SPEAKER;
Jungshik Jangc9ff9682014-09-15 17:41:06 +09004089 } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
4090 device = AudioSystem.DEVICE_OUT_HDMI_ARC;
4091 } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
4092 device = AudioSystem.DEVICE_OUT_SPDIF;
4093 } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
4094 device = AudioSystem.DEVICE_OUT_AUX_LINE;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004095 } else {
4096 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
4097 }
4098 }
4099 return device;
4100 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004101
John Spurlock8a52c442015-03-26 14:23:58 -04004102 private int getDevicesForStream(int stream) {
4103 return getDevicesForStream(stream, true /*checkOthers*/);
4104 }
4105
4106 private int getDevicesForStream(int stream, boolean checkOthers) {
4107 ensureValidStreamType(stream);
4108 synchronized (VolumeStreamState.class) {
4109 return mStreamStates[stream].observeDevicesForStream_syncVSS(checkOthers);
4110 }
4111 }
4112
4113 private void observeDevicesForStreams(int skipStream) {
4114 synchronized (VolumeStreamState.class) {
4115 for (int stream = 0; stream < mStreamStates.length; stream++) {
4116 if (stream != skipStream) {
4117 mStreamStates[stream].observeDevicesForStream_syncVSS(false /*checkOthers*/);
4118 }
4119 }
4120 }
4121 }
4122
Paul McLean10804eb2015-01-28 11:16:35 -08004123 /*
4124 * A class just for packaging up a set of connection parameters.
4125 */
Jean-Michel Trivicf170362017-08-24 17:24:57 -07004126 class WiredDeviceConnectionState {
John Spurlock90874332015-03-10 16:00:54 -04004127 public final int mType;
4128 public final int mState;
4129 public final String mAddress;
4130 public final String mName;
4131 public final String mCaller;
Paul McLean10804eb2015-01-28 11:16:35 -08004132
John Spurlock90874332015-03-10 16:00:54 -04004133 public WiredDeviceConnectionState(int type, int state, String address, String name,
4134 String caller) {
Paul McLean10804eb2015-01-28 11:16:35 -08004135 mType = type;
4136 mState = state;
4137 mAddress = address;
4138 mName = name;
John Spurlock90874332015-03-10 16:00:54 -04004139 mCaller = caller;
Paul McLean10804eb2015-01-28 11:16:35 -08004140 }
4141 }
4142
John Spurlock90874332015-03-10 16:00:54 -04004143 public void setWiredDeviceConnectionState(int type, int state, String address, String name,
4144 String caller) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004145 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004146 if (DEBUG_DEVICES) {
4147 Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
4148 + address + ")");
4149 }
Eric Laurentcdae4762017-04-28 18:00:04 -07004150 int delay = checkSendBecomingNoisyIntent(type, state, AudioSystem.DEVICE_NONE);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07004151 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004152 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08004153 0 /* arg1 unused */,
4154 0 /* arg2 unused */,
John Spurlock90874332015-03-10 16:00:54 -04004155 new WiredDeviceConnectionState(type, state, address, name, caller),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004156 delay);
4157 }
4158 }
4159
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004160 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004161 {
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08004162 return setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
4163 device, state, profile, false /* suppressNoisyIntent */);
4164 }
4165
4166 public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice device,
4167 int state, int profile, boolean suppressNoisyIntent)
4168 {
Eric Laurent4724ea72017-05-23 10:39:38 -07004169 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, device)) {
Eric Laurentcdae4762017-04-28 18:00:04 -07004170 return 0;
4171 }
4172 return setBluetoothA2dpDeviceConnectionStateInt(
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08004173 device, state, profile, suppressNoisyIntent, AudioSystem.DEVICE_NONE);
Eric Laurentcdae4762017-04-28 18:00:04 -07004174 }
4175
4176 public int setBluetoothA2dpDeviceConnectionStateInt(
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08004177 BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent,
4178 int musicDevice)
Eric Laurentcdae4762017-04-28 18:00:04 -07004179 {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004180 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004181 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
4182 throw new IllegalArgumentException("invalid profile " + profile);
4183 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004184 synchronized (mConnectedDevices) {
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08004185 if (profile == BluetoothProfile.A2DP && !suppressNoisyIntent) {
Eric Laurentcdae4762017-04-28 18:00:04 -07004186 int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004187 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Eric Laurentcdae4762017-04-28 18:00:04 -07004188 intState, musicDevice);
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004189 } else {
4190 delay = 0;
4191 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07004192 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004193 (profile == BluetoothProfile.A2DP ?
4194 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004195 state,
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08004196 0 /* arg2 unused */,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004197 device,
4198 delay);
4199 }
4200 return delay;
4201 }
4202
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08004203 public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device)
4204 {
4205 synchronized (mConnectedDevices) {
4206 queueMsgUnderWakeLock(mAudioHandler,
4207 MSG_A2DP_DEVICE_CONFIG_CHANGE,
4208 0 /* arg1 unused */,
4209 0 /* arg1 unused */,
4210 device,
4211 0 /* delay */);
4212 }
4213 }
4214
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07004215 private static final int DEVICE_MEDIA_UNMUTED_ON_PLUG =
4216 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
4217 AudioSystem.DEVICE_OUT_LINE |
4218 AudioSystem.DEVICE_OUT_ALL_A2DP |
4219 AudioSystem.DEVICE_OUT_ALL_USB |
4220 AudioSystem.DEVICE_OUT_HDMI;
4221
4222 private void onAccessoryPlugMediaUnmute(int newDevice) {
4223 if (DEBUG_VOL) {
4224 Log.i(TAG, String.format("onAccessoryPlugMediaUnmute newDevice=%d [%s]",
4225 newDevice, AudioSystem.getOutputDeviceName(newDevice)));
4226 }
4227 synchronized (mConnectedDevices) {
Eric Laurent7fb83d92017-09-28 09:36:36 -07004228 if (mNm.getZenMode() != Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
4229 && (newDevice & DEVICE_MEDIA_UNMUTED_ON_PLUG) != 0
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07004230 && mStreamStates[AudioSystem.STREAM_MUSIC].mIsMuted
4231 && mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(newDevice) != 0
4232 && (newDevice & AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC)) != 0)
4233 {
4234 if (DEBUG_VOL) {
4235 Log.i(TAG, String.format(" onAccessoryPlugMediaUnmute unmuting device=%d [%s]",
4236 newDevice, AudioSystem.getOutputDeviceName(newDevice)));
4237 }
4238 mStreamStates[AudioSystem.STREAM_MUSIC].mute(false);
4239 }
4240 }
4241 }
4242
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004243 ///////////////////////////////////////////////////////////////////////////
4244 // Inner classes
4245 ///////////////////////////////////////////////////////////////////////////
4246
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004247 // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
4248 // 1 mScoclient OR mSafeMediaVolumeState
4249 // 2 mSetModeDeathHandlers
4250 // 3 mSettingsLock
4251 // 4 VolumeStreamState.class
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004252 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004253 private final int mStreamType;
John Spurlockb6e19e32015-03-10 21:33:44 -04004254 private final int mIndexMin;
4255 private final int mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004256
RoboErik4197cb62015-01-21 15:45:32 -08004257 private boolean mIsMuted;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07004258 private String mVolumeIndexSettingName;
John Spurlock8a52c442015-03-26 14:23:58 -04004259 private int mObservedDevices;
John Spurlockb6e19e32015-03-10 21:33:44 -04004260
John Spurlock2bb02ec2015-03-02 13:13:06 -05004261 private final SparseIntArray mIndexMap = new SparseIntArray(8);
John Spurlockf63860c2015-02-19 09:46:27 -05004262 private final Intent mVolumeChanged;
John Spurlock8a52c442015-03-26 14:23:58 -04004263 private final Intent mStreamDevicesChanged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004264
Eric Laurenta553c252009-07-17 12:17:14 -07004265 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004266
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004267 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004268
4269 mStreamType = streamType;
John Spurlockb6e19e32015-03-10 21:33:44 -04004270 mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;
4271 mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;
4272 AudioSystem.initStreamVolume(streamType, mIndexMin / 10, mIndexMax / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004273
Eric Laurent33902db2012-10-07 16:15:07 -07004274 readSettings();
John Spurlockf63860c2015-02-19 09:46:27 -05004275 mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
4276 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
John Spurlock8a52c442015-03-26 14:23:58 -04004277 mStreamDevicesChanged = new Intent(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
4278 mStreamDevicesChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
4279 }
4280
4281 public int observeDevicesForStream_syncVSS(boolean checkOthers) {
4282 final int devices = AudioSystem.getDevicesForStream(mStreamType);
4283 if (devices == mObservedDevices) {
4284 return devices;
4285 }
4286 final int prevDevices = mObservedDevices;
4287 mObservedDevices = devices;
4288 if (checkOthers) {
4289 // one stream's devices have changed, check the others
4290 observeDevicesForStreams(mStreamType);
4291 }
4292 // log base stream changes to the event log
4293 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
4294 EventLogTags.writeStreamDevicesChanged(mStreamType, prevDevices, devices);
4295 }
4296 sendBroadcastToAll(mStreamDevicesChanged
4297 .putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, prevDevices)
4298 .putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, devices));
4299 return devices;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004300 }
4301
Jean-Michel Trivia53b7052017-04-12 18:27:01 -07004302 public @Nullable String getSettingNameForDevice(int device) {
4303 if (!hasValidSettingsName()) {
4304 return null;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004305 }
Jean-Michel Trivia53b7052017-04-12 18:27:01 -07004306 final String suffix = AudioSystem.getOutputDeviceName(device);
4307 if (suffix.isEmpty()) {
4308 return mVolumeIndexSettingName;
4309 }
4310 return mVolumeIndexSettingName + "_" + suffix;
4311 }
4312
4313 private boolean hasValidSettingsName() {
4314 return (mVolumeIndexSettingName != null && !mVolumeIndexSettingName.isEmpty());
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07004315 }
4316
Eric Laurentfdbee862014-05-12 15:26:12 -07004317 public void readSettings() {
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004318 synchronized (mSettingsLock) {
4319 synchronized (VolumeStreamState.class) {
4320 // force maximum volume on all streams if fixed volume property is set
4321 if (mUseFixedVolume) {
4322 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
4323 return;
4324 }
4325 // do not read system stream volume from settings: this stream is always aliased
4326 // to another stream type and its volume is never persisted. Values in settings can
4327 // only be stale values
4328 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
4329 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
4330 int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
Eric Laurentfdbee862014-05-12 15:26:12 -07004331 if (mCameraSoundForced) {
4332 index = mIndexMax;
4333 }
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004334 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
4335 return;
Eric Laurentdd45d012012-10-08 09:04:34 -07004336 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004337 }
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004338 }
4339 synchronized (VolumeStreamState.class) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004340 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
4341
4342 for (int i = 0; remainingDevices != 0; i++) {
4343 int device = (1 << i);
4344 if ((device & remainingDevices) == 0) {
4345 continue;
4346 }
4347 remainingDevices &= ~device;
4348
4349 // retrieve current volume for device
Eric Laurentfdbee862014-05-12 15:26:12 -07004350 // if no volume stored for current stream and device, use default volume if default
4351 // device, continue otherwise
4352 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
John Spurlock61560172015-02-06 19:46:04 -05004353 AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
Jean-Michel Trivia53b7052017-04-12 18:27:01 -07004354 int index;
4355 if (!hasValidSettingsName()) {
4356 index = defaultIndex;
4357 } else {
4358 String name = getSettingNameForDevice(device);
4359 index = Settings.System.getIntForUser(
4360 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
4361 }
Eric Laurentfdbee862014-05-12 15:26:12 -07004362 if (index == -1) {
4363 continue;
4364 }
4365
John Spurlock2bb02ec2015-03-02 13:13:06 -05004366 mIndexMap.put(device, getValidIndex(10 * index));
Eric Laurentdd45d012012-10-08 09:04:34 -07004367 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004368 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004369 }
4370
Liejun Tao39fb5672016-03-09 15:52:13 -06004371 private int getAbsoluteVolumeIndex(int index) {
4372 /* Special handling for Bluetooth Absolute Volume scenario
4373 * If we send full audio gain, some accessories are too loud even at its lowest
4374 * volume. We are not able to enumerate all such accessories, so here is the
4375 * workaround from phone side.
4376 * Pre-scale volume at lowest volume steps 1 2 and 3.
4377 * For volume step 0, set audio gain to 0 as some accessories won't mute on their end.
4378 */
4379 if (index == 0) {
4380 // 0% for volume 0
4381 index = 0;
4382 } else if (index == 1) {
4383 // 50% for volume 1
4384 index = (int)(mIndexMax * 0.5) /10;
4385 } else if (index == 2) {
4386 // 70% for volume 2
4387 index = (int)(mIndexMax * 0.70) /10;
4388 } else if (index == 3) {
4389 // 85% for volume 3
4390 index = (int)(mIndexMax * 0.85) /10;
4391 } else {
4392 // otherwise, full gain
4393 index = (mIndexMax + 5)/10;
4394 }
4395 return index;
4396 }
4397
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004398 // must be called while synchronized VolumeStreamState.class
4399 public void applyDeviceVolume_syncVSS(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07004400 int index;
RoboErik4197cb62015-01-21 15:45:32 -08004401 if (mIsMuted) {
Eric Laurent42b041e2013-03-29 11:36:03 -07004402 index = 0;
Liejun Tao4565a472016-01-20 17:52:20 -06004403 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) {
Liejun Tao39fb5672016-03-09 15:52:13 -06004404 index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
Liejun Tao4565a472016-01-20 17:52:20 -06004405 } else if ((device & mFullVolumeDevices) != 0) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004406 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07004407 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07004408 index = (getIndex(device) + 5)/10;
4409 }
4410 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004411 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004412
Eric Laurentfdbee862014-05-12 15:26:12 -07004413 public void applyAllVolumes() {
4414 synchronized (VolumeStreamState.class) {
Eric Laurentd9ac2be2016-04-07 14:04:23 -07004415 // apply device specific volumes first
Eric Laurentfdbee862014-05-12 15:26:12 -07004416 int index;
John Spurlock2bb02ec2015-03-02 13:13:06 -05004417 for (int i = 0; i < mIndexMap.size(); i++) {
Eric Laurentd9ac2be2016-04-07 14:04:23 -07004418 final int device = mIndexMap.keyAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07004419 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
RoboErik4197cb62015-01-21 15:45:32 -08004420 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004421 index = 0;
Liejun Tao39fb5672016-03-09 15:52:13 -06004422 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
4423 mAvrcpAbsVolSupported) {
4424 index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
4425 } else if ((device & mFullVolumeDevices) != 0) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004426 index = (mIndexMax + 5)/10;
4427 } else {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004428 index = (mIndexMap.valueAt(i) + 5)/10;
Eric Laurentfdbee862014-05-12 15:26:12 -07004429 }
4430 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07004431 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004432 }
Eric Laurentd9ac2be2016-04-07 14:04:23 -07004433 // apply default volume last: by convention , default device volume will be used
4434 // by audio policy manager if no explicit volume is present for a given device type
4435 if (mIsMuted) {
4436 index = 0;
4437 } else {
4438 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
4439 }
4440 AudioSystem.setStreamVolumeIndex(
4441 mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004442 }
4443 }
4444
John Spurlock90874332015-03-10 16:00:54 -04004445 public boolean adjustIndex(int deltaIndex, int device, String caller) {
4446 return setIndex(getIndex(device) + deltaIndex, device, caller);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004447 }
4448
John Spurlock90874332015-03-10 16:00:54 -04004449 public boolean setIndex(int index, int device, String caller) {
John Spurlockf63860c2015-02-19 09:46:27 -05004450 boolean changed = false;
4451 int oldIndex;
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004452 synchronized (mSettingsLock) {
4453 synchronized (VolumeStreamState.class) {
4454 oldIndex = getIndex(device);
4455 index = getValidIndex(index);
Eric Laurentfdbee862014-05-12 15:26:12 -07004456 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
4457 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07004458 }
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004459 mIndexMap.put(device, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07004460
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004461 changed = oldIndex != index;
4462 // Apply change to all streams using this one as alias if:
4463 // - the index actually changed OR
4464 // - there is no volume index stored for this device on alias stream.
4465 // If changing volume of current device, also change volume of current
4466 // device on aliased stream
4467 final boolean currentDevice = (device == getDeviceForStream(mStreamType));
4468 final int numStreamTypes = AudioSystem.getNumStreamTypes();
4469 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4470 final VolumeStreamState aliasStreamState = mStreamStates[streamType];
4471 if (streamType != mStreamType &&
4472 mStreamVolumeAlias[streamType] == mStreamType &&
4473 (changed || !aliasStreamState.hasIndexForDevice(device))) {
4474 final int scaledIndex = rescaleIndex(index, mStreamType, streamType);
4475 aliasStreamState.setIndex(scaledIndex, device, caller);
4476 if (currentDevice) {
4477 aliasStreamState.setIndex(scaledIndex,
4478 getDeviceForStream(streamType), caller);
4479 }
Eric Laurentfdbee862014-05-12 15:26:12 -07004480 }
4481 }
Eric Laurentfdbee862014-05-12 15:26:12 -07004482 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004483 }
John Spurlockf63860c2015-02-19 09:46:27 -05004484 if (changed) {
4485 oldIndex = (oldIndex + 5) / 10;
4486 index = (index + 5) / 10;
John Spurlock90874332015-03-10 16:00:54 -04004487 // log base stream changes to the event log
4488 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
4489 if (caller == null) {
4490 Log.w(TAG, "No caller for volume_changed event", new Throwable());
4491 }
4492 EventLogTags.writeVolumeChanged(mStreamType, oldIndex, index, mIndexMax / 10,
4493 caller);
4494 }
4495 // fire changed intents for all streams
John Spurlockf63860c2015-02-19 09:46:27 -05004496 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
4497 mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
Jean-Michel Trivi560877d2015-06-25 17:38:35 -07004498 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
4499 mStreamVolumeAlias[mStreamType]);
John Spurlockf63860c2015-02-19 09:46:27 -05004500 sendBroadcastToAll(mVolumeChanged);
4501 }
4502 return changed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004503 }
4504
Eric Laurentfdbee862014-05-12 15:26:12 -07004505 public int getIndex(int device) {
4506 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004507 int index = mIndexMap.get(device, -1);
4508 if (index == -1) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004509 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
John Spurlock2bb02ec2015-03-02 13:13:06 -05004510 index = mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurentfdbee862014-05-12 15:26:12 -07004511 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05004512 return index;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004513 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07004514 }
4515
Eric Laurent3fb608e2016-11-03 16:27:40 -07004516 public boolean hasIndexForDevice(int device) {
4517 synchronized (VolumeStreamState.class) {
4518 return (mIndexMap.get(device, -1) != -1);
4519 }
4520 }
4521
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004522 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07004523 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004524 }
4525
John Spurlockb6e19e32015-03-10 21:33:44 -04004526 public int getMinIndex() {
4527 return mIndexMin;
4528 }
4529
Jean-Michel Trivi170a0ee2017-04-14 18:13:26 -07004530 /**
4531 * Copies all device/index pairs from the given VolumeStreamState after initializing
4532 * them with the volume for DEVICE_OUT_DEFAULT. No-op if the source VolumeStreamState
4533 * has the same stream type as this instance.
4534 * @param srcStream
4535 * @param caller
4536 */
John Spurlock90874332015-03-10 16:00:54 -04004537 public void setAllIndexes(VolumeStreamState srcStream, String caller) {
Jean-Michel Trivi170a0ee2017-04-14 18:13:26 -07004538 if (mStreamType == srcStream.mStreamType) {
4539 return;
4540 }
Jean-Michel Triviad37c2c2018-01-19 09:40:36 -08004541 synchronized (mSettingsLock) {
4542 synchronized (VolumeStreamState.class) {
4543 int srcStreamType = srcStream.getStreamType();
4544 // apply default device volume from source stream to all devices first in case
4545 // some devices are present in this stream state but not in source stream state
4546 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurentfdbee862014-05-12 15:26:12 -07004547 index = rescaleIndex(index, srcStreamType, mStreamType);
Jean-Michel Triviad37c2c2018-01-19 09:40:36 -08004548 for (int i = 0; i < mIndexMap.size(); i++) {
4549 mIndexMap.put(mIndexMap.keyAt(i), index);
4550 }
4551 // Now apply actual volume for devices in source stream state
4552 SparseIntArray srcMap = srcStream.mIndexMap;
4553 for (int i = 0; i < srcMap.size(); i++) {
4554 int device = srcMap.keyAt(i);
4555 index = srcMap.valueAt(i);
4556 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07004557
Jean-Michel Triviad37c2c2018-01-19 09:40:36 -08004558 setIndex(index, device, caller);
4559 }
Eric Laurentfdbee862014-05-12 15:26:12 -07004560 }
Eric Laurent6d517662012-04-23 18:42:39 -07004561 }
4562 }
4563
Jean-Michel Triviad37c2c2018-01-19 09:40:36 -08004564 @GuardedBy("mSettingsLock")
Eric Laurentfdbee862014-05-12 15:26:12 -07004565 public void setAllIndexesToMax() {
4566 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004567 for (int i = 0; i < mIndexMap.size(); i++) {
4568 mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07004569 }
Eric Laurentdd45d012012-10-08 09:04:34 -07004570 }
Eric Laurentdd45d012012-10-08 09:04:34 -07004571 }
4572
RoboErik4197cb62015-01-21 15:45:32 -08004573 public void mute(boolean state) {
John Spurlock22b9ee12015-02-18 22:51:44 -05004574 boolean changed = false;
Eric Laurentfdbee862014-05-12 15:26:12 -07004575 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08004576 if (state != mIsMuted) {
John Spurlock22b9ee12015-02-18 22:51:44 -05004577 changed = true;
RoboErik4197cb62015-01-21 15:45:32 -08004578 mIsMuted = state;
John Spurlock22b9ee12015-02-18 22:51:44 -05004579
RoboErik4197cb62015-01-21 15:45:32 -08004580 // Set the new mute volume. This propagates the values to
4581 // the audio system, otherwise the volume won't be changed
4582 // at the lower level.
4583 sendMsg(mAudioHandler,
4584 MSG_SET_ALL_VOLUMES,
4585 SENDMSG_QUEUE,
4586 0,
4587 0,
4588 this, 0);
Eric Laurentfdbee862014-05-12 15:26:12 -07004589 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004590 }
John Spurlock22b9ee12015-02-18 22:51:44 -05004591 if (changed) {
4592 // Stream mute changed, fire the intent.
4593 Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
4594 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
4595 intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
4596 sendBroadcastToAll(intent);
4597 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004598 }
4599
Eric Laurent6d517662012-04-23 18:42:39 -07004600 public int getStreamType() {
4601 return mStreamType;
4602 }
4603
Eric Laurent212532b2014-07-21 15:43:18 -07004604 public void checkFixedVolumeDevices() {
4605 synchronized (VolumeStreamState.class) {
4606 // ignore settings for fixed volume devices: volume should always be at max or 0
4607 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004608 for (int i = 0; i < mIndexMap.size(); i++) {
4609 int device = mIndexMap.keyAt(i);
4610 int index = mIndexMap.valueAt(i);
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07004611 if (((device & mFullVolumeDevices) != 0)
4612 || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004613 mIndexMap.put(device, mIndexMax);
Eric Laurent212532b2014-07-21 15:43:18 -07004614 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004615 applyDeviceVolume_syncVSS(device);
Eric Laurent212532b2014-07-21 15:43:18 -07004616 }
4617 }
4618 }
4619 }
4620
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004621 private int getValidIndex(int index) {
John Spurlockb6e19e32015-03-10 21:33:44 -04004622 if (index < mIndexMin) {
4623 return mIndexMin;
John Spurlockee5ad722015-03-03 16:17:21 -05004624 } else if (mUseFixedVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07004625 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004626 }
4627
4628 return index;
4629 }
4630
Eric Laurentbffc3d12012-05-07 17:43:49 -07004631 private void dump(PrintWriter pw) {
RoboErik4197cb62015-01-21 15:45:32 -08004632 pw.print(" Muted: ");
4633 pw.println(mIsMuted);
John Spurlockb6e19e32015-03-10 21:33:44 -04004634 pw.print(" Min: ");
4635 pw.println((mIndexMin + 5) / 10);
John Spurlock2b29bc42014-08-26 16:40:35 -04004636 pw.print(" Max: ");
4637 pw.println((mIndexMax + 5) / 10);
Eric Laurentbffc3d12012-05-07 17:43:49 -07004638 pw.print(" Current: ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05004639 for (int i = 0; i < mIndexMap.size(); i++) {
4640 if (i > 0) {
4641 pw.print(", ");
4642 }
4643 final int device = mIndexMap.keyAt(i);
John Spurlock2b29bc42014-08-26 16:40:35 -04004644 pw.print(Integer.toHexString(device));
4645 final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
4646 : AudioSystem.getOutputDeviceName(device);
4647 if (!deviceName.isEmpty()) {
4648 pw.print(" (");
4649 pw.print(deviceName);
4650 pw.print(")");
4651 }
4652 pw.print(": ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05004653 final int index = (mIndexMap.valueAt(i) + 5) / 10;
John Spurlock2b29bc42014-08-26 16:40:35 -04004654 pw.print(index);
Eric Laurentbffc3d12012-05-07 17:43:49 -07004655 }
John Spurlockb32fc972015-03-05 13:58:00 -05004656 pw.println();
4657 pw.print(" Devices: ");
John Spurlock8a52c442015-03-26 14:23:58 -04004658 final int devices = getDevicesForStream(mStreamType);
John Spurlockb32fc972015-03-05 13:58:00 -05004659 int device, i = 0, n = 0;
John Spurlock1ff1e6e2015-03-09 14:21:20 -04004660 // iterate all devices from 1 to DEVICE_OUT_DEFAULT exclusive
4661 // (the default device is not returned by getDevicesForStream)
4662 while ((device = 1 << i) != AudioSystem.DEVICE_OUT_DEFAULT) {
John Spurlockb32fc972015-03-05 13:58:00 -05004663 if ((devices & device) != 0) {
4664 if (n++ > 0) {
4665 pw.print(", ");
4666 }
4667 pw.print(AudioSystem.getOutputDeviceName(device));
4668 }
4669 i++;
4670 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07004671 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004672 }
4673
4674 /** Thread that handles native AudioSystem control. */
4675 private class AudioSystemThread extends Thread {
4676 AudioSystemThread() {
4677 super("AudioService");
4678 }
4679
4680 @Override
4681 public void run() {
4682 // Set this thread up so the handler will work on it
4683 Looper.prepare();
4684
4685 synchronized(AudioService.this) {
4686 mAudioHandler = new AudioHandler();
4687
4688 // Notify that the handler has been created
4689 AudioService.this.notify();
4690 }
4691
4692 // Listen for volume change requests that are set by VolumePanel
4693 Looper.loop();
4694 }
4695 }
4696
4697 /** Handles internal volume messages in separate volume thread. */
4698 private class AudioHandler extends Handler {
4699
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004700 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004701
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004702 synchronized (VolumeStreamState.class) {
4703 // Apply volume
4704 streamState.applyDeviceVolume_syncVSS(device);
Eric Laurenta553c252009-07-17 12:17:14 -07004705
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004706 // Apply change to all streams using this one as alias
4707 int numStreamTypes = AudioSystem.getNumStreamTypes();
4708 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4709 if (streamType != streamState.mStreamType &&
4710 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
4711 // Make sure volume is also maxed out on A2DP device for aliased stream
4712 // that may have a different device selected
4713 int streamDevice = getDeviceForStream(streamType);
4714 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
4715 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
4716 mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
4717 }
4718 mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
Eric Laurentcd772d02013-10-30 18:31:07 -07004719 }
Eric Laurenta553c252009-07-17 12:17:14 -07004720 }
4721 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004722 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08004723 sendMsg(mAudioHandler,
4724 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08004725 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004726 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07004727 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08004728 streamState,
4729 PERSIST_DELAY);
4730
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004731 }
4732
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004733 private void setAllVolumes(VolumeStreamState streamState) {
4734
4735 // Apply volume
4736 streamState.applyAllVolumes();
4737
4738 // Apply change to all streams using this one as alias
4739 int numStreamTypes = AudioSystem.getNumStreamTypes();
4740 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4741 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07004742 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004743 mStreamStates[streamType].applyAllVolumes();
4744 }
4745 }
4746 }
4747
Eric Laurent42b041e2013-03-29 11:36:03 -07004748 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07004749 if (mUseFixedVolume) {
4750 return;
4751 }
Muyuan Li1ed6df62016-06-18 11:16:52 -07004752 if (mIsSingleVolume && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
Eric Laurent212532b2014-07-21 15:43:18 -07004753 return;
4754 }
Jean-Michel Trivia53b7052017-04-12 18:27:01 -07004755 if (streamState.hasValidSettingsName()) {
4756 System.putIntForUser(mContentResolver,
4757 streamState.getSettingNameForDevice(device),
4758 (streamState.getIndex(device) + 5)/ 10,
4759 UserHandle.USER_CURRENT);
4760 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004761 }
4762
Glenn Kastenba195eb2011-12-13 09:30:40 -08004763 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07004764 if (mUseFixedVolume) {
4765 return;
4766 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07004767 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004768 }
4769
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004770 private boolean onLoadSoundEffects() {
4771 int status;
4772
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004773 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004774 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004775 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
4776 return false;
4777 }
4778
4779 if (mSoundPool != null) {
4780 return true;
4781 }
4782
4783 loadTouchSoundAssets();
4784
Jean-Michel Trivi55a30c42014-07-20 17:56:11 -07004785 mSoundPool = new SoundPool.Builder()
4786 .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
4787 .setAudioAttributes(new AudioAttributes.Builder()
4788 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
4789 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
4790 .build())
4791 .build();
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004792 mSoundPoolCallBack = null;
4793 mSoundPoolListenerThread = new SoundPoolListenerThread();
4794 mSoundPoolListenerThread.start();
4795 int attempts = 3;
4796 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
4797 try {
4798 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07004799 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004800 } catch (InterruptedException e) {
4801 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
4802 }
4803 }
4804
4805 if (mSoundPoolCallBack == null) {
4806 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
4807 if (mSoundPoolLooper != null) {
4808 mSoundPoolLooper.quit();
4809 mSoundPoolLooper = null;
4810 }
4811 mSoundPoolListenerThread = null;
4812 mSoundPool.release();
4813 mSoundPool = null;
4814 return false;
4815 }
4816 /*
4817 * poolId table: The value -1 in this table indicates that corresponding
4818 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
4819 * Once loaded, the value in poolId is the sample ID and the same
4820 * sample can be reused for another effect using the same file.
4821 */
4822 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4823 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4824 poolId[fileIdx] = -1;
4825 }
4826 /*
4827 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
4828 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
4829 * this indicates we have a valid sample loaded for this effect.
4830 */
4831
4832 int numSamples = 0;
4833 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4834 // Do not load sample if this effect uses the MediaPlayer
4835 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
4836 continue;
4837 }
4838 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
4839 String filePath = Environment.getRootDirectory()
4840 + SOUND_EFFECTS_PATH
4841 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
4842 int sampleId = mSoundPool.load(filePath, 0);
4843 if (sampleId <= 0) {
4844 Log.w(TAG, "Soundpool could not load file: "+filePath);
4845 } else {
4846 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
4847 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
4848 numSamples++;
4849 }
4850 } else {
4851 SOUND_EFFECT_FILES_MAP[effect][1] =
4852 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
4853 }
4854 }
4855 // wait for all samples to be loaded
4856 if (numSamples > 0) {
4857 mSoundPoolCallBack.setSamples(poolId);
4858
4859 attempts = 3;
4860 status = 1;
4861 while ((status == 1) && (attempts-- > 0)) {
4862 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07004863 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004864 status = mSoundPoolCallBack.status();
4865 } catch (InterruptedException e) {
4866 Log.w(TAG, "Interrupted while waiting sound pool callback.");
4867 }
4868 }
4869 } else {
4870 status = -1;
4871 }
4872
4873 if (mSoundPoolLooper != null) {
4874 mSoundPoolLooper.quit();
4875 mSoundPoolLooper = null;
4876 }
4877 mSoundPoolListenerThread = null;
4878 if (status != 0) {
4879 Log.w(TAG,
4880 "onLoadSoundEffects(), Error "+status+ " while loading samples");
4881 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4882 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
4883 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4884 }
4885 }
4886
4887 mSoundPool.release();
4888 mSoundPool = null;
4889 }
4890 }
4891 return (status == 0);
4892 }
4893
4894 /**
4895 * Unloads samples from the sound pool.
4896 * This method can be called to free some memory when
4897 * sound effects are disabled.
4898 */
4899 private void onUnloadSoundEffects() {
4900 synchronized (mSoundEffectsLock) {
4901 if (mSoundPool == null) {
4902 return;
4903 }
4904
4905 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4906 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4907 poolId[fileIdx] = 0;
4908 }
4909
4910 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4911 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
4912 continue;
4913 }
4914 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
4915 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
4916 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4917 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
4918 }
4919 }
4920 mSoundPool.release();
4921 mSoundPool = null;
4922 }
4923 }
4924
4925 private void onPlaySoundEffect(int effectType, int volume) {
4926 synchronized (mSoundEffectsLock) {
4927
4928 onLoadSoundEffects();
4929
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004930 if (mSoundPool == null) {
4931 return;
4932 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004933 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08004934 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004935 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07004936 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004937 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07004938 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004939 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004940
4941 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004942 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
4943 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004944 } else {
4945 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004946 try {
Eric Laurente78fced2013-03-15 16:03:47 -07004947 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
4948 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004949 mediaPlayer.setDataSource(filePath);
4950 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
4951 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08004952 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004953 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
4954 public void onCompletion(MediaPlayer mp) {
4955 cleanupPlayer(mp);
4956 }
4957 });
4958 mediaPlayer.setOnErrorListener(new OnErrorListener() {
4959 public boolean onError(MediaPlayer mp, int what, int extra) {
4960 cleanupPlayer(mp);
4961 return true;
4962 }
4963 });
4964 mediaPlayer.start();
4965 } catch (IOException ex) {
4966 Log.w(TAG, "MediaPlayer IOException: "+ex);
4967 } catch (IllegalArgumentException ex) {
4968 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
4969 } catch (IllegalStateException ex) {
4970 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004971 }
4972 }
4973 }
4974 }
4975
4976 private void cleanupPlayer(MediaPlayer mp) {
4977 if (mp != null) {
4978 try {
4979 mp.stop();
4980 mp.release();
4981 } catch (IllegalStateException ex) {
4982 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
4983 }
4984 }
4985 }
4986
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07004987 private void setForceUse(int usage, int config, String eventSource) {
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004988 synchronized (mConnectedDevices) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07004989 setForceUseInt_SyncDevices(usage, config, eventSource);
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004990 }
Eric Laurentfa640152011-03-12 15:59:51 -08004991 }
4992
Eric Laurent05274f32012-11-29 12:48:18 -08004993 private void onPersistSafeVolumeState(int state) {
4994 Settings.Global.putInt(mContentResolver,
4995 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
4996 state);
4997 }
4998
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004999 @Override
5000 public void handleMessage(Message msg) {
Eric Laurentafbb0472011-12-15 09:04:23 -08005001 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005002
Eric Laurent9bc8358d2011-11-18 16:43:31 -08005003 case MSG_SET_DEVICE_VOLUME:
5004 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
5005 break;
5006
5007 case MSG_SET_ALL_VOLUMES:
5008 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005009 break;
5010
5011 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07005012 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005013 break;
5014
5015 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08005016 // note that the value persisted is the current ringer mode, not the
5017 // value of ringer mode as of the time the request was made to persist
John Spurlock661f2cf2014-11-17 10:29:10 -05005018 persistRingerMode(getRingerModeInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005019 break;
5020
Andy Hunged0ea402015-10-30 14:11:46 -07005021 case MSG_AUDIO_SERVER_DIED:
5022 onAudioServerDied();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005023 break;
5024
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07005025 case MSG_UNLOAD_SOUND_EFFECTS:
5026 onUnloadSoundEffects();
5027 break;
5028
Eric Laurent117b7bb2011-01-16 17:07:27 -08005029 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07005030 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
5031 // can take several dozens of milliseconds to complete
5032 boolean loaded = onLoadSoundEffects();
5033 if (msg.obj != null) {
5034 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
5035 synchronized (reply) {
5036 reply.mStatus = loaded ? 0 : -1;
5037 reply.notify();
5038 }
5039 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08005040 break;
5041
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005042 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07005043 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005044 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005045
5046 case MSG_BTA2DP_DOCK_TIMEOUT:
5047 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005048 synchronized (mConnectedDevices) {
5049 makeA2dpDeviceUnavailableNow( (String) msg.obj );
5050 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005051 break;
Eric Laurentfa640152011-03-12 15:59:51 -08005052
5053 case MSG_SET_FORCE_USE:
Sungsoocf09fe62016-09-28 16:21:48 +09005054 case MSG_SET_FORCE_BT_A2DP_USE:
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005055 setForceUse(msg.arg1, msg.arg2, (String) msg.obj);
Eric Laurentfa640152011-03-12 15:59:51 -08005056 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07005057
Eric Laurentdc03c612011-04-01 10:59:41 -07005058 case MSG_BT_HEADSET_CNCT_FAILED:
5059 resetBluetoothSco();
5060 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005061
5062 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
Paul McLean10804eb2015-01-28 11:16:35 -08005063 { WiredDeviceConnectionState connectState =
5064 (WiredDeviceConnectionState)msg.obj;
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005065 mWiredDevLogger.log(new WiredDevConnectEvent(connectState));
Paul McLean10804eb2015-01-28 11:16:35 -08005066 onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
John Spurlock90874332015-03-10 16:00:54 -04005067 connectState.mAddress, connectState.mName, connectState.mCaller);
Paul McLean10804eb2015-01-28 11:16:35 -08005068 mAudioEventWakeLock.release();
5069 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005070 break;
5071
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005072 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
5073 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
5074 mAudioEventWakeLock.release();
5075 break;
5076
5077 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
5078 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005079 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005080 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07005081
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005082 case MSG_A2DP_DEVICE_CONFIG_CHANGE:
5083 onBluetoothA2dpDeviceConfigChange((BluetoothDevice)msg.obj);
5084 mAudioEventWakeLock.release();
5085 break;
5086
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -07005087 case MSG_DISABLE_AUDIO_FOR_UID:
5088 mPlaybackMonitor.disableAudioForUid( msg.arg1 == 1 /* disable */,
5089 msg.arg2 /* uid */);
5090 mAudioEventWakeLock.release();
5091 break;
5092
Dianne Hackborn632ca412012-06-14 19:34:10 -07005093 case MSG_REPORT_NEW_ROUTES: {
5094 int N = mRoutesObservers.beginBroadcast();
5095 if (N > 0) {
5096 AudioRoutesInfo routes;
5097 synchronized (mCurAudioRoutes) {
5098 routes = new AudioRoutesInfo(mCurAudioRoutes);
5099 }
5100 while (N > 0) {
5101 N--;
5102 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
5103 try {
5104 obs.dispatchAudioRoutesChanged(routes);
5105 } catch (RemoteException e) {
5106 }
5107 }
5108 }
5109 mRoutesObservers.finishBroadcast();
John Spurlock8a52c442015-03-26 14:23:58 -04005110 observeDevicesForStreams(-1);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005111 break;
5112 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005113
Eric Laurentc34dcc12012-09-10 13:51:52 -07005114 case MSG_CHECK_MUSIC_ACTIVE:
John Spurlock90874332015-03-10 16:00:54 -04005115 onCheckMusicActive((String) msg.obj);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005116 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07005117
5118 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
5119 onSendBecomingNoisyIntent();
5120 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07005121
5122 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
5123 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
John Spurlock90874332015-03-10 16:00:54 -04005124 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED),
5125 (String) msg.obj);
Eric Laurentd640bd32012-09-28 18:01:48 -07005126 break;
Eric Laurent05274f32012-11-29 12:48:18 -08005127 case MSG_PERSIST_SAFE_VOLUME_STATE:
5128 onPersistSafeVolumeState(msg.arg1);
5129 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08005130
Eric Laurent2a57ca92013-03-07 17:29:27 -08005131 case MSG_BROADCAST_BT_CONNECTION_STATE:
5132 onBroadcastScoConnectionState(msg.arg1);
5133 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07005134
5135 case MSG_SYSTEM_READY:
5136 onSystemReady();
5137 break;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005138
Eric Laurent0867bed2015-05-20 14:49:08 -07005139 case MSG_INDICATE_SYSTEM_READY:
5140 onIndicateSystemReady();
5141 break;
5142
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07005143 case MSG_ACCESSORY_PLUG_MEDIA_UNMUTE:
5144 onAccessoryPlugMediaUnmute(msg.arg1);
5145 break;
5146
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005147 case MSG_PERSIST_MUSIC_ACTIVE_MS:
5148 final int musicActiveMs = msg.arg1;
5149 Settings.Secure.putIntForUser(mContentResolver,
5150 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
5151 UserHandle.USER_CURRENT);
5152 break;
Eric Laurentc0232482016-03-15 18:19:23 -07005153
RoboErik5452e252015-02-06 15:33:53 -08005154 case MSG_UNMUTE_STREAM:
5155 onUnmuteStream(msg.arg1, msg.arg2);
5156 break;
Eric Laurentc0232482016-03-15 18:19:23 -07005157
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07005158 case MSG_DYN_POLICY_MIX_STATE_UPDATE:
5159 onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1);
5160 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005161 }
5162 }
5163 }
5164
Jason Parekhb1096152009-03-24 17:48:25 -07005165 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07005166
Phil Burked43bf52016-03-01 17:01:35 -08005167 private int mEncodedSurroundMode;
5168
Jason Parekhb1096152009-03-24 17:48:25 -07005169 SettingsObserver() {
5170 super(new Handler());
5171 mContentResolver.registerContentObserver(Settings.System.getUriFor(
5172 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07005173 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
5174 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Andy Hung7b98e9a2016-02-25 18:34:50 -08005175 mContentResolver.registerContentObserver(Settings.System.getUriFor(
5176 Settings.System.MASTER_MONO), false, this);
Phil Burked43bf52016-03-01 17:01:35 -08005177
5178 mEncodedSurroundMode = Settings.Global.getInt(
5179 mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT,
5180 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
5181 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
5182 Settings.Global.ENCODED_SURROUND_OUTPUT), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07005183 }
5184
5185 @Override
5186 public void onChange(boolean selfChange) {
5187 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08005188 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
5189 // However there appear to be some missing locks around mRingerModeMutedStreams
5190 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
5191 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07005192 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07005193 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07005194 /*
5195 * Ensure all stream types that should be affected by ringer mode
5196 * are in the proper state.
5197 */
John Spurlock661f2cf2014-11-17 10:29:10 -05005198 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurenta553c252009-07-17 12:17:14 -07005199 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07005200 readDockAudioSettings(mContentResolver);
Andy Hung7b98e9a2016-02-25 18:34:50 -08005201 updateMasterMono(mContentResolver);
Phil Burked43bf52016-03-01 17:01:35 -08005202 updateEncodedSurroundOutput();
5203 }
5204 }
5205
5206 private void updateEncodedSurroundOutput() {
5207 int newSurroundMode = Settings.Global.getInt(
5208 mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT,
5209 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
5210 // Did it change?
5211 if (mEncodedSurroundMode != newSurroundMode) {
5212 // Send to AudioPolicyManager
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005213 sendEncodedSurroundMode(newSurroundMode, "SettingsObserver");
Phil Burked43bf52016-03-01 17:01:35 -08005214 synchronized(mConnectedDevices) {
5215 // Is HDMI connected?
5216 String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_HDMI, "");
5217 DeviceListSpec deviceSpec = mConnectedDevices.get(key);
5218 if (deviceSpec != null) {
5219 // Toggle HDMI to retrigger broadcast with proper formats.
5220 setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
5221 AudioSystem.DEVICE_STATE_UNAVAILABLE, "", "",
5222 "android"); // disconnect
5223 setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
5224 AudioSystem.DEVICE_STATE_AVAILABLE, "", "",
5225 "android"); // reconnect
5226 }
5227 }
5228 mEncodedSurroundMode = newSurroundMode;
Eric Laurenta553c252009-07-17 12:17:14 -07005229 }
Jason Parekhb1096152009-03-24 17:48:25 -07005230 }
Jason Parekhb1096152009-03-24 17:48:25 -07005231 }
Eric Laurenta553c252009-07-17 12:17:14 -07005232
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005233 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005234 private void makeA2dpDeviceAvailable(String address, String name, String eventSource) {
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07005235 // enable A2DP before notifying A2DP connection to avoid unnecessary processing in
Eric Laurent78472112012-05-21 08:57:21 -07005236 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07005237 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
5238 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
5239 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005240 setBluetoothA2dpOnInt(true, eventSource);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005241 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07005242 AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005243 // Reset A2DP suspend state each time a new sink is connected
5244 AudioSystem.setParameters("A2dpSuspended=false");
Paul McLean394a8e12015-03-03 10:29:19 -07005245 mConnectedDevices.put(
5246 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
Paul McLean20eec5b2015-05-09 13:02:18 -07005247 new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
Paul McLean394a8e12015-03-03 10:29:19 -07005248 address));
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07005249 sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
5250 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, null, 0);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005251 }
5252
Eric Laurent5bfaeae2012-09-21 18:44:48 -07005253 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005254 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07005255 }
5256
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005257 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005258 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07005259 synchronized (mA2dpAvrcpLock) {
5260 mAvrcpAbsVolSupported = false;
5261 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005262 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07005263 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07005264 mConnectedDevices.remove(
5265 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
RoboErik5535ea82014-09-25 14:53:16 -07005266 synchronized (mCurAudioRoutes) {
5267 // Remove A2DP routes as well
John Spurlock61560172015-02-06 19:46:04 -05005268 if (mCurAudioRoutes.bluetoothName != null) {
5269 mCurAudioRoutes.bluetoothName = null;
RoboErik5535ea82014-09-25 14:53:16 -07005270 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
5271 SENDMSG_NOOP, 0, 0, null, 0);
5272 }
5273 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005274 }
5275
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005276 // must be called synchronized on mConnectedDevices
Eric Laurentd138e4e2015-05-15 16:41:15 -07005277 private void makeA2dpDeviceUnavailableLater(String address, int delayMs) {
Eric Laurent3b591262010-04-20 07:01:00 -07005278 // prevent any activity on the A2DP audio output to avoid unwanted
5279 // reconnection of the sink.
5280 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005281 // the device will be made unavailable later, so consider it disconnected right away
Paul McLean394a8e12015-03-03 10:29:19 -07005282 mConnectedDevices.remove(
5283 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005284 // send the delayed message to make the device unavailable later
5285 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
Eric Laurentd138e4e2015-05-15 16:41:15 -07005286 mAudioHandler.sendMessageDelayed(msg, delayMs);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005287
5288 }
5289
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005290 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005291 private void makeA2dpSrcAvailable(String address) {
5292 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07005293 AudioSystem.DEVICE_STATE_AVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07005294 mConnectedDevices.put(
5295 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
Paul McLean20eec5b2015-05-09 13:02:18 -07005296 new DeviceListSpec(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "",
Paul McLean394a8e12015-03-03 10:29:19 -07005297 address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005298 }
5299
5300 // must be called synchronized on mConnectedDevices
5301 private void makeA2dpSrcUnavailable(String address) {
5302 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07005303 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07005304 mConnectedDevices.remove(
5305 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005306 }
5307
5308 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07005309 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005310 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
5311 }
5312
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005313 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07005314 private boolean hasScheduledA2dpDockTimeout() {
5315 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
5316 }
5317
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005318 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005319 {
Eric Laurent4724ea72017-05-23 10:39:38 -07005320 if (DEBUG_DEVICES) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005321 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice+"state=" + state);
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005322 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005323 if (btDevice == null) {
5324 return;
5325 }
5326 String address = btDevice.getAddress();
5327 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
5328 address = "";
5329 }
John Du5a0cf7a2013-07-19 11:30:34 -07005330
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005331 synchronized (mConnectedDevices) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005332 final String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
5333 btDevice.getAddress());
5334 final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
Paul McLean394a8e12015-03-03 10:29:19 -07005335 boolean isConnected = deviceSpec != null;
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005336
5337 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
5338 if (btDevice.isBluetoothDock()) {
5339 if (state == BluetoothProfile.STATE_DISCONNECTED) {
5340 // introduction of a delay for transient disconnections of docks when
5341 // power is rapidly turned off/on, this message will be canceled if
5342 // we reconnect the dock under a preset delay
Eric Laurentd138e4e2015-05-15 16:41:15 -07005343 makeA2dpDeviceUnavailableLater(address, BTA2DP_DOCK_TIMEOUT_MILLIS);
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005344 // the next time isConnected is evaluated, it will be false for the dock
5345 }
5346 } else {
5347 makeA2dpDeviceUnavailableNow(address);
5348 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07005349 synchronized (mCurAudioRoutes) {
John Spurlock61560172015-02-06 19:46:04 -05005350 if (mCurAudioRoutes.bluetoothName != null) {
5351 mCurAudioRoutes.bluetoothName = null;
Dianne Hackborn632ca412012-06-14 19:34:10 -07005352 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
5353 SENDMSG_NOOP, 0, 0, null, 0);
5354 }
5355 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005356 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
5357 if (btDevice.isBluetoothDock()) {
5358 // this could be a reconnection after a transient disconnection
5359 cancelA2dpDeviceTimeout();
5360 mDockAddress = address;
5361 } else {
5362 // this could be a connection of another A2DP device before the timeout of
5363 // a dock: cancel the dock timeout, and make the dock unavailable now
5364 if(hasScheduledA2dpDockTimeout()) {
5365 cancelA2dpDeviceTimeout();
5366 makeA2dpDeviceUnavailableNow(mDockAddress);
5367 }
5368 }
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005369 makeA2dpDeviceAvailable(address, btDevice.getName(),
5370 "onSetA2dpSinkConnectionState");
Dianne Hackborn632ca412012-06-14 19:34:10 -07005371 synchronized (mCurAudioRoutes) {
5372 String name = btDevice.getAliasName();
John Spurlock61560172015-02-06 19:46:04 -05005373 if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
5374 mCurAudioRoutes.bluetoothName = name;
Dianne Hackborn632ca412012-06-14 19:34:10 -07005375 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
5376 SENDMSG_NOOP, 0, 0, null, 0);
5377 }
5378 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005379 }
5380 }
5381 }
5382
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005383 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
5384 {
5385 if (DEBUG_VOL) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005386 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice=" + btDevice + " state=" + state);
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005387 }
5388 if (btDevice == null) {
5389 return;
5390 }
5391 String address = btDevice.getAddress();
5392 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
5393 address = "";
5394 }
5395
5396 synchronized (mConnectedDevices) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005397 final String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
5398 final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
Paul McLean394a8e12015-03-03 10:29:19 -07005399 boolean isConnected = deviceSpec != null;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005400
5401 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
5402 makeA2dpSrcUnavailable(address);
5403 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
5404 makeA2dpSrcAvailable(address);
5405 }
5406 }
5407 }
5408
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005409 private void onBluetoothA2dpDeviceConfigChange(BluetoothDevice btDevice)
5410 {
Eric Laurent5205a352017-04-27 18:31:22 -07005411 if (DEBUG_DEVICES) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005412 Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice);
5413 }
5414 if (btDevice == null) {
5415 return;
5416 }
5417 String address = btDevice.getAddress();
5418 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
5419 address = "";
5420 }
5421
5422 int device = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
5423 synchronized (mConnectedDevices) {
Eric Laurent4724ea72017-05-23 10:39:38 -07005424 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, btDevice)) {
Eric Laurentcdae4762017-04-28 18:00:04 -07005425 return;
5426 }
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005427 final String key = makeDeviceListKey(device, address);
5428 final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
5429 if (deviceSpec != null) {
5430 // Device is connected
Eric Laurentcdae4762017-04-28 18:00:04 -07005431 int musicDevice = getDeviceForStream(AudioSystem.STREAM_MUSIC);
Eric Laurent5205a352017-04-27 18:31:22 -07005432 if (AudioSystem.handleDeviceConfigChange(device, address,
5433 btDevice.getName()) != AudioSystem.AUDIO_STATUS_OK) {
5434 // force A2DP device disconnection in case of error so that AudioService state is
5435 // consistent with audio policy manager state
Eric Laurentcdae4762017-04-28 18:00:04 -07005436 setBluetoothA2dpDeviceConnectionStateInt(
5437 btDevice, BluetoothA2dp.STATE_DISCONNECTED, BluetoothProfile.A2DP,
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005438 false /* suppressNoisyIntent */, musicDevice);
Eric Laurent5205a352017-04-27 18:31:22 -07005439 }
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005440 }
5441 }
5442 }
5443
John Du5a0cf7a2013-07-19 11:30:34 -07005444 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
5445 // address is not used for now, but may be used when multiple a2dp devices are supported
5446 synchronized (mA2dpAvrcpLock) {
5447 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07005448 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07005449 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
5450 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
5451 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
5452 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
5453 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07005454 }
5455 }
5456
Paul McLean394a8e12015-03-03 10:29:19 -07005457 private boolean handleDeviceConnection(boolean connect, int device, String address,
5458 String deviceName) {
5459 if (DEBUG_DEVICES) {
5460 Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device)
5461 + " address:" + address + " name:" + deviceName + ")");
5462 }
Eric Laurent59f48272012-04-05 19:42:21 -07005463 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07005464 String deviceKey = makeDeviceListKey(device, address);
5465 if (DEBUG_DEVICES) {
5466 Slog.i(TAG, "deviceKey:" + deviceKey);
5467 }
5468 DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
5469 boolean isConnected = deviceSpec != null;
5470 if (DEBUG_DEVICES) {
5471 Slog.i(TAG, "deviceSpec:" + deviceSpec + " is(already)Connected:" + isConnected);
5472 }
5473 if (connect && !isConnected) {
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07005474 final int res = AudioSystem.setDeviceConnectionState(device,
5475 AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);
5476 if (res != AudioSystem.AUDIO_STATUS_OK) {
5477 Slog.e(TAG, "not connecting device 0x" + Integer.toHexString(device) +
5478 " due to command error " + res );
5479 return false;
5480 }
Paul McLean394a8e12015-03-03 10:29:19 -07005481 mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07005482 sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
5483 device, 0, null, 0);
Paul McLean394a8e12015-03-03 10:29:19 -07005484 return true;
5485 } else if (!connect && isConnected) {
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07005486 AudioSystem.setDeviceConnectionState(device,
5487 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName);
5488 // always remove even if disconnection failed
Paul McLean394a8e12015-03-03 10:29:19 -07005489 mConnectedDevices.remove(deviceKey);
5490 return true;
Eric Laurent59f48272012-04-05 19:42:21 -07005491 }
5492 }
5493 return false;
5494 }
5495
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005496 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
Eric Laurent9a5b2622017-04-18 18:20:56 -07005497 // sent if:
5498 // - none of these devices are connected anymore after one is disconnected AND
5499 // - the device being disconnected is actually used for music.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005500 // Access synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005501 int mBecomingNoisyIntentDevices =
5502 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07005503 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07005504 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Jon Eklund43cc8bb2014-07-28 16:07:24 -05005505 AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005506
5507 // must be called before removing the device from mConnectedDevices
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005508 // Called synchronized on mConnectedDevices
Eric Laurentcdae4762017-04-28 18:00:04 -07005509 // musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying
5510 // from AudioSystem
5511 private int checkSendBecomingNoisyIntent(int device, int state, int musicDevice) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005512 int delay = 0;
5513 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
5514 int devices = 0;
John Spurlock8c3dc852015-04-23 21:32:37 -04005515 for (int i = 0; i < mConnectedDevices.size(); i++) {
5516 int dev = mConnectedDevices.valueAt(i).mDeviceType;
Paul McLean394a8e12015-03-03 10:29:19 -07005517 if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
5518 && ((dev & mBecomingNoisyIntentDevices) != 0)) {
5519 devices |= dev;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005520 }
5521 }
Eric Laurentcdae4762017-04-28 18:00:04 -07005522 if (musicDevice == AudioSystem.DEVICE_NONE) {
5523 musicDevice = getDeviceForStream(AudioSystem.STREAM_MUSIC);
5524 }
5525 // ignore condition on device being actually used for music when in communication
5526 // because music routing is altered in this case.
5527 if (((device == musicDevice) || isInCommunication()) && (device == devices)) {
5528 mAudioHandler.removeMessages(MSG_BROADCAST_AUDIO_BECOMING_NOISY);
Eric Laurent5bfaeae2012-09-21 18:44:48 -07005529 sendMsg(mAudioHandler,
5530 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
5531 SENDMSG_REPLACE,
5532 0,
5533 0,
5534 null,
5535 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005536 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005537 }
5538 }
5539
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005540 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
5541 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005542 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
Eric Laurentadbe8bf2014-11-03 18:26:32 -08005543 synchronized (mLastDeviceConnectMsgTime) {
5544 long time = SystemClock.uptimeMillis();
5545 if (mLastDeviceConnectMsgTime > time) {
Matthew Xiec525cf72015-01-22 20:13:17 -08005546 delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
Eric Laurentadbe8bf2014-11-03 18:26:32 -08005547 }
5548 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005549 }
5550 return delay;
5551 }
5552
Eric Laurenteab40d12017-06-09 12:45:21 -07005553 private void updateAudioRoutes(int device, int state)
5554 {
Dianne Hackborn632ca412012-06-14 19:34:10 -07005555 int connType = 0;
5556
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005557 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07005558 connType = AudioRoutesInfo.MAIN_HEADSET;
Jon Eklund43cc8bb2014-07-28 16:07:24 -05005559 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
5560 device == AudioSystem.DEVICE_OUT_LINE) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07005561 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurent6fa42452015-01-09 15:09:40 -08005562 } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
5563 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07005564 connType = AudioRoutesInfo.MAIN_HDMI;
Eric Laurenteab40d12017-06-09 12:45:21 -07005565 } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE||
5566 device == AudioSystem.DEVICE_OUT_USB_HEADSET) {
Paul McLean10804eb2015-01-28 11:16:35 -08005567 connType = AudioRoutesInfo.MAIN_USB;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005568 }
5569
Dianne Hackborn632ca412012-06-14 19:34:10 -07005570 synchronized (mCurAudioRoutes) {
5571 if (connType != 0) {
John Spurlock61560172015-02-06 19:46:04 -05005572 int newConn = mCurAudioRoutes.mainType;
Dianne Hackborn632ca412012-06-14 19:34:10 -07005573 if (state != 0) {
5574 newConn |= connType;
5575 } else {
5576 newConn &= ~connType;
5577 }
John Spurlock61560172015-02-06 19:46:04 -05005578 if (newConn != mCurAudioRoutes.mainType) {
5579 mCurAudioRoutes.mainType = newConn;
Dianne Hackborn632ca412012-06-14 19:34:10 -07005580 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
5581 SENDMSG_NOOP, 0, 0, null, 0);
5582 }
5583 }
5584 }
Eric Laurenteab40d12017-06-09 12:45:21 -07005585 }
5586
5587 private void sendDeviceConnectionIntent(int device, int state, String address,
5588 String deviceName) {
5589 if (DEBUG_DEVICES) {
5590 Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
5591 " state:0x" + Integer.toHexString(state) + " address:" + address +
5592 " name:" + deviceName + ");");
5593 }
5594 Intent intent = new Intent();
5595
5596 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
5597 intent.setAction(Intent.ACTION_HEADSET_PLUG);
5598 intent.putExtra("microphone", 1);
5599 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
5600 device == AudioSystem.DEVICE_OUT_LINE) {
5601 intent.setAction(Intent.ACTION_HEADSET_PLUG);
Jean-Michel Trivi87d31ec2017-08-11 18:28:20 -07005602 intent.putExtra("microphone", 0);
Paul McLean145c9532017-08-04 11:12:19 -06005603 } else if (device == AudioSystem.DEVICE_OUT_USB_HEADSET) {
5604 intent.setAction(Intent.ACTION_HEADSET_PLUG);
Jean-Michel Trivi87d31ec2017-08-11 18:28:20 -07005605 intent.putExtra("microphone",
5606 AudioSystem.getDeviceConnectionState(AudioSystem.DEVICE_IN_USB_HEADSET, "")
5607 == AudioSystem.DEVICE_STATE_AVAILABLE ? 1 : 0);
5608 } else if (device == AudioSystem.DEVICE_IN_USB_HEADSET) {
5609 if (AudioSystem.getDeviceConnectionState(AudioSystem.DEVICE_OUT_USB_HEADSET, "")
5610 == AudioSystem.DEVICE_STATE_AVAILABLE) {
5611 intent.setAction(Intent.ACTION_HEADSET_PLUG);
5612 intent.putExtra("microphone", 1);
5613 } else {
5614 // do not send ACTION_HEADSET_PLUG when only the input side is seen as changing
5615 return;
5616 }
Eric Laurenteab40d12017-06-09 12:45:21 -07005617 } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
5618 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
5619 configureHdmiPlugIntent(intent, state);
5620 }
5621
Jean-Michel Trivi87a264d2017-08-15 17:52:22 -07005622 if (intent.getAction() == null) {
5623 return;
5624 }
5625
Eric Laurenteab40d12017-06-09 12:45:21 -07005626 intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
5627 intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
5628 intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
5629
5630 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005631
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005632 final long ident = Binder.clearCallingIdentity();
5633 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08005634 ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005635 } finally {
5636 Binder.restoreCallingIdentity(ident);
5637 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005638 }
5639
Eric Laurentbbe3e742017-04-28 18:11:50 -07005640 private static final int DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG =
5641 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
5642 AudioSystem.DEVICE_OUT_LINE |
5643 AudioSystem.DEVICE_OUT_ALL_USB;
5644
Paul McLean10804eb2015-01-28 11:16:35 -08005645 private void onSetWiredDeviceConnectionState(int device, int state, String address,
John Spurlock90874332015-03-10 16:00:54 -04005646 String deviceName, String caller) {
Paul McLean394a8e12015-03-03 10:29:19 -07005647 if (DEBUG_DEVICES) {
John Spurlock90874332015-03-10 16:00:54 -04005648 Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
5649 + " state:" + Integer.toHexString(state)
5650 + " address:" + address
5651 + " deviceName:" + deviceName
5652 + " caller: " + caller + ");");
Paul McLean394a8e12015-03-03 10:29:19 -07005653 }
Paul McLean10804eb2015-01-28 11:16:35 -08005654
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005655 synchronized (mConnectedDevices) {
Eric Laurentbbe3e742017-04-28 18:11:50 -07005656 if ((state == 0) && ((device & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0)) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005657 setBluetoothA2dpOnInt(true, "onSetWiredDeviceConnectionState state 0");
Sungsoocf09fe62016-09-28 16:21:48 +09005658 }
Paul McLean145c9532017-08-04 11:12:19 -06005659
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07005660 if (!handleDeviceConnection(state == 1, device, address, deviceName)) {
5661 // change of connection state failed, bailout
5662 return;
5663 }
Eric Laurentf1a457d2012-09-20 16:27:23 -07005664 if (state != 0) {
Eric Laurentbbe3e742017-04-28 18:11:50 -07005665 if ((device & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005666 setBluetoothA2dpOnInt(false, "onSetWiredDeviceConnectionState state not 0");
Sungsoocf09fe62016-09-28 16:21:48 +09005667 }
Eric Laurentf1a457d2012-09-20 16:27:23 -07005668 if ((device & mSafeMediaVolumeDevices) != 0) {
5669 sendMsg(mAudioHandler,
5670 MSG_CHECK_MUSIC_ACTIVE,
5671 SENDMSG_REPLACE,
5672 0,
5673 0,
John Spurlock90874332015-03-10 16:00:54 -04005674 caller,
Eric Laurentf1a457d2012-09-20 16:27:23 -07005675 MUSIC_ACTIVE_POLL_PERIOD_MS);
5676 }
Eric Laurent212532b2014-07-21 15:43:18 -07005677 // Television devices without CEC service apply software volume on HDMI output
5678 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
5679 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
5680 checkAllFixedVolumeDevices();
5681 if (mHdmiManager != null) {
5682 synchronized (mHdmiManager) {
5683 if (mHdmiPlaybackClient != null) {
5684 mHdmiCecSink = false;
5685 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
5686 }
5687 }
5688 }
5689 }
5690 } else {
5691 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
5692 if (mHdmiManager != null) {
5693 synchronized (mHdmiManager) {
5694 mHdmiCecSink = false;
5695 }
5696 }
5697 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005698 }
Jean-Michel Trivi87a264d2017-08-15 17:52:22 -07005699 sendDeviceConnectionIntent(device, state, address, deviceName);
Eric Laurenteab40d12017-06-09 12:45:21 -07005700 updateAudioRoutes(device, state);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005701 }
5702 }
5703
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005704 private void configureHdmiPlugIntent(Intent intent, int state) {
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005705 intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
5706 intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005707 if (state == 1) {
5708 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
5709 int[] portGeneration = new int[1];
5710 int status = AudioSystem.listAudioPorts(ports, portGeneration);
5711 if (status == AudioManager.SUCCESS) {
5712 for (AudioPort port : ports) {
5713 if (port instanceof AudioDevicePort) {
5714 final AudioDevicePort devicePort = (AudioDevicePort) port;
Eric Laurent6fa42452015-01-09 15:09:40 -08005715 if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
5716 devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005717 // format the list of supported encodings
Eric Laurentcae34662015-05-19 16:46:52 -07005718 int[] formats = AudioFormat.filterPublicFormats(devicePort.formats());
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005719 if (formats.length > 0) {
5720 ArrayList<Integer> encodingList = new ArrayList(1);
5721 for (int format : formats) {
5722 // a format in the list can be 0, skip it
5723 if (format != AudioFormat.ENCODING_INVALID) {
5724 encodingList.add(format);
5725 }
5726 }
5727 int[] encodingArray = new int[encodingList.size()];
5728 for (int i = 0 ; i < encodingArray.length ; i++) {
5729 encodingArray[i] = encodingList.get(i);
5730 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005731 intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005732 }
5733 // find the maximum supported number of channels
5734 int maxChannels = 0;
5735 for (int mask : devicePort.channelMasks()) {
5736 int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
5737 if (channelCount > maxChannels) {
5738 maxChannels = channelCount;
5739 }
5740 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005741 intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005742 }
5743 }
5744 }
5745 }
5746 }
5747 }
5748
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07005749 /* cache of the address of the last dock the device was connected to */
5750 private String mDockAddress;
5751
Eric Laurenta553c252009-07-17 12:17:14 -07005752 /**
5753 * Receiver for misc intent broadcasts the Phone app cares about.
5754 */
5755 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
5756 @Override
5757 public void onReceive(Context context, Intent intent) {
5758 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07005759 int outDevice;
5760 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07005761 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07005762
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08005763 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
5764 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
5765 Intent.EXTRA_DOCK_STATE_UNDOCKED);
5766 int config;
5767 switch (dockState) {
5768 case Intent.EXTRA_DOCK_STATE_DESK:
5769 config = AudioSystem.FORCE_BT_DESK_DOCK;
5770 break;
5771 case Intent.EXTRA_DOCK_STATE_CAR:
5772 config = AudioSystem.FORCE_BT_CAR_DOCK;
5773 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05005774 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08005775 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05005776 break;
5777 case Intent.EXTRA_DOCK_STATE_HE_DESK:
5778 config = AudioSystem.FORCE_DIGITAL_DOCK;
5779 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08005780 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
5781 default:
5782 config = AudioSystem.FORCE_NONE;
5783 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08005784 // Low end docks have a menu to enable or disable audio
5785 // (see mDockAudioMediaEnabled)
5786 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
5787 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
5788 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005789 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_DOCK, config,
5790 "ACTION_DOCK_EVENT intent"));
Eric Laurent08ed1b92012-11-05 14:54:12 -08005791 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
5792 }
5793 mDockState = dockState;
Jack He8dd33942018-01-17 15:45:12 -08005794 } else if (action.equals(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED)) {
Eric Laurentdca56b92011-09-02 14:20:56 -07005795 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Jack He8dd33942018-01-17 15:45:12 -08005796 setBtScoActiveDevice(btDevice);
Paul McLeandf361462014-04-10 16:02:55 -07005797 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005798 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07005799 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005800 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005801 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07005802 // broadcast intent if the connection was initated by AudioService
5803 if (!mScoClients.isEmpty() &&
5804 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
5805 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
5806 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005807 broadcast = true;
5808 }
5809 switch (btState) {
5810 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07005811 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07005812 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5813 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5814 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005815 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005816 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005817 break;
5818 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07005819 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08005820 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07005821 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08005822 break;
5823 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07005824 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5825 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5826 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005827 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005828 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005829 default:
5830 // do not broadcast CONNECTING or invalid state
5831 broadcast = false;
5832 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005833 }
5834 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005835 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07005836 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07005837 //FIXME: this is to maintain compatibility with deprecated intent
5838 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08005839 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07005840 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005841 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08005842 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005843 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06005844 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005845 RotationHelper.enable();
Jon Eklund318f0fe2014-01-23 17:53:48 -06005846 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005847 AudioSystem.setParameters("screen_state=on");
5848 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06005849 if (mMonitorRotation) {
5850 //reduce wakeups (save current) by only listening when display is on
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005851 RotationHelper.disable();
Jon Eklund318f0fe2014-01-23 17:53:48 -06005852 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005853 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07005854 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005855 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07005856 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Yasuhiro Matsuda4ced7192015-07-10 22:08:44 +09005857 if (mUserSwitchedReceived) {
5858 // attempt to stop music playback for background user except on first user
5859 // switch (i.e. first boot)
5860 sendMsg(mAudioHandler,
5861 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
5862 SENDMSG_REPLACE,
5863 0,
5864 0,
5865 null,
5866 0);
5867 }
5868 mUserSwitchedReceived = true;
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07005869 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005870 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07005871
Eric Laurent5bfaeae2012-09-21 18:44:48 -07005872 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07005873 readAudioSettings(true /*userSwitch*/);
5874 // preserve STREAM_MUSIC volume from one user to the next.
5875 sendMsg(mAudioHandler,
5876 MSG_SET_ALL_VOLUMES,
5877 SENDMSG_QUEUE,
5878 0,
5879 0,
5880 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005881 } else if (action.equals(Intent.ACTION_USER_BACKGROUND)) {
5882 // Disable audio recording for the background user/profile
5883 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
5884 if (userId >= 0) {
5885 // TODO Kill recording streams instead of killing processes holding permission
5886 UserInfo userInfo = UserManagerService.getInstance().getUserInfo(userId);
5887 killBackgroundUserProcessesWithRecordAudioPermission(userInfo);
5888 }
Makoto Onukiac65e1e2015-11-20 15:33:17 -08005889 UserManagerService.getInstance().setUserRestriction(
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005890 UserManager.DISALLOW_RECORD_AUDIO, true, userId);
5891 } else if (action.equals(Intent.ACTION_USER_FOREGROUND)) {
5892 // Enable audio recording for foreground user/profile
5893 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Makoto Onukiac65e1e2015-11-20 15:33:17 -08005894 UserManagerService.getInstance().setUserRestriction(
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005895 UserManager.DISALLOW_RECORD_AUDIO, false, userId);
Eric Laurentb70b78a2016-01-13 19:16:04 -08005896 } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
5897 state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
5898 if (state == BluetoothAdapter.STATE_OFF ||
5899 state == BluetoothAdapter.STATE_TURNING_OFF) {
5900 disconnectAllBluetoothProfiles();
5901 }
Marco Nelissenfb6df0b2017-02-15 15:25:24 -08005902 } else if (action.equals(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION) ||
5903 action.equals(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION)) {
5904 handleAudioEffectBroadcast(context, intent);
Eric Laurenta553c252009-07-17 12:17:14 -07005905 }
5906 }
Paul McLeanc837a452014-04-09 09:04:43 -07005907 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005908
Makoto Onukid45a4a22015-11-02 17:17:38 -08005909 private class AudioServiceUserRestrictionsListener implements UserRestrictionsListener {
5910
5911 @Override
5912 public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
5913 Bundle prevRestrictions) {
5914 // Update mic mute state.
5915 {
5916 final boolean wasRestricted =
5917 prevRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
5918 final boolean isRestricted =
5919 newRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
5920 if (wasRestricted != isRestricted) {
5921 setMicrophoneMuteNoCallerCheck(isRestricted, userId);
5922 }
5923 }
5924
5925 // Update speaker mute state.
5926 {
5927 final boolean wasRestricted =
Tony Makc1205112016-07-22 16:02:59 +01005928 prevRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)
Esteban Talavera492b4722017-02-13 14:59:45 +00005929 || prevRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_DEVICE);
Makoto Onukid45a4a22015-11-02 17:17:38 -08005930 final boolean isRestricted =
Tony Makc1205112016-07-22 16:02:59 +01005931 newRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)
Esteban Talavera492b4722017-02-13 14:59:45 +00005932 || newRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_DEVICE);
Makoto Onukid45a4a22015-11-02 17:17:38 -08005933 if (wasRestricted != isRestricted) {
5934 setMasterMuteInternalNoCallerCheck(isRestricted, /* flags =*/ 0, userId);
5935 }
5936 }
5937 }
5938 } // end class AudioServiceUserRestrictionsListener
5939
Marco Nelissenfb6df0b2017-02-15 15:25:24 -08005940 private void handleAudioEffectBroadcast(Context context, Intent intent) {
5941 String target = intent.getPackage();
5942 if (target != null) {
5943 Log.w(TAG, "effect broadcast already targeted to " + target);
5944 return;
5945 }
5946 intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
5947 // TODO this should target a user-selected panel
5948 List<ResolveInfo> ril = context.getPackageManager().queryBroadcastReceivers(
5949 intent, 0 /* flags */);
5950 if (ril != null && ril.size() != 0) {
5951 ResolveInfo ri = ril.get(0);
5952 if (ri != null && ri.activityInfo != null && ri.activityInfo.packageName != null) {
5953 intent.setPackage(ri.activityInfo.packageName);
5954 context.sendBroadcastAsUser(intent, UserHandle.ALL);
5955 return;
5956 }
5957 }
5958 Log.w(TAG, "couldn't find receiver package for effect intent");
5959 }
5960
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005961 private void killBackgroundUserProcessesWithRecordAudioPermission(UserInfo oldUser) {
5962 PackageManager pm = mContext.getPackageManager();
5963 // Find the home activity of the user. It should not be killed to avoid expensive restart,
5964 // when the user switches back. For managed profiles, we should kill all recording apps
5965 ComponentName homeActivityName = null;
5966 if (!oldUser.isManagedProfile()) {
Sudheer Shankafc46e9b2016-10-21 17:55:27 -07005967 homeActivityName = mActivityManagerInternal.getHomeActivityForUser(oldUser.id);
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005968 }
5969 final String[] permissions = { Manifest.permission.RECORD_AUDIO };
5970 List<PackageInfo> packages;
5971 try {
5972 packages = AppGlobals.getPackageManager()
5973 .getPackagesHoldingPermissions(permissions, 0, oldUser.id).getList();
5974 } catch (RemoteException e) {
5975 throw new AndroidRuntimeException(e);
5976 }
5977 for (int j = packages.size() - 1; j >= 0; j--) {
5978 PackageInfo pkg = packages.get(j);
Fyodor Kupolovbcb6c1e2015-05-11 12:05:15 -07005979 // Skip system processes
5980 if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
5981 continue;
5982 }
Amith Yamasanic1cbaab2015-07-21 11:46:14 -07005983 // Skip packages that have permission to interact across users
5984 if (pm.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS, pkg.packageName)
5985 == PackageManager.PERMISSION_GRANTED) {
5986 continue;
5987 }
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005988 if (homeActivityName != null
5989 && pkg.packageName.equals(homeActivityName.getPackageName())
5990 && pkg.applicationInfo.isSystemApp()) {
5991 continue;
5992 }
5993 try {
Svetoslavaa41add2015-08-06 15:03:55 -07005994 final int uid = pkg.applicationInfo.uid;
Sudheer Shankadc589ac2016-11-10 15:30:17 -08005995 ActivityManager.getService().killUid(UserHandle.getAppId(uid),
Svetoslavaa41add2015-08-06 15:03:55 -07005996 UserHandle.getUserId(uid),
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005997 "killBackgroundUserProcessesWithAudioRecordPermission");
5998 } catch (RemoteException e) {
5999 Log.w(TAG, "Error calling killUid", e);
6000 }
6001 }
6002 }
6003
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07006004
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07006005 //==========================================================================================
6006 // Audio Focus
6007 //==========================================================================================
Jean-Michel Trivi9228af62018-01-05 17:06:17 -08006008 /**
6009 * Returns whether a focus request is eligible to force ducking.
6010 * Will return true if:
6011 * - the AudioAttributes have a usage of USAGE_ASSISTANCE_ACCESSIBILITY,
6012 * - the focus request is AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
6013 * - the associated Bundle has KEY_ACCESSIBILITY_FORCE_FOCUS_DUCKING set to true,
6014 * - the uid of the requester is a known accessibility service or root.
6015 * @param aa AudioAttributes of the focus request
6016 * @param uid uid of the focus requester
6017 * @return true if ducking is to be forced
6018 */
6019 private boolean forceFocusDuckingForAccessibility(@Nullable AudioAttributes aa,
6020 int request, int uid) {
6021 if (aa == null || aa.getUsage() != AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY
6022 || request != AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK) {
6023 return false;
6024 }
6025 final Bundle extraInfo = aa.getBundle();
6026 if (extraInfo == null ||
6027 !extraInfo.getBoolean(AudioFocusRequest.KEY_ACCESSIBILITY_FORCE_FOCUS_DUCKING)) {
6028 return false;
6029 }
6030 if (uid == 0) {
6031 return true;
6032 }
6033 synchronized (mAccessibilityServiceUidsLock) {
6034 if (mAccessibilityServiceUids != null) {
6035 int callingUid = Binder.getCallingUid();
6036 for (int i = 0; i < mAccessibilityServiceUids.length; i++) {
6037 if (mAccessibilityServiceUids[i] == callingUid) {
6038 return true;
6039 }
6040 }
6041 }
6042 }
6043 return false;
6044 }
6045
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08006046 public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006047 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07006048 IAudioPolicyCallback pcb, int sdk) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006049 // permission checks
6050 if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
John Spurlock61560172015-02-06 19:46:04 -05006051 if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006052 if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
6053 android.Manifest.permission.MODIFY_PHONE_STATE)) {
6054 Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
6055 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
6056 }
6057 } else {
6058 // only a registered audio policy can be used to lock focus
6059 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006060 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
6061 Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006062 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
6063 }
6064 }
6065 }
6066 }
6067
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08006068 return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
Jean-Michel Trivi9228af62018-01-05 17:06:17 -08006069 clientId, callingPackageName, flags, sdk,
6070 forceFocusDuckingForAccessibility(aa, durationHint, Binder.getCallingUid()));
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07006071 }
6072
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07006073 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa,
6074 String callingPackageName) {
6075 return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa, callingPackageName);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07006076 }
6077
6078 public void unregisterAudioFocusClient(String clientId) {
6079 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07006080 }
6081
Jean-Michel Trivi23805662013-07-31 14:19:18 -07006082 public int getCurrentAudioFocus() {
6083 return mMediaFocusControl.getCurrentAudioFocus();
6084 }
6085
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08006086 public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) {
6087 return mMediaFocusControl.getFocusRampTimeMs(focusGain, attr);
6088 }
6089
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07006090 //==========================================================================================
John Spurlock5e783732015-02-19 10:28:59 -05006091 private boolean readCameraSoundForced() {
6092 return SystemProperties.getBoolean("audio.camerasound.force", false) ||
6093 mContext.getResources().getBoolean(
6094 com.android.internal.R.bool.config_camera_sound_forced);
6095 }
6096
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07006097 //==========================================================================================
6098 // Device orientation
6099 //==========================================================================================
6100 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07006101 * Handles device configuration changes that may map to a change in the orientation
6102 * or orientation.
6103 * Monitoring orientation and rotation is optional, and is defined by the definition and value
6104 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07006105 */
6106 private void handleConfigurationChanged(Context context) {
6107 try {
6108 // reading new orientation "safely" (i.e. under try catch) in case anything
6109 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07006110 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07006111 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07006112 if (mMonitorOrientation) {
6113 int newOrientation = config.orientation;
6114 if (newOrientation != mDeviceOrientation) {
6115 mDeviceOrientation = newOrientation;
6116 setOrientationForAudioSystem();
6117 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07006118 }
Eric Laurentd640bd32012-09-28 18:01:48 -07006119 sendMsg(mAudioHandler,
6120 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
6121 SENDMSG_REPLACE,
6122 0,
6123 0,
John Spurlock90874332015-03-10 16:00:54 -04006124 TAG,
Eric Laurentd640bd32012-09-28 18:01:48 -07006125 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07006126
John Spurlock5e783732015-02-19 10:28:59 -05006127 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -07006128 synchronized (mSettingsLock) {
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08006129 final boolean cameraSoundForcedChanged = (cameraSoundForced != mCameraSoundForced);
6130 mCameraSoundForced = cameraSoundForced;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07006131 if (cameraSoundForcedChanged) {
Muyuan Li1ed6df62016-06-18 11:16:52 -07006132 if (!mIsSingleVolume) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07006133 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
6134 if (cameraSoundForced) {
6135 s.setAllIndexesToMax();
6136 mRingerModeAffectedStreams &=
6137 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
6138 } else {
John Spurlock90874332015-03-10 16:00:54 -04006139 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07006140 mRingerModeAffectedStreams |=
6141 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
6142 }
6143 // take new state into account for streams muted by ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05006144 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07006145 }
6146
6147 sendMsg(mAudioHandler,
6148 MSG_SET_FORCE_USE,
6149 SENDMSG_QUEUE,
6150 AudioSystem.FOR_SYSTEM,
6151 cameraSoundForced ?
6152 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006153 new String("handleConfigurationChanged"),
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07006154 0);
6155
6156 sendMsg(mAudioHandler,
6157 MSG_SET_ALL_VOLUMES,
6158 SENDMSG_QUEUE,
6159 0,
6160 0,
6161 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
6162 }
Eric Laurentdd45d012012-10-08 09:04:34 -07006163 }
John Spurlock3346a802014-05-20 16:25:37 -04006164 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07006165 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07006166 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07006167 }
6168 }
6169
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07006170 //TODO move to an external "orientation helper" class
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07006171 private void setOrientationForAudioSystem() {
6172 switch (mDeviceOrientation) {
6173 case Configuration.ORIENTATION_LANDSCAPE:
6174 //Log.i(TAG, "orientation is landscape");
6175 AudioSystem.setParameters("orientation=landscape");
6176 break;
6177 case Configuration.ORIENTATION_PORTRAIT:
6178 //Log.i(TAG, "orientation is portrait");
6179 AudioSystem.setParameters("orientation=portrait");
6180 break;
6181 case Configuration.ORIENTATION_SQUARE:
6182 //Log.i(TAG, "orientation is square");
6183 AudioSystem.setParameters("orientation=square");
6184 break;
6185 case Configuration.ORIENTATION_UNDEFINED:
6186 //Log.i(TAG, "orientation is undefined");
6187 AudioSystem.setParameters("orientation=undefined");
6188 break;
6189 default:
6190 Log.e(TAG, "Unknown orientation");
6191 }
6192 }
6193
Sungsoocf09fe62016-09-28 16:21:48 +09006194 // Handles request to override default use of A2DP for media.
6195 // Must be called synchronized on mConnectedDevices
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006196 public void setBluetoothA2dpOnInt(boolean on, String eventSource) {
Sungsoocf09fe62016-09-28 16:21:48 +09006197 synchronized (mBluetoothA2dpEnabledLock) {
6198 mBluetoothA2dpEnabled = on;
6199 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
6200 setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006201 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
6202 eventSource);
Sungsoocf09fe62016-09-28 16:21:48 +09006203 }
6204 }
6205
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08006206 // Must be called synchronized on mConnectedDevices
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006207 private void setForceUseInt_SyncDevices(int usage, int config, String eventSource) {
Eric Laurent9a5b2622017-04-18 18:20:56 -07006208 if (usage == AudioSystem.FOR_MEDIA) {
6209 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
6210 SENDMSG_NOOP, 0, 0, null, 0);
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08006211 }
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006212 mForceUseLogger.log(new ForceUseEvent(usage, config, eventSource));
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08006213 AudioSystem.setForceUse(usage, config);
6214 }
6215
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08006216 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07006217 public void setRingtonePlayer(IRingtonePlayer player) {
6218 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
6219 mRingtonePlayer = player;
6220 }
6221
6222 @Override
6223 public IRingtonePlayer getRingtonePlayer() {
6224 return mRingtonePlayer;
6225 }
6226
6227 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07006228 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
6229 synchronized (mCurAudioRoutes) {
6230 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
6231 mRoutesObservers.register(observer);
6232 return routes;
6233 }
6234 }
6235
Eric Laurentc34dcc12012-09-10 13:51:52 -07006236
6237 //==========================================================================================
6238 // Safe media volume management.
6239 // MUSIC stream volume level is limited when headphones are connected according to safety
6240 // regulation. When the user attempts to raise the volume above the limit, a warning is
6241 // displayed and the user has to acknowlegde before the volume is actually changed.
6242 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
6243 // property. Platforms with a different limit must set this property accordingly in their
6244 // overlay.
6245 //==========================================================================================
6246
Eric Laurentd640bd32012-09-28 18:01:48 -07006247 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
6248 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
6249 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
6250 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
6251 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
6252 // (when user opts out).
John Spurlock35134602014-07-24 18:10:48 -04006253 private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
6254 private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
6255 private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed
6256 private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
Eric Laurentd640bd32012-09-28 18:01:48 -07006257 private Integer mSafeMediaVolumeState;
6258
6259 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07006260 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07006261 private int mSafeMediaVolumeIndex;
Eric Laurentb378a13a2017-07-11 14:08:11 -07006262 // mSafeUsbMediaVolumeIndex is used for USB Headsets and is the music volume UI index
6263 // corresponding to a gain of -30 dBFS in audio flinger mixer.
Eric Laurent0e5deb32017-09-01 15:12:42 -07006264 // We remove -22 dBs from the theoretical -15dB to account for the EQ + bass boost
6265 // amplification when both effects are on with all band gains at maximum.
Eric Laurentb378a13a2017-07-11 14:08:11 -07006266 // This level corresponds to a loudness of 85 dB SPL for the warning to be displayed when
6267 // the headset is compliant to EN 60950 with a max loudness of 100dB SPL.
Eric Laurenteab40d12017-06-09 12:45:21 -07006268 private int mSafeUsbMediaVolumeIndex;
Eric Laurent0e5deb32017-09-01 15:12:42 -07006269 private static final float SAFE_VOLUME_GAIN_DBFS = -37.0f;
Eric Laurentc34dcc12012-09-10 13:51:52 -07006270 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
6271 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
Eric Laurenteab40d12017-06-09 12:45:21 -07006272 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
6273 AudioSystem.DEVICE_OUT_USB_HEADSET;
Eric Laurentc34dcc12012-09-10 13:51:52 -07006274 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
6275 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
6276 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
6277 private int mMusicActiveMs;
6278 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
6279 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07006280 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07006281
Eric Laurenteab40d12017-06-09 12:45:21 -07006282 private int safeMediaVolumeIndex(int device) {
6283 if ((device & mSafeMediaVolumeDevices) == 0) {
6284 return MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC];
6285 }
6286 if (device == AudioSystem.DEVICE_OUT_USB_HEADSET) {
6287 return mSafeUsbMediaVolumeIndex;
6288 } else {
6289 return mSafeMediaVolumeIndex;
6290 }
6291 }
6292
John Spurlock90874332015-03-10 16:00:54 -04006293 private void setSafeMediaVolumeEnabled(boolean on, String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07006294 synchronized (mSafeMediaVolumeState) {
6295 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
6296 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
6297 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
6298 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
John Spurlock90874332015-03-10 16:00:54 -04006299 enforceSafeMediaVolume(caller);
Eric Laurentd640bd32012-09-28 18:01:48 -07006300 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
6301 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04006302 mMusicActiveMs = 1; // nonzero = confirmed
6303 saveMusicActiveMs();
Eric Laurentd640bd32012-09-28 18:01:48 -07006304 sendMsg(mAudioHandler,
6305 MSG_CHECK_MUSIC_ACTIVE,
6306 SENDMSG_REPLACE,
6307 0,
6308 0,
John Spurlock90874332015-03-10 16:00:54 -04006309 caller,
Eric Laurentd640bd32012-09-28 18:01:48 -07006310 MUSIC_ACTIVE_POLL_PERIOD_MS);
6311 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07006312 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07006313 }
6314 }
6315
John Spurlock90874332015-03-10 16:00:54 -04006316 private void enforceSafeMediaVolume(String caller) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07006317 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07006318 int devices = mSafeMediaVolumeDevices;
6319 int i = 0;
6320
6321 while (devices != 0) {
6322 int device = 1 << i++;
6323 if ((device & devices) == 0) {
6324 continue;
6325 }
Eric Laurent42b041e2013-03-29 11:36:03 -07006326 int index = streamState.getIndex(device);
Eric Laurenteab40d12017-06-09 12:45:21 -07006327 if (index > safeMediaVolumeIndex(device)) {
6328 streamState.setIndex(safeMediaVolumeIndex(device), device, caller);
Eric Laurent42b041e2013-03-29 11:36:03 -07006329 sendMsg(mAudioHandler,
6330 MSG_SET_DEVICE_VOLUME,
6331 SENDMSG_QUEUE,
6332 device,
6333 0,
6334 streamState,
6335 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07006336 }
6337 devices &= ~device;
6338 }
6339 }
6340
6341 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07006342 synchronized (mSafeMediaVolumeState) {
6343 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07006344 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
6345 ((device & mSafeMediaVolumeDevices) != 0) &&
Eric Laurenteab40d12017-06-09 12:45:21 -07006346 (index > safeMediaVolumeIndex(device))) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07006347 return false;
6348 }
6349 return true;
6350 }
6351 }
6352
John Spurlock3346a802014-05-20 16:25:37 -04006353 @Override
John Spurlock90874332015-03-10 16:00:54 -04006354 public void disableSafeMediaVolume(String callingPackage) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05006355 enforceVolumeController("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07006356 synchronized (mSafeMediaVolumeState) {
John Spurlock90874332015-03-10 16:00:54 -04006357 setSafeMediaVolumeEnabled(false, callingPackage);
Eric Laurentfde16d52012-12-03 14:42:39 -08006358 if (mPendingVolumeCommand != null) {
6359 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
6360 mPendingVolumeCommand.mIndex,
6361 mPendingVolumeCommand.mFlags,
John Spurlock90874332015-03-10 16:00:54 -04006362 mPendingVolumeCommand.mDevice,
6363 callingPackage);
Eric Laurentfde16d52012-12-03 14:42:39 -08006364 mPendingVolumeCommand = null;
6365 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07006366 }
6367 }
6368
Jungshik Jang41d97462014-06-30 22:26:29 +09006369 //==========================================================================================
6370 // Hdmi Cec system audio mode.
John Spurlockbc82b122015-03-02 16:12:38 -05006371 // If Hdmi Cec's system audio mode is on, audio service should send the volume change
6372 // to HdmiControlService so that the audio receiver can handle it.
Jungshik Jang41d97462014-06-30 22:26:29 +09006373 //==========================================================================================
6374
Eric Laurent212532b2014-07-21 15:43:18 -07006375 private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
6376 public void onComplete(int status) {
6377 if (mHdmiManager != null) {
6378 synchronized (mHdmiManager) {
6379 mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
6380 // Television devices without CEC service apply software volume on HDMI output
6381 if (isPlatformTelevision() && !mHdmiCecSink) {
6382 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
6383 }
6384 checkAllFixedVolumeDevices();
6385 }
6386 }
6387 }
6388 };
6389
Jungshik Jang41d97462014-06-30 22:26:29 +09006390 // If HDMI-CEC system audio is supported
6391 private boolean mHdmiSystemAudioSupported = false;
6392 // Set only when device is tv.
6393 private HdmiTvClient mHdmiTvClient;
Eric Laurent0b03f992014-11-18 18:08:02 -08006394 // true if the device has system feature PackageManager.FEATURE_LEANBACK.
Eric Laurent212532b2014-07-21 15:43:18 -07006395 // cached HdmiControlManager interface
6396 private HdmiControlManager mHdmiManager;
6397 // Set only when device is a set-top box.
6398 private HdmiPlaybackClient mHdmiPlaybackClient;
6399 // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
6400 private boolean mHdmiCecSink;
6401
6402 private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
Jungshik Jang41d97462014-06-30 22:26:29 +09006403
6404 @Override
Jungshik Jang12307ca2014-07-15 19:27:56 +09006405 public int setHdmiSystemAudioSupported(boolean on) {
Eric Laurent212532b2014-07-21 15:43:18 -07006406 int device = AudioSystem.DEVICE_NONE;
6407 if (mHdmiManager != null) {
6408 synchronized (mHdmiManager) {
6409 if (mHdmiTvClient == null) {
6410 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
6411 return device;
6412 }
Jungshik Jang41d97462014-06-30 22:26:29 +09006413
Eric Laurent212532b2014-07-21 15:43:18 -07006414 synchronized (mHdmiTvClient) {
6415 if (mHdmiSystemAudioSupported != on) {
6416 mHdmiSystemAudioSupported = on;
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006417 final int config = on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
6418 AudioSystem.FORCE_NONE;
6419 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
6420 config, "setHdmiSystemAudioSupported"));
6421 AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO, config);
Eric Laurent212532b2014-07-21 15:43:18 -07006422 }
John Spurlock8a52c442015-03-26 14:23:58 -04006423 device = getDevicesForStream(AudioSystem.STREAM_MUSIC);
Eric Laurent212532b2014-07-21 15:43:18 -07006424 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09006425 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09006426 }
Eric Laurent212532b2014-07-21 15:43:18 -07006427 return device;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09006428 }
Jungshik Jang41d97462014-06-30 22:26:29 +09006429
Terry Heoe7d6d972014-09-04 21:05:28 +09006430 @Override
6431 public boolean isHdmiSystemAudioSupported() {
6432 return mHdmiSystemAudioSupported;
6433 }
6434
Eric Laurentdd45d012012-10-08 09:04:34 -07006435 //==========================================================================================
Jean-Michel Triviac487672016-11-11 10:05:18 -08006436 // Accessibility
6437
Jean-Michel Trivicfa55532017-01-18 11:17:51 -08006438 private void initA11yMonitoring() {
6439 final AccessibilityManager accessibilityManager =
6440 (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
Jean-Michel Triviac487672016-11-11 10:05:18 -08006441 updateDefaultStreamOverrideDelay(accessibilityManager.isTouchExplorationEnabled());
Jean-Michel Trivi7592b982017-02-01 15:12:15 -08006442 updateA11yVolumeAlias(accessibilityManager.isAccessibilityVolumeStreamActive());
Phil Weaver26d709f2017-04-20 17:19:14 -07006443 accessibilityManager.addTouchExplorationStateChangeListener(this, null);
6444 accessibilityManager.addAccessibilityServicesStateChangeListener(this, null);
Jean-Michel Triviac487672016-11-11 10:05:18 -08006445 }
6446
6447 //---------------------------------------------------------------------------------
6448 // A11y: taking touch exploration into account for selecting the default
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07006449 // stream override timeout when adjusting volume
Jean-Michel Triviac487672016-11-11 10:05:18 -08006450 //---------------------------------------------------------------------------------
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07006451
Jean-Michel Triviac487672016-11-11 10:05:18 -08006452 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05006453 // - STREAM_RING on phones during this period after a notification stopped
6454 // - STREAM_MUSIC otherwise
6455
Jean-Michel Triviac487672016-11-11 10:05:18 -08006456 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 0;
6457 private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07006458
Jean-Michel Triviac487672016-11-11 10:05:18 -08006459 private static int sStreamOverrideDelayMs;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07006460
Jean-Michel Triviac487672016-11-11 10:05:18 -08006461 @Override
6462 public void onTouchExplorationStateChanged(boolean enabled) {
6463 updateDefaultStreamOverrideDelay(enabled);
6464 }
6465
6466 private void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
6467 if (touchExploreEnabled) {
6468 sStreamOverrideDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
6469 } else {
6470 sStreamOverrideDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07006471 }
Jean-Michel Triviac487672016-11-11 10:05:18 -08006472 if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
6473 + " stream override delay is now " + sStreamOverrideDelayMs + " ms");
6474 }
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07006475
Jean-Michel Triviac487672016-11-11 10:05:18 -08006476 //---------------------------------------------------------------------------------
6477 // A11y: taking a11y state into account for the handling of a11y prompts volume
6478 //---------------------------------------------------------------------------------
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07006479
Jean-Michel Triviac487672016-11-11 10:05:18 -08006480 private static boolean sIndependentA11yVolume = false;
6481
Jean-Michel Trivicfa55532017-01-18 11:17:51 -08006482 // implementation of AccessibilityServicesStateChangeListener
6483 @Override
Phil Weaver4cab9302017-03-30 15:27:39 -07006484 public void onAccessibilityServicesStateChanged(AccessibilityManager accessibilityManager) {
Jean-Michel Trivicfa55532017-01-18 11:17:51 -08006485 updateA11yVolumeAlias(accessibilityManager.isAccessibilityVolumeStreamActive());
6486 }
6487
6488 private void updateA11yVolumeAlias(boolean a11VolEnabled) {
6489 if (DEBUG_VOL) Log.d(TAG, "Accessibility volume enabled = " + a11VolEnabled);
6490 if (sIndependentA11yVolume != a11VolEnabled) {
6491 sIndependentA11yVolume = a11VolEnabled;
6492 // update the volume mapping scheme
6493 updateStreamVolumeAlias(true /*updateVolumes*/, TAG);
6494 // update the volume controller behavior
6495 mVolumeController.setA11yMode(sIndependentA11yVolume ?
6496 VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME :
6497 VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME);
Jean-Michel Trivia53b7052017-04-12 18:27:01 -07006498 mVolumeController.postVolumeChanged(AudioManager.STREAM_ACCESSIBILITY, 0);
Jean-Michel Trivicfa55532017-01-18 11:17:51 -08006499 }
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07006500 }
6501
6502 //==========================================================================================
Eric Laurentdd45d012012-10-08 09:04:34 -07006503 // Camera shutter sound policy.
6504 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
6505 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
6506 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
6507 //==========================================================================================
6508
6509 // cached value of com.android.internal.R.bool.config_camera_sound_forced
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08006510 @GuardedBy("mSettingsLock")
6511 private boolean mCameraSoundForced;
Eric Laurentdd45d012012-10-08 09:04:34 -07006512
6513 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
6514 public boolean isCameraSoundForced() {
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08006515 synchronized (mSettingsLock) {
Eric Laurentdd45d012012-10-08 09:04:34 -07006516 return mCameraSoundForced;
6517 }
6518 }
6519
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006520 //==========================================================================================
6521 // AudioService logging and dumpsys
6522 //==========================================================================================
6523 final int LOG_NB_EVENTS_PHONE_STATE = 20;
6524 final int LOG_NB_EVENTS_WIRED_DEV_CONNECTION = 30;
6525 final int LOG_NB_EVENTS_FORCE_USE = 20;
Jean-Michel Trivicf170362017-08-24 17:24:57 -07006526 final int LOG_NB_EVENTS_VOLUME = 40;
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006527
6528 final private AudioEventLogger mModeLogger = new AudioEventLogger(LOG_NB_EVENTS_PHONE_STATE,
6529 "phone state (logged after successfull call to AudioSystem.setPhoneState(int))");
6530
6531 final private AudioEventLogger mWiredDevLogger = new AudioEventLogger(
6532 LOG_NB_EVENTS_WIRED_DEV_CONNECTION,
6533 "wired device connection (logged before onSetWiredDeviceConnectionState() is executed)"
6534 );
6535
6536 final private AudioEventLogger mForceUseLogger = new AudioEventLogger(
6537 LOG_NB_EVENTS_FORCE_USE,
6538 "force use (logged before setForceUse() is executed)");
6539
Jean-Michel Trivicf170362017-08-24 17:24:57 -07006540 final private AudioEventLogger mVolumeLogger = new AudioEventLogger(LOG_NB_EVENTS_VOLUME,
6541 "volume changes (logged when command received by AudioService)");
6542
Eric Laurentdd45d012012-10-08 09:04:34 -07006543 private static final String[] RINGER_MODE_NAMES = new String[] {
6544 "SILENT",
6545 "VIBRATE",
6546 "NORMAL"
6547 };
6548
6549 private void dumpRingerMode(PrintWriter pw) {
6550 pw.println("\nRinger mode: ");
John Spurlock661f2cf2014-11-17 10:29:10 -05006551 pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
6552 pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
John Spurlock50ced3f2015-05-11 16:00:09 -04006553 dumpRingerModeStreams(pw, "affected", mRingerModeAffectedStreams);
6554 dumpRingerModeStreams(pw, "muted", mRingerModeMutedStreams);
John Spurlock661f2cf2014-11-17 10:29:10 -05006555 pw.print("- delegate = "); pw.println(mRingerModeDelegate);
Eric Laurentdd45d012012-10-08 09:04:34 -07006556 }
6557
John Spurlock50ced3f2015-05-11 16:00:09 -04006558 private void dumpRingerModeStreams(PrintWriter pw, String type, int streams) {
6559 pw.print("- ringer mode "); pw.print(type); pw.print(" streams = 0x");
6560 pw.print(Integer.toHexString(streams));
6561 if (streams != 0) {
6562 pw.print(" (");
6563 boolean first = true;
6564 for (int i = 0; i < AudioSystem.STREAM_NAMES.length; i++) {
6565 final int stream = (1 << i);
6566 if ((streams & stream) != 0) {
6567 if (!first) pw.print(',');
6568 pw.print(AudioSystem.STREAM_NAMES[i]);
6569 streams &= ~stream;
6570 first = false;
6571 }
6572 }
6573 if (streams != 0) {
6574 if (!first) pw.print(',');
6575 pw.print(streams);
6576 }
6577 pw.print(')');
6578 }
6579 pw.println();
6580 }
6581
Dianne Hackborn632ca412012-06-14 19:34:10 -07006582 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08006583 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06006584 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07006585
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07006586 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07006587 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07006588 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07006589 pw.println("\nAudio routes:");
John Spurlock61560172015-02-06 19:46:04 -05006590 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
6591 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
John Spurlock35134602014-07-24 18:10:48 -04006592
6593 pw.println("\nOther state:");
John Spurlock3346a802014-05-20 16:25:37 -04006594 pw.print(" mVolumeController="); pw.println(mVolumeController);
John Spurlock35134602014-07-24 18:10:48 -04006595 pw.print(" mSafeMediaVolumeState=");
6596 pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
6597 pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
Eric Laurenteab40d12017-06-09 12:45:21 -07006598 pw.print(" mSafeUsbMediaVolumeIndex="); pw.println(mSafeUsbMediaVolumeIndex);
Jean-Michel Trivi7592b982017-02-01 15:12:15 -08006599 pw.print(" sIndependentA11yVolume="); pw.println(sIndependentA11yVolume);
John Spurlock35134602014-07-24 18:10:48 -04006600 pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
6601 pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04006602 pw.print(" mMcc="); pw.println(mMcc);
John Spurlock5e783732015-02-19 10:28:59 -05006603 pw.print(" mCameraSoundForced="); pw.println(mCameraSoundForced);
John Spurlock661f2cf2014-11-17 10:29:10 -05006604 pw.print(" mHasVibrator="); pw.println(mHasVibrator);
John Spurlocka48d7792015-03-03 17:35:57 -05006605 pw.print(" mVolumePolicy="); pw.println(mVolumePolicy);
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07006606 pw.print(" mAvrcpAbsVolSupported="); pw.println(mAvrcpAbsVolSupported);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006607
6608 dumpAudioPolicies(pw);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08006609
6610 mPlaybackMonitor.dump(pw);
Jean-Michel Trivi66ffacf2017-02-04 17:25:31 -08006611
6612 mRecordMonitor.dump(pw);
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006613
Jean-Michel Trivicf170362017-08-24 17:24:57 -07006614 pw.println("\n");
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006615 pw.println("\nEvent logs:");
6616 mModeLogger.dump(pw);
6617 pw.println("\n");
6618 mWiredDevLogger.dump(pw);
6619 pw.println("\n");
6620 mForceUseLogger.dump(pw);
Jean-Michel Trivicf170362017-08-24 17:24:57 -07006621 pw.println("\n");
6622 mVolumeLogger.dump(pw);
John Spurlock35134602014-07-24 18:10:48 -04006623 }
6624
6625 private static String safeMediaVolumeStateToString(Integer state) {
6626 switch(state) {
6627 case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
6628 case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
6629 case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
6630 case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
6631 }
6632 return null;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08006633 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07006634
6635 // Inform AudioFlinger of our device's low RAM attribute
6636 private static void readAndSetLowRamDevice()
6637 {
Andy Hung79583582018-01-23 13:58:02 -08006638 boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic();
6639 long totalMemory = 1024 * 1024 * 1024; // 1GB is the default if ActivityManager fails.
6640
6641 try {
6642 final ActivityManager.MemoryInfo info = new ActivityManager.MemoryInfo();
6643 ActivityManager.getService().getMemoryInfo(info);
6644 totalMemory = info.totalMem;
6645 } catch (RemoteException e) {
6646 Log.w(TAG, "Cannot obtain MemoryInfo from ActivityManager, assume low memory device");
6647 isLowRamDevice = true;
6648 }
6649
6650 final int status = AudioSystem.setLowRamDevice(isLowRamDevice, totalMemory);
Glenn Kastenfd116ad2013-07-12 17:10:39 -07006651 if (status != 0) {
6652 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
6653 }
6654 }
John Spurlock3346a802014-05-20 16:25:37 -04006655
John Spurlockcdb57ae2015-02-11 19:04:11 -05006656 private void enforceVolumeController(String action) {
John Spurlock3346a802014-05-20 16:25:37 -04006657 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
6658 "Only SystemUI can " + action);
6659 }
6660
6661 @Override
6662 public void setVolumeController(final IVolumeController controller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05006663 enforceVolumeController("set the volume controller");
John Spurlock3346a802014-05-20 16:25:37 -04006664
6665 // return early if things are not actually changing
6666 if (mVolumeController.isSameBinder(controller)) {
6667 return;
6668 }
6669
6670 // dismiss the old volume controller
6671 mVolumeController.postDismiss();
6672 if (controller != null) {
6673 // we are about to register a new controller, listen for its death
6674 try {
6675 controller.asBinder().linkToDeath(new DeathRecipient() {
6676 @Override
6677 public void binderDied() {
6678 if (mVolumeController.isSameBinder(controller)) {
6679 Log.w(TAG, "Current remote volume controller died, unregistering");
6680 setVolumeController(null);
6681 }
6682 }
6683 }, 0);
6684 } catch (RemoteException e) {
6685 // noop
6686 }
6687 }
6688 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04006689 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
6690 }
6691
6692 @Override
6693 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05006694 enforceVolumeController("notify about volume controller visibility");
John Spurlock33f4e042014-07-11 13:10:58 -04006695
6696 // return early if the controller is not current
6697 if (!mVolumeController.isSameBinder(controller)) {
6698 return;
6699 }
6700
6701 mVolumeController.setVisible(visible);
6702 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04006703 }
RoboErikd09bd0c2014-06-24 17:45:19 -07006704
John Spurlocka48d7792015-03-03 17:35:57 -05006705 @Override
6706 public void setVolumePolicy(VolumePolicy policy) {
6707 enforceVolumeController("set volume policy");
John Spurlockb02c7442015-04-14 09:32:25 -04006708 if (policy != null && !policy.equals(mVolumePolicy)) {
John Spurlocka48d7792015-03-03 17:35:57 -05006709 mVolumePolicy = policy;
John Spurlockb02c7442015-04-14 09:32:25 -04006710 if (DEBUG_VOL) Log.d(TAG, "Volume policy changed: " + mVolumePolicy);
John Spurlocka48d7792015-03-03 17:35:57 -05006711 }
6712 }
6713
RoboErikd09bd0c2014-06-24 17:45:19 -07006714 public static class VolumeController {
6715 private static final String TAG = "VolumeController";
6716
6717 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04006718 private boolean mVisible;
6719 private long mNextLongPress;
6720 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07006721
6722 public void setController(IVolumeController controller) {
6723 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04006724 mVisible = false;
6725 }
6726
6727 public void loadSettings(ContentResolver cr) {
6728 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
6729 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
6730 }
6731
RoboErik4197cb62015-01-21 15:45:32 -08006732 public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
6733 if (isMute) {
6734 return false;
6735 }
John Spurlock33f4e042014-07-11 13:10:58 -04006736 boolean suppress = false;
6737 if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
6738 final long now = SystemClock.uptimeMillis();
6739 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
6740 // ui will become visible
6741 if (mNextLongPress < now) {
6742 mNextLongPress = now + mLongPressTimeout;
6743 }
6744 suppress = true;
6745 } else if (mNextLongPress > 0) { // in a long-press
6746 if (now > mNextLongPress) {
6747 // long press triggered, no more suppression
6748 mNextLongPress = 0;
6749 } else {
6750 // keep suppressing until the long press triggers
6751 suppress = true;
6752 }
6753 }
6754 }
6755 return suppress;
6756 }
6757
6758 public void setVisible(boolean visible) {
6759 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07006760 }
6761
6762 public boolean isSameBinder(IVolumeController controller) {
6763 return Objects.equals(asBinder(), binder(controller));
6764 }
6765
6766 public IBinder asBinder() {
6767 return binder(mController);
6768 }
6769
6770 private static IBinder binder(IVolumeController controller) {
6771 return controller == null ? null : controller.asBinder();
6772 }
6773
6774 @Override
6775 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04006776 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07006777 }
6778
6779 public void postDisplaySafeVolumeWarning(int flags) {
6780 if (mController == null)
6781 return;
6782 try {
6783 mController.displaySafeVolumeWarning(flags);
6784 } catch (RemoteException e) {
6785 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
6786 }
6787 }
6788
6789 public void postVolumeChanged(int streamType, int flags) {
6790 if (mController == null)
6791 return;
6792 try {
6793 mController.volumeChanged(streamType, flags);
6794 } catch (RemoteException e) {
6795 Log.w(TAG, "Error calling volumeChanged", e);
6796 }
6797 }
6798
RoboErikd09bd0c2014-06-24 17:45:19 -07006799 public void postMasterMuteChanged(int flags) {
6800 if (mController == null)
6801 return;
6802 try {
6803 mController.masterMuteChanged(flags);
6804 } catch (RemoteException e) {
6805 Log.w(TAG, "Error calling masterMuteChanged", e);
6806 }
6807 }
6808
6809 public void setLayoutDirection(int layoutDirection) {
6810 if (mController == null)
6811 return;
6812 try {
6813 mController.setLayoutDirection(layoutDirection);
6814 } catch (RemoteException e) {
6815 Log.w(TAG, "Error calling setLayoutDirection", e);
6816 }
6817 }
6818
6819 public void postDismiss() {
6820 if (mController == null)
6821 return;
6822 try {
6823 mController.dismiss();
6824 } catch (RemoteException e) {
6825 Log.w(TAG, "Error calling dismiss", e);
6826 }
6827 }
Jean-Michel Triviac487672016-11-11 10:05:18 -08006828
6829 public void setA11yMode(int a11yMode) {
6830 if (mController == null)
6831 return;
6832 try {
6833 mController.setA11yMode(a11yMode);
6834 } catch (RemoteException e) {
6835 Log.w(TAG, "Error calling setA11Mode", e);
6836 }
6837 }
RoboErikd09bd0c2014-06-24 17:45:19 -07006838 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006839
RoboErik0dac35a2014-08-12 15:48:49 -07006840 /**
6841 * Interface for system components to get some extra functionality through
6842 * LocalServices.
6843 */
6844 final class AudioServiceInternal extends AudioManagerInternal {
John Spurlock661f2cf2014-11-17 10:29:10 -05006845 @Override
6846 public void setRingerModeDelegate(RingerModeDelegate delegate) {
6847 mRingerModeDelegate = delegate;
6848 if (mRingerModeDelegate != null) {
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08006849 synchronized (mSettingsLock) {
6850 updateRingerModeAffectedStreams();
6851 }
John Spurlock661f2cf2014-11-17 10:29:10 -05006852 setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
6853 }
6854 }
RoboErik272e1612014-09-05 11:39:29 -07006855
6856 @Override
6857 public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
6858 String callingPackage, int uid) {
6859 // direction and stream type swap here because the public
6860 // adjustSuggested has a different order than the other methods.
John Spurlock90874332015-03-10 16:00:54 -04006861 adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage,
6862 callingPackage, uid);
RoboErik272e1612014-09-05 11:39:29 -07006863 }
6864
RoboErik0dac35a2014-08-12 15:48:49 -07006865 @Override
6866 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
6867 String callingPackage, int uid) {
John Spurlock90874332015-03-10 16:00:54 -04006868 adjustStreamVolume(streamType, direction, flags, callingPackage,
6869 callingPackage, uid);
RoboErik0dac35a2014-08-12 15:48:49 -07006870 }
6871
6872 @Override
6873 public void setStreamVolumeForUid(int streamType, int direction, int flags,
6874 String callingPackage, int uid) {
John Spurlock90874332015-03-10 16:00:54 -04006875 setStreamVolume(streamType, direction, flags, callingPackage, callingPackage, uid);
RoboErik0dac35a2014-08-12 15:48:49 -07006876 }
RoboErik519c7742014-11-18 10:59:09 -08006877
6878 @Override
John Spurlock661f2cf2014-11-17 10:29:10 -05006879 public int getRingerModeInternal() {
6880 return AudioService.this.getRingerModeInternal();
6881 }
6882
6883 @Override
6884 public void setRingerModeInternal(int ringerMode, String caller) {
6885 AudioService.this.setRingerModeInternal(ringerMode, caller);
6886 }
John Spurlockcdb57ae2015-02-11 19:04:11 -05006887
6888 @Override
John Spurlock50ced3f2015-05-11 16:00:09 -04006889 public void updateRingerModeAffectedStreamsInternal() {
6890 synchronized (mSettingsLock) {
6891 if (updateRingerModeAffectedStreams()) {
6892 setRingerModeInt(getRingerModeInternal(), false);
6893 }
6894 }
6895 }
Phil Weaverf1a9aff2017-03-23 17:21:29 -07006896
6897 @Override
6898 public void setAccessibilityServiceUids(IntArray uids) {
6899 synchronized (mAccessibilityServiceUidsLock) {
6900 if (uids.size() == 0) {
6901 mAccessibilityServiceUids = null;
6902 } else {
6903 boolean changed = (mAccessibilityServiceUids == null)
6904 || (mAccessibilityServiceUids.length != uids.size());
6905 if (!changed) {
6906 for (int i = 0; i < mAccessibilityServiceUids.length; i++) {
6907 if (uids.get(i) != mAccessibilityServiceUids[i]) {
6908 changed = true;
6909 break;
6910 }
6911 }
6912 }
6913 if (changed) {
6914 mAccessibilityServiceUids = uids.toArray();
6915 }
6916 }
6917 }
6918 }
RoboErik0dac35a2014-08-12 15:48:49 -07006919 }
6920
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006921 //==========================================================================================
6922 // Audio policy management
6923 //==========================================================================================
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006924 public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07006925 boolean hasFocusListener, boolean isFocusPolicy) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006926 AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
6927
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006928 if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
6929 + " with config:" + policyConfig);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006930 String regId = null;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006931 // error handling
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006932 boolean hasPermissionForPolicy =
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006933 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006934 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
6935 if (!hasPermissionForPolicy) {
6936 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
6937 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006938 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006939 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006940
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006941 synchronized (mAudioPolicies) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006942 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006943 if (mAudioPolicies.containsKey(pcb.asBinder())) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006944 Slog.e(TAG, "Cannot re-register policy");
6945 return null;
6946 }
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07006947 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener,
6948 isFocusPolicy);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006949 pcb.asBinder().linkToDeath(app, 0/*flags*/);
6950 regId = app.getRegistrationId();
6951 mAudioPolicies.put(pcb.asBinder(), app);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006952 } catch (RemoteException e) {
6953 // audio policy owner has already died!
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006954 Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006955 " binder death", e);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006956 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006957 }
6958 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006959 return regId;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006960 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006961
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006962 public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
6963 if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006964 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006965 AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006966 if (app == null) {
6967 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
6968 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006969 return;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006970 } else {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006971 pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006972 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006973 app.release();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006974 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006975 // TODO implement clearing mix attribute matching info in native audio policy
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006976 }
6977
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006978 public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
6979 if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
6980 + " policy " + pcb.asBinder());
6981 // error handling
6982 boolean hasPermissionForPolicy =
6983 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
6984 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
6985 if (!hasPermissionForPolicy) {
6986 Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
6987 + Binder.getCallingPid() + " / uid "
6988 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
6989 return AudioManager.ERROR;
6990 }
6991
6992 synchronized (mAudioPolicies) {
6993 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
6994 Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
6995 return AudioManager.ERROR;
6996 }
6997 final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
6998 if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6999 // is there already one policy managing ducking?
Eric Laurent0867bed2015-05-20 14:49:08 -07007000 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007001 if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
7002 Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
7003 return AudioManager.ERROR;
7004 }
7005 }
7006 }
7007 app.mFocusDuckBehavior = duckingBehavior;
7008 mMediaFocusControl.setDuckingInExtPolicyAvailable(
7009 duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
7010 }
7011 return AudioManager.SUCCESS;
7012 }
7013
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08007014 private void dumpAudioPolicies(PrintWriter pw) {
7015 pw.println("\nAudio policies:");
7016 synchronized (mAudioPolicies) {
Eric Laurent0867bed2015-05-20 14:49:08 -07007017 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08007018 pw.println(policy.toLogFriendlyString());
7019 }
7020 }
7021 }
7022
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08007023 //======================
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08007024 // Audio policy callbacks from AudioSystem for dynamic policies
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007025 //======================
7026 private final AudioSystem.DynamicPolicyCallback mDynPolicyCallback =
7027 new AudioSystem.DynamicPolicyCallback() {
7028 public void onDynamicPolicyMixStateUpdate(String regId, int state) {
7029 if (!TextUtils.isEmpty(regId)) {
7030 sendMsg(mAudioHandler, MSG_DYN_POLICY_MIX_STATE_UPDATE, SENDMSG_QUEUE,
7031 state /*arg1*/, 0 /*arg2 ignored*/, regId /*obj*/, 0 /*delay*/);
7032 }
7033 }
7034 };
7035
7036 private void onDynPolicyMixStateUpdate(String regId, int state) {
7037 if (DEBUG_AP) Log.d(TAG, "onDynamicPolicyMixStateUpdate("+ regId + ", " + state +")");
7038 synchronized (mAudioPolicies) {
7039 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
7040 for (AudioMix mix : policy.getMixes()) {
7041 if (mix.getRegistration().equals(regId)) {
7042 try {
7043 policy.mPolicyCallback.notifyMixStateUpdate(regId, state);
7044 } catch (RemoteException e) {
7045 Log.e(TAG, "Can't call notifyMixStateUpdate() on IAudioPolicyCallback "
7046 + policy.mPolicyCallback.asBinder(), e);
7047 }
7048 return;
7049 }
7050 }
7051 }
7052 }
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08007053 }
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007054
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08007055 //======================
7056 // Audio policy callbacks from AudioSystem for recording configuration updates
7057 //======================
Jean-Michel Trivi66ffacf2017-02-04 17:25:31 -08007058 private final RecordingActivityMonitor mRecordMonitor;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08007059
7060 public void registerRecordingCallback(IRecordingConfigDispatcher rcdb) {
Jean-Michel Trivi66ffacf2017-02-04 17:25:31 -08007061 final boolean isPrivileged =
7062 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
7063 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
7064 mRecordMonitor.registerRecordingCallback(rcdb, isPrivileged);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08007065 }
7066
7067 public void unregisterRecordingCallback(IRecordingConfigDispatcher rcdb) {
7068 mRecordMonitor.unregisterRecordingCallback(rcdb);
7069 }
7070
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07007071 public List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
Jean-Michel Trivi66ffacf2017-02-04 17:25:31 -08007072 final boolean isPrivileged =
7073 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
7074 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
7075 return mRecordMonitor.getActiveRecordingConfigurations(isPrivileged);
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007076 }
7077
Robin Lee7af9a742017-02-20 14:47:30 +00007078 public void disableRingtoneSync(final int userId) {
Andre Lago7bdc6d82016-09-22 18:00:41 +01007079 final int callingUserId = UserHandle.getCallingUserId();
Robin Lee7af9a742017-02-20 14:47:30 +00007080 if (callingUserId != userId) {
7081 mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
7082 "disable sound settings syncing for another profile");
7083 }
Andre Lago7bdc6d82016-09-22 18:00:41 +01007084 final long token = Binder.clearCallingIdentity();
7085 try {
Robin Lee7af9a742017-02-20 14:47:30 +00007086 // Disable the sync setting so the profile uses its own sound settings.
7087 Settings.Secure.putIntForUser(mContentResolver, Settings.Secure.SYNC_PARENT_SOUNDS,
7088 0 /* false */, userId);
Andre Lago7bdc6d82016-09-22 18:00:41 +01007089 } finally {
7090 Binder.restoreCallingIdentity(token);
7091 }
7092 }
7093
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007094 //======================
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -08007095 // Audio playback notification
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007096 //======================
Eric Laurente5a351c2017-09-27 20:11:51 -07007097 private final PlaybackActivityMonitor mPlaybackMonitor;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007098
7099 public void registerPlaybackCallback(IPlaybackConfigDispatcher pcdb) {
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -08007100 final boolean isPrivileged =
Jaewan Kim92dea332017-02-02 11:52:08 +09007101 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007102 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
7103 mPlaybackMonitor.registerPlaybackCallback(pcdb, isPrivileged);
7104 }
7105
7106 public void unregisterPlaybackCallback(IPlaybackConfigDispatcher pcdb) {
7107 mPlaybackMonitor.unregisterPlaybackCallback(pcdb);
7108 }
7109
7110 public List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() {
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -08007111 final boolean isPrivileged =
Jaewan Kim92dea332017-02-02 11:52:08 +09007112 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -08007113 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
7114 return mPlaybackMonitor.getActivePlaybackConfigurations(isPrivileged);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007115 }
7116
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -08007117 public int trackPlayer(PlayerBase.PlayerIdCard pic) {
7118 return mPlaybackMonitor.trackPlayer(pic);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007119 }
7120
7121 public void playerAttributes(int piid, AudioAttributes attr) {
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -08007122 mPlaybackMonitor.playerAttributes(piid, attr, Binder.getCallingUid());
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007123 }
7124
7125 public void playerEvent(int piid, int event) {
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -08007126 mPlaybackMonitor.playerEvent(piid, event, Binder.getCallingUid());
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007127 }
7128
Jean-Michel Trivi3120059d2017-08-28 12:40:55 -07007129 public void playerHasOpPlayAudio(int piid, boolean hasOpPlayAudio) {
7130 mPlaybackMonitor.playerHasOpPlayAudio(piid, hasOpPlayAudio, Binder.getCallingUid());
7131 }
7132
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007133 public void releasePlayer(int piid) {
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -08007134 mPlaybackMonitor.releasePlayer(piid, Binder.getCallingUid());
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007135 }
7136
7137 //======================
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08007138 // Audio policy proxy
7139 //======================
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007140 /**
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08007141 * This internal class inherits from AudioPolicyConfig, each instance contains all the
7142 * mixes of an AudioPolicy and their configurations.
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007143 */
7144 public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007145 private static final String TAG = "AudioPolicyProxy";
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007146 IAudioPolicyCallback mPolicyCallback;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007147 boolean mHasFocusListener;
7148 /**
7149 * Audio focus ducking behavior for an audio policy.
7150 * This variable reflects the value that was successfully set in
7151 * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
7152 * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
7153 * is handling ducking for audio focus.
7154 */
7155 int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07007156 boolean mIsFocusPolicy = false;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007157
7158 AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07007159 boolean hasFocusListener, boolean isFocusPolicy) {
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007160 super(config);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08007161 setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007162 mPolicyCallback = token;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007163 mHasFocusListener = hasFocusListener;
7164 if (mHasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007165 mMediaFocusControl.addFocusFollower(mPolicyCallback);
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07007166 // can only ever be true if there is a focus listener
7167 if (isFocusPolicy) {
7168 mIsFocusPolicy = true;
7169 mMediaFocusControl.setFocusPolicy(mPolicyCallback);
7170 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007171 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08007172 connectMixes();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007173 }
7174
7175 public void binderDied() {
7176 synchronized (mAudioPolicies) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007177 Log.i(TAG, "audio policy " + mPolicyCallback + " died");
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007178 release();
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007179 mAudioPolicies.remove(mPolicyCallback.asBinder());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007180 }
7181 }
7182
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007183 String getRegistrationId() {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08007184 return getRegistration();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007185 }
7186
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007187 void release() {
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07007188 if (mIsFocusPolicy) {
7189 mMediaFocusControl.unsetFocusPolicy(mPolicyCallback);
7190 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007191 if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
7192 mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
7193 }
7194 if (mHasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007195 mMediaFocusControl.removeFocusFollower(mPolicyCallback);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007196 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08007197 AudioSystem.registerPolicyMixes(mMixes, false);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007198 }
7199
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08007200 void connectMixes() {
7201 AudioSystem.registerPolicyMixes(mMixes, true);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007202 }
7203 };
7204
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07007205 //======================
7206 // Audio policy: focus
7207 //======================
7208 /** */
7209 public int dispatchFocusChange(AudioFocusInfo afi, int focusChange, IAudioPolicyCallback pcb) {
7210 synchronized (mAudioPolicies) {
7211 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
7212 throw new IllegalStateException("Unregistered AudioPolicy for focus dispatch");
7213 }
7214 return mMediaFocusControl.dispatchFocusChange(afi, focusChange);
7215 }
7216 }
7217
7218 //======================
7219 // misc
7220 //======================
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007221 private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
7222 new HashMap<IBinder, AudioPolicyProxy>();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007223 private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
Phil Burkac0f7042016-02-24 12:19:08 -08007224}