blob: f4c99f5e549171f3bfa1f2cf64e06f5f7f3c09b3 [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;
Phil Weaverf1a9aff2017-03-23 17:21:29 -0700141import java.util.Arrays;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700142import java.util.HashMap;
143import java.util.Iterator;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -0700144import java.util.List;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700145import java.util.NoSuchElementException;
RoboErikd09bd0c2014-06-24 17:45:19 -0700146import java.util.Objects;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147
148/**
149 * The implementation of the volume manager service.
150 * <p>
151 * This implementation focuses on delivering a responsive UI. Most methods are
152 * asynchronous to external calls. For example, the task of setting a volume
153 * will update our internal state, but in a separate thread will set the system
154 * volume and later persist to the database. Similarly, setting the ringer mode
155 * will update the state and broadcast a change and in a separate thread later
156 * persist the ringer mode.
157 *
158 * @hide
159 */
Jean-Michel Triviac487672016-11-11 10:05:18 -0800160public class AudioService extends IAudioService.Stub
161 implements AccessibilityManager.TouchExplorationStateChangeListener,
Jean-Michel Trivicfa55532017-01-18 11:17:51 -0800162 AccessibilityManager.AccessibilityServicesStateChangeListener {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163
164 private static final String TAG = "AudioService";
165
Jean-Michel Trivi339567d2014-07-29 09:53:34 -0700166 /** Debug audio mode */
167 protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -0700168
169 /** Debug audio policy feature */
170 protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);
171
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700172 /** Debug volumes */
John Spurlockae641c92014-06-30 18:11:40 -0400173 protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700174
Paul McLean394a8e12015-03-03 10:29:19 -0700175 /** debug calls to devices APIs */
176 protected static final boolean DEBUG_DEVICES = Log.isLoggable(TAG + ".DEVICES", Log.DEBUG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 /** How long to delay before persisting a change in volume/ringer mode. */
RoboErik45edba12012-03-27 17:54:36 -0700178 private static final int PERSIST_DELAY = 500;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179
RoboErik5452e252015-02-06 15:33:53 -0800180 /** How long to delay after a volume down event before unmuting a stream */
181 private static final int UNMUTE_STREAM_DELAY = 350;
182
John Spurlock3346a802014-05-20 16:25:37 -0400183 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400184 * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
185 */
186 private static final int FLAG_ADJUST_VOLUME = 1;
187
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700188 private final Context mContext;
189 private final ContentResolver mContentResolver;
190 private final AppOpsManager mAppOps;
Eric Laurent212532b2014-07-21 15:43:18 -0700191
Eric Laurent212532b2014-07-21 15:43:18 -0700192 // the platform type affects volume and silent mode behavior
193 private final int mPlatformType;
194
Muyuan Li1ed6df62016-06-18 11:16:52 -0700195 // indicates whether the system maps all streams to a single stream.
196 private final boolean mIsSingleVolume;
197
Eric Laurent212532b2014-07-21 15:43:18 -0700198 private boolean isPlatformVoice() {
John Spurlock61560172015-02-06 19:46:04 -0500199 return mPlatformType == AudioSystem.PLATFORM_VOICE;
Eric Laurent212532b2014-07-21 15:43:18 -0700200 }
201
202 private boolean isPlatformTelevision() {
John Spurlock61560172015-02-06 19:46:04 -0500203 return mPlatformType == AudioSystem.PLATFORM_TELEVISION;
Eric Laurent212532b2014-07-21 15:43:18 -0700204 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800205
John Spurlock3346a802014-05-20 16:25:37 -0400206 /** The controller for the volume UI. */
207 private final VolumeController mVolumeController = new VolumeController();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208
209 // sendMsg() flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800210 /** If the msg is already queued, replace it with this one. */
211 private static final int SENDMSG_REPLACE = 0;
212 /** If the msg is already queued, ignore this one and leave the old. */
213 private static final int SENDMSG_NOOP = 1;
214 /** If the msg is already queued, queue this one and leave the old. */
215 private static final int SENDMSG_QUEUE = 2;
216
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700217 // AudioHandler messages
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800218 private static final int MSG_SET_DEVICE_VOLUME = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 private static final int MSG_PERSIST_VOLUME = 1;
220 private static final int MSG_PERSIST_RINGER_MODE = 3;
Andy Hunged0ea402015-10-30 14:11:46 -0700221 private static final int MSG_AUDIO_SERVER_DIED = 4;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700222 private static final int MSG_PLAY_SOUND_EFFECT = 5;
223 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
224 private static final int MSG_LOAD_SOUND_EFFECTS = 7;
225 private static final int MSG_SET_FORCE_USE = 8;
226 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
227 private static final int MSG_SET_ALL_VOLUMES = 10;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700228 private static final int MSG_REPORT_NEW_ROUTES = 12;
Sungsoocf09fe62016-09-28 16:21:48 +0900229 private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700230 private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
231 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
232 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
233 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
234 private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
235 private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
236 private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700237 private static final int MSG_SYSTEM_READY = 21;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400238 private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
RoboErik5452e252015-02-06 15:33:53 -0800239 private static final int MSG_UNMUTE_STREAM = 24;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -0700240 private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 25;
Eric Laurent0867bed2015-05-20 14:49:08 -0700241 private static final int MSG_INDICATE_SYSTEM_READY = 26;
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -0700242 private static final int MSG_ACCESSORY_PLUG_MEDIA_UNMUTE = 27;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700243 // start of messages handled under wakelock
244 // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
Jean-Michel Trivie12c39b2012-06-06 10:51:58 -0700245 // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700246 private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
Mike Lockwood0a40ec22014-05-21 10:08:50 -0700247 private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
248 private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800249 private static final int MSG_A2DP_DEVICE_CONFIG_CHANGE = 103;
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -0700250 private static final int MSG_DISABLE_AUDIO_FOR_UID = 104;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700251 // end of messages handled under wakelock
Eric Laurentafbb0472011-12-15 09:04:23 -0800252
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -0700253 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
Eric Laurentdc03c612011-04-01 10:59:41 -0700254 // Timeout for connection to bluetooth headset service
255 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
256
Eric Laurent0867bed2015-05-20 14:49:08 -0700257 // retry delay in case of failure to indicate system ready to AudioFlinger
258 private static final int INDICATE_SYSTEM_READY_RETRY_DELAY_MS = 1000;
259
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260 /** @see AudioSystemThread */
261 private AudioSystemThread mAudioSystemThread;
262 /** @see AudioHandler */
263 private AudioHandler mAudioHandler;
264 /** @see VolumeStreamState */
265 private VolumeStreamState[] mStreamStates;
Jason Parekhb1096152009-03-24 17:48:25 -0700266 private SettingsObserver mSettingsObserver;
Eric Laurenta553c252009-07-17 12:17:14 -0700267
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700268 private int mMode = AudioSystem.MODE_NORMAL;
Glenn Kastenba195eb2011-12-13 09:30:40 -0800269 // protects mRingerMode
270 private final Object mSettingsLock = new Object();
Eric Laurent45c90ce2012-04-24 18:44:22 -0700271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 private SoundPool mSoundPool;
Glenn Kasten30c918c2011-11-10 17:56:41 -0800273 private final Object mSoundEffectsLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274 private static final int NUM_SOUNDPOOL_CHANNELS = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275
276 /* Sound effect file names */
277 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
Eric Laurente78fced2013-03-15 16:03:47 -0700278 private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279
280 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
281 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
282 * uses soundpool (second column) */
Eric Laurente78fced2013-03-15 16:03:47 -0700283 private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284
John Spurlockb6e19e32015-03-10 21:33:44 -0400285 /** Maximum volume index values for audio streams */
Eric Laurent91377de2014-10-10 15:24:04 -0700286 private static int[] MAX_STREAM_VOLUME = new int[] {
Eric Laurent6ee99522009-08-25 06:30:59 -0700287 5, // STREAM_VOICE_CALL
288 7, // STREAM_SYSTEM
289 7, // STREAM_RING
290 15, // STREAM_MUSIC
291 7, // STREAM_ALARM
292 7, // STREAM_NOTIFICATION
293 15, // STREAM_BLUETOOTH_SCO
294 7, // STREAM_SYSTEM_ENFORCED
295 15, // STREAM_DTMF
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800296 15, // STREAM_TTS
297 15 // STREAM_ACCESSIBILITY
Jared Suttles59820132009-08-13 21:50:52 -0500298 };
Eric Laurent91377de2014-10-10 15:24:04 -0700299
John Spurlockb6e19e32015-03-10 21:33:44 -0400300 /** Minimum volume index values for audio streams */
301 private static int[] MIN_STREAM_VOLUME = new int[] {
302 1, // STREAM_VOICE_CALL
303 0, // STREAM_SYSTEM
304 0, // STREAM_RING
305 0, // STREAM_MUSIC
306 0, // STREAM_ALARM
307 0, // STREAM_NOTIFICATION
Eric Laurente4381ec2015-10-29 17:52:48 -0700308 0, // STREAM_BLUETOOTH_SCO
John Spurlockb6e19e32015-03-10 21:33:44 -0400309 0, // STREAM_SYSTEM_ENFORCED
310 0, // STREAM_DTMF
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800311 0, // STREAM_TTS
312 0 // STREAM_ACCESSIBILITY
John Spurlockb6e19e32015-03-10 21:33:44 -0400313 };
314
Eric Laurent6d517662012-04-23 18:42:39 -0700315 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
Eric Laurenta553c252009-07-17 12:17:14 -0700316 * of another stream: This avoids multiplying the volume settings for hidden
317 * stream types that follow other stream behavior for volume settings
Eric Laurent6d517662012-04-23 18:42:39 -0700318 * NOTE: do not create loops in aliases!
319 * Some streams alias to different streams according to device category (phone or tablet) or
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700320 * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
Eric Laurent212532b2014-07-21 15:43:18 -0700321 * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
322 * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
323 * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
324 private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700325 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
326 AudioSystem.STREAM_RING, // STREAM_SYSTEM
327 AudioSystem.STREAM_RING, // STREAM_RING
328 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
329 AudioSystem.STREAM_ALARM, // STREAM_ALARM
330 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
331 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
332 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
333 AudioSystem.STREAM_RING, // STREAM_DTMF
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800334 AudioSystem.STREAM_MUSIC, // STREAM_TTS
335 AudioSystem.STREAM_MUSIC // STREAM_ACCESSIBILITY
Eric Laurenta553c252009-07-17 12:17:14 -0700336 };
Eric Laurent212532b2014-07-21 15:43:18 -0700337 private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
338 AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL
339 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
340 AudioSystem.STREAM_MUSIC, // STREAM_RING
341 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
342 AudioSystem.STREAM_MUSIC, // STREAM_ALARM
343 AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
344 AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO
345 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
346 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800347 AudioSystem.STREAM_MUSIC, // STREAM_TTS
348 AudioSystem.STREAM_MUSIC // STREAM_ACCESSIBILITY
Eric Laurent212532b2014-07-21 15:43:18 -0700349 };
350 private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700351 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
John Spurlock4f0f1202014-08-05 13:28:33 -0400352 AudioSystem.STREAM_RING, // STREAM_SYSTEM
Eric Laurent6d517662012-04-23 18:42:39 -0700353 AudioSystem.STREAM_RING, // STREAM_RING
354 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
355 AudioSystem.STREAM_ALARM, // STREAM_ALARM
356 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
357 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
John Spurlock4f0f1202014-08-05 13:28:33 -0400358 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
359 AudioSystem.STREAM_RING, // STREAM_DTMF
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800360 AudioSystem.STREAM_MUSIC, // STREAM_TTS
361 AudioSystem.STREAM_MUSIC // STREAM_ACCESSIBILITY
Eric Laurent6d517662012-04-23 18:42:39 -0700362 };
Yue Li949865b2017-05-24 17:25:28 -0700363 protected static int[] mStreamVolumeAlias;
Eric Laurenta553c252009-07-17 12:17:14 -0700364
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700365 /**
366 * Map AudioSystem.STREAM_* constants to app ops. This should be used
367 * after mapping through mStreamVolumeAlias.
368 */
John Spurlock59dc9c12015-03-02 11:20:15 -0500369 private static final int[] STREAM_VOLUME_OPS = new int[] {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700370 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL
371 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM
372 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING
373 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC
374 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM
375 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION
376 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO
377 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED
378 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF
379 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800380 AppOpsManager.OP_AUDIO_ACCESSIBILITY_VOLUME, // STREAM_ACCESSIBILITY
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700381 };
382
Eric Laurent83a017b2013-03-19 18:15:31 -0700383 private final boolean mUseFixedVolume;
384
Glenn Kasten30c918c2011-11-10 17:56:41 -0800385 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 public void onError(int error) {
387 switch (error) {
388 case AudioSystem.AUDIO_STATUS_SERVER_DIED:
Andy Hunged0ea402015-10-30 14:11:46 -0700389 sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED,
Eric Laurentdfb881f2013-07-18 14:41:39 -0700390 SENDMSG_NOOP, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 break;
392 default:
393 break;
394 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700395 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 };
397
398 /**
399 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
400 * {@link AudioManager#RINGER_MODE_SILENT}, or
401 * {@link AudioManager#RINGER_MODE_VIBRATE}.
402 */
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -0800403 @GuardedBy("mSettingsLock")
John Spurlock661f2cf2014-11-17 10:29:10 -0500404 private int mRingerMode; // internal ringer mode, affects muting of underlying streams
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -0800405 @GuardedBy("mSettingsLock")
John Spurlock661f2cf2014-11-17 10:29:10 -0500406 private int mRingerModeExternal = -1; // reported ringer mode to outside clients (AudioManager)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407
Eric Laurent9bcf4012009-06-12 06:09:28 -0700408 /** @see System#MODE_RINGER_STREAMS_AFFECTED */
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700409 private int mRingerModeAffectedStreams = 0;
Eric Laurent9bcf4012009-06-12 06:09:28 -0700410
Eric Laurent5b4e6542010-03-19 20:02:21 -0700411 // Streams currently muted by ringer mode
412 private int mRingerModeMutedStreams;
413
John Spurlock3ce37252015-02-17 13:20:45 -0500414 /** Streams that can be muted. Do not resolve to aliases when checking.
415 * @see System#MUTE_STREAMS_AFFECTED */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 private int mMuteAffectedStreams;
417
418 /**
Eric Laurentbffc3d12012-05-07 17:43:49 -0700419 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
420 * mVibrateSetting is just maintained during deprecation period but vibration policy is
421 * now only controlled by mHasVibrator and mRingerMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 */
423 private int mVibrateSetting;
424
Eric Laurentbffc3d12012-05-07 17:43:49 -0700425 // Is there a vibrator
426 private final boolean mHasVibrator;
427
Eric Laurenta553c252009-07-17 12:17:14 -0700428 // Broadcast receiver for device connections intent broadcasts
429 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
430
Makoto Onukid45a4a22015-11-02 17:17:38 -0800431 /** Interface for UserManagerService. */
432 private final UserManagerInternal mUserManagerInternal;
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700433 private final ActivityManagerInternal mActivityManagerInternal;
Makoto Onukid45a4a22015-11-02 17:17:38 -0800434
435 private final UserRestrictionsListener mUserRestrictionsListener =
436 new AudioServiceUserRestrictionsListener();
437
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700438 // Devices currently connected
Paul McLean394a8e12015-03-03 10:29:19 -0700439 // Use makeDeviceListKey() to make a unique key for this list.
440 private class DeviceListSpec {
441 int mDeviceType;
442 String mDeviceName;
443 String mDeviceAddress;
444
445 public DeviceListSpec(int deviceType, String deviceName, String deviceAddress) {
446 mDeviceType = deviceType;
447 mDeviceName = deviceName;
448 mDeviceAddress = deviceAddress;
449 }
450
451 public String toString() {
452 return "[type:0x" + Integer.toHexString(mDeviceType) + " name:" + mDeviceName
453 + " address:" + mDeviceAddress + "]";
454 }
455 }
456
457 // Generate a unique key for the mConnectedDevices List by composing the device "type"
458 // and the "address" associated with a specific instance of that device type
459 private String makeDeviceListKey(int device, String deviceAddress) {
460 return "0x" + Integer.toHexString(device) + ":" + deviceAddress;
461 }
462
John Spurlock8c3dc852015-04-23 21:32:37 -0400463 private final ArrayMap<String, DeviceListSpec> mConnectedDevices = new ArrayMap<>();
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700464
465 // Forced device usage for communications
466 private int mForcedUseForComm;
Sharad Sangle1d188442017-05-09 16:05:40 +0530467 private int mForcedUseForCommExt; // External state returned by getters: always consistent
468 // with requests by setters
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700469
Eric Laurent9272b4b2010-01-23 17:12:59 -0800470 // List of binder death handlers for setMode() client processes.
471 // The last process to have called setMode() is at the top of the list.
Glenn Kasten30c918c2011-11-10 17:56:41 -0800472 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
Eric Laurenteb14a782009-12-17 03:12:59 -0800473
Eric Laurent3def1ee2010-03-17 23:26:26 -0700474 // List of clients having issued a SCO start request
Glenn Kasten30c918c2011-11-10 17:56:41 -0800475 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
Eric Laurent3def1ee2010-03-17 23:26:26 -0700476
477 // BluetoothHeadset API to control SCO connection
478 private BluetoothHeadset mBluetoothHeadset;
479
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700480 // Bluetooth headset device
481 private BluetoothDevice mBluetoothHeadsetDevice;
Eric Laurent3def1ee2010-03-17 23:26:26 -0700482
Eric Laurent62ef7672010-11-24 10:58:32 -0800483 // Indicate if SCO audio connection is currently active and if the initiator is
484 // audio service (internal) or bluetooth headset (external)
485 private int mScoAudioState;
486 // SCO audio state is not active
487 private static final int SCO_STATE_INACTIVE = 0;
Eric Laurentdc03c612011-04-01 10:59:41 -0700488 // SCO audio activation request waiting for headset service to connect
489 private static final int SCO_STATE_ACTIVATE_REQ = 1;
Eric Laurent25fc29b2013-04-05 12:13:54 -0700490 // SCO audio state is active or starting due to a request from AudioManager API
Eric Laurentdc03c612011-04-01 10:59:41 -0700491 private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
492 // SCO audio deactivation request waiting for headset service to connect
493 private static final int SCO_STATE_DEACTIVATE_REQ = 5;
494
Eric Laurent62ef7672010-11-24 10:58:32 -0800495 // SCO audio state is active due to an action in BT handsfree (either voice recognition or
496 // in call audio)
497 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
Eric Laurentdc03c612011-04-01 10:59:41 -0700498 // Deactivation request for all SCO connections (initiated by audio mode change)
499 // waiting for headset service to connect
500 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
501
Eric Laurentc18c9132013-04-12 17:24:56 -0700502 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
503 // originated from an app targeting an API version before JB MR2 and raw audio after that.
504 private int mScoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -0700505 // SCO audio mode is undefined
506 private static final int SCO_MODE_UNDEFINED = -1;
Eric Laurentc18c9132013-04-12 17:24:56 -0700507 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
508 private static final int SCO_MODE_VIRTUAL_CALL = 0;
509 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
510 private static final int SCO_MODE_RAW = 1;
Liejun Taof4e51d82014-07-16 11:18:29 -0700511 // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
512 private static final int SCO_MODE_VR = 2;
513
514 private static final int SCO_MODE_MAX = 2;
Eric Laurentc18c9132013-04-12 17:24:56 -0700515
Eric Laurentdc03c612011-04-01 10:59:41 -0700516 // Current connection state indicated by bluetooth headset
517 private int mScoConnectionState;
Eric Laurent62ef7672010-11-24 10:58:32 -0800518
Eric Laurenta60e2122010-12-28 16:49:07 -0800519 // true if boot sequence has been completed
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700520 private boolean mSystemReady;
Yasuhiro Matsuda4ced7192015-07-10 22:08:44 +0900521 // true if Intent.ACTION_USER_SWITCHED has ever been received
522 private boolean mUserSwitchedReceived;
Eric Laurenta60e2122010-12-28 16:49:07 -0800523 // listener for SoundPool sample load completion indication
524 private SoundPoolCallback mSoundPoolCallBack;
525 // thread for SoundPool listener
526 private SoundPoolListenerThread mSoundPoolListenerThread;
527 // message looper for SoundPool listener
528 private Looper mSoundPoolLooper = null;
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700529 // volume applied to sound played with playSoundEffect()
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700530 private static int sSoundEffectVolumeDb;
Eric Laurent25101b02011-02-02 09:33:30 -0800531 // previous volume adjustment direction received by checkForRingerModeChange()
532 private int mPrevVolDirection = AudioManager.ADJUST_SAME;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700533 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
534 // is controlled by Vol keys.
Jean-Michel Trivia7880d42017-04-15 12:41:05 -0700535 private int mVolumeControlStream = -1;
536 // interpretation of whether the volume stream has been selected by the user by clicking on a
537 // volume slider to change which volume is controlled by the volume keys. Is false
538 // when mVolumeControlStream is -1.
539 private boolean mUserSelectedVolumeControlStream = false;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700540 private final Object mForceControlStreamLock = new Object();
541 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
542 // server process so in theory it is not necessary to monitor the client death.
543 // However it is good to be ready for future evolutions.
544 private ForceControlStreamClient mForceControlStreamClient = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700545 // Used to play ringtones outside system_server
546 private volatile IRingtonePlayer mRingtonePlayer;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800547
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700548 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
549
Eric Laurent78472112012-05-21 08:57:21 -0700550 // Request to override default use of A2DP for media.
Sungsoo486f7d32016-09-28 16:20:52 +0900551 private boolean mBluetoothA2dpEnabled;
Eric Laurent78472112012-05-21 08:57:21 -0700552 private final Object mBluetoothA2dpEnabledLock = new Object();
553
Dianne Hackborn632ca412012-06-14 19:34:10 -0700554 // Monitoring of audio routes. Protected by mCurAudioRoutes.
555 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
556 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
557 = new RemoteCallbackList<IAudioRoutesObserver>();
558
Eric Laurent4bbcc652012-09-24 14:26:30 -0700559 // Devices for which the volume is fixed and VolumePanel slider should be disabled
Eric Laurent212532b2014-07-21 15:43:18 -0700560 int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700561 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Eric Laurent212532b2014-07-21 15:43:18 -0700562 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
563 AudioSystem.DEVICE_OUT_HDMI_ARC |
564 AudioSystem.DEVICE_OUT_SPDIF |
565 AudioSystem.DEVICE_OUT_AUX_LINE;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700566 int mFullVolumeDevices = 0;
Eric Laurent4bbcc652012-09-24 14:26:30 -0700567
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700568 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700569 private final boolean mMonitorOrientation;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700570 private final boolean mMonitorRotation;
Eric Laurentd640bd32012-09-28 18:01:48 -0700571
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700572 private boolean mDockAudioMediaEnabled = true;
573
Eric Laurent08ed1b92012-11-05 14:54:12 -0800574 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
575
Eric Laurentfde16d52012-12-03 14:42:39 -0800576 // Used when safe volume warning message display is requested by setStreamVolume(). In this
577 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
578 // and used later when/if disableSafeMediaVolume() is called.
579 private StreamVolumeCommand mPendingVolumeCommand;
580
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700581 private PowerManager.WakeLock mAudioEventWakeLock;
582
583 private final MediaFocusControl mMediaFocusControl;
584
John Du5a0cf7a2013-07-19 11:30:34 -0700585 // Reference to BluetoothA2dp to query for AbsoluteVolume.
586 private BluetoothA2dp mA2dp;
seunghwan.hong4fe77952014-10-29 17:43:20 +0900587 // lock always taken synchronized on mConnectedDevices
John Du5a0cf7a2013-07-19 11:30:34 -0700588 private final Object mA2dpAvrcpLock = new Object();
589 // If absolute volume is supported in AVRCP device
590 private boolean mAvrcpAbsVolSupported = false;
591
Eric Laurentadbe8bf2014-11-03 18:26:32 -0800592 private static Long mLastDeviceConnectMsgTime = new Long(0);
593
Julia Reynolds48034f82016-03-09 10:15:16 -0500594 private NotificationManager mNm;
John Spurlock661f2cf2014-11-17 10:29:10 -0500595 private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
John Spurlocka48d7792015-03-03 17:35:57 -0500596 private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
John Spurlock07e72432015-03-13 11:46:52 -0400597 private long mLoweredFromNormalToVibrateTime;
John Spurlock661f2cf2014-11-17 10:29:10 -0500598
Phil Weaverf1a9aff2017-03-23 17:21:29 -0700599 // Array of Uids of valid accessibility services to check if caller is one of them
600 private int[] mAccessibilityServiceUids;
601 private final Object mAccessibilityServiceUidsLock = new Object();
602
Paul McLean10804eb2015-01-28 11:16:35 -0800603 // Intent "extra" data keys.
604 public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName";
605 public static final String CONNECT_INTENT_KEY_STATE = "state";
606 public static final String CONNECT_INTENT_KEY_ADDRESS = "address";
607 public static final String CONNECT_INTENT_KEY_HAS_PLAYBACK = "hasPlayback";
608 public static final String CONNECT_INTENT_KEY_HAS_CAPTURE = "hasCapture";
609 public static final String CONNECT_INTENT_KEY_HAS_MIDI = "hasMIDI";
610 public static final String CONNECT_INTENT_KEY_DEVICE_CLASS = "class";
611
612 // Defines the format for the connection "address" for ALSA devices
613 public static String makeAlsaAddressString(int card, int device) {
614 return "card=" + card + ";device=" + device + ";";
615 }
616
Makoto Onukie1aef852015-10-15 17:28:35 -0700617 public static final class Lifecycle extends SystemService {
618 private AudioService mService;
619
620 public Lifecycle(Context context) {
621 super(context);
622 mService = new AudioService(context);
623 }
624
625 @Override
626 public void onStart() {
627 publishBinderService(Context.AUDIO_SERVICE, mService);
628 }
629
630 @Override
631 public void onBootPhase(int phase) {
632 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
633 mService.systemReady();
634 }
635 }
636 }
637
Dianne Hackborn3e99f652017-07-05 16:33:56 -0700638 final private IUidObserver mUidObserver = new IUidObserver.Stub() {
639 @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
640 }
641
642 @Override public void onUidGone(int uid, boolean disabled) {
643 // Once the uid is no longer running, no need to keep trying to disable its audio.
644 disableAudioForUid(false, uid);
645 }
646
647 @Override public void onUidActive(int uid) throws RemoteException {
648 }
649
650 @Override public void onUidIdle(int uid, boolean disabled) {
651 }
652
653 @Override public void onUidCachedChanged(int uid, boolean cached) {
654 disableAudioForUid(cached, uid);
655 }
656
657 private void disableAudioForUid(boolean disable, int uid) {
658 queueMsgUnderWakeLock(mAudioHandler, MSG_DISABLE_AUDIO_FOR_UID,
659 disable ? 1 : 0 /* arg1 */, uid /* arg2 */,
660 null /* obj */, 0 /* delay */);
661 }
662 };
663
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 ///////////////////////////////////////////////////////////////////////////
665 // Construction
666 ///////////////////////////////////////////////////////////////////////////
667
668 /** @hide */
669 public AudioService(Context context) {
670 mContext = context;
671 mContentResolver = context.getContentResolver();
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700672 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700673
John Spurlock61560172015-02-06 19:46:04 -0500674 mPlatformType = AudioSystem.getPlatformType(context);
Jared Suttles59820132009-08-13 21:50:52 -0500675
Muyuan Li1ed6df62016-06-18 11:16:52 -0700676 mIsSingleVolume = AudioSystem.isSingleVolume(context);
677
Makoto Onukid45a4a22015-11-02 17:17:38 -0800678 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700679 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
Makoto Onukid45a4a22015-11-02 17:17:38 -0800680
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700681 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700682 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700683
Eric Laurentbffc3d12012-05-07 17:43:49 -0700684 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
685 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
686
John Spurlockb6e19e32015-03-10 21:33:44 -0400687 // Initialize volume
Eric Laurent403bd342017-07-11 16:21:44 -0700688 int maxCallVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps", -1);
689 if (maxCallVolume != -1) {
690 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxCallVolume;
691 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] =
692 (maxCallVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700693 }
Eric Laurent403bd342017-07-11 16:21:44 -0700694
695 int maxMusicVolume = SystemProperties.getInt("ro.config.media_vol_steps", -1);
696 if (maxMusicVolume != -1) {
697 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxMusicVolume;
698 }
699
700 int defaultMusicVolume = SystemProperties.getInt("ro.config.media_vol_default", -1);
701 if (defaultMusicVolume != -1 &&
702 defaultMusicVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
703 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = defaultMusicVolume;
704 } else {
Hank Freund45926dc2015-12-11 10:50:45 -0800705 if (isPlatformTelevision()) {
Eric Laurent403bd342017-07-11 16:21:44 -0700706 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] =
707 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] / 4;
Hank Freund45926dc2015-12-11 10:50:45 -0800708 } else {
Eric Laurent403bd342017-07-11 16:21:44 -0700709 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] =
710 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] / 3;
Hank Freund45926dc2015-12-11 10:50:45 -0800711 }
Eric Laurent91377de2014-10-10 15:24:04 -0700712 }
Jared Suttles59820132009-08-13 21:50:52 -0500713
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700714 sSoundEffectVolumeDb = context.getResources().getInteger(
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700715 com.android.internal.R.integer.config_soundEffectVolumeDb);
Eric Laurent25101b02011-02-02 09:33:30 -0800716
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700717 mForcedUseForComm = AudioSystem.FORCE_NONE;
Eric Laurentdd45d012012-10-08 09:04:34 -0700718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719 createAudioSystemThread();
Eric Laurentdd45d012012-10-08 09:04:34 -0700720
Eric Laurentdfb881f2013-07-18 14:41:39 -0700721 AudioSystem.setErrorCallback(mAudioSystemCallback);
722
John Spurlock5e783732015-02-19 10:28:59 -0500723 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -0700724 mCameraSoundForced = new Boolean(cameraSoundForced);
725 sendMsg(mAudioHandler,
726 MSG_SET_FORCE_USE,
727 SENDMSG_QUEUE,
728 AudioSystem.FOR_SYSTEM,
729 cameraSoundForced ?
730 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700731 new String("AudioService ctor"),
Eric Laurentdd45d012012-10-08 09:04:34 -0700732 0);
733
Eric Laurent05274f32012-11-29 12:48:18 -0800734 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
735 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
736 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
737 // The default safe volume index read here will be replaced by the actual value when
738 // the mcc is read by onConfigureSafeVolume()
739 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
740 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
741
Eric Laurent83a017b2013-03-19 18:15:31 -0700742 mUseFixedVolume = mContext.getResources().getBoolean(
743 com.android.internal.R.bool.config_useFixedVolume);
744
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700745 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
746 // array initialized by updateStreamVolumeAlias()
John Spurlock90874332015-03-10 16:00:54 -0400747 updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 readPersistedSettings();
Eric Laurentc0232482016-03-15 18:19:23 -0700749 readUserRestrictions();
Eric Laurentc1d41662011-07-19 11:21:13 -0700750 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700751 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700752
Eric Laurentb378a13a2017-07-11 14:08:11 -0700753 // mSafeUsbMediaVolumeIndex must be initialized after createStreamStates() because it
754 // relies on audio policy having correct ranges for volume indexes.
755 mSafeUsbMediaVolumeIndex = getSafeUsbMediaVolumeIndex();
756
Eric Laurente5a351c2017-09-27 20:11:51 -0700757 mPlaybackMonitor =
758 new PlaybackActivityMonitor(context, MAX_STREAM_VOLUME[AudioSystem.STREAM_ALARM]);
759
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -0800760 mMediaFocusControl = new MediaFocusControl(mContext, mPlaybackMonitor);
John Spurlockb6e19e32015-03-10 21:33:44 -0400761
Jean-Michel Trivi66ffacf2017-02-04 17:25:31 -0800762 mRecordMonitor = new RecordingActivityMonitor(mContext);
763
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700764 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700765
766 // Call setRingerModeInt() to apply correct mute
767 // state on streams affected by ringer mode.
768 mRingerModeMutedStreams = 0;
John Spurlock661f2cf2014-11-17 10:29:10 -0500769 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3891c4c2010-04-20 09:40:57 -0700770
Eric Laurenta553c252009-07-17 12:17:14 -0700771 // Register for device connection intent broadcasts.
772 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700773 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700774 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
775 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700776 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
777 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700778 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700779 intentFilter.addAction(Intent.ACTION_USER_BACKGROUND);
780 intentFilter.addAction(Intent.ACTION_USER_FOREGROUND);
Paul McLeanc837a452014-04-09 09:04:43 -0700781 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Eric Laurentb70b78a2016-01-13 19:16:04 -0800782 intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700783
Eric Laurentd640bd32012-09-28 18:01:48 -0700784 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700785 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700786 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
787 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700788 Log.v(TAG, "monitoring device orientation");
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700789 // initialize orientation in AudioSystem
790 setOrientationForAudioSystem();
791 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700792 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
793 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -0700794 RotationHelper.init(mContext, mAudioHandler);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700795 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700796
Marco Nelissenfb6df0b2017-02-15 15:25:24 -0800797 intentFilter.addAction(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
798 intentFilter.addAction(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
799
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700800 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null);
Jared Suttles59820132009-08-13 21:50:52 -0500801
RoboErik0dac35a2014-08-12 15:48:49 -0700802 LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
Makoto Onukid45a4a22015-11-02 17:17:38 -0800803
804 mUserManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -0800805
806 mRecordMonitor.initMonitor();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 }
808
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700809 public void systemReady() {
810 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
811 0, 0, null, 0);
Dianne Hackborn3e3600e2017-08-31 11:15:26 -0700812 if (false) {
813 // This is turned off for now, because it is racy and thus causes apps to break.
814 // Currently banning a uid means that if an app tries to start playing an audio
815 // stream, that will be preventing, and unbanning it will not allow that stream
816 // to resume. However these changes in uid state are racy with what the app is doing,
817 // so that after taking a process out of the cached state we can't guarantee that
818 // we will unban the uid before the app actually tries to start playing audio.
819 // (To do that, the activity manager would need to wait until it knows for sure
820 // that the ban has been removed, before telling the app to do whatever it is
821 // supposed to do that caused it to go out of the cached state.)
822 try {
823 ActivityManager.getService().registerUidObserver(mUidObserver,
824 ActivityManager.UID_OBSERVER_CACHED | ActivityManager.UID_OBSERVER_GONE,
825 ActivityManager.PROCESS_STATE_UNKNOWN, null);
826 } catch (RemoteException e) {
827 // ignored; both services live in system_server
828 }
Dianne Hackborn3e99f652017-07-05 16:33:56 -0700829 }
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700830 }
831
832 public void onSystemReady() {
833 mSystemReady = true;
834 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
835 0, 0, null, 0);
836
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700837 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
838 resetBluetoothSco();
839 getBluetoothHeadset();
840 //FIXME: this is to maintain compatibility with deprecated intent
841 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
842 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
843 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
844 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
845 sendStickyBroadcastToAll(newIntent);
846
847 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
848 if (adapter != null) {
849 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
850 BluetoothProfile.A2DP);
851 }
852
Jeff Sharkey73ea0ae2016-08-10 17:30:38 -0600853 if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_HDMI_CEC)) {
854 mHdmiManager = mContext.getSystemService(HdmiControlManager.class);
Eric Laurent212532b2014-07-21 15:43:18 -0700855 synchronized (mHdmiManager) {
856 mHdmiTvClient = mHdmiManager.getTvClient();
Jungshik Jangc9ff9682014-09-15 17:41:06 +0900857 if (mHdmiTvClient != null) {
858 mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
859 }
Eric Laurent212532b2014-07-21 15:43:18 -0700860 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
861 mHdmiCecSink = false;
862 }
863 }
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900864
Julia Reynolds48034f82016-03-09 10:15:16 -0500865 mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
866
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700867 sendMsg(mAudioHandler,
868 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
869 SENDMSG_REPLACE,
870 0,
871 0,
John Spurlock90874332015-03-10 16:00:54 -0400872 TAG,
Eric Laurent03332ab2017-02-09 18:29:15 -0800873 SystemProperties.getBoolean("audio.safemedia.bypass", false) ?
874 0 : SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700875
Jean-Michel Trivicfa55532017-01-18 11:17:51 -0800876 initA11yMonitoring();
Eric Laurent0867bed2015-05-20 14:49:08 -0700877 onIndicateSystemReady();
878 }
879
880 void onIndicateSystemReady() {
881 if (AudioSystem.systemReady() == AudioSystem.SUCCESS) {
882 return;
883 }
884 sendMsg(mAudioHandler,
885 MSG_INDICATE_SYSTEM_READY,
886 SENDMSG_REPLACE,
887 0,
888 0,
889 null,
890 INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
891 }
892
Andy Hunged0ea402015-10-30 14:11:46 -0700893 public void onAudioServerDied() {
Eric Laurent0867bed2015-05-20 14:49:08 -0700894 if (!mSystemReady ||
895 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Andy Hunged0ea402015-10-30 14:11:46 -0700896 Log.e(TAG, "Audioserver died.");
897 sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent0867bed2015-05-20 14:49:08 -0700898 null, 500);
899 return;
900 }
Andy Hunged0ea402015-10-30 14:11:46 -0700901 Log.e(TAG, "Audioserver started.");
Eric Laurent0867bed2015-05-20 14:49:08 -0700902
903 // indicate to audio HAL that we start the reconfiguration phase after a media
904 // server crash
905 // Note that we only execute this when the media server
906 // process restarts after a crash, not the first time it is started.
907 AudioSystem.setParameters("restarting=true");
908
909 readAndSetLowRamDevice();
910
911 // Restore device connection states
912 synchronized (mConnectedDevices) {
913 for (int i = 0; i < mConnectedDevices.size(); i++) {
914 DeviceListSpec spec = mConnectedDevices.valueAt(i);
915 AudioSystem.setDeviceConnectionState(
916 spec.mDeviceType,
917 AudioSystem.DEVICE_STATE_AVAILABLE,
918 spec.mDeviceAddress,
919 spec.mDeviceName);
920 }
921 }
922 // Restore call state
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700923 if (AudioSystem.setPhoneState(mMode) == AudioSystem.AUDIO_STATUS_OK) {
924 mModeLogger.log(new AudioEventLogger.StringEvent(
925 "onAudioServerDied causes setPhoneState(" + AudioSystem.modeToString(mMode) + ")"));
926 }
Eric Laurent0867bed2015-05-20 14:49:08 -0700927
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700928 // Restore forced usage for communications and record
929 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm,
930 "onAudioServerDied"));
Eric Laurent0867bed2015-05-20 14:49:08 -0700931 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700932 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_RECORD, mForcedUseForComm,
933 "onAudioServerDied"));
Eric Laurent0867bed2015-05-20 14:49:08 -0700934 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -0800935 final int forSys;
936 synchronized (mSettingsLock) {
937 forSys = mCameraSoundForced ?
938 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE;
939 }
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700940 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_SYSTEM, forSys,
941 "onAudioServerDied"));
942 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, forSys);
Eric Laurent0867bed2015-05-20 14:49:08 -0700943
944 // Restore stream volumes
945 int numStreamTypes = AudioSystem.getNumStreamTypes();
946 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
947 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurente4381ec2015-10-29 17:52:48 -0700948 AudioSystem.initStreamVolume(
949 streamType, streamState.mIndexMin / 10, streamState.mIndexMax / 10);
Eric Laurent0867bed2015-05-20 14:49:08 -0700950
951 streamState.applyAllVolumes();
952 }
953
Andy Hungf04b84d2015-12-18 17:33:27 -0800954 // Restore mono mode
Andy Hung7b98e9a2016-02-25 18:34:50 -0800955 updateMasterMono(mContentResolver);
Andy Hungf04b84d2015-12-18 17:33:27 -0800956
Eric Laurent0867bed2015-05-20 14:49:08 -0700957 // Restore ringer mode
958 setRingerModeInt(getRingerModeInternal(), false);
959
960 // Reset device orientation (if monitored for this device)
961 if (mMonitorOrientation) {
962 setOrientationForAudioSystem();
963 }
964 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -0700965 RotationHelper.updateOrientation();
Eric Laurent0867bed2015-05-20 14:49:08 -0700966 }
967
Sungsoocf09fe62016-09-28 16:21:48 +0900968 synchronized (mBluetoothA2dpEnabledLock) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700969 final int forMed = mBluetoothA2dpEnabled ?
970 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP;
971 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_MEDIA, forMed,
972 "onAudioServerDied"));
973 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, forMed);
Sungsoocf09fe62016-09-28 16:21:48 +0900974 }
975
Eric Laurent0867bed2015-05-20 14:49:08 -0700976 synchronized (mSettingsLock) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -0700977 final int forDock = mDockAudioMediaEnabled ?
978 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE;
979 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_DOCK, forDock,
980 "onAudioServerDied"));
981 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, forDock);
982 sendEncodedSurroundMode(mContentResolver, "onAudioServerDied");
Eric Laurent0867bed2015-05-20 14:49:08 -0700983 }
984 if (mHdmiManager != null) {
985 synchronized (mHdmiManager) {
986 if (mHdmiTvClient != null) {
987 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
988 }
989 }
990 }
991
992 synchronized (mAudioPolicies) {
993 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
994 policy.connectMixes();
995 }
996 }
997
998 onIndicateSystemReady();
999 // indicate the end of reconfiguration phase to audio HAL
1000 AudioSystem.setParameters("restarting=false");
Eric Laurent4a5eeb92014-05-06 10:49:04 -07001001 }
1002
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001003 private void createAudioSystemThread() {
1004 mAudioSystemThread = new AudioSystemThread();
1005 mAudioSystemThread.start();
1006 waitForAudioHandlerCreation();
1007 }
1008
1009 /** Waits for the volume handler to be created by the other thread. */
1010 private void waitForAudioHandlerCreation() {
1011 synchronized(this) {
1012 while (mAudioHandler == null) {
1013 try {
1014 // Wait for mAudioHandler to be set by the other thread
1015 wait();
1016 } catch (InterruptedException e) {
1017 Log.e(TAG, "Interrupted while waiting on volume handler.");
1018 }
1019 }
1020 }
1021 }
1022
Eric Laurent24482012012-05-10 09:41:17 -07001023 private void checkAllAliasStreamVolumes() {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001024 synchronized (VolumeStreamState.class) {
1025 int numStreamTypes = AudioSystem.getNumStreamTypes();
1026 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
Jean-Michel Trivi170a0ee2017-04-14 18:13:26 -07001027 mStreamStates[streamType]
1028 .setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], TAG);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001029 // apply stream volume
RoboErik4197cb62015-01-21 15:45:32 -08001030 if (!mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001031 mStreamStates[streamType].applyAllVolumes();
1032 }
Eric Laurent24482012012-05-10 09:41:17 -07001033 }
1034 }
1035 }
1036
Eric Laurent212532b2014-07-21 15:43:18 -07001037 private void checkAllFixedVolumeDevices()
1038 {
1039 int numStreamTypes = AudioSystem.getNumStreamTypes();
1040 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
1041 mStreamStates[streamType].checkFixedVolumeDevices();
1042 }
1043 }
1044
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07001045 private void checkAllFixedVolumeDevices(int streamType) {
1046 mStreamStates[streamType].checkFixedVolumeDevices();
1047 }
1048
John Spurlockb6e19e32015-03-10 21:33:44 -04001049 private void checkMuteAffectedStreams() {
1050 // any stream with a min level > 0 is not muteable by definition
Nadav Bar6b7751d2017-12-24 16:03:08 +02001051 // STREAM_VOICE_CALL can be muted by applications that has the the MODIFY_PHONE_STATE permission.
John Spurlockb6e19e32015-03-10 21:33:44 -04001052 for (int i = 0; i < mStreamStates.length; i++) {
1053 final VolumeStreamState vss = mStreamStates[i];
Nadav Bar6b7751d2017-12-24 16:03:08 +02001054 if (vss.mIndexMin > 0 &&
1055 vss.mStreamType != AudioSystem.STREAM_VOICE_CALL) {
John Spurlockb6e19e32015-03-10 21:33:44 -04001056 mMuteAffectedStreams &= ~(1 << vss.mStreamType);
1057 }
1058 }
1059 }
1060
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001062 int numStreamTypes = AudioSystem.getNumStreamTypes();
1063 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
1064
1065 for (int i = 0; i < numStreamTypes; i++) {
Jean-Michel Trivia53b7052017-04-12 18:27:01 -07001066 streams[i] =
1067 new VolumeStreamState(System.VOLUME_SETTINGS_INT[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -07001068 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001069
Eric Laurent212532b2014-07-21 15:43:18 -07001070 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07001071 checkAllAliasStreamVolumes();
John Spurlockb6e19e32015-03-10 21:33:44 -04001072 checkMuteAffectedStreams();
Eric Laurent403bd342017-07-11 16:21:44 -07001073 updateDefaultVolumes();
1074 }
1075
1076 // Update default indexes from aliased streams. Must be called after mStreamStates is created
1077 private void updateDefaultVolumes() {
1078 for (int stream = 0; stream < mStreamStates.length; stream++) {
1079 if (stream != mStreamVolumeAlias[stream]) {
1080 AudioSystem.DEFAULT_STREAM_VOLUME[stream] = rescaleIndex(
1081 AudioSystem.DEFAULT_STREAM_VOLUME[mStreamVolumeAlias[stream]],
1082 mStreamVolumeAlias[stream],
1083 stream);
1084 }
1085 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 }
1087
Eric Laurentbffc3d12012-05-07 17:43:49 -07001088 private void dumpStreamStates(PrintWriter pw) {
1089 pw.println("\nStream volumes (device: index)");
1090 int numStreamTypes = AudioSystem.getNumStreamTypes();
1091 for (int i = 0; i < numStreamTypes; i++) {
John Spurlock61560172015-02-06 19:46:04 -05001092 pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":");
Eric Laurentbffc3d12012-05-07 17:43:49 -07001093 mStreamStates[i].dump(pw);
1094 pw.println("");
1095 }
Eric Laurentdd45d012012-10-08 09:04:34 -07001096 pw.print("\n- mute affected streams = 0x");
1097 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -07001098 }
1099
John Spurlock90874332015-03-10 16:00:54 -04001100 private void updateStreamVolumeAlias(boolean updateVolumes, String caller) {
Eric Laurent6d517662012-04-23 18:42:39 -07001101 int dtmfStreamAlias;
Jean-Michel Triviac487672016-11-11 10:05:18 -08001102 final int a11yStreamAlias = sIndependentA11yVolume ?
1103 AudioSystem.STREAM_ACCESSIBILITY : AudioSystem.STREAM_MUSIC;
Eric Laurent212532b2014-07-21 15:43:18 -07001104
Muyuan Li1ed6df62016-06-18 11:16:52 -07001105 if (mIsSingleVolume) {
Eric Laurent212532b2014-07-21 15:43:18 -07001106 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
1107 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
Muyuan Li1ed6df62016-06-18 11:16:52 -07001108 } else {
1109 switch (mPlatformType) {
1110 case AudioSystem.PLATFORM_VOICE:
1111 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
1112 dtmfStreamAlias = AudioSystem.STREAM_RING;
1113 break;
1114 default:
1115 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
1116 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
1117 }
Eric Laurent6d517662012-04-23 18:42:39 -07001118 }
Eric Laurent212532b2014-07-21 15:43:18 -07001119
Muyuan Li1ed6df62016-06-18 11:16:52 -07001120 if (mIsSingleVolume) {
Eric Laurent212532b2014-07-21 15:43:18 -07001121 mRingerModeAffectedStreams = 0;
Eric Laurent24e0d9b2013-10-03 18:15:07 -07001122 } else {
Eric Laurent212532b2014-07-21 15:43:18 -07001123 if (isInCommunication()) {
1124 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
1125 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
1126 } else {
1127 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
1128 }
Eric Laurent6d517662012-04-23 18:42:39 -07001129 }
Eric Laurent212532b2014-07-21 15:43:18 -07001130
Eric Laurent6d517662012-04-23 18:42:39 -07001131 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
Jean-Michel Trivi170a0ee2017-04-14 18:13:26 -07001132 mStreamVolumeAlias[AudioSystem.STREAM_ACCESSIBILITY] = a11yStreamAlias;
Jean-Michel Triviac487672016-11-11 10:05:18 -08001133
Eric Laurent403bd342017-07-11 16:21:44 -07001134 if (updateVolumes && mStreamStates != null) {
1135 updateDefaultVolumes();
1136
John Spurlock90874332015-03-10 16:00:54 -04001137 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
1138 caller);
Jean-Michel Trivi170a0ee2017-04-14 18:13:26 -07001139
1140 mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].mVolumeIndexSettingName =
1141 System.VOLUME_SETTINGS_INT[a11yStreamAlias];
Jean-Michel Triviac487672016-11-11 10:05:18 -08001142 mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].setAllIndexes(
1143 mStreamStates[a11yStreamAlias], caller);
Jean-Michel Trivi170a0ee2017-04-14 18:13:26 -07001144 if (sIndependentA11yVolume) {
1145 // restore the a11y values from the settings
1146 mStreamStates[AudioSystem.STREAM_ACCESSIBILITY].readSettings();
1147 }
1148
Eric Laurent24e0d9b2013-10-03 18:15:07 -07001149 // apply stream mute states according to new value of mRingerModeAffectedStreams
John Spurlock661f2cf2014-11-17 10:29:10 -05001150 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent6d517662012-04-23 18:42:39 -07001151 sendMsg(mAudioHandler,
1152 MSG_SET_ALL_VOLUMES,
1153 SENDMSG_QUEUE,
1154 0,
1155 0,
1156 mStreamStates[AudioSystem.STREAM_DTMF], 0);
Jean-Michel Triviac487672016-11-11 10:05:18 -08001157 sendMsg(mAudioHandler,
1158 MSG_SET_ALL_VOLUMES,
1159 SENDMSG_QUEUE,
1160 0,
1161 0,
1162 mStreamStates[AudioSystem.STREAM_ACCESSIBILITY], 0);
Eric Laurent6d517662012-04-23 18:42:39 -07001163 }
1164 }
1165
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001166 private void readDockAudioSettings(ContentResolver cr)
1167 {
1168 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -07001169 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001170
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001171 sendMsg(mAudioHandler,
1172 MSG_SET_FORCE_USE,
1173 SENDMSG_QUEUE,
1174 AudioSystem.FOR_DOCK,
1175 mDockAudioMediaEnabled ?
1176 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001177 new String("readDockAudioSettings"),
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001178 0);
1179 }
1180
Phil Burkac0f7042016-02-24 12:19:08 -08001181
Andy Hung7b98e9a2016-02-25 18:34:50 -08001182 private void updateMasterMono(ContentResolver cr)
1183 {
1184 final boolean masterMono = System.getIntForUser(
1185 cr, System.MASTER_MONO, 0 /* default */, UserHandle.USER_CURRENT) == 1;
1186 if (DEBUG_VOL) {
1187 Log.d(TAG, String.format("Master mono %b", masterMono));
1188 }
1189 AudioSystem.setMasterMono(masterMono);
1190 }
1191
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001192 private void sendEncodedSurroundMode(ContentResolver cr, String eventSource)
Phil Burkac0f7042016-02-24 12:19:08 -08001193 {
1194 int encodedSurroundMode = Settings.Global.getInt(
1195 cr, Settings.Global.ENCODED_SURROUND_OUTPUT,
1196 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001197 sendEncodedSurroundMode(encodedSurroundMode, eventSource);
Phil Burkac0f7042016-02-24 12:19:08 -08001198 }
1199
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001200 private void sendEncodedSurroundMode(int encodedSurroundMode, String eventSource)
Phil Burkac0f7042016-02-24 12:19:08 -08001201 {
1202 // initialize to guaranteed bad value
1203 int forceSetting = AudioSystem.NUM_FORCE_CONFIG;
1204 switch (encodedSurroundMode) {
1205 case Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO:
1206 forceSetting = AudioSystem.FORCE_NONE;
1207 break;
1208 case Settings.Global.ENCODED_SURROUND_OUTPUT_NEVER:
1209 forceSetting = AudioSystem.FORCE_ENCODED_SURROUND_NEVER;
1210 break;
1211 case Settings.Global.ENCODED_SURROUND_OUTPUT_ALWAYS:
1212 forceSetting = AudioSystem.FORCE_ENCODED_SURROUND_ALWAYS;
1213 break;
1214 default:
1215 Log.e(TAG, "updateSurroundSoundSettings: illegal value "
1216 + encodedSurroundMode);
1217 break;
1218 }
1219 if (forceSetting != AudioSystem.NUM_FORCE_CONFIG) {
1220 sendMsg(mAudioHandler,
1221 MSG_SET_FORCE_USE,
1222 SENDMSG_QUEUE,
1223 AudioSystem.FOR_ENCODED_SURROUND,
1224 forceSetting,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001225 eventSource,
Phil Burkac0f7042016-02-24 12:19:08 -08001226 0);
1227 }
1228 }
1229
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001230 private void readPersistedSettings() {
1231 final ContentResolver cr = mContentResolver;
1232
Eric Laurentbffc3d12012-05-07 17:43:49 -07001233 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07001234 Settings.Global.getInt(
1235 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -07001236 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -07001237 // sanity check in case the settings are restored from a device with incompatible
1238 // ringer modes
John Spurlock97559372014-10-24 16:27:36 -04001239 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001240 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -07001241 }
1242 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1243 ringerMode = AudioManager.RINGER_MODE_SILENT;
1244 }
1245 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07001246 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -08001247 }
Muyuan Li1ed6df62016-06-18 11:16:52 -07001248 if (mUseFixedVolume || mIsSingleVolume) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001249 ringerMode = AudioManager.RINGER_MODE_NORMAL;
1250 }
Glenn Kastenba195eb2011-12-13 09:30:40 -08001251 synchronized(mSettingsLock) {
1252 mRingerMode = ringerMode;
John Spurlock661f2cf2014-11-17 10:29:10 -05001253 if (mRingerModeExternal == -1) {
1254 mRingerModeExternal = mRingerMode;
1255 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256
Eric Laurentdd45d012012-10-08 09:04:34 -07001257 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
1258 // are still needed while setVibrateSetting() and getVibrateSetting() are being
1259 // deprecated.
John Spurlock61560172015-02-06 19:46:04 -05001260 mVibrateSetting = AudioSystem.getValueForVibrateSetting(0,
Eric Laurentdd45d012012-10-08 09:04:34 -07001261 AudioManager.VIBRATE_TYPE_NOTIFICATION,
1262 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
1263 : AudioManager.VIBRATE_SETTING_OFF);
John Spurlock61560172015-02-06 19:46:04 -05001264 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting,
Eric Laurentdd45d012012-10-08 09:04:34 -07001265 AudioManager.VIBRATE_TYPE_RINGER,
1266 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
1267 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001268
Eric Laurent24e0d9b2013-10-03 18:15:07 -07001269 updateRingerModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001270 readDockAudioSettings(cr);
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07001271 sendEncodedSurroundMode(cr, "readPersistedSettings");
Eric Laurent402f7f22011-02-04 12:30:32 -08001272 }
Eric Laurentc1d41662011-07-19 11:21:13 -07001273
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001274 mMuteAffectedStreams = System.getIntForUser(cr,
John Spurlock61560172015-02-06 19:46:04 -05001275 System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
John Spurlock24c05182015-02-05 12:30:36 -05001276 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001277
Andy Hung7b98e9a2016-02-25 18:34:50 -08001278 updateMasterMono(cr);
Andy Hungf04b84d2015-12-18 17:33:27 -08001279
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001280 // Each stream will read its own persisted settings
1281
John Spurlockbcc10872014-11-28 15:29:21 -05001282 // Broadcast the sticky intents
1283 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
1284 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285
1286 // Broadcast vibrate settings
1287 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
1288 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07001289
John Spurlock33f4e042014-07-11 13:10:58 -04001290 // Load settings for the volume controller
1291 mVolumeController.loadSettings(cr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001292 }
1293
Eric Laurentc0232482016-03-15 18:19:23 -07001294 private void readUserRestrictions() {
1295 final int currentUser = getCurrentUserId();
1296
1297 // Check the current user restriction.
Tony Makc1205112016-07-22 16:02:59 +01001298 boolean masterMute =
1299 mUserManagerInternal.getUserRestriction(currentUser,
Esteban Talavera492b4722017-02-13 14:59:45 +00001300 UserManager.DISALLOW_UNMUTE_DEVICE)
Tony Makc1205112016-07-22 16:02:59 +01001301 || mUserManagerInternal.getUserRestriction(currentUser,
1302 UserManager.DISALLOW_ADJUST_VOLUME);
Eric Laurentc0232482016-03-15 18:19:23 -07001303 if (mUseFixedVolume) {
1304 masterMute = false;
1305 AudioSystem.setMasterVolume(1.0f);
1306 }
1307 if (DEBUG_VOL) {
1308 Log.d(TAG, String.format("Master mute %s, user=%d", masterMute, currentUser));
1309 }
1310 setSystemAudioMute(masterMute);
1311 AudioSystem.setMasterMute(masterMute);
1312 broadcastMasterMuteStatus(masterMute);
1313
1314 boolean microphoneMute = mUserManagerInternal.getUserRestriction(
1315 currentUser, UserManager.DISALLOW_UNMUTE_MICROPHONE);
1316 if (DEBUG_VOL) {
1317 Log.d(TAG, String.format("Mic mute %s, user=%d", microphoneMute, currentUser));
1318 }
1319 AudioSystem.muteMicrophone(microphoneMute);
1320 }
1321
Eric Laurenta553c252009-07-17 12:17:14 -07001322 private int rescaleIndex(int index, int srcStream, int dstStream) {
1323 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
1324 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001325
1326 ///////////////////////////////////////////////////////////////////////////
1327 // IPC methods
1328 ///////////////////////////////////////////////////////////////////////////
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001329 /** @see AudioManager#adjustVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001330 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001331 String callingPackage, String caller) {
RoboErik272e1612014-09-05 11:39:29 -07001332 adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
John Spurlock90874332015-03-10 16:00:54 -04001333 caller, Binder.getCallingUid());
RoboErik272e1612014-09-05 11:39:29 -07001334 }
1335
1336 private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001337 String callingPackage, String caller, int uid) {
1338 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001339 + ", flags=" + flags + ", caller=" + caller
1340 + ", volControlStream=" + mVolumeControlStream
1341 + ", userSelect=" + mUserSelectedVolumeControlStream);
Jean-Michel Trivicf170362017-08-24 17:24:57 -07001342 mVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_SUGG_VOL, suggestedStreamType,
1343 direction/*val1*/, flags/*val2*/, new StringBuilder(callingPackage)
1344 .append("/").append(caller).append(" uid:").append(uid).toString()));
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001345 final int streamType;
1346 if (mUserSelectedVolumeControlStream) { // implies mVolumeControlStream != -1
Eric Laurent45c90ce2012-04-24 18:44:22 -07001347 streamType = mVolumeControlStream;
Eric Laurent402f7f22011-02-04 12:30:32 -08001348 } else {
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001349 final int maybeActiveStreamType = getActiveStreamType(suggestedStreamType);
1350 final boolean activeForReal;
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05001351 if (maybeActiveStreamType == AudioSystem.STREAM_RING
1352 || maybeActiveStreamType == AudioSystem.STREAM_NOTIFICATION) {
1353 activeForReal = wasStreamActiveRecently(maybeActiveStreamType, 0);
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001354 } else {
1355 activeForReal = AudioSystem.isStreamActive(maybeActiveStreamType, 0);
1356 }
1357 if (activeForReal || mVolumeControlStream == -1) {
1358 streamType = maybeActiveStreamType;
1359 } else {
1360 streamType = mVolumeControlStream;
1361 }
Eric Laurent402f7f22011-02-04 12:30:32 -08001362 }
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001363
1364 final boolean isMute = isMuteAdjust(direction);
1365
John Spurlock0a376af2015-03-26 16:24:12 -04001366 ensureValidStreamType(streamType);
John Spurlock33f4e042014-07-11 13:10:58 -04001367 final int resolvedStream = mStreamVolumeAlias[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001368
RoboErik2811dd32014-08-12 09:48:13 -07001369 // Play sounds on STREAM_RING only.
1370 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
John Spurlock33f4e042014-07-11 13:10:58 -04001371 resolvedStream != AudioSystem.STREAM_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001372 flags &= ~AudioManager.FLAG_PLAY_SOUND;
1373 }
1374
John Spurlock33f4e042014-07-11 13:10:58 -04001375 // For notifications/ring, show the ui before making any adjustments
RoboErik4197cb62015-01-21 15:45:32 -08001376 // Don't suppress mute/unmute requests
1377 if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
John Spurlock33f4e042014-07-11 13:10:58 -04001378 direction = 0;
1379 flags &= ~AudioManager.FLAG_PLAY_SOUND;
1380 flags &= ~AudioManager.FLAG_VIBRATE;
1381 if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
1382 }
1383
John Spurlock90874332015-03-10 16:00:54 -04001384 adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385 }
1386
1387 /** @see AudioManager#adjustStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001388 public void adjustStreamVolume(int streamType, int direction, int flags,
1389 String callingPackage) {
Phil Weaverf1a9aff2017-03-23 17:21:29 -07001390 if ((streamType == AudioManager.STREAM_ACCESSIBILITY) && !canChangeAccessibilityVolume()) {
Jean-Michel Triviab2d9312017-03-13 15:33:39 -07001391 Log.w(TAG, "Trying to call adjustStreamVolume() for a11y without"
Phil Weaverf1a9aff2017-03-23 17:21:29 -07001392 + "CHANGE_ACCESSIBILITY_VOLUME / callingPackage=" + callingPackage);
Jean-Michel Triviab2d9312017-03-13 15:33:39 -07001393 return;
1394 }
Jean-Michel Trivicf170362017-08-24 17:24:57 -07001395 mVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_ADJUST_STREAM_VOL, streamType,
1396 direction/*val1*/, flags/*val2*/, callingPackage));
John Spurlock90874332015-03-10 16:00:54 -04001397 adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage,
1398 Binder.getCallingUid());
RoboErik0dac35a2014-08-12 15:48:49 -07001399 }
1400
1401 private void adjustStreamVolume(int streamType, int direction, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001402 String callingPackage, String caller, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001403 if (mUseFixedVolume) {
1404 return;
1405 }
John Spurlock90874332015-03-10 16:00:54 -04001406 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream=" + streamType + ", dir=" + direction
1407 + ", flags=" + flags + ", caller=" + caller);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07001408
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001409 ensureValidDirection(direction);
1410 ensureValidStreamType(streamType);
1411
RoboErik4197cb62015-01-21 15:45:32 -08001412 boolean isMuteAdjust = isMuteAdjust(direction);
1413
John Spurlock3ce37252015-02-17 13:20:45 -05001414 if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
1415 return;
1416 }
1417
Nadav Bar6b7751d2017-12-24 16:03:08 +02001418 // If adjust is mute and the stream is STREAM_VOICE_CALL, make sure
1419 // that the calling app have the MODIFY_PHONE_STATE permission.
1420 if (isMuteAdjust &&
1421 streamType == AudioSystem.STREAM_VOICE_CALL &&
1422 mContext.checkCallingOrSelfPermission(
1423 android.Manifest.permission.MODIFY_PHONE_STATE)
1424 != PackageManager.PERMISSION_GRANTED) {
1425 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: adjustStreamVolume from pid="
1426 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
1427 return;
1428 }
1429
Eric Laurent96a33d12011-11-08 10:31:57 -08001430 // use stream type alias here so that streams with same alias have the same behavior,
1431 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
1432 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
Eric Laurent6d517662012-04-23 18:42:39 -07001433 int streamTypeAlias = mStreamVolumeAlias[streamType];
RoboErik4197cb62015-01-21 15:45:32 -08001434
Eric Laurentb024c302011-10-14 17:19:27 -07001435 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001436
1437 final int device = getDeviceForStream(streamTypeAlias);
Eric Laurent3ef75492012-11-28 12:12:23 -08001438
Eric Laurent42b041e2013-03-29 11:36:03 -07001439 int aliasIndex = streamState.getIndex(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440 boolean adjustVolume = true;
Eric Laurent3ef75492012-11-28 12:12:23 -08001441 int step;
Eric Laurent24482012012-05-10 09:41:17 -07001442
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001443 // skip a2dp absolute volume control request when the device
1444 // is not an a2dp device
1445 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1446 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1447 return;
1448 }
1449
Kenny Guy70e0c582015-06-30 19:18:28 +01001450 // If we are being called by the system (e.g. hardware keys) check for current user
1451 // so we handle user restrictions correctly.
1452 if (uid == android.os.Process.SYSTEM_UID) {
1453 uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
1454 }
John Spurlock59dc9c12015-03-02 11:20:15 -05001455 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001456 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001457 return;
1458 }
1459
Eric Laurentfde16d52012-12-03 14:42:39 -08001460 // reset any pending volume command
1461 synchronized (mSafeMediaVolumeState) {
1462 mPendingVolumeCommand = null;
1463 }
1464
Eric Laurent3ef75492012-11-28 12:12:23 -08001465 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1466 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1467 ((device & mFixedVolumeDevices) != 0)) {
1468 flags |= AudioManager.FLAG_FIXED_VOLUME;
1469
1470 // Always toggle between max safe volume and 0 for fixed volume devices where safe
1471 // volume is enforced, and max and 0 for the others.
1472 // This is simulated by stepping by the full allowed volume range
1473 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1474 (device & mSafeMediaVolumeDevices) != 0) {
Eric Laurenteab40d12017-06-09 12:45:21 -07001475 step = safeMediaVolumeIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001476 } else {
1477 step = streamState.getMaxIndex();
1478 }
1479 if (aliasIndex != 0) {
1480 aliasIndex = step;
1481 }
1482 } else {
1483 // convert one UI step (+/-1) into a number of internal units on the stream alias
1484 step = rescaleIndex(10, streamType, streamTypeAlias);
1485 }
1486
Eric Laurent42b041e2013-03-29 11:36:03 -07001487 // If either the client forces allowing ringer modes for this adjustment,
1488 // or the stream type is one that is affected by ringer modes
1489 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlockee5ad722015-03-03 16:17:21 -05001490 (streamTypeAlias == getUiSoundsStreamType())) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001491 int ringerMode = getRingerModeInternal();
Eric Laurent42b041e2013-03-29 11:36:03 -07001492 // do not vibrate if already in vibrate mode
1493 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
1494 flags &= ~AudioManager.FLAG_VIBRATE;
Eric Laurent3ef75492012-11-28 12:12:23 -08001495 }
RoboErik5452e252015-02-06 15:33:53 -08001496 // Check if the ringer mode handles this adjustment. If it does we don't
1497 // need to adjust the volume further.
John Spurlock50ced3f2015-05-11 16:00:09 -04001498 final int result = checkForRingerModeChange(aliasIndex, direction, step,
Julia Reynoldsed783792016-04-08 15:27:35 -04001499 streamState.mIsMuted, callingPackage, flags);
John Spurlocka11b4af2014-06-01 11:52:23 -04001500 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
1501 // If suppressing a volume adjustment in silent mode, display the UI hint
1502 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
1503 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
1504 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001505 // If suppressing a volume down adjustment in vibrate mode, display the UI hint
1506 if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
1507 flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
1508 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001509 }
John Spurlock50ced3f2015-05-11 16:00:09 -04001510 // If the ringermode is suppressing media, prevent changes
Julia Reynoldsed783792016-04-08 15:27:35 -04001511 if (!volumeAdjustmentAllowedByDnd(streamTypeAlias, flags)) {
John Spurlock50ced3f2015-05-11 16:00:09 -04001512 adjustVolume = false;
1513 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001514 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001515
Eric Laurent42b041e2013-03-29 11:36:03 -07001516 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
RoboErik5452e252015-02-06 15:33:53 -08001517 mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001518
John Du5a0cf7a2013-07-19 11:30:34 -07001519 // Check if volume update should be send to AVRCP
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001520 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1521 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1522 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1523 synchronized (mA2dpAvrcpLock) {
1524 if (mA2dp != null && mAvrcpAbsVolSupported) {
1525 mA2dp.adjustAvrcpAbsoluteVolume(direction);
1526 }
John Du5a0cf7a2013-07-19 11:30:34 -07001527 }
1528 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001529
RoboErik4197cb62015-01-21 15:45:32 -08001530 if (isMuteAdjust) {
1531 boolean state;
1532 if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
1533 state = !streamState.mIsMuted;
1534 } else {
1535 state = direction == AudioManager.ADJUST_MUTE;
1536 }
1537 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1538 setSystemAudioMute(state);
1539 }
1540 for (int stream = 0; stream < mStreamStates.length; stream++) {
1541 if (streamTypeAlias == mStreamVolumeAlias[stream]) {
Sungmin Choi841ed0a2015-07-26 23:09:49 -07001542 if (!(readCameraSoundForced()
1543 && (mStreamStates[stream].getStreamType()
1544 == AudioSystem.STREAM_SYSTEM_ENFORCED))) {
1545 mStreamStates[stream].mute(state);
1546 }
RoboErik4197cb62015-01-21 15:45:32 -08001547 }
1548 }
1549 } else if ((direction == AudioManager.ADJUST_RAISE) &&
Eric Laurent42b041e2013-03-29 11:36:03 -07001550 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
RoboErik4197cb62015-01-21 15:45:32 -08001551 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -04001552 mVolumeController.postDisplaySafeVolumeWarning(flags);
John Spurlock90874332015-03-10 16:00:54 -04001553 } else if (streamState.adjustIndex(direction * step, device, caller)
1554 || streamState.mIsMuted) {
RoboErik4197cb62015-01-21 15:45:32 -08001555 // Post message to set system volume (it in turn will post a
1556 // message to persist).
1557 if (streamState.mIsMuted) {
1558 // Unmute the stream if it was previously muted
RoboErik5452e252015-02-06 15:33:53 -08001559 if (direction == AudioManager.ADJUST_RAISE) {
1560 // unmute immediately for volume up
1561 streamState.mute(false);
1562 } else if (direction == AudioManager.ADJUST_LOWER) {
Muyuan Li1ed6df62016-06-18 11:16:52 -07001563 if (mIsSingleVolume) {
John Spurlocka48d7792015-03-03 17:35:57 -05001564 sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
1565 streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
1566 }
RoboErik5452e252015-02-06 15:33:53 -08001567 }
RoboErik4197cb62015-01-21 15:45:32 -08001568 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001569 sendMsg(mAudioHandler,
1570 MSG_SET_DEVICE_VOLUME,
1571 SENDMSG_QUEUE,
1572 device,
1573 0,
1574 streamState,
1575 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001576 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001577
RoboErik4197cb62015-01-21 15:45:32 -08001578 // Check if volume update should be sent to Hdmi system audio.
Jungshik Jang41d97462014-06-30 22:26:29 +09001579 int newIndex = mStreamStates[streamType].getIndex(device);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001580 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1581 setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
1582 }
Eric Laurent212532b2014-07-21 15:43:18 -07001583 if (mHdmiManager != null) {
1584 synchronized (mHdmiManager) {
Eric Laurent212532b2014-07-21 15:43:18 -07001585 // mHdmiCecSink true => mHdmiPlaybackClient != null
1586 if (mHdmiCecSink &&
1587 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1588 oldIndex != newIndex) {
1589 synchronized (mHdmiPlaybackClient) {
1590 int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
RoboErik4197cb62015-01-21 15:45:32 -08001591 KeyEvent.KEYCODE_VOLUME_UP;
Donghyun Cho5f6d404e2016-03-17 20:39:25 +09001592 final long ident = Binder.clearCallingIdentity();
1593 try {
1594 mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1595 mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1596 } finally {
1597 Binder.restoreCallingIdentity(ident);
1598 }
Eric Laurent212532b2014-07-21 15:43:18 -07001599 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001600 }
1601 }
1602 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001603 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001604 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001605 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001606 }
1607
RoboErik5452e252015-02-06 15:33:53 -08001608 // Called after a delay when volume down is pressed while muted
1609 private void onUnmuteStream(int stream, int flags) {
1610 VolumeStreamState streamState = mStreamStates[stream];
1611 streamState.mute(false);
1612
1613 final int device = getDeviceForStream(stream);
1614 final int index = mStreamStates[stream].getIndex(device);
1615 sendVolumeUpdate(stream, index, index, flags);
1616 }
1617
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001618 private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
1619 if (mHdmiManager == null
1620 || mHdmiTvClient == null
1621 || oldVolume == newVolume
1622 || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
1623
1624 // Sets the audio volume of AVR when we are in system audio mode. The new volume info
1625 // is tranformed to HDMI-CEC commands and passed through CEC bus.
1626 synchronized (mHdmiManager) {
1627 if (!mHdmiSystemAudioSupported) return;
1628 synchronized (mHdmiTvClient) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001629 final long token = Binder.clearCallingIdentity();
1630 try {
Jinsuk Kim7a9ba422015-02-16 16:47:38 +09001631 mHdmiTvClient.setSystemAudioVolume(oldVolume, newVolume, maxVolume);
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001632 } finally {
1633 Binder.restoreCallingIdentity(token);
1634 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001635 }
1636 }
1637 }
1638
Eric Laurentfde16d52012-12-03 14:42:39 -08001639 // StreamVolumeCommand contains the information needed to defer the process of
1640 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1641 class StreamVolumeCommand {
1642 public final int mStreamType;
1643 public final int mIndex;
1644 public final int mFlags;
1645 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001646
Eric Laurentfde16d52012-12-03 14:42:39 -08001647 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1648 mStreamType = streamType;
1649 mIndex = index;
1650 mFlags = flags;
1651 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001652 }
John Spurlock35134602014-07-24 18:10:48 -04001653
1654 @Override
1655 public String toString() {
1656 return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1657 .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1658 .append(mDevice).append('}').toString();
1659 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001660 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001661
Julia Reynolds48034f82016-03-09 10:15:16 -05001662 private int getNewRingerMode(int stream, int index, int flags) {
Zak Cohen47798292017-11-30 12:34:20 -08001663 // setRingerMode does nothing if the device is single volume,so the value would be unchanged
1664 if (mIsSingleVolume) {
1665 return getRingerModeExternal();
1666 }
1667
John Spurlockee5ad722015-03-03 16:17:21 -05001668 // setting volume on ui sounds stream type also controls silent mode
Eric Laurent3ef75492012-11-28 12:12:23 -08001669 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlock75ae23c2015-06-02 16:26:43 -04001670 (stream == getUiSoundsStreamType())) {
Eric Laurent3ef75492012-11-28 12:12:23 -08001671 int newRingerMode;
1672 if (index == 0) {
1673 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlocka48d7792015-03-03 17:35:57 -05001674 : mVolumePolicy.volumeDownToEnterSilent ? AudioManager.RINGER_MODE_SILENT
Julia Reynolds48034f82016-03-09 10:15:16 -05001675 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001676 } else {
1677 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1678 }
Julia Reynolds48034f82016-03-09 10:15:16 -05001679 return newRingerMode;
1680 }
1681 return getRingerModeExternal();
1682 }
1683
1684 private boolean isAndroidNPlus(String caller) {
1685 try {
1686 final ApplicationInfo applicationInfo =
1687 mContext.getPackageManager().getApplicationInfoAsUser(
1688 caller, 0, UserHandle.getUserId(Binder.getCallingUid()));
1689 if (applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
1690 return true;
1691 }
1692 return false;
1693 } catch (PackageManager.NameNotFoundException e) {
1694 return true;
1695 }
1696 }
1697
1698 private boolean wouldToggleZenMode(int newMode) {
1699 if (getRingerModeExternal() == AudioManager.RINGER_MODE_SILENT
1700 && newMode != AudioManager.RINGER_MODE_SILENT) {
1701 return true;
1702 } else if (getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT
1703 && newMode == AudioManager.RINGER_MODE_SILENT) {
1704 return true;
1705 }
1706 return false;
1707 }
1708
1709 private void onSetStreamVolume(int streamType, int index, int flags, int device,
1710 String caller) {
1711 final int stream = mStreamVolumeAlias[streamType];
1712 setStreamVolumeInt(stream, index, device, false, caller);
1713 // setting volume on ui sounds stream type also controls silent mode
1714 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1715 (stream == getUiSoundsStreamType())) {
1716 setRingerMode(getNewRingerMode(stream, index, flags),
1717 TAG + ".onSetStreamVolume", false /*external*/);
Eric Laurent3ef75492012-11-28 12:12:23 -08001718 }
John Spurlock75ae23c2015-06-02 16:26:43 -04001719 // setting non-zero volume for a muted stream unmutes the stream and vice versa
1720 mStreamStates[stream].mute(index == 0);
Eric Laurentfde16d52012-12-03 14:42:39 -08001721 }
1722
1723 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001724 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
Phil Weaverf1a9aff2017-03-23 17:21:29 -07001725 if ((streamType == AudioManager.STREAM_ACCESSIBILITY) && !canChangeAccessibilityVolume()) {
Jean-Michel Triviab2d9312017-03-13 15:33:39 -07001726 Log.w(TAG, "Trying to call setStreamVolume() for a11y without"
Phil Weaverf1a9aff2017-03-23 17:21:29 -07001727 + " CHANGE_ACCESSIBILITY_VOLUME callingPackage=" + callingPackage);
Jean-Michel Triviab2d9312017-03-13 15:33:39 -07001728 return;
1729 }
Nadav Bar6b7751d2017-12-24 16:03:08 +02001730 if ((streamType == AudioManager.STREAM_VOICE_CALL) &&
1731 (index == 0) &&
1732 (mContext.checkCallingOrSelfPermission(
1733 android.Manifest.permission.MODIFY_PHONE_STATE)
1734 != PackageManager.PERMISSION_GRANTED)) {
1735 Log.w(TAG, "Trying to call setStreamVolume() for STREAM_VOICE_CALL and index 0 without"
1736 + " MODIFY_PHONE_STATE callingPackage=" + callingPackage);
1737 return;
1738 }
Jean-Michel Trivicf170362017-08-24 17:24:57 -07001739 mVolumeLogger.log(new VolumeEvent(VolumeEvent.VOL_SET_STREAM_VOL, streamType,
1740 index/*val1*/, flags/*val2*/, callingPackage));
John Spurlock90874332015-03-10 16:00:54 -04001741 setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
1742 Binder.getCallingUid());
RoboErik0dac35a2014-08-12 15:48:49 -07001743 }
1744
Phil Weaverf1a9aff2017-03-23 17:21:29 -07001745 private boolean canChangeAccessibilityVolume() {
1746 synchronized (mAccessibilityServiceUidsLock) {
1747 if (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
1748 android.Manifest.permission.CHANGE_ACCESSIBILITY_VOLUME)) {
1749 return true;
1750 }
1751 if (mAccessibilityServiceUids != null) {
1752 int callingUid = Binder.getCallingUid();
1753 for (int i = 0; i < mAccessibilityServiceUids.length; i++) {
1754 if (mAccessibilityServiceUids[i] == callingUid) {
1755 return true;
1756 }
1757 }
1758 }
1759 return false;
1760 }
1761 }
1762
RoboErik0dac35a2014-08-12 15:48:49 -07001763 private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
John Spurlock90874332015-03-10 16:00:54 -04001764 String caller, int uid) {
Jean-Michel Triviac487672016-11-11 10:05:18 -08001765 if (DEBUG_VOL) {
1766 Log.d(TAG, "setStreamVolume(stream=" + streamType+", index=" + index
1767 + ", calling=" + callingPackage + ")");
1768 }
Eric Laurent83a017b2013-03-19 18:15:31 -07001769 if (mUseFixedVolume) {
1770 return;
1771 }
1772
Eric Laurentfde16d52012-12-03 14:42:39 -08001773 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001774 int streamTypeAlias = mStreamVolumeAlias[streamType];
1775 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001776
1777 final int device = getDeviceForStream(streamType);
1778 int oldIndex;
1779
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001780 // skip a2dp absolute volume control request when the device
1781 // is not an a2dp device
1782 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1783 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1784 return;
1785 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001786 // If we are being called by the system (e.g. hardware keys) check for current user
1787 // so we handle user restrictions correctly.
1788 if (uid == android.os.Process.SYSTEM_UID) {
1789 uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
1790 }
John Spurlock59dc9c12015-03-02 11:20:15 -05001791 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001792 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001793 return;
1794 }
1795
Julia Reynolds48034f82016-03-09 10:15:16 -05001796 if (isAndroidNPlus(callingPackage)
1797 && wouldToggleZenMode(getNewRingerMode(streamTypeAlias, index, flags))
1798 && !mNm.isNotificationPolicyAccessGrantedForPackage(callingPackage)) {
1799 throw new SecurityException("Not allowed to change Do Not Disturb state");
1800 }
1801
Julia Reynoldsed783792016-04-08 15:27:35 -04001802 if (!volumeAdjustmentAllowedByDnd(streamTypeAlias, flags)) {
1803 return;
1804 }
1805
Eric Laurentfde16d52012-12-03 14:42:39 -08001806 synchronized (mSafeMediaVolumeState) {
1807 // reset any pending volume command
1808 mPendingVolumeCommand = null;
1809
Eric Laurent42b041e2013-03-29 11:36:03 -07001810 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001811
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001812 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001813
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001814 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1815 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1816 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1817 synchronized (mA2dpAvrcpLock) {
1818 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001819 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001820 }
John Du5a0cf7a2013-07-19 11:30:34 -07001821 }
1822 }
1823
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001824 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1825 setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
Jungshik Jang41d97462014-06-30 22:26:29 +09001826 }
1827
Eric Laurentfde16d52012-12-03 14:42:39 -08001828 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001829 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001830 ((device & mFixedVolumeDevices) != 0)) {
1831 flags |= AudioManager.FLAG_FIXED_VOLUME;
1832
1833 // volume is either 0 or max allowed for fixed volume devices
1834 if (index != 0) {
1835 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1836 (device & mSafeMediaVolumeDevices) != 0) {
Eric Laurenteab40d12017-06-09 12:45:21 -07001837 index = safeMediaVolumeIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001838 } else {
1839 index = streamState.getMaxIndex();
1840 }
1841 }
1842 }
1843
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001844 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001845 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001846 mPendingVolumeCommand = new StreamVolumeCommand(
1847 streamType, index, flags, device);
1848 } else {
John Spurlock90874332015-03-10 16:00:54 -04001849 onSetStreamVolume(streamType, index, flags, device, caller);
Eric Laurent42b041e2013-03-29 11:36:03 -07001850 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001851 }
1852 }
Eric Laurent25101b02011-02-02 09:33:30 -08001853 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001854 }
1855
Julia Reynoldsed783792016-04-08 15:27:35 -04001856 // No ringer affected streams can be changed in total silence mode except those that
1857 // will cause the device to exit total silence mode.
1858 private boolean volumeAdjustmentAllowedByDnd(int streamTypeAlias, int flags) {
1859 if (mNm.getZenMode() == Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
1860 && isStreamMutedByRingerMode(streamTypeAlias)) {
1861 if (!(((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1862 (streamTypeAlias == getUiSoundsStreamType()))) {
1863 return false;
1864 }
1865 }
1866 return true;
1867 }
1868
Eric Laurent45c90ce2012-04-24 18:44:22 -07001869 /** @see AudioManager#forceVolumeControlStream(int) */
1870 public void forceVolumeControlStream(int streamType, IBinder cb) {
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001871 if (DEBUG_VOL) { Log.d(TAG, String.format("forceVolumeControlStream(%d)", streamType)); }
Eric Laurent45c90ce2012-04-24 18:44:22 -07001872 synchronized(mForceControlStreamLock) {
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001873 if (mVolumeControlStream != -1 && streamType != -1) {
1874 mUserSelectedVolumeControlStream = true;
1875 }
Eric Laurent45c90ce2012-04-24 18:44:22 -07001876 mVolumeControlStream = streamType;
1877 if (mVolumeControlStream == -1) {
1878 if (mForceControlStreamClient != null) {
1879 mForceControlStreamClient.release();
1880 mForceControlStreamClient = null;
1881 }
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001882 mUserSelectedVolumeControlStream = false;
Eric Laurent45c90ce2012-04-24 18:44:22 -07001883 } else {
1884 mForceControlStreamClient = new ForceControlStreamClient(cb);
1885 }
1886 }
1887 }
1888
1889 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1890 private IBinder mCb; // To be notified of client's death
1891
1892 ForceControlStreamClient(IBinder cb) {
1893 if (cb != null) {
1894 try {
1895 cb.linkToDeath(this, 0);
1896 } catch (RemoteException e) {
1897 // Client has died!
1898 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1899 cb = null;
1900 }
1901 }
1902 mCb = cb;
1903 }
1904
1905 public void binderDied() {
1906 synchronized(mForceControlStreamLock) {
1907 Log.w(TAG, "SCO client died");
1908 if (mForceControlStreamClient != this) {
1909 Log.w(TAG, "unregistered control stream client died");
1910 } else {
1911 mForceControlStreamClient = null;
1912 mVolumeControlStream = -1;
Jean-Michel Trivia7880d42017-04-15 12:41:05 -07001913 mUserSelectedVolumeControlStream = false;
Eric Laurent45c90ce2012-04-24 18:44:22 -07001914 }
1915 }
1916 }
1917
1918 public void release() {
1919 if (mCb != null) {
1920 mCb.unlinkToDeath(this, 0);
1921 mCb = null;
1922 }
1923 }
1924 }
1925
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001926 private void sendBroadcastToAll(Intent intent) {
Christopher Tate267603f2015-01-20 14:21:21 -08001927 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
John Spurlock86490862015-02-25 11:22:52 -05001928 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001929 final long ident = Binder.clearCallingIdentity();
1930 try {
1931 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1932 } finally {
1933 Binder.restoreCallingIdentity(ident);
1934 }
1935 }
1936
1937 private void sendStickyBroadcastToAll(Intent intent) {
John Spurlock86490862015-02-25 11:22:52 -05001938 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001939 final long ident = Binder.clearCallingIdentity();
1940 try {
1941 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1942 } finally {
1943 Binder.restoreCallingIdentity(ident);
1944 }
1945 }
1946
Kenny Guy70e0c582015-06-30 19:18:28 +01001947 private int getCurrentUserId() {
1948 final long ident = Binder.clearCallingIdentity();
1949 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08001950 UserInfo currentUser = ActivityManager.getService().getCurrentUser();
Kenny Guy70e0c582015-06-30 19:18:28 +01001951 return currentUser.id;
1952 } catch (RemoteException e) {
1953 // Activity manager not running, nothing we can do assume user 0.
1954 } finally {
1955 Binder.restoreCallingIdentity(ident);
1956 }
Xiaohui Chen7c696362015-09-16 09:56:14 -07001957 return UserHandle.USER_SYSTEM;
Kenny Guy70e0c582015-06-30 19:18:28 +01001958 }
1959
Eric Laurent25101b02011-02-02 09:33:30 -08001960 // UI update and Broadcast Intent
Yue Li949865b2017-05-24 17:25:28 -07001961 protected void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
John Spurlock72966d62015-06-18 15:45:07 -04001962 streamType = mStreamVolumeAlias[streamType];
Eric Laurent25101b02011-02-02 09:33:30 -08001963
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001964 if (streamType == AudioSystem.STREAM_MUSIC) {
1965 flags = updateFlagsForSystemAudio(flags);
Jungshik Jang1a6be6e2014-09-16 11:04:54 +09001966 }
John Spurlock3346a802014-05-20 16:25:37 -04001967 mVolumeController.postVolumeChanged(streamType, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001968 }
1969
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001970 // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
1971 // receives volume notification from Audio Receiver.
1972 private int updateFlagsForSystemAudio(int flags) {
1973 if (mHdmiTvClient != null) {
1974 synchronized (mHdmiTvClient) {
1975 if (mHdmiSystemAudioSupported &&
1976 ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
1977 flags &= ~AudioManager.FLAG_SHOW_UI;
1978 }
1979 }
1980 }
1981 return flags;
1982 }
1983
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001984 // UI update and Broadcast Intent
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001985 private void sendMasterMuteUpdate(boolean muted, int flags) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001986 mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
Justin Koh57978ed2012-04-03 17:37:58 -07001987 broadcastMasterMuteStatus(muted);
1988 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001989
Justin Koh57978ed2012-04-03 17:37:58 -07001990 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001991 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1992 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001993 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1994 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001995 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001996 }
1997
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001998 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001999 * Sets the stream state's index, and posts a message to set system volume.
2000 * This will not call out to the UI. Assumes a valid stream type.
2001 *
2002 * @param streamType Type of the stream
2003 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002004 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002005 * @param force If true, set the volume even if the desired volume is same
2006 * as the current volume.
2007 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002008 private void setStreamVolumeInt(int streamType,
2009 int index,
2010 int device,
John Spurlock90874332015-03-10 16:00:54 -04002011 boolean force,
2012 String caller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002013 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07002014
John Spurlock90874332015-03-10 16:00:54 -04002015 if (streamState.setIndex(index, device, caller) || force) {
Eric Laurent42b041e2013-03-29 11:36:03 -07002016 // Post message to set system volume (it in turn will post a message
2017 // to persist).
2018 sendMsg(mAudioHandler,
2019 MSG_SET_DEVICE_VOLUME,
2020 SENDMSG_QUEUE,
2021 device,
2022 0,
2023 streamState,
2024 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002025 }
2026 }
2027
Jinsuk Kim336cdb42014-11-29 06:27:00 +09002028 private void setSystemAudioMute(boolean state) {
2029 if (mHdmiManager == null || mHdmiTvClient == null) return;
2030 synchronized (mHdmiManager) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09002031 if (!mHdmiSystemAudioSupported) return;
2032 synchronized (mHdmiTvClient) {
2033 final long token = Binder.clearCallingIdentity();
2034 try {
2035 mHdmiTvClient.setSystemAudioMute(state);
2036 } finally {
2037 Binder.restoreCallingIdentity(token);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09002038 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09002039 }
2040 }
2041 }
2042
Eric Laurent25101b02011-02-02 09:33:30 -08002043 /** get stream mute state. */
2044 public boolean isStreamMute(int streamType) {
RoboErik7c82ced2014-12-04 17:39:08 -08002045 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
2046 streamType = getActiveStreamType(streamType);
2047 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002048 synchronized (VolumeStreamState.class) {
jiabin93d32ef2017-07-11 13:50:02 -07002049 ensureValidStreamType(streamType);
RoboErik4197cb62015-01-21 15:45:32 -08002050 return mStreamStates[streamType].mIsMuted;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002051 }
Eric Laurent25101b02011-02-02 09:33:30 -08002052 }
2053
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07002054 private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
2055 private IBinder mICallback; // To be notified of client's death
2056
2057 RmtSbmxFullVolDeathHandler(IBinder cb) {
2058 mICallback = cb;
2059 try {
2060 cb.linkToDeath(this, 0/*flags*/);
2061 } catch (RemoteException e) {
2062 Log.e(TAG, "can't link to death", e);
2063 }
2064 }
2065
2066 boolean isHandlerFor(IBinder cb) {
2067 return mICallback.equals(cb);
2068 }
2069
2070 void forget() {
2071 try {
2072 mICallback.unlinkToDeath(this, 0/*flags*/);
2073 } catch (NoSuchElementException e) {
2074 Log.e(TAG, "error unlinking to death", e);
2075 }
2076 }
2077
2078 public void binderDied() {
2079 Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
2080 forceRemoteSubmixFullVolume(false, mICallback);
2081 }
2082 }
2083
2084 /**
2085 * call must be synchronized on mRmtSbmxFullVolDeathHandlers
2086 * @return true if there is a registered death handler, false otherwise */
2087 private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
2088 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
2089 while (it.hasNext()) {
2090 final RmtSbmxFullVolDeathHandler handler = it.next();
2091 if (handler.isHandlerFor(cb)) {
2092 handler.forget();
2093 mRmtSbmxFullVolDeathHandlers.remove(handler);
2094 return true;
2095 }
2096 }
2097 return false;
2098 }
2099
2100 /** call synchronized on mRmtSbmxFullVolDeathHandlers */
2101 private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
2102 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
2103 while (it.hasNext()) {
2104 if (it.next().isHandlerFor(cb)) {
2105 return true;
2106 }
2107 }
2108 return false;
2109 }
2110
2111 private int mRmtSbmxFullVolRefCount = 0;
2112 private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
2113 new ArrayList<RmtSbmxFullVolDeathHandler>();
2114
2115 public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
2116 if (cb == null) {
2117 return;
2118 }
2119 if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
2120 android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
2121 Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
2122 return;
2123 }
2124 synchronized(mRmtSbmxFullVolDeathHandlers) {
2125 boolean applyRequired = false;
2126 if (startForcing) {
2127 if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
2128 mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
2129 if (mRmtSbmxFullVolRefCount == 0) {
2130 mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
2131 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
2132 applyRequired = true;
2133 }
2134 mRmtSbmxFullVolRefCount++;
2135 }
2136 } else {
2137 if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
2138 mRmtSbmxFullVolRefCount--;
2139 if (mRmtSbmxFullVolRefCount == 0) {
2140 mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
2141 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
2142 applyRequired = true;
2143 }
2144 }
2145 }
2146 if (applyRequired) {
2147 // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
2148 checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
2149 mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
2150 }
2151 }
2152 }
2153
Kenny Guy70e0c582015-06-30 19:18:28 +01002154 private void setMasterMuteInternal(boolean mute, int flags, String callingPackage, int uid,
2155 int userId) {
2156 // If we are being called by the system check for user we are going to change
2157 // so we handle user restrictions correctly.
2158 if (uid == android.os.Process.SYSTEM_UID) {
2159 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
2160 }
Makoto Onuki4f160732015-10-27 17:15:38 -07002161 // If OP_AUDIO_MASTER_VOLUME is set, disallow unmuting.
2162 if (!mute && mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
RoboErik7c82ced2014-12-04 17:39:08 -08002163 != AppOpsManager.MODE_ALLOWED) {
Julia Reynolds4a21b252014-06-04 11:11:43 -04002164 return;
2165 }
Kenny Guy70e0c582015-06-30 19:18:28 +01002166 if (userId != UserHandle.getCallingUserId() &&
2167 mContext.checkCallingOrSelfPermission(
2168 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
2169 != PackageManager.PERMISSION_GRANTED) {
2170 return;
2171 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08002172 setMasterMuteInternalNoCallerCheck(mute, flags, userId);
2173 }
2174
2175 private void setMasterMuteInternalNoCallerCheck(boolean mute, int flags, int userId) {
2176 if (DEBUG_VOL) {
2177 Log.d(TAG, String.format("Master mute %s, %d, user=%d", mute, flags, userId));
2178 }
2179 if (mUseFixedVolume) {
2180 return; // If using fixed volume, we don't mute.
2181 }
Kenny Guy70e0c582015-06-30 19:18:28 +01002182 if (getCurrentUserId() == userId) {
2183 if (mute != AudioSystem.getMasterMute()) {
2184 setSystemAudioMute(mute);
2185 AudioSystem.setMasterMute(mute);
Kenny Guy70e0c582015-06-30 19:18:28 +01002186 sendMasterMuteUpdate(mute, flags);
RoboErik7c82ced2014-12-04 17:39:08 -08002187
Kenny Guy70e0c582015-06-30 19:18:28 +01002188 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
2189 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute);
2190 sendBroadcastToAll(intent);
2191 }
Jason Simmons1ce5b262012-02-02 13:00:17 -08002192 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08002193 }
2194
2195 /** get master mute state. */
2196 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08002197 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08002198 }
2199
Kenny Guy70e0c582015-06-30 19:18:28 +01002200 public void setMasterMute(boolean mute, int flags, String callingPackage, int userId) {
2201 setMasterMuteInternal(mute, flags, callingPackage, Binder.getCallingUid(),
2202 userId);
John Spurlockee5ad722015-03-03 16:17:21 -05002203 }
2204
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002205 /** @see AudioManager#getStreamVolume(int) */
2206 public int getStreamVolume(int streamType) {
2207 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002208 int device = getDeviceForStream(streamType);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002209 synchronized (VolumeStreamState.class) {
2210 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07002211
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002212 // by convention getStreamVolume() returns 0 when a stream is muted.
RoboErik4197cb62015-01-21 15:45:32 -08002213 if (mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002214 index = 0;
2215 }
2216 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
2217 (device & mFixedVolumeDevices) != 0) {
2218 index = mStreamStates[streamType].getMaxIndex();
2219 }
2220 return (index + 5) / 10;
Eric Laurent42b041e2013-03-29 11:36:03 -07002221 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002222 }
2223
2224 /** @see AudioManager#getStreamMaxVolume(int) */
2225 public int getStreamMaxVolume(int streamType) {
2226 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07002227 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002228 }
2229
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08002230 /** @see AudioManager#getStreamMinVolumeInt(int) */
John Spurlockb6e19e32015-03-10 21:33:44 -04002231 public int getStreamMinVolume(int streamType) {
2232 ensureValidStreamType(streamType);
2233 return (mStreamStates[streamType].getMinIndex() + 5) / 10;
2234 }
2235
Eric Laurent25101b02011-02-02 09:33:30 -08002236 /** Get last audible volume before stream was muted. */
2237 public int getLastAudibleStreamVolume(int streamType) {
2238 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002239 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07002240 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08002241 }
2242
John Spurlockee5ad722015-03-03 16:17:21 -05002243 /** @see AudioManager#getUiSoundsStreamType() */
2244 public int getUiSoundsStreamType() {
John Spurlock4f0f1202014-08-05 13:28:33 -04002245 return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
Eric Laurent6d517662012-04-23 18:42:39 -07002246 }
2247
Makoto Onukid45a4a22015-11-02 17:17:38 -08002248 /** @see AudioManager#setMicrophoneMute(boolean) */
2249 @Override
Kenny Guy70e0c582015-06-30 19:18:28 +01002250 public void setMicrophoneMute(boolean on, String callingPackage, int userId) {
2251 // If we are being called by the system check for user we are going to change
2252 // so we handle user restrictions correctly.
2253 int uid = Binder.getCallingUid();
2254 if (uid == android.os.Process.SYSTEM_UID) {
2255 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
2256 }
Makoto Onuki4f160732015-10-27 17:15:38 -07002257 // If OP_MUTE_MICROPHONE is set, disallow unmuting.
2258 if (!on && mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, uid, callingPackage)
Kenny Guy70e0c582015-06-30 19:18:28 +01002259 != AppOpsManager.MODE_ALLOWED) {
Emily Bernier22c921a2014-05-28 11:01:32 -04002260 return;
2261 }
Jean-Michel Trivi4a4fea02014-08-29 18:14:09 -07002262 if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
2263 return;
2264 }
Kenny Guy70e0c582015-06-30 19:18:28 +01002265 if (userId != UserHandle.getCallingUserId() &&
2266 mContext.checkCallingOrSelfPermission(
2267 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
2268 != PackageManager.PERMISSION_GRANTED) {
2269 return;
2270 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08002271 setMicrophoneMuteNoCallerCheck(on, userId);
2272 }
Emily Bernier22c921a2014-05-28 11:01:32 -04002273
Makoto Onukid45a4a22015-11-02 17:17:38 -08002274 private void setMicrophoneMuteNoCallerCheck(boolean on, int userId) {
2275 if (DEBUG_VOL) {
2276 Log.d(TAG, String.format("Mic mute %s, user=%d", on, userId));
2277 }
Jean-Michel Trivi7be17d22017-12-21 18:09:21 -08002278 // only mute for the current user
Kenny Guy70e0c582015-06-30 19:18:28 +01002279 if (getCurrentUserId() == userId) {
Jean-Michel Trivi7be17d22017-12-21 18:09:21 -08002280 final boolean currentMute = AudioSystem.isMicrophoneMuted();
Kenny Guy70e0c582015-06-30 19:18:28 +01002281 AudioSystem.muteMicrophone(on);
Jean-Michel Trivi7be17d22017-12-21 18:09:21 -08002282 if (on != currentMute) {
2283 mContext.sendBroadcast(new Intent(AudioManager.ACTION_MICROPHONE_MUTE_CHANGED)
2284 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY));
2285 }
Kenny Guy70e0c582015-06-30 19:18:28 +01002286 }
Emily Bernier22c921a2014-05-28 11:01:32 -04002287 }
2288
John Spurlock661f2cf2014-11-17 10:29:10 -05002289 @Override
2290 public int getRingerModeExternal() {
2291 synchronized(mSettingsLock) {
2292 return mRingerModeExternal;
2293 }
2294 }
2295
2296 @Override
2297 public int getRingerModeInternal() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08002298 synchronized(mSettingsLock) {
2299 return mRingerMode;
2300 }
2301 }
2302
2303 private void ensureValidRingerMode(int ringerMode) {
John Spurlock97559372014-10-24 16:27:36 -04002304 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08002305 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
2306 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002307 }
2308
John Spurlock97559372014-10-24 16:27:36 -04002309 /** @see AudioManager#isValidRingerMode(int) */
2310 public boolean isValidRingerMode(int ringerMode) {
2311 return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
2312 }
2313
John Spurlock661f2cf2014-11-17 10:29:10 -05002314 public void setRingerModeExternal(int ringerMode, String caller) {
Julia Reynolds48034f82016-03-09 10:15:16 -05002315 if (isAndroidNPlus(caller) && wouldToggleZenMode(ringerMode)
2316 && !mNm.isNotificationPolicyAccessGrantedForPackage(caller)) {
2317 throw new SecurityException("Not allowed to change Do Not Disturb state");
2318 }
2319
John Spurlockaf88a192014-12-23 16:14:44 -05002320 setRingerMode(ringerMode, caller, true /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05002321 }
2322
2323 public void setRingerModeInternal(int ringerMode, String caller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05002324 enforceVolumeController("setRingerModeInternal");
John Spurlockaf88a192014-12-23 16:14:44 -05002325 setRingerMode(ringerMode, caller, false /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05002326 }
2327
2328 private void setRingerMode(int ringerMode, String caller, boolean external) {
Muyuan Li1ed6df62016-06-18 11:16:52 -07002329 if (mUseFixedVolume || mIsSingleVolume) {
Eric Laurent83a017b2013-03-19 18:15:31 -07002330 return;
2331 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002332 if (caller == null || caller.length() == 0) {
2333 throw new IllegalArgumentException("Bad caller: " + caller);
2334 }
John Spurlock97559372014-10-24 16:27:36 -04002335 ensureValidRingerMode(ringerMode);
Eric Laurent24482012012-05-10 09:41:17 -07002336 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
2337 ringerMode = AudioManager.RINGER_MODE_SILENT;
2338 }
John Spurlockaf88a192014-12-23 16:14:44 -05002339 final long identity = Binder.clearCallingIdentity();
2340 try {
2341 synchronized (mSettingsLock) {
2342 final int ringerModeInternal = getRingerModeInternal();
2343 final int ringerModeExternal = getRingerModeExternal();
2344 if (external) {
2345 setRingerModeExt(ringerMode);
2346 if (mRingerModeDelegate != null) {
2347 ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
John Spurlocka48d7792015-03-03 17:35:57 -05002348 ringerMode, caller, ringerModeInternal, mVolumePolicy);
John Spurlockaf88a192014-12-23 16:14:44 -05002349 }
2350 if (ringerMode != ringerModeInternal) {
2351 setRingerModeInt(ringerMode, true /*persist*/);
2352 }
2353 } else /*internal*/ {
2354 if (ringerMode != ringerModeInternal) {
2355 setRingerModeInt(ringerMode, true /*persist*/);
2356 }
2357 if (mRingerModeDelegate != null) {
2358 ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
John Spurlocka48d7792015-03-03 17:35:57 -05002359 ringerMode, caller, ringerModeExternal, mVolumePolicy);
John Spurlockaf88a192014-12-23 16:14:44 -05002360 }
2361 setRingerModeExt(ringerMode);
John Spurlock57627792014-12-11 11:29:54 -05002362 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002363 }
John Spurlockaf88a192014-12-23 16:14:44 -05002364 } finally {
2365 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002366 }
2367 }
2368
John Spurlock661f2cf2014-11-17 10:29:10 -05002369 private void setRingerModeExt(int ringerMode) {
2370 synchronized(mSettingsLock) {
2371 if (ringerMode == mRingerModeExternal) return;
2372 mRingerModeExternal = ringerMode;
John Spurlocke5b42d92014-10-15 12:03:48 -04002373 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002374 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05002375 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
John Spurlocke5b42d92014-10-15 12:03:48 -04002376 }
2377
John Spurlock50ced3f2015-05-11 16:00:09 -04002378 private void muteRingerModeStreams() {
Eric Laurent5b4e6542010-03-19 20:02:21 -07002379 // Mute stream if not previously muted by ringer mode and ringer mode
2380 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
2381 // Unmute stream if previously muted by ringer mode and ringer mode
2382 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07002383 int numStreamTypes = AudioSystem.getNumStreamTypes();
John Spurlock50ced3f2015-05-11 16:00:09 -04002384 final boolean ringerModeMute = mRingerMode == AudioManager.RINGER_MODE_VIBRATE
2385 || mRingerMode == AudioManager.RINGER_MODE_SILENT;
Eric Laurent5b4e6542010-03-19 20:02:21 -07002386 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002387 final boolean isMuted = isStreamMutedByRingerMode(streamType);
2388 final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
2389 if (isMuted == shouldMute) continue;
2390 if (!shouldMute) {
2391 // unmute
2392 // ring and notifications volume should never be 0 when not silenced
John Spurlockd9c75db2015-04-28 11:19:13 -04002393 if (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002394 synchronized (VolumeStreamState.class) {
John Spurlocka48d7792015-03-03 17:35:57 -05002395 final VolumeStreamState vss = mStreamStates[streamType];
2396 for (int i = 0; i < vss.mIndexMap.size(); i++) {
2397 int device = vss.mIndexMap.keyAt(i);
2398 int value = vss.mIndexMap.valueAt(i);
John Spurlock2bb02ec2015-03-02 13:13:06 -05002399 if (value == 0) {
John Spurlocka48d7792015-03-03 17:35:57 -05002400 vss.setIndex(10, device, TAG);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002401 }
2402 }
Eric Laurent9e0d25f2015-02-12 17:28:53 -08002403 // Persist volume for stream ring when it is changed here
2404 final int device = getDeviceForStream(streamType);
2405 sendMsg(mAudioHandler,
2406 MSG_PERSIST_VOLUME,
2407 SENDMSG_QUEUE,
2408 device,
2409 0,
2410 mStreamStates[streamType],
2411 PERSIST_DELAY);
Eric Laurentb024c302011-10-14 17:19:27 -07002412 }
Eric Laurent9bcf4012009-06-12 06:09:28 -07002413 }
RoboErik4197cb62015-01-21 15:45:32 -08002414 mStreamStates[streamType].mute(false);
John Spurlock661f2cf2014-11-17 10:29:10 -05002415 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent5b4e6542010-03-19 20:02:21 -07002416 } else {
John Spurlock661f2cf2014-11-17 10:29:10 -05002417 // mute
RoboErik4197cb62015-01-21 15:45:32 -08002418 mStreamStates[streamType].mute(true);
John Spurlock661f2cf2014-11-17 10:29:10 -05002419 mRingerModeMutedStreams |= (1 << streamType);
Jason Parekhb1096152009-03-24 17:48:25 -07002420 }
2421 }
John Spurlock50ced3f2015-05-11 16:00:09 -04002422 }
2423
2424 private void setRingerModeInt(int ringerMode, boolean persist) {
2425 final boolean change;
2426 synchronized(mSettingsLock) {
2427 change = mRingerMode != ringerMode;
2428 mRingerMode = ringerMode;
2429 }
2430
2431 muteRingerModeStreams();
Eric Laurenta553c252009-07-17 12:17:14 -07002432
Jason Parekhb1096152009-03-24 17:48:25 -07002433 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07002434 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002435 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07002436 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
2437 }
John Spurlockbcc10872014-11-28 15:29:21 -05002438 if (change) {
2439 // Send sticky broadcast
2440 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
2441 }
Jason Parekhb1096152009-03-24 17:48:25 -07002442 }
2443
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002444 /** @see AudioManager#shouldVibrate(int) */
2445 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002446 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002447
2448 switch (getVibrateSetting(vibrateType)) {
2449
2450 case AudioManager.VIBRATE_SETTING_ON:
John Spurlock57627792014-12-11 11:29:54 -05002451 return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002452
2453 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
John Spurlock57627792014-12-11 11:29:54 -05002454 return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002455
2456 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04002457 // return false, even for incoming calls
2458 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002459
2460 default:
2461 return false;
2462 }
2463 }
2464
2465 /** @see AudioManager#getVibrateSetting(int) */
2466 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002467 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002468 return (mVibrateSetting >> (vibrateType * 2)) & 3;
2469 }
2470
2471 /** @see AudioManager#setVibrateSetting(int, int) */
2472 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
2473
Eric Laurentbffc3d12012-05-07 17:43:49 -07002474 if (!mHasVibrator) return;
2475
John Spurlock61560172015-02-06 19:46:04 -05002476 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
2477 vibrateSetting);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002478
2479 // Broadcast change
2480 broadcastVibrateSetting(vibrateType);
2481
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002482 }
2483
Eric Laurent9272b4b2010-01-23 17:12:59 -08002484 private class SetModeDeathHandler implements IBinder.DeathRecipient {
2485 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002486 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002487 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
2488
Eric Laurent9f103de2011-09-08 15:04:23 -07002489 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08002490 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07002491 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002492 }
2493
2494 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07002495 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002496 synchronized(mSetModeDeathHandlers) {
2497 Log.w(TAG, "setMode() client died");
2498 int index = mSetModeDeathHandlers.indexOf(this);
2499 if (index < 0) {
2500 Log.w(TAG, "unregistered setMode() client died");
2501 } else {
John Spurlock90874332015-03-10 16:00:54 -04002502 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid, TAG);
Eric Laurent9272b4b2010-01-23 17:12:59 -08002503 }
2504 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002505 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2506 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002507 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07002508 final long ident = Binder.clearCallingIdentity();
2509 disconnectBluetoothSco(newModeOwnerPid);
2510 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07002511 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08002512 }
2513
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002514 public int getPid() {
2515 return mPid;
2516 }
2517
Eric Laurent9272b4b2010-01-23 17:12:59 -08002518 public void setMode(int mode) {
2519 mMode = mode;
2520 }
2521
2522 public int getMode() {
2523 return mMode;
2524 }
2525
2526 public IBinder getBinder() {
2527 return mCb;
2528 }
2529 }
2530
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002531 /** @see AudioManager#setMode(int) */
John Spurlock90874332015-03-10 16:00:54 -04002532 public void setMode(int mode, IBinder cb, String callingPackage) {
2533 if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ", callingPackage=" + callingPackage + ")"); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002534 if (!checkAudioSettingsPermission("setMode()")) {
2535 return;
2536 }
Eric Laurenta553c252009-07-17 12:17:14 -07002537
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07002538 if ( (mode == AudioSystem.MODE_IN_CALL) &&
2539 (mContext.checkCallingOrSelfPermission(
2540 android.Manifest.permission.MODIFY_PHONE_STATE)
2541 != PackageManager.PERMISSION_GRANTED)) {
2542 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
2543 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
2544 return;
2545 }
2546
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08002547 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07002548 return;
2549 }
2550
Eric Laurentd7454be2011-09-14 08:45:58 -07002551 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002552 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07002553 if (mode == AudioSystem.MODE_CURRENT) {
2554 mode = mMode;
2555 }
John Spurlock90874332015-03-10 16:00:54 -04002556 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid(), callingPackage);
Eric Laurent9f103de2011-09-08 15:04:23 -07002557 }
2558 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2559 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002560 if (newModeOwnerPid != 0) {
2561 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07002562 }
2563 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002564
Eric Laurent9f103de2011-09-08 15:04:23 -07002565 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07002566 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07002567 // any mode other than NORMAL.
John Spurlock90874332015-03-10 16:00:54 -04002568 private int setModeInt(int mode, IBinder cb, int pid, String caller) {
2569 if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ", caller="
2570 + caller + ")"); }
Eric Laurentd7454be2011-09-14 08:45:58 -07002571 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002572 if (cb == null) {
2573 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07002574 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07002575 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002576
Eric Laurent9f103de2011-09-08 15:04:23 -07002577 SetModeDeathHandler hdlr = null;
2578 Iterator iter = mSetModeDeathHandlers.iterator();
2579 while (iter.hasNext()) {
2580 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
2581 if (h.getPid() == pid) {
2582 hdlr = h;
2583 // Remove from client list so that it is re-inserted at top of list
2584 iter.remove();
2585 hdlr.getBinder().unlinkToDeath(hdlr, 0);
2586 break;
2587 }
2588 }
2589 int status = AudioSystem.AUDIO_STATUS_OK;
Eric Laurent6afa6502017-09-28 15:18:19 -07002590 int actualMode;
Eric Laurent9f103de2011-09-08 15:04:23 -07002591 do {
Eric Laurent6afa6502017-09-28 15:18:19 -07002592 actualMode = mode;
Eric Laurent9f103de2011-09-08 15:04:23 -07002593 if (mode == AudioSystem.MODE_NORMAL) {
2594 // get new mode from client at top the list if any
2595 if (!mSetModeDeathHandlers.isEmpty()) {
2596 hdlr = mSetModeDeathHandlers.get(0);
2597 cb = hdlr.getBinder();
Eric Laurent6afa6502017-09-28 15:18:19 -07002598 actualMode = hdlr.getMode();
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002599 if (DEBUG_MODE) {
2600 Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
2601 + hdlr.mPid);
2602 }
Eric Laurentb9c9d262009-05-06 08:13:20 -07002603 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002604 } else {
2605 if (hdlr == null) {
2606 hdlr = new SetModeDeathHandler(cb, pid);
2607 }
2608 // Register for client death notification
2609 try {
2610 cb.linkToDeath(hdlr, 0);
2611 } catch (RemoteException e) {
2612 // Client has died!
2613 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
2614 }
2615
2616 // Last client to call setMode() is always at top of client list
2617 // as required by SetModeDeathHandler.binderDied()
2618 mSetModeDeathHandlers.add(0, hdlr);
2619 hdlr.setMode(mode);
2620 }
2621
Eric Laurent6afa6502017-09-28 15:18:19 -07002622 if (actualMode != mMode) {
2623 status = AudioSystem.setPhoneState(actualMode);
Eric Laurent9f103de2011-09-08 15:04:23 -07002624 if (status == AudioSystem.AUDIO_STATUS_OK) {
Eric Laurent6afa6502017-09-28 15:18:19 -07002625 if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + actualMode); }
2626 mMode = actualMode;
Eric Laurent9f103de2011-09-08 15:04:23 -07002627 } else {
2628 if (hdlr != null) {
2629 mSetModeDeathHandlers.remove(hdlr);
2630 cb.unlinkToDeath(hdlr, 0);
2631 }
2632 // force reading new top of mSetModeDeathHandlers stack
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002633 if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002634 mode = AudioSystem.MODE_NORMAL;
2635 }
2636 } else {
2637 status = AudioSystem.AUDIO_STATUS_OK;
2638 }
2639 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
2640
2641 if (status == AudioSystem.AUDIO_STATUS_OK) {
Eric Laurent6afa6502017-09-28 15:18:19 -07002642 if (actualMode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002643 if (mSetModeDeathHandlers.isEmpty()) {
2644 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
2645 } else {
2646 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2647 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002648 }
Eric Laurent6afa6502017-09-28 15:18:19 -07002649 // Note: newModeOwnerPid is always 0 when actualMode is MODE_NORMAL
2650 mModeLogger.log(
2651 new PhoneStateEvent(caller, pid, mode, newModeOwnerPid, actualMode));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002652 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002653 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07002654 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
John Spurlock90874332015-03-10 16:00:54 -04002655 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, caller);
Eric Laurent6d517662012-04-23 18:42:39 -07002656
John Spurlock90874332015-03-10 16:00:54 -04002657 updateStreamVolumeAlias(true /*updateVolumes*/, caller);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002658 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002659 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002660 }
2661
2662 /** @see AudioManager#getMode() */
2663 public int getMode() {
2664 return mMode;
2665 }
2666
Eric Laurente78fced2013-03-15 16:03:47 -07002667 //==========================================================================================
2668 // Sound Effects
2669 //==========================================================================================
2670
2671 private static final String TAG_AUDIO_ASSETS = "audio_assets";
2672 private static final String ATTR_VERSION = "version";
2673 private static final String TAG_GROUP = "group";
2674 private static final String ATTR_GROUP_NAME = "name";
2675 private static final String TAG_ASSET = "asset";
2676 private static final String ATTR_ASSET_ID = "id";
2677 private static final String ATTR_ASSET_FILE = "file";
2678
2679 private static final String ASSET_FILE_VERSION = "1.0";
2680 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
2681
Glenn Kasten167d1a22013-07-23 16:24:41 -07002682 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002683
2684 class LoadSoundEffectReply {
2685 public int mStatus = 1;
2686 };
2687
Eric Laurente78fced2013-03-15 16:03:47 -07002688 private void loadTouchSoundAssetDefaults() {
2689 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
2690 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
2691 SOUND_EFFECT_FILES_MAP[i][0] = 0;
2692 SOUND_EFFECT_FILES_MAP[i][1] = -1;
2693 }
2694 }
2695
2696 private void loadTouchSoundAssets() {
2697 XmlResourceParser parser = null;
2698
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002699 // only load assets once.
2700 if (!SOUND_EFFECT_FILES.isEmpty()) {
2701 return;
2702 }
2703
Eric Laurente78fced2013-03-15 16:03:47 -07002704 loadTouchSoundAssetDefaults();
2705
2706 try {
2707 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
2708
2709 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
2710 String version = parser.getAttributeValue(null, ATTR_VERSION);
2711 boolean inTouchSoundsGroup = false;
2712
2713 if (ASSET_FILE_VERSION.equals(version)) {
2714 while (true) {
2715 XmlUtils.nextElement(parser);
2716 String element = parser.getName();
2717 if (element == null) {
2718 break;
2719 }
2720 if (element.equals(TAG_GROUP)) {
2721 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
2722 if (GROUP_TOUCH_SOUNDS.equals(name)) {
2723 inTouchSoundsGroup = true;
2724 break;
2725 }
2726 }
2727 }
2728 while (inTouchSoundsGroup) {
2729 XmlUtils.nextElement(parser);
2730 String element = parser.getName();
2731 if (element == null) {
2732 break;
2733 }
2734 if (element.equals(TAG_ASSET)) {
2735 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
2736 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
2737 int fx;
2738
2739 try {
2740 Field field = AudioManager.class.getField(id);
2741 fx = field.getInt(null);
2742 } catch (Exception e) {
2743 Log.w(TAG, "Invalid touch sound ID: "+id);
2744 continue;
2745 }
2746
2747 int i = SOUND_EFFECT_FILES.indexOf(file);
2748 if (i == -1) {
2749 i = SOUND_EFFECT_FILES.size();
2750 SOUND_EFFECT_FILES.add(file);
2751 }
2752 SOUND_EFFECT_FILES_MAP[fx][0] = i;
2753 } else {
2754 break;
2755 }
2756 }
2757 }
2758 } catch (Resources.NotFoundException e) {
2759 Log.w(TAG, "audio assets file not found", e);
2760 } catch (XmlPullParserException e) {
2761 Log.w(TAG, "XML parser exception reading touch sound assets", e);
2762 } catch (IOException e) {
2763 Log.w(TAG, "I/O exception reading touch sound assets", e);
2764 } finally {
2765 if (parser != null) {
2766 parser.close();
2767 }
2768 }
2769 }
2770
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002771 /** @see AudioManager#playSoundEffect(int) */
2772 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002773 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002774 }
2775
2776 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002777 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07002778 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
2779 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
2780 return;
2781 }
2782
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002783 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002784 effectType, (int) (volume * 1000), null, 0);
2785 }
2786
2787 /**
2788 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08002789 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002790 */
2791 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002792 int attempts = 3;
2793 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08002794
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002795 synchronized (reply) {
2796 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
2797 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08002798 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07002799 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002800 } catch (InterruptedException e) {
2801 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08002802 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002803 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002804 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002805 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002806 }
2807
2808 /**
2809 * Unloads samples from the sound pool.
2810 * This method can be called to free some memory when
2811 * sound effects are disabled.
2812 */
2813 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002814 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002815 }
2816
Eric Laurenta60e2122010-12-28 16:49:07 -08002817 class SoundPoolListenerThread extends Thread {
2818 public SoundPoolListenerThread() {
2819 super("SoundPoolListenerThread");
2820 }
2821
2822 @Override
2823 public void run() {
2824
2825 Looper.prepare();
2826 mSoundPoolLooper = Looper.myLooper();
2827
2828 synchronized (mSoundEffectsLock) {
2829 if (mSoundPool != null) {
2830 mSoundPoolCallBack = new SoundPoolCallback();
2831 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2832 }
2833 mSoundEffectsLock.notify();
2834 }
2835 Looper.loop();
2836 }
2837 }
2838
2839 private final class SoundPoolCallback implements
2840 android.media.SoundPool.OnLoadCompleteListener {
2841
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002842 int mStatus = 1; // 1 means neither error nor last sample loaded yet
2843 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08002844
2845 public int status() {
2846 return mStatus;
2847 }
2848
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002849 public void setSamples(int[] samples) {
2850 for (int i = 0; i < samples.length; i++) {
2851 // do not wait ack for samples rejected upfront by SoundPool
2852 if (samples[i] > 0) {
2853 mSamples.add(samples[i]);
2854 }
2855 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002856 }
2857
2858 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2859 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002860 int i = mSamples.indexOf(sampleId);
2861 if (i >= 0) {
2862 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08002863 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002864 if ((status != 0) || mSamples. isEmpty()) {
2865 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08002866 mSoundEffectsLock.notify();
2867 }
2868 }
2869 }
2870 }
2871
Eric Laurent4050c932009-07-08 02:52:14 -07002872 /** @see AudioManager#reloadAudioSettings() */
2873 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002874 readAudioSettings(false /*userSwitch*/);
2875 }
2876
2877 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07002878 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2879 readPersistedSettings();
Eric Laurentc0232482016-03-15 18:19:23 -07002880 readUserRestrictions();
Eric Laurent4050c932009-07-08 02:52:14 -07002881
2882 // restore volume settings
2883 int numStreamTypes = AudioSystem.getNumStreamTypes();
2884 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2885 VolumeStreamState streamState = mStreamStates[streamType];
2886
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002887 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2888 continue;
2889 }
2890
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002891 streamState.readSettings();
2892 synchronized (VolumeStreamState.class) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002893 // unmute stream that was muted but is not affect by mute anymore
RoboErik4197cb62015-01-21 15:45:32 -08002894 if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07002895 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
RoboErik4197cb62015-01-21 15:45:32 -08002896 streamState.mIsMuted = false;
Eric Laurent4050c932009-07-08 02:52:14 -07002897 }
Eric Laurent4050c932009-07-08 02:52:14 -07002898 }
2899 }
2900
Eric Laurent33902db2012-10-07 16:15:07 -07002901 // apply new ringer mode before checking volume for alias streams so that streams
2902 // muted by ringer mode have the correct volume
John Spurlock661f2cf2014-11-17 10:29:10 -05002903 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent33902db2012-10-07 16:15:07 -07002904
Eric Laurent212532b2014-07-21 15:43:18 -07002905 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07002906 checkAllAliasStreamVolumes();
John Spurlockb6e19e32015-03-10 21:33:44 -04002907 checkMuteAffectedStreams();
Eric Laurent24482012012-05-10 09:41:17 -07002908
Eric Laurentd640bd32012-09-28 18:01:48 -07002909 synchronized (mSafeMediaVolumeState) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002910 mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2911 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2912 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
Eric Laurentd640bd32012-09-28 18:01:48 -07002913 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
John Spurlock90874332015-03-10 16:00:54 -04002914 enforceSafeMediaVolume(TAG);
Eric Laurentf1a457d2012-09-20 16:27:23 -07002915 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07002916 }
Eric Laurent4050c932009-07-08 02:52:14 -07002917 }
2918
Dianne Hackborn961cae92013-03-20 14:59:43 -07002919 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002920 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002921 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2922 return;
2923 }
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07002924 // for logging only
2925 final String eventSource = new StringBuilder("setSpeakerphoneOn(").append(on)
2926 .append(") from u/pid:").append(Binder.getCallingUid()).append("/")
2927 .append(Binder.getCallingPid()).toString();
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002928
2929 if (on) {
2930 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2931 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07002932 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE,
2933 eventSource, 0);
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002934 }
2935 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2936 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2937 mForcedUseForComm = AudioSystem.FORCE_NONE;
2938 }
Eric Laurentfa640152011-03-12 15:59:51 -08002939
Sharad Sangle1d188442017-05-09 16:05:40 +05302940 mForcedUseForCommExt = mForcedUseForComm;
Eric Laurentafbb0472011-12-15 09:04:23 -08002941 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07002942 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002943 }
2944
2945 /** @see AudioManager#isSpeakerphoneOn() */
2946 public boolean isSpeakerphoneOn() {
Sharad Sangle1d188442017-05-09 16:05:40 +05302947 return (mForcedUseForCommExt == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002948 }
2949
Dianne Hackborn961cae92013-03-20 14:59:43 -07002950 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurent48221252015-09-24 18:41:48 -07002951 public void setBluetoothScoOn(boolean on) {
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002952 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2953 return;
2954 }
Sharad Sangle1d188442017-05-09 16:05:40 +05302955
2956 // Only enable calls from system components
2957 if (Binder.getCallingUid() >= FIRST_APPLICATION_UID) {
2958 mForcedUseForCommExt = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE;
2959 return;
2960 }
2961
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07002962 // for logging only
2963 final String eventSource = new StringBuilder("setBluetoothScoOn(").append(on)
2964 .append(") from u/pid:").append(Binder.getCallingUid()).append("/")
2965 .append(Binder.getCallingPid()).toString();
2966 setBluetoothScoOnInt(on, eventSource);
Eric Laurent48221252015-09-24 18:41:48 -07002967 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002968
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07002969 public void setBluetoothScoOnInt(boolean on, String eventSource) {
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002970 if (on) {
Sharad Sangle1d188442017-05-09 16:05:40 +05302971 // do not accept SCO ON if SCO audio is not connected
2972 synchronized(mScoClients) {
2973 if ((mBluetoothHeadset != null) &&
2974 (mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2975 != BluetoothHeadset.STATE_AUDIO_CONNECTED)) {
2976 mForcedUseForCommExt = AudioSystem.FORCE_BT_SCO;
2977 return;
2978 }
2979 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002980 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2981 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2982 mForcedUseForComm = AudioSystem.FORCE_NONE;
2983 }
Sharad Sangle1d188442017-05-09 16:05:40 +05302984 mForcedUseForCommExt = mForcedUseForComm;
2985 AudioSystem.setParameters("BT_SCO="+ (on ? "on" : "off"));
Eric Laurentafbb0472011-12-15 09:04:23 -08002986 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07002987 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, eventSource, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08002988 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07002989 AudioSystem.FOR_RECORD, mForcedUseForComm, eventSource, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002990 }
2991
2992 /** @see AudioManager#isBluetoothScoOn() */
2993 public boolean isBluetoothScoOn() {
Sharad Sangle1d188442017-05-09 16:05:40 +05302994 return (mForcedUseForCommExt == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002995 }
2996
Sungsoocf09fe62016-09-28 16:21:48 +09002997 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07002998 public void setBluetoothA2dpOn(boolean on) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07002999 // for logging only
3000 final String eventSource = new StringBuilder("setBluetoothA2dpOn(").append(on)
3001 .append(") from u/pid:").append(Binder.getCallingUid()).append("/")
3002 .append(Binder.getCallingPid()).toString();
3003
Sungsoocf09fe62016-09-28 16:21:48 +09003004 synchronized (mBluetoothA2dpEnabledLock) {
3005 mBluetoothA2dpEnabled = on;
3006 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
3007 AudioSystem.FOR_MEDIA,
3008 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07003009 eventSource, 0);
Sungsoocf09fe62016-09-28 16:21:48 +09003010 }
Eric Laurent78472112012-05-21 08:57:21 -07003011 }
3012
Sungsoocf09fe62016-09-28 16:21:48 +09003013 /** @see AudioManager#isBluetoothA2dpOn() */
Eric Laurent78472112012-05-21 08:57:21 -07003014 public boolean isBluetoothA2dpOn() {
Sungsoocf09fe62016-09-28 16:21:48 +09003015 synchronized (mBluetoothA2dpEnabledLock) {
3016 return mBluetoothA2dpEnabled;
3017 }
Eric Laurent78472112012-05-21 08:57:21 -07003018 }
3019
Eric Laurent3def1ee2010-03-17 23:26:26 -07003020 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07003021 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
3022 int scoAudioMode =
3023 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
Liejun Taof4e51d82014-07-16 11:18:29 -07003024 SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
Eric Laurent83900752014-05-15 15:14:22 -07003025 startBluetoothScoInt(cb, scoAudioMode);
3026 }
3027
3028 /** @see AudioManager#startBluetoothScoVirtualCall() */
3029 public void startBluetoothScoVirtualCall(IBinder cb) {
3030 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
3031 }
3032
3033 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07003034 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07003035 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07003036 return;
3037 }
Eric Laurent854938a2011-02-22 12:05:20 -08003038 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07003039 // The calling identity must be cleared before calling ScoClient.incCount().
3040 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
3041 // and this must be done on behalf of system server to make sure permissions are granted.
3042 // The caller identity must be cleared after getScoClient() because it is needed if a new
3043 // client is created.
3044 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07003045 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08003046 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003047 }
3048
3049 /** @see AudioManager#stopBluetoothSco() */
3050 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07003051 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07003052 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07003053 return;
3054 }
Eric Laurent854938a2011-02-22 12:05:20 -08003055 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07003056 // The calling identity must be cleared before calling ScoClient.decCount().
3057 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
3058 // and this must be done on behalf of system server to make sure permissions are granted.
3059 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08003060 if (client != null) {
3061 client.decCount();
3062 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08003063 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003064 }
3065
Eric Laurent78472112012-05-21 08:57:21 -07003066
Eric Laurent3def1ee2010-03-17 23:26:26 -07003067 private class ScoClient implements IBinder.DeathRecipient {
3068 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07003069 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003070 private int mStartcount; // number of SCO connections started by this client
3071
3072 ScoClient(IBinder cb) {
3073 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07003074 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07003075 mStartcount = 0;
3076 }
3077
3078 public void binderDied() {
3079 synchronized(mScoClients) {
3080 Log.w(TAG, "SCO client died");
3081 int index = mScoClients.indexOf(this);
3082 if (index < 0) {
3083 Log.w(TAG, "unregistered SCO client died");
3084 } else {
3085 clearCount(true);
3086 mScoClients.remove(this);
3087 }
3088 }
3089 }
3090
Eric Laurent83900752014-05-15 15:14:22 -07003091 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07003092 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07003093 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003094 if (mStartcount == 0) {
3095 try {
3096 mCb.linkToDeath(this, 0);
3097 } catch (RemoteException e) {
3098 // client has already died!
3099 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
3100 }
3101 }
3102 mStartcount++;
3103 }
3104 }
3105
3106 public void decCount() {
3107 synchronized(mScoClients) {
3108 if (mStartcount == 0) {
3109 Log.w(TAG, "ScoClient.decCount() already 0");
3110 } else {
3111 mStartcount--;
3112 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07003113 try {
3114 mCb.unlinkToDeath(this, 0);
3115 } catch (NoSuchElementException e) {
3116 Log.w(TAG, "decCount() going to 0 but not registered to binder");
3117 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07003118 }
Eric Laurentc18c9132013-04-12 17:24:56 -07003119 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003120 }
3121 }
3122 }
3123
3124 public void clearCount(boolean stopSco) {
3125 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07003126 if (mStartcount != 0) {
3127 try {
3128 mCb.unlinkToDeath(this, 0);
3129 } catch (NoSuchElementException e) {
3130 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
3131 }
3132 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07003133 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003134 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003135 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003136 }
3137 }
3138 }
3139
3140 public int getCount() {
3141 return mStartcount;
3142 }
3143
3144 public IBinder getBinder() {
3145 return mCb;
3146 }
3147
Eric Laurentd7454be2011-09-14 08:45:58 -07003148 public int getPid() {
3149 return mCreatorPid;
3150 }
3151
Eric Laurent3def1ee2010-03-17 23:26:26 -07003152 public int totalCount() {
3153 synchronized(mScoClients) {
3154 int count = 0;
3155 int size = mScoClients.size();
3156 for (int i = 0; i < size; i++) {
3157 count += mScoClients.get(i).getCount();
3158 }
3159 return count;
3160 }
3161 }
3162
Eric Laurent83900752014-05-15 15:14:22 -07003163 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08003164 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07003165 if (totalCount() == 0) {
3166 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
3167 // Make sure that the state transitions to CONNECTING even if we cannot initiate
3168 // the connection.
3169 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
3170 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07003171 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07003172 synchronized(mSetModeDeathHandlers) {
3173 if ((mSetModeDeathHandlers.isEmpty() ||
3174 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
3175 (mScoAudioState == SCO_STATE_INACTIVE ||
3176 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
3177 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07003178 mScoAudioMode = scoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -07003179 if (scoAudioMode == SCO_MODE_UNDEFINED) {
Andre Eisenbach570cc532014-10-28 17:03:18 -07003180 if (mBluetoothHeadsetDevice != null) {
3181 mScoAudioMode = new Integer(Settings.Global.getInt(
3182 mContentResolver,
3183 "bluetooth_sco_channel_"+
3184 mBluetoothHeadsetDevice.getAddress(),
3185 SCO_MODE_VIRTUAL_CALL));
3186 if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
3187 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
3188 }
3189 } else {
3190 mScoAudioMode = SCO_MODE_RAW;
Liejun Taof4e51d82014-07-16 11:18:29 -07003191 }
3192 }
Eric Laurent9f103de2011-09-08 15:04:23 -07003193 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07003194 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07003195 if (mScoAudioMode == SCO_MODE_RAW) {
3196 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003197 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003198 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
3199 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003200 } else if (mScoAudioMode == SCO_MODE_VR) {
3201 status = mBluetoothHeadset.startVoiceRecognition(
3202 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003203 }
Liejun Taof4e51d82014-07-16 11:18:29 -07003204
Eric Laurentc18c9132013-04-12 17:24:56 -07003205 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07003206 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
3207 } else {
3208 broadcastScoConnectionState(
3209 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3210 }
3211 } else if (getBluetoothHeadset()) {
3212 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07003213 }
Eric Laurent9f103de2011-09-08 15:04:23 -07003214 } else {
3215 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
3216 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07003217 }
3218 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07003219 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07003220 }
Eric Laurentdc03c612011-04-01 10:59:41 -07003221 }
Eric Laurent62ef7672010-11-24 10:58:32 -08003222 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07003223 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
3224 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
3225 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07003226 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07003227 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07003228 if (mScoAudioMode == SCO_MODE_RAW) {
3229 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003230 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003231 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
3232 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003233 } else if (mScoAudioMode == SCO_MODE_VR) {
3234 status = mBluetoothHeadset.stopVoiceRecognition(
3235 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003236 }
Liejun Taof4e51d82014-07-16 11:18:29 -07003237
Eric Laurentc18c9132013-04-12 17:24:56 -07003238 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07003239 mScoAudioState = SCO_STATE_INACTIVE;
3240 broadcastScoConnectionState(
3241 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3242 }
3243 } else if (getBluetoothHeadset()) {
3244 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
3245 }
3246 } else {
3247 mScoAudioState = SCO_STATE_INACTIVE;
3248 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3249 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07003250 }
3251 }
3252 }
3253 }
3254
Eric Laurent62ef7672010-11-24 10:58:32 -08003255 private void checkScoAudioState() {
3256 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07003257 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08003258 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
3259 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
3260 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
3261 }
3262 }
3263
Eric Laurent854938a2011-02-22 12:05:20 -08003264 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07003265 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08003266 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003267 int size = mScoClients.size();
3268 for (int i = 0; i < size; i++) {
3269 client = mScoClients.get(i);
3270 if (client.getBinder() == cb)
3271 return client;
3272 }
Eric Laurent854938a2011-02-22 12:05:20 -08003273 if (create) {
3274 client = new ScoClient(cb);
3275 mScoClients.add(client);
3276 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07003277 return client;
3278 }
3279 }
3280
Eric Laurentd7454be2011-09-14 08:45:58 -07003281 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07003282 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08003283 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003284 int size = mScoClients.size();
3285 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08003286 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07003287 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08003288 cl.clearCount(stopSco);
3289 } else {
3290 savedClient = cl;
3291 }
3292 }
3293 mScoClients.clear();
3294 if (savedClient != null) {
3295 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003296 }
3297 }
3298 }
3299
Eric Laurentdc03c612011-04-01 10:59:41 -07003300 private boolean getBluetoothHeadset() {
3301 boolean result = false;
3302 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
3303 if (adapter != null) {
3304 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
3305 BluetoothProfile.HEADSET);
3306 }
3307 // If we could not get a bluetooth headset proxy, send a failure message
3308 // without delay to reset the SCO audio state and clear SCO clients.
3309 // If we could get a proxy, send a delayed failure message that will reset our state
3310 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08003311 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07003312 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
3313 return result;
3314 }
3315
Eric Laurentd7454be2011-09-14 08:45:58 -07003316 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07003317 synchronized(mScoClients) {
3318 checkScoAudioState();
3319 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
3320 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
3321 if (mBluetoothHeadsetDevice != null) {
3322 if (mBluetoothHeadset != null) {
3323 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07003324 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08003325 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07003326 SENDMSG_REPLACE, 0, 0, null, 0);
3327 }
3328 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
3329 getBluetoothHeadset()) {
3330 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
3331 }
3332 }
3333 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07003334 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07003335 }
3336 }
3337 }
3338
3339 private void resetBluetoothSco() {
3340 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07003341 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07003342 mScoAudioState = SCO_STATE_INACTIVE;
3343 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3344 }
Eric Laurent48221252015-09-24 18:41:48 -07003345 AudioSystem.setParameters("A2dpSuspended=false");
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07003346 setBluetoothScoOnInt(false, "resetBluetoothSco");
Eric Laurentdc03c612011-04-01 10:59:41 -07003347 }
3348
3349 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08003350 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
3351 SENDMSG_QUEUE, state, 0, null, 0);
3352 }
3353
3354 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07003355 if (state != mScoConnectionState) {
3356 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
3357 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
3358 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
3359 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003360 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07003361 mScoConnectionState = state;
3362 }
3363 }
3364
Eric Laurent98859b22015-06-12 14:35:59 -07003365 void setBtScoDeviceConnectionState(BluetoothDevice btDevice, int state) {
3366 if (btDevice == null) {
3367 return;
3368 }
3369
3370 String address = btDevice.getAddress();
3371 BluetoothClass btClass = btDevice.getBluetoothClass();
3372 int outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
3373 int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
3374 if (btClass != null) {
3375 switch (btClass.getDeviceClass()) {
3376 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
3377 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
3378 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
3379 break;
3380 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
3381 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
3382 break;
3383 }
3384 }
3385
3386 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
3387 address = "";
3388 }
3389
3390 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
3391
3392 String btDeviceName = btDevice.getName();
3393 boolean success =
3394 handleDeviceConnection(connected, outDevice, address, btDeviceName) &&
3395 handleDeviceConnection(connected, inDevice, address, btDeviceName);
Satish Kodishala29809802016-01-18 14:23:12 +05303396
3397 if (!success) {
3398 return;
3399 }
3400
3401 /* When one BT headset is disconnected while another BT headset
3402 * is connected, don't mess with the headset device.
3403 */
3404 if ((state == BluetoothProfile.STATE_DISCONNECTED ||
3405 state == BluetoothProfile.STATE_DISCONNECTING) &&
3406 mBluetoothHeadset != null &&
3407 mBluetoothHeadset.getAudioState(btDevice) == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
3408 Log.w(TAG, "SCO connected through another device, returning");
3409 return;
3410 }
3411
3412 synchronized (mScoClients) {
3413 if (connected) {
3414 mBluetoothHeadsetDevice = btDevice;
3415 } else {
3416 mBluetoothHeadsetDevice = null;
3417 resetBluetoothSco();
Eric Laurent98859b22015-06-12 14:35:59 -07003418 }
3419 }
3420 }
3421
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07003422 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
3423 new BluetoothProfile.ServiceListener() {
3424 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003425 BluetoothDevice btDevice;
3426 List<BluetoothDevice> deviceList;
3427 switch(profile) {
3428 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09003429 synchronized (mConnectedDevices) {
3430 synchronized (mA2dpAvrcpLock) {
3431 mA2dp = (BluetoothA2dp) proxy;
3432 deviceList = mA2dp.getConnectedDevices();
3433 if (deviceList.size() > 0) {
3434 btDevice = deviceList.get(0);
John Du5a0cf7a2013-07-19 11:30:34 -07003435 int state = mA2dp.getConnectionState(btDevice);
Eric Laurentcdae4762017-04-28 18:00:04 -07003436 int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
John Du5a0cf7a2013-07-19 11:30:34 -07003437 int delay = checkSendBecomingNoisyIntent(
Eric Laurentcdae4762017-04-28 18:00:04 -07003438 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, intState,
3439 AudioSystem.DEVICE_NONE);
John Du5a0cf7a2013-07-19 11:30:34 -07003440 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003441 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07003442 state,
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08003443 0 /* arg2 unused */,
John Du5a0cf7a2013-07-19 11:30:34 -07003444 btDevice,
3445 delay);
3446 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003447 }
Eric Laurent62ef7672010-11-24 10:58:32 -08003448 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003449 break;
3450
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003451 case BluetoothProfile.A2DP_SINK:
3452 deviceList = proxy.getConnectedDevices();
3453 if (deviceList.size() > 0) {
3454 btDevice = deviceList.get(0);
3455 synchronized (mConnectedDevices) {
3456 int state = proxy.getConnectionState(btDevice);
3457 queueMsgUnderWakeLock(mAudioHandler,
3458 MSG_SET_A2DP_SRC_CONNECTION_STATE,
3459 state,
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08003460 0 /* arg2 unused */,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003461 btDevice,
3462 0 /* delay */);
3463 }
3464 }
3465 break;
3466
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003467 case BluetoothProfile.HEADSET:
3468 synchronized (mScoClients) {
3469 // Discard timeout message
3470 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
3471 mBluetoothHeadset = (BluetoothHeadset) proxy;
3472 deviceList = mBluetoothHeadset.getConnectedDevices();
3473 if (deviceList.size() > 0) {
3474 mBluetoothHeadsetDevice = deviceList.get(0);
3475 } else {
3476 mBluetoothHeadsetDevice = null;
3477 }
3478 // Refresh SCO audio state
3479 checkScoAudioState();
3480 // Continue pending action if any
3481 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
3482 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
3483 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
3484 boolean status = false;
3485 if (mBluetoothHeadsetDevice != null) {
3486 switch (mScoAudioState) {
3487 case SCO_STATE_ACTIVATE_REQ:
3488 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07003489 if (mScoAudioMode == SCO_MODE_RAW) {
3490 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003491 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003492 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
3493 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003494 } else if (mScoAudioMode == SCO_MODE_VR) {
3495 status = mBluetoothHeadset.startVoiceRecognition(
3496 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003497 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003498 break;
3499 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07003500 if (mScoAudioMode == SCO_MODE_RAW) {
3501 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003502 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003503 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
3504 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003505 } else if (mScoAudioMode == SCO_MODE_VR) {
3506 status = mBluetoothHeadset.stopVoiceRecognition(
3507 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003508 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003509 break;
3510 case SCO_STATE_DEACTIVATE_EXT_REQ:
3511 status = mBluetoothHeadset.stopVoiceRecognition(
3512 mBluetoothHeadsetDevice);
3513 }
3514 }
3515 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08003516 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003517 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07003518 }
3519 }
Eric Laurentdc03c612011-04-01 10:59:41 -07003520 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003521 break;
3522
3523 default:
3524 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003525 }
3526 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07003527 public void onServiceDisconnected(int profile) {
Eric Laurentb70b78a2016-01-13 19:16:04 -08003528
Paul McLean394a8e12015-03-03 10:29:19 -07003529 switch (profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003530 case BluetoothProfile.A2DP:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003531 disconnectA2dp();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003532 break;
3533
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003534 case BluetoothProfile.A2DP_SINK:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003535 disconnectA2dpSink();
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003536 break;
3537
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003538 case BluetoothProfile.HEADSET:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003539 disconnectHeadset();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003540 break;
3541
3542 default:
3543 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003544 }
3545 }
3546 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003547
Eric Laurentb70b78a2016-01-13 19:16:04 -08003548 void disconnectAllBluetoothProfiles() {
3549 disconnectA2dp();
3550 disconnectA2dpSink();
3551 disconnectHeadset();
3552 }
3553
3554 void disconnectA2dp() {
3555 synchronized (mConnectedDevices) {
3556 synchronized (mA2dpAvrcpLock) {
3557 ArraySet<String> toRemove = null;
3558 // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
3559 for (int i = 0; i < mConnectedDevices.size(); i++) {
3560 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
3561 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
3562 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
3563 toRemove.add(deviceSpec.mDeviceAddress);
3564 }
3565 }
3566 if (toRemove != null) {
Eric Laurentcdae4762017-04-28 18:00:04 -07003567 int delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3568 0, AudioSystem.DEVICE_NONE);
Eric Laurentb70b78a2016-01-13 19:16:04 -08003569 for (int i = 0; i < toRemove.size(); i++) {
3570 makeA2dpDeviceUnavailableLater(toRemove.valueAt(i), delay);
3571 }
3572 }
3573 }
3574 }
3575 }
3576
3577 void disconnectA2dpSink() {
3578 synchronized (mConnectedDevices) {
3579 ArraySet<String> toRemove = null;
3580 // Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
3581 for(int i = 0; i < mConnectedDevices.size(); i++) {
3582 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
3583 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) {
3584 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
3585 toRemove.add(deviceSpec.mDeviceAddress);
3586 }
3587 }
3588 if (toRemove != null) {
3589 for (int i = 0; i < toRemove.size(); i++) {
3590 makeA2dpSrcUnavailable(toRemove.valueAt(i));
3591 }
3592 }
3593 }
3594 }
3595
3596 void disconnectHeadset() {
3597 synchronized (mScoClients) {
3598 if (mBluetoothHeadsetDevice != null) {
3599 setBtScoDeviceConnectionState(mBluetoothHeadsetDevice,
3600 BluetoothProfile.STATE_DISCONNECTED);
3601 }
3602 mBluetoothHeadset = null;
3603 }
3604 }
3605
John Spurlock90874332015-03-10 16:00:54 -04003606 private void onCheckMusicActive(String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07003607 synchronized (mSafeMediaVolumeState) {
3608 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07003609 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
3610
3611 if ((device & mSafeMediaVolumeDevices) != 0) {
3612 sendMsg(mAudioHandler,
3613 MSG_CHECK_MUSIC_ACTIVE,
3614 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07003615 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07003616 0,
John Spurlock90874332015-03-10 16:00:54 -04003617 caller,
Eric Laurentc34dcc12012-09-10 13:51:52 -07003618 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07003619 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07003620 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
Eric Laurenteab40d12017-06-09 12:45:21 -07003621 (index > safeMediaVolumeIndex(device))) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07003622 // Approximate cumulative active music time
3623 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
3624 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
John Spurlock90874332015-03-10 16:00:54 -04003625 setSafeMediaVolumeEnabled(true, caller);
Eric Laurentc34dcc12012-09-10 13:51:52 -07003626 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07003627 }
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003628 saveMusicActiveMs();
Eric Laurentc34dcc12012-09-10 13:51:52 -07003629 }
3630 }
3631 }
3632 }
3633 }
3634
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003635 private void saveMusicActiveMs() {
3636 mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
3637 }
3638
Eric Laurenteab40d12017-06-09 12:45:21 -07003639 private int getSafeUsbMediaVolumeIndex()
3640 {
3641 // determine UI volume index corresponding to the wanted safe gain in dBFS
3642 int min = MIN_STREAM_VOLUME[AudioSystem.STREAM_MUSIC];
3643 int max = MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC];
3644
3645 while (Math.abs(max-min) > 1) {
3646 int index = (max + min) / 2;
3647 float gainDB = AudioSystem.getStreamVolumeDB(
3648 AudioSystem.STREAM_MUSIC, index, AudioSystem.DEVICE_OUT_USB_HEADSET);
Eric Laurentb378a13a2017-07-11 14:08:11 -07003649 if (Float.isNaN(gainDB)) {
Eric Laurenteab40d12017-06-09 12:45:21 -07003650 //keep last min in case of read error
3651 break;
Eric Laurentb378a13a2017-07-11 14:08:11 -07003652 } else if (gainDB == SAFE_VOLUME_GAIN_DBFS) {
Eric Laurenteab40d12017-06-09 12:45:21 -07003653 min = index;
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 } else {
3658 max = index;
3659 }
3660 }
3661 return min * 10;
3662 }
3663
John Spurlock90874332015-03-10 16:00:54 -04003664 private void onConfigureSafeVolume(boolean force, String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07003665 synchronized (mSafeMediaVolumeState) {
3666 int mcc = mContext.getResources().getConfiguration().mcc;
3667 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
3668 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
3669 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
Eric Laurenteab40d12017-06-09 12:45:21 -07003670
3671 mSafeUsbMediaVolumeIndex = getSafeUsbMediaVolumeIndex();
3672
John Spurlock35134602014-07-24 18:10:48 -04003673 boolean safeMediaVolumeEnabled =
3674 SystemProperties.getBoolean("audio.safemedia.force", false)
3675 || mContext.getResources().getBoolean(
3676 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08003677
Ricardo Garcia3a30a762015-06-23 15:54:45 -07003678 boolean safeMediaVolumeBypass =
3679 SystemProperties.getBoolean("audio.safemedia.bypass", false);
3680
Eric Laurent05274f32012-11-29 12:48:18 -08003681 // The persisted state is either "disabled" or "active": this is the state applied
3682 // next time we boot and cannot be "inactive"
3683 int persistedState;
Ricardo Garcia3a30a762015-06-23 15:54:45 -07003684 if (safeMediaVolumeEnabled && !safeMediaVolumeBypass) {
Eric Laurent05274f32012-11-29 12:48:18 -08003685 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
3686 // The state can already be "inactive" here if the user has forced it before
3687 // the 30 seconds timeout for forced configuration. In this case we don't reset
3688 // it to "active".
3689 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003690 if (mMusicActiveMs == 0) {
3691 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
John Spurlock90874332015-03-10 16:00:54 -04003692 enforceSafeMediaVolume(caller);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003693 } else {
3694 // We have existing playback time recorded, already confirmed.
3695 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
3696 }
Eric Laurent05274f32012-11-29 12:48:18 -08003697 }
Eric Laurentd640bd32012-09-28 18:01:48 -07003698 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08003699 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07003700 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
3701 }
3702 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08003703 sendMsg(mAudioHandler,
3704 MSG_PERSIST_SAFE_VOLUME_STATE,
3705 SENDMSG_QUEUE,
3706 persistedState,
3707 0,
3708 null,
3709 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07003710 }
3711 }
3712 }
3713
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003714 ///////////////////////////////////////////////////////////////////////////
3715 // Internal methods
3716 ///////////////////////////////////////////////////////////////////////////
3717
3718 /**
3719 * Checks if the adjustment should change ringer mode instead of just
3720 * adjusting volume. If so, this will set the proper ringer mode and volume
3721 * indices on the stream states.
3722 */
Julia Reynoldsed783792016-04-08 15:27:35 -04003723 private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted,
3724 String caller, int flags) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003725 int result = FLAG_ADJUST_VOLUME;
Zak Cohen47798292017-11-30 12:34:20 -08003726 if (isPlatformTelevision() || mIsSingleVolume) {
Hank Freund21003f62015-12-08 09:05:46 -08003727 return result;
3728 }
3729
John Spurlock661f2cf2014-11-17 10:29:10 -05003730 int ringerMode = getRingerModeInternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003731
Eric Laurentbffc3d12012-05-07 17:43:49 -07003732 switch (ringerMode) {
3733 case RINGER_MODE_NORMAL:
3734 if (direction == AudioManager.ADJUST_LOWER) {
3735 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07003736 // "step" is the delta in internal index units corresponding to a
3737 // change of 1 in UI index units.
3738 // Because of rounding when rescaling from one stream index range to its alias
3739 // index range, we cannot simply test oldIndex == step:
3740 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
3741 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003742 ringerMode = RINGER_MODE_VIBRATE;
John Spurlock07e72432015-03-13 11:46:52 -04003743 mLoweredFromNormalToVibrateTime = SystemClock.uptimeMillis();
Eric Laurentbffc3d12012-05-07 17:43:49 -07003744 }
3745 } else {
John Spurlockd9c75db2015-04-28 11:19:13 -04003746 if (oldIndex == step && mVolumePolicy.volumeDownToEnterSilent) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003747 ringerMode = RINGER_MODE_SILENT;
3748 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07003749 }
Muyuan Li1ed6df62016-06-18 11:16:52 -07003750 } else if (mIsSingleVolume && (direction == AudioManager.ADJUST_TOGGLE_MUTE
John Spurlocka48d7792015-03-03 17:35:57 -05003751 || direction == AudioManager.ADJUST_MUTE)) {
RoboErik5452e252015-02-06 15:33:53 -08003752 if (mHasVibrator) {
3753 ringerMode = RINGER_MODE_VIBRATE;
3754 } else {
3755 ringerMode = RINGER_MODE_SILENT;
3756 }
3757 // Setting the ringer mode will toggle mute
3758 result &= ~FLAG_ADJUST_VOLUME;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003759 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003760 break;
3761 case RINGER_MODE_VIBRATE:
3762 if (!mHasVibrator) {
3763 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
3764 "but no vibrator is present");
3765 break;
3766 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003767 if ((direction == AudioManager.ADJUST_LOWER)) {
RoboErik5452e252015-02-06 15:33:53 -08003768 // This is the case we were muted with the volume turned up
Muyuan Li1ed6df62016-06-18 11:16:52 -07003769 if (mIsSingleVolume && oldIndex >= 2 * step && isMuted) {
RoboErik5452e252015-02-06 15:33:53 -08003770 ringerMode = RINGER_MODE_NORMAL;
3771 } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
John Spurlocka48d7792015-03-03 17:35:57 -05003772 if (mVolumePolicy.volumeDownToEnterSilent) {
John Spurlock07e72432015-03-13 11:46:52 -04003773 final long diff = SystemClock.uptimeMillis()
3774 - mLoweredFromNormalToVibrateTime;
John Spurlockd9c75db2015-04-28 11:19:13 -04003775 if (diff > mVolumePolicy.vibrateToSilentDebounce
3776 && mRingerModeDelegate.canVolumeDownEnterSilent()) {
John Spurlock07e72432015-03-13 11:46:52 -04003777 ringerMode = RINGER_MODE_SILENT;
3778 }
John Spurlock795a5142014-12-08 14:09:35 -05003779 } else {
3780 result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
3781 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003782 }
RoboErik5452e252015-02-06 15:33:53 -08003783 } else if (direction == AudioManager.ADJUST_RAISE
3784 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3785 || direction == AudioManager.ADJUST_UNMUTE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003786 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07003787 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003788 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003789 break;
3790 case RINGER_MODE_SILENT:
Muyuan Li1ed6df62016-06-18 11:16:52 -07003791 if (mIsSingleVolume && direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
RoboErik5452e252015-02-06 15:33:53 -08003792 // This is the case we were muted with the volume turned up
3793 ringerMode = RINGER_MODE_NORMAL;
3794 } else if (direction == AudioManager.ADJUST_RAISE
3795 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3796 || direction == AudioManager.ADJUST_UNMUTE) {
John Spurlocka48d7792015-03-03 17:35:57 -05003797 if (!mVolumePolicy.volumeUpToExitSilent) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003798 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003799 } else {
RoboErik5452e252015-02-06 15:33:53 -08003800 if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003801 ringerMode = RINGER_MODE_VIBRATE;
3802 } else {
RoboErik5452e252015-02-06 15:33:53 -08003803 // If we don't have a vibrator or they were toggling mute
3804 // go straight back to normal.
John Spurlocka11b4af2014-06-01 11:52:23 -04003805 ringerMode = RINGER_MODE_NORMAL;
3806 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003807 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05003808 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003809 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003810 break;
3811 default:
3812 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
3813 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003814 }
3815
Julia Reynoldsed783792016-04-08 15:27:35 -04003816 if (isAndroidNPlus(caller) && wouldToggleZenMode(ringerMode)
3817 && !mNm.isNotificationPolicyAccessGrantedForPackage(caller)
3818 && (flags & AudioManager.FLAG_FROM_KEY) == 0) {
3819 throw new SecurityException("Not allowed to change Do Not Disturb state");
3820 }
3821
John Spurlock661f2cf2014-11-17 10:29:10 -05003822 setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003823
Eric Laurent25101b02011-02-02 09:33:30 -08003824 mPrevVolDirection = direction;
3825
John Spurlocka11b4af2014-06-01 11:52:23 -04003826 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003827 }
3828
John Spurlock3346a802014-05-20 16:25:37 -04003829 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003830 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07003831 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003832 }
3833
Eric Laurent5b4e6542010-03-19 20:02:21 -07003834 private boolean isStreamMutedByRingerMode(int streamType) {
3835 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
3836 }
3837
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08003838 @GuardedBy("mSettingsLock")
John Spurlock50ced3f2015-05-11 16:00:09 -04003839 private boolean updateRingerModeAffectedStreams() {
3840 int ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003841 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3842 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
3843 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
3844 UserHandle.USER_CURRENT);
3845
Muyuan Li1ed6df62016-06-18 11:16:52 -07003846 if (mIsSingleVolume) {
John Spurlock50ced3f2015-05-11 16:00:09 -04003847 ringerModeAffectedStreams = 0;
3848 } else if (mRingerModeDelegate != null) {
3849 ringerModeAffectedStreams = mRingerModeDelegate
3850 .getRingerModeAffectedStreams(ringerModeAffectedStreams);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003851 }
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08003852 if (mCameraSoundForced) {
3853 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3854 } else {
3855 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003856 }
3857 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
3858 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
3859 } else {
3860 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
3861 }
3862
3863 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3864 Settings.System.putIntForUser(mContentResolver,
3865 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3866 ringerModeAffectedStreams,
3867 UserHandle.USER_CURRENT);
3868 mRingerModeAffectedStreams = ringerModeAffectedStreams;
3869 return true;
3870 }
3871 return false;
3872 }
3873
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05003874 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003875 public boolean isStreamAffectedByMute(int streamType) {
3876 return (mMuteAffectedStreams & (1 << streamType)) != 0;
3877 }
3878
3879 private void ensureValidDirection(int direction) {
RoboErik4197cb62015-01-21 15:45:32 -08003880 switch (direction) {
3881 case AudioManager.ADJUST_LOWER:
3882 case AudioManager.ADJUST_RAISE:
3883 case AudioManager.ADJUST_SAME:
3884 case AudioManager.ADJUST_MUTE:
3885 case AudioManager.ADJUST_UNMUTE:
3886 case AudioManager.ADJUST_TOGGLE_MUTE:
3887 break;
3888 default:
3889 throw new IllegalArgumentException("Bad direction " + direction);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003890 }
3891 }
3892
3893 private void ensureValidStreamType(int streamType) {
3894 if (streamType < 0 || streamType >= mStreamStates.length) {
3895 throw new IllegalArgumentException("Bad stream type " + streamType);
3896 }
3897 }
3898
RoboErik4197cb62015-01-21 15:45:32 -08003899 private boolean isMuteAdjust(int adjust) {
3900 return adjust == AudioManager.ADJUST_MUTE || adjust == AudioManager.ADJUST_UNMUTE
3901 || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
3902 }
3903
Eric Laurent6d517662012-04-23 18:42:39 -07003904 private boolean isInCommunication() {
Nancy Chen0eb1e402014-08-21 22:52:29 -07003905 boolean IsInCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003906
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003907 TelecomManager telecomManager =
3908 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
Eric Laurent38edfda2014-12-18 17:38:04 -08003909
3910 final long ident = Binder.clearCallingIdentity();
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003911 IsInCall = telecomManager.isInCall();
Eric Laurent38edfda2014-12-18 17:38:04 -08003912 Binder.restoreCallingIdentity(ident);
Santos Cordon9eb45932014-06-27 12:28:43 -07003913
Eric Laurentda1af762017-12-15 16:54:35 -08003914 return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION ||
3915 getMode() == AudioManager.MODE_IN_CALL);
Eric Laurent6d517662012-04-23 18:42:39 -07003916 }
Eric Laurent25101b02011-02-02 09:33:30 -08003917
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003918 /**
3919 * For code clarity for getActiveStreamType(int)
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05003920 * @param delay_ms max time since last stream activity to consider
3921 * @return true if stream is active in streams handled by AudioFlinger now or
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003922 * in the last "delay_ms" ms.
3923 */
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05003924 private boolean wasStreamActiveRecently(int stream, int delay_ms) {
3925 return AudioSystem.isStreamActive(stream, delay_ms)
3926 || AudioSystem.isStreamActiveRemotely(stream, delay_ms);
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003927 }
3928
Eric Laurent6d517662012-04-23 18:42:39 -07003929 private int getActiveStreamType(int suggestedStreamType) {
Muyuan Li1ed6df62016-06-18 11:16:52 -07003930 if (mIsSingleVolume
3931 && suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
3932 return AudioSystem.STREAM_MUSIC;
3933 }
3934
Eric Laurent212532b2014-07-21 15:43:18 -07003935 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003936 case AudioSystem.PLATFORM_VOICE:
Eric Laurent6d517662012-04-23 18:42:39 -07003937 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003938 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3939 == AudioSystem.FORCE_BT_SCO) {
3940 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
3941 return AudioSystem.STREAM_BLUETOOTH_SCO;
3942 } else {
3943 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
3944 return AudioSystem.STREAM_VOICE_CALL;
3945 }
Eric Laurent25101b02011-02-02 09:33:30 -08003946 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05003947 if (wasStreamActiveRecently(AudioSystem.STREAM_RING, sStreamOverrideDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003948 if (DEBUG_VOL)
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05003949 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING stream active");
3950 return AudioSystem.STREAM_RING;
3951 } else if (wasStreamActiveRecently(
3952 AudioSystem.STREAM_NOTIFICATION, sStreamOverrideDelayMs)) {
3953 if (DEBUG_VOL)
3954 Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION stream active");
3955 return AudioSystem.STREAM_NOTIFICATION;
3956 } else {
3957 if (DEBUG_VOL)
3958 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC b/c default");
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003959 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003960 }
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05003961 } else if (
3962 wasStreamActiveRecently(AudioSystem.STREAM_NOTIFICATION, sStreamOverrideDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003963 if (DEBUG_VOL)
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05003964 Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION stream active");
3965 return AudioSystem.STREAM_NOTIFICATION;
3966 } else if (wasStreamActiveRecently(AudioSystem.STREAM_RING, sStreamOverrideDelayMs)) {
3967 if (DEBUG_VOL)
3968 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING stream active");
3969 return AudioSystem.STREAM_RING;
Eric Laurent25101b02011-02-02 09:33:30 -08003970 }
Eric Laurent212532b2014-07-21 15:43:18 -07003971 default:
Eric Laurent6d517662012-04-23 18:42:39 -07003972 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003973 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3974 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003975 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08003976 return AudioSystem.STREAM_BLUETOOTH_SCO;
3977 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003978 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08003979 return AudioSystem.STREAM_VOICE_CALL;
3980 }
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05003981 } else if (AudioSystem.isStreamActive(
3982 AudioSystem.STREAM_NOTIFICATION, sStreamOverrideDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003983 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08003984 return AudioSystem.STREAM_NOTIFICATION;
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05003985 } else if (AudioSystem.isStreamActive(
3986 AudioSystem.STREAM_RING, sStreamOverrideDelayMs)) {
3987 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING");
3988 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003989 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05003990 if (AudioSystem.isStreamActive(
3991 AudioSystem.STREAM_NOTIFICATION, sStreamOverrideDelayMs)) {
3992 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
John Spurlockeb1d88d2014-07-19 14:49:19 -04003993 return AudioSystem.STREAM_NOTIFICATION;
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05003994 } else if (AudioSystem.isStreamActive(
3995 AudioSystem.STREAM_RING, sStreamOverrideDelayMs)) {
3996 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING");
3997 return AudioSystem.STREAM_RING;
3998 } else {
3999 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default");
4000 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004001 }
Joe Onoratoc7fcba42011-01-05 16:53:11 -08004002 }
Eric Laurent212532b2014-07-21 15:43:18 -07004003 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004004 }
Eric Laurent212532b2014-07-21 15:43:18 -07004005 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
4006 + suggestedStreamType);
4007 return suggestedStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004008 }
4009
John Spurlockbcc10872014-11-28 15:29:21 -05004010 private void broadcastRingerMode(String action, int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004011 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05004012 Intent broadcast = new Intent(action);
Glenn Kastenba195eb2011-12-13 09:30:40 -08004013 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08004014 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
4015 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004016 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004017 }
4018
4019 private void broadcastVibrateSetting(int vibrateType) {
4020 // Send broadcast
Sudheer Shankafc46e9b2016-10-21 17:55:27 -07004021 if (mActivityManagerInternal.isSystemReady()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004022 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
4023 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
4024 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004025 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004026 }
4027 }
4028
4029 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07004030 /**
4031 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
4032 * Note that the wake lock needs to be released after the message has been handled.
4033 */
4034 private void queueMsgUnderWakeLock(Handler handler, int msg,
4035 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07004036 final long ident = Binder.clearCallingIdentity();
4037 // Always acquire the wake lock as AudioService because it is released by the
4038 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004039 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07004040 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07004041 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
4042 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004043
Eric Laurentafbb0472011-12-15 09:04:23 -08004044 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004045 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004046
4047 if (existingMsgPolicy == SENDMSG_REPLACE) {
4048 handler.removeMessages(msg);
4049 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
4050 return;
4051 }
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004052 synchronized (mLastDeviceConnectMsgTime) {
4053 long time = SystemClock.uptimeMillis() + delay;
4054 handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
4055 if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
4056 msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
4057 msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
4058 mLastDeviceConnectMsgTime = time;
4059 }
4060 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004061 }
4062
4063 boolean checkAudioSettingsPermission(String method) {
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07004064 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004065 == PackageManager.PERMISSION_GRANTED) {
4066 return true;
4067 }
4068 String msg = "Audio Settings Permission Denial: " + method + " from pid="
4069 + Binder.getCallingPid()
4070 + ", uid=" + Binder.getCallingUid();
4071 Log.w(TAG, msg);
4072 return false;
4073 }
4074
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004075 private int getDeviceForStream(int stream) {
John Spurlock8a52c442015-03-26 14:23:58 -04004076 int device = getDevicesForStream(stream);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004077 if ((device & (device - 1)) != 0) {
4078 // Multiple device selection is either:
4079 // - speaker + one other device: give priority to speaker in this case.
4080 // - one A2DP device + another device: happens with duplicated output. In this case
4081 // retain the device on the A2DP output as the other must not correspond to an active
4082 // selection if not the speaker.
Jungshik Jangc9ff9682014-09-15 17:41:06 +09004083 // - HDMI-CEC system audio mode only output: give priority to available item in order.
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004084 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
4085 device = AudioSystem.DEVICE_OUT_SPEAKER;
Jungshik Jangc9ff9682014-09-15 17:41:06 +09004086 } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
4087 device = AudioSystem.DEVICE_OUT_HDMI_ARC;
4088 } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
4089 device = AudioSystem.DEVICE_OUT_SPDIF;
4090 } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
4091 device = AudioSystem.DEVICE_OUT_AUX_LINE;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004092 } else {
4093 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
4094 }
4095 }
4096 return device;
4097 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004098
John Spurlock8a52c442015-03-26 14:23:58 -04004099 private int getDevicesForStream(int stream) {
4100 return getDevicesForStream(stream, true /*checkOthers*/);
4101 }
4102
4103 private int getDevicesForStream(int stream, boolean checkOthers) {
4104 ensureValidStreamType(stream);
4105 synchronized (VolumeStreamState.class) {
4106 return mStreamStates[stream].observeDevicesForStream_syncVSS(checkOthers);
4107 }
4108 }
4109
4110 private void observeDevicesForStreams(int skipStream) {
4111 synchronized (VolumeStreamState.class) {
4112 for (int stream = 0; stream < mStreamStates.length; stream++) {
4113 if (stream != skipStream) {
4114 mStreamStates[stream].observeDevicesForStream_syncVSS(false /*checkOthers*/);
4115 }
4116 }
4117 }
4118 }
4119
Paul McLean10804eb2015-01-28 11:16:35 -08004120 /*
4121 * A class just for packaging up a set of connection parameters.
4122 */
Jean-Michel Trivicf170362017-08-24 17:24:57 -07004123 class WiredDeviceConnectionState {
John Spurlock90874332015-03-10 16:00:54 -04004124 public final int mType;
4125 public final int mState;
4126 public final String mAddress;
4127 public final String mName;
4128 public final String mCaller;
Paul McLean10804eb2015-01-28 11:16:35 -08004129
John Spurlock90874332015-03-10 16:00:54 -04004130 public WiredDeviceConnectionState(int type, int state, String address, String name,
4131 String caller) {
Paul McLean10804eb2015-01-28 11:16:35 -08004132 mType = type;
4133 mState = state;
4134 mAddress = address;
4135 mName = name;
John Spurlock90874332015-03-10 16:00:54 -04004136 mCaller = caller;
Paul McLean10804eb2015-01-28 11:16:35 -08004137 }
4138 }
4139
John Spurlock90874332015-03-10 16:00:54 -04004140 public void setWiredDeviceConnectionState(int type, int state, String address, String name,
4141 String caller) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004142 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004143 if (DEBUG_DEVICES) {
4144 Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
4145 + address + ")");
4146 }
Eric Laurentcdae4762017-04-28 18:00:04 -07004147 int delay = checkSendBecomingNoisyIntent(type, state, AudioSystem.DEVICE_NONE);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07004148 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004149 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08004150 0 /* arg1 unused */,
4151 0 /* arg2 unused */,
John Spurlock90874332015-03-10 16:00:54 -04004152 new WiredDeviceConnectionState(type, state, address, name, caller),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004153 delay);
4154 }
4155 }
4156
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004157 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004158 {
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08004159 return setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
4160 device, state, profile, false /* suppressNoisyIntent */);
4161 }
4162
4163 public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice device,
4164 int state, int profile, boolean suppressNoisyIntent)
4165 {
Eric Laurent4724ea72017-05-23 10:39:38 -07004166 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, device)) {
Eric Laurentcdae4762017-04-28 18:00:04 -07004167 return 0;
4168 }
4169 return setBluetoothA2dpDeviceConnectionStateInt(
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08004170 device, state, profile, suppressNoisyIntent, AudioSystem.DEVICE_NONE);
Eric Laurentcdae4762017-04-28 18:00:04 -07004171 }
4172
4173 public int setBluetoothA2dpDeviceConnectionStateInt(
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08004174 BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent,
4175 int musicDevice)
Eric Laurentcdae4762017-04-28 18:00:04 -07004176 {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004177 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004178 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
4179 throw new IllegalArgumentException("invalid profile " + profile);
4180 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004181 synchronized (mConnectedDevices) {
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08004182 if (profile == BluetoothProfile.A2DP && !suppressNoisyIntent) {
Eric Laurentcdae4762017-04-28 18:00:04 -07004183 int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004184 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Eric Laurentcdae4762017-04-28 18:00:04 -07004185 intState, musicDevice);
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004186 } else {
4187 delay = 0;
4188 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07004189 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004190 (profile == BluetoothProfile.A2DP ?
4191 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004192 state,
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08004193 0 /* arg2 unused */,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004194 device,
4195 delay);
4196 }
4197 return delay;
4198 }
4199
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08004200 public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device)
4201 {
4202 synchronized (mConnectedDevices) {
4203 queueMsgUnderWakeLock(mAudioHandler,
4204 MSG_A2DP_DEVICE_CONFIG_CHANGE,
4205 0 /* arg1 unused */,
4206 0 /* arg1 unused */,
4207 device,
4208 0 /* delay */);
4209 }
4210 }
4211
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07004212 private static final int DEVICE_MEDIA_UNMUTED_ON_PLUG =
4213 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
4214 AudioSystem.DEVICE_OUT_LINE |
4215 AudioSystem.DEVICE_OUT_ALL_A2DP |
4216 AudioSystem.DEVICE_OUT_ALL_USB |
4217 AudioSystem.DEVICE_OUT_HDMI;
4218
4219 private void onAccessoryPlugMediaUnmute(int newDevice) {
4220 if (DEBUG_VOL) {
4221 Log.i(TAG, String.format("onAccessoryPlugMediaUnmute newDevice=%d [%s]",
4222 newDevice, AudioSystem.getOutputDeviceName(newDevice)));
4223 }
4224 synchronized (mConnectedDevices) {
Eric Laurent7fb83d92017-09-28 09:36:36 -07004225 if (mNm.getZenMode() != Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
4226 && (newDevice & DEVICE_MEDIA_UNMUTED_ON_PLUG) != 0
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07004227 && mStreamStates[AudioSystem.STREAM_MUSIC].mIsMuted
4228 && mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(newDevice) != 0
4229 && (newDevice & AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC)) != 0)
4230 {
4231 if (DEBUG_VOL) {
4232 Log.i(TAG, String.format(" onAccessoryPlugMediaUnmute unmuting device=%d [%s]",
4233 newDevice, AudioSystem.getOutputDeviceName(newDevice)));
4234 }
4235 mStreamStates[AudioSystem.STREAM_MUSIC].mute(false);
4236 }
4237 }
4238 }
4239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004240 ///////////////////////////////////////////////////////////////////////////
4241 // Inner classes
4242 ///////////////////////////////////////////////////////////////////////////
4243
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004244 // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
4245 // 1 mScoclient OR mSafeMediaVolumeState
4246 // 2 mSetModeDeathHandlers
4247 // 3 mSettingsLock
4248 // 4 VolumeStreamState.class
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004249 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004250 private final int mStreamType;
John Spurlockb6e19e32015-03-10 21:33:44 -04004251 private final int mIndexMin;
4252 private final int mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004253
RoboErik4197cb62015-01-21 15:45:32 -08004254 private boolean mIsMuted;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07004255 private String mVolumeIndexSettingName;
John Spurlock8a52c442015-03-26 14:23:58 -04004256 private int mObservedDevices;
John Spurlockb6e19e32015-03-10 21:33:44 -04004257
John Spurlock2bb02ec2015-03-02 13:13:06 -05004258 private final SparseIntArray mIndexMap = new SparseIntArray(8);
John Spurlockf63860c2015-02-19 09:46:27 -05004259 private final Intent mVolumeChanged;
John Spurlock8a52c442015-03-26 14:23:58 -04004260 private final Intent mStreamDevicesChanged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004261
Eric Laurenta553c252009-07-17 12:17:14 -07004262 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004263
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004264 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004265
4266 mStreamType = streamType;
John Spurlockb6e19e32015-03-10 21:33:44 -04004267 mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;
4268 mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;
4269 AudioSystem.initStreamVolume(streamType, mIndexMin / 10, mIndexMax / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004270
Eric Laurent33902db2012-10-07 16:15:07 -07004271 readSettings();
John Spurlockf63860c2015-02-19 09:46:27 -05004272 mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
4273 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
John Spurlock8a52c442015-03-26 14:23:58 -04004274 mStreamDevicesChanged = new Intent(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
4275 mStreamDevicesChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
4276 }
4277
4278 public int observeDevicesForStream_syncVSS(boolean checkOthers) {
4279 final int devices = AudioSystem.getDevicesForStream(mStreamType);
4280 if (devices == mObservedDevices) {
4281 return devices;
4282 }
4283 final int prevDevices = mObservedDevices;
4284 mObservedDevices = devices;
4285 if (checkOthers) {
4286 // one stream's devices have changed, check the others
4287 observeDevicesForStreams(mStreamType);
4288 }
4289 // log base stream changes to the event log
4290 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
4291 EventLogTags.writeStreamDevicesChanged(mStreamType, prevDevices, devices);
4292 }
4293 sendBroadcastToAll(mStreamDevicesChanged
4294 .putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, prevDevices)
4295 .putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, devices));
4296 return devices;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004297 }
4298
Jean-Michel Trivia53b7052017-04-12 18:27:01 -07004299 public @Nullable String getSettingNameForDevice(int device) {
4300 if (!hasValidSettingsName()) {
4301 return null;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004302 }
Jean-Michel Trivia53b7052017-04-12 18:27:01 -07004303 final String suffix = AudioSystem.getOutputDeviceName(device);
4304 if (suffix.isEmpty()) {
4305 return mVolumeIndexSettingName;
4306 }
4307 return mVolumeIndexSettingName + "_" + suffix;
4308 }
4309
4310 private boolean hasValidSettingsName() {
4311 return (mVolumeIndexSettingName != null && !mVolumeIndexSettingName.isEmpty());
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07004312 }
4313
Eric Laurentfdbee862014-05-12 15:26:12 -07004314 public void readSettings() {
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004315 synchronized (mSettingsLock) {
4316 synchronized (VolumeStreamState.class) {
4317 // force maximum volume on all streams if fixed volume property is set
4318 if (mUseFixedVolume) {
4319 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
4320 return;
4321 }
4322 // do not read system stream volume from settings: this stream is always aliased
4323 // to another stream type and its volume is never persisted. Values in settings can
4324 // only be stale values
4325 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
4326 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
4327 int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
Eric Laurentfdbee862014-05-12 15:26:12 -07004328 if (mCameraSoundForced) {
4329 index = mIndexMax;
4330 }
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004331 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
4332 return;
Eric Laurentdd45d012012-10-08 09:04:34 -07004333 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004334 }
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004335 }
4336 synchronized (VolumeStreamState.class) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004337 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
4338
4339 for (int i = 0; remainingDevices != 0; i++) {
4340 int device = (1 << i);
4341 if ((device & remainingDevices) == 0) {
4342 continue;
4343 }
4344 remainingDevices &= ~device;
4345
4346 // retrieve current volume for device
Eric Laurentfdbee862014-05-12 15:26:12 -07004347 // if no volume stored for current stream and device, use default volume if default
4348 // device, continue otherwise
4349 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
John Spurlock61560172015-02-06 19:46:04 -05004350 AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
Jean-Michel Trivia53b7052017-04-12 18:27:01 -07004351 int index;
4352 if (!hasValidSettingsName()) {
4353 index = defaultIndex;
4354 } else {
4355 String name = getSettingNameForDevice(device);
4356 index = Settings.System.getIntForUser(
4357 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
4358 }
Eric Laurentfdbee862014-05-12 15:26:12 -07004359 if (index == -1) {
4360 continue;
4361 }
4362
John Spurlock2bb02ec2015-03-02 13:13:06 -05004363 mIndexMap.put(device, getValidIndex(10 * index));
Eric Laurentdd45d012012-10-08 09:04:34 -07004364 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004365 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004366 }
4367
Liejun Tao39fb5672016-03-09 15:52:13 -06004368 private int getAbsoluteVolumeIndex(int index) {
4369 /* Special handling for Bluetooth Absolute Volume scenario
4370 * If we send full audio gain, some accessories are too loud even at its lowest
4371 * volume. We are not able to enumerate all such accessories, so here is the
4372 * workaround from phone side.
4373 * Pre-scale volume at lowest volume steps 1 2 and 3.
4374 * For volume step 0, set audio gain to 0 as some accessories won't mute on their end.
4375 */
4376 if (index == 0) {
4377 // 0% for volume 0
4378 index = 0;
4379 } else if (index == 1) {
4380 // 50% for volume 1
4381 index = (int)(mIndexMax * 0.5) /10;
4382 } else if (index == 2) {
4383 // 70% for volume 2
4384 index = (int)(mIndexMax * 0.70) /10;
4385 } else if (index == 3) {
4386 // 85% for volume 3
4387 index = (int)(mIndexMax * 0.85) /10;
4388 } else {
4389 // otherwise, full gain
4390 index = (mIndexMax + 5)/10;
4391 }
4392 return index;
4393 }
4394
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004395 // must be called while synchronized VolumeStreamState.class
4396 public void applyDeviceVolume_syncVSS(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07004397 int index;
RoboErik4197cb62015-01-21 15:45:32 -08004398 if (mIsMuted) {
Eric Laurent42b041e2013-03-29 11:36:03 -07004399 index = 0;
Liejun Tao4565a472016-01-20 17:52:20 -06004400 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) {
Liejun Tao39fb5672016-03-09 15:52:13 -06004401 index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
Liejun Tao4565a472016-01-20 17:52:20 -06004402 } else if ((device & mFullVolumeDevices) != 0) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004403 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07004404 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07004405 index = (getIndex(device) + 5)/10;
4406 }
4407 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004408 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004409
Eric Laurentfdbee862014-05-12 15:26:12 -07004410 public void applyAllVolumes() {
4411 synchronized (VolumeStreamState.class) {
Eric Laurentd9ac2be2016-04-07 14:04:23 -07004412 // apply device specific volumes first
Eric Laurentfdbee862014-05-12 15:26:12 -07004413 int index;
John Spurlock2bb02ec2015-03-02 13:13:06 -05004414 for (int i = 0; i < mIndexMap.size(); i++) {
Eric Laurentd9ac2be2016-04-07 14:04:23 -07004415 final int device = mIndexMap.keyAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07004416 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
RoboErik4197cb62015-01-21 15:45:32 -08004417 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004418 index = 0;
Liejun Tao39fb5672016-03-09 15:52:13 -06004419 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
4420 mAvrcpAbsVolSupported) {
4421 index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
4422 } else if ((device & mFullVolumeDevices) != 0) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004423 index = (mIndexMax + 5)/10;
4424 } else {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004425 index = (mIndexMap.valueAt(i) + 5)/10;
Eric Laurentfdbee862014-05-12 15:26:12 -07004426 }
4427 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07004428 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004429 }
Eric Laurentd9ac2be2016-04-07 14:04:23 -07004430 // apply default volume last: by convention , default device volume will be used
4431 // by audio policy manager if no explicit volume is present for a given device type
4432 if (mIsMuted) {
4433 index = 0;
4434 } else {
4435 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
4436 }
4437 AudioSystem.setStreamVolumeIndex(
4438 mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004439 }
4440 }
4441
John Spurlock90874332015-03-10 16:00:54 -04004442 public boolean adjustIndex(int deltaIndex, int device, String caller) {
4443 return setIndex(getIndex(device) + deltaIndex, device, caller);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004444 }
4445
John Spurlock90874332015-03-10 16:00:54 -04004446 public boolean setIndex(int index, int device, String caller) {
John Spurlockf63860c2015-02-19 09:46:27 -05004447 boolean changed = false;
4448 int oldIndex;
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004449 synchronized (mSettingsLock) {
4450 synchronized (VolumeStreamState.class) {
4451 oldIndex = getIndex(device);
4452 index = getValidIndex(index);
Eric Laurentfdbee862014-05-12 15:26:12 -07004453 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
4454 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07004455 }
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004456 mIndexMap.put(device, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07004457
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08004458 changed = oldIndex != index;
4459 // Apply change to all streams using this one as alias if:
4460 // - the index actually changed OR
4461 // - there is no volume index stored for this device on alias stream.
4462 // If changing volume of current device, also change volume of current
4463 // device on aliased stream
4464 final boolean currentDevice = (device == getDeviceForStream(mStreamType));
4465 final int numStreamTypes = AudioSystem.getNumStreamTypes();
4466 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4467 final VolumeStreamState aliasStreamState = mStreamStates[streamType];
4468 if (streamType != mStreamType &&
4469 mStreamVolumeAlias[streamType] == mStreamType &&
4470 (changed || !aliasStreamState.hasIndexForDevice(device))) {
4471 final int scaledIndex = rescaleIndex(index, mStreamType, streamType);
4472 aliasStreamState.setIndex(scaledIndex, device, caller);
4473 if (currentDevice) {
4474 aliasStreamState.setIndex(scaledIndex,
4475 getDeviceForStream(streamType), caller);
4476 }
Eric Laurentfdbee862014-05-12 15:26:12 -07004477 }
4478 }
Eric Laurentfdbee862014-05-12 15:26:12 -07004479 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004480 }
John Spurlockf63860c2015-02-19 09:46:27 -05004481 if (changed) {
4482 oldIndex = (oldIndex + 5) / 10;
4483 index = (index + 5) / 10;
John Spurlock90874332015-03-10 16:00:54 -04004484 // log base stream changes to the event log
4485 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
4486 if (caller == null) {
4487 Log.w(TAG, "No caller for volume_changed event", new Throwable());
4488 }
4489 EventLogTags.writeVolumeChanged(mStreamType, oldIndex, index, mIndexMax / 10,
4490 caller);
4491 }
4492 // fire changed intents for all streams
John Spurlockf63860c2015-02-19 09:46:27 -05004493 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
4494 mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
Jean-Michel Trivi560877d2015-06-25 17:38:35 -07004495 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
4496 mStreamVolumeAlias[mStreamType]);
John Spurlockf63860c2015-02-19 09:46:27 -05004497 sendBroadcastToAll(mVolumeChanged);
4498 }
4499 return changed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004500 }
4501
Eric Laurentfdbee862014-05-12 15:26:12 -07004502 public int getIndex(int device) {
4503 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004504 int index = mIndexMap.get(device, -1);
4505 if (index == -1) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004506 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
John Spurlock2bb02ec2015-03-02 13:13:06 -05004507 index = mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurentfdbee862014-05-12 15:26:12 -07004508 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05004509 return index;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004510 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07004511 }
4512
Eric Laurent3fb608e2016-11-03 16:27:40 -07004513 public boolean hasIndexForDevice(int device) {
4514 synchronized (VolumeStreamState.class) {
4515 return (mIndexMap.get(device, -1) != -1);
4516 }
4517 }
4518
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004519 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07004520 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004521 }
4522
John Spurlockb6e19e32015-03-10 21:33:44 -04004523 public int getMinIndex() {
4524 return mIndexMin;
4525 }
4526
Jean-Michel Trivi170a0ee2017-04-14 18:13:26 -07004527 /**
4528 * Copies all device/index pairs from the given VolumeStreamState after initializing
4529 * them with the volume for DEVICE_OUT_DEFAULT. No-op if the source VolumeStreamState
4530 * has the same stream type as this instance.
4531 * @param srcStream
4532 * @param caller
4533 */
John Spurlock90874332015-03-10 16:00:54 -04004534 public void setAllIndexes(VolumeStreamState srcStream, String caller) {
Jean-Michel Trivi170a0ee2017-04-14 18:13:26 -07004535 if (mStreamType == srcStream.mStreamType) {
4536 return;
4537 }
Jean-Michel Triviad37c2c2018-01-19 09:40:36 -08004538 synchronized (mSettingsLock) {
4539 synchronized (VolumeStreamState.class) {
4540 int srcStreamType = srcStream.getStreamType();
4541 // apply default device volume from source stream to all devices first in case
4542 // some devices are present in this stream state but not in source stream state
4543 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurentfdbee862014-05-12 15:26:12 -07004544 index = rescaleIndex(index, srcStreamType, mStreamType);
Jean-Michel Triviad37c2c2018-01-19 09:40:36 -08004545 for (int i = 0; i < mIndexMap.size(); i++) {
4546 mIndexMap.put(mIndexMap.keyAt(i), index);
4547 }
4548 // Now apply actual volume for devices in source stream state
4549 SparseIntArray srcMap = srcStream.mIndexMap;
4550 for (int i = 0; i < srcMap.size(); i++) {
4551 int device = srcMap.keyAt(i);
4552 index = srcMap.valueAt(i);
4553 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07004554
Jean-Michel Triviad37c2c2018-01-19 09:40:36 -08004555 setIndex(index, device, caller);
4556 }
Eric Laurentfdbee862014-05-12 15:26:12 -07004557 }
Eric Laurent6d517662012-04-23 18:42:39 -07004558 }
4559 }
4560
Jean-Michel Triviad37c2c2018-01-19 09:40:36 -08004561 @GuardedBy("mSettingsLock")
Eric Laurentfdbee862014-05-12 15:26:12 -07004562 public void setAllIndexesToMax() {
4563 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004564 for (int i = 0; i < mIndexMap.size(); i++) {
4565 mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07004566 }
Eric Laurentdd45d012012-10-08 09:04:34 -07004567 }
Eric Laurentdd45d012012-10-08 09:04:34 -07004568 }
4569
RoboErik4197cb62015-01-21 15:45:32 -08004570 public void mute(boolean state) {
John Spurlock22b9ee12015-02-18 22:51:44 -05004571 boolean changed = false;
Eric Laurentfdbee862014-05-12 15:26:12 -07004572 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08004573 if (state != mIsMuted) {
John Spurlock22b9ee12015-02-18 22:51:44 -05004574 changed = true;
RoboErik4197cb62015-01-21 15:45:32 -08004575 mIsMuted = state;
John Spurlock22b9ee12015-02-18 22:51:44 -05004576
RoboErik4197cb62015-01-21 15:45:32 -08004577 // Set the new mute volume. This propagates the values to
4578 // the audio system, otherwise the volume won't be changed
4579 // at the lower level.
4580 sendMsg(mAudioHandler,
4581 MSG_SET_ALL_VOLUMES,
4582 SENDMSG_QUEUE,
4583 0,
4584 0,
4585 this, 0);
Eric Laurentfdbee862014-05-12 15:26:12 -07004586 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004587 }
John Spurlock22b9ee12015-02-18 22:51:44 -05004588 if (changed) {
4589 // Stream mute changed, fire the intent.
4590 Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
4591 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
4592 intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
4593 sendBroadcastToAll(intent);
4594 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004595 }
4596
Eric Laurent6d517662012-04-23 18:42:39 -07004597 public int getStreamType() {
4598 return mStreamType;
4599 }
4600
Eric Laurent212532b2014-07-21 15:43:18 -07004601 public void checkFixedVolumeDevices() {
4602 synchronized (VolumeStreamState.class) {
4603 // ignore settings for fixed volume devices: volume should always be at max or 0
4604 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004605 for (int i = 0; i < mIndexMap.size(); i++) {
4606 int device = mIndexMap.keyAt(i);
4607 int index = mIndexMap.valueAt(i);
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07004608 if (((device & mFullVolumeDevices) != 0)
4609 || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004610 mIndexMap.put(device, mIndexMax);
Eric Laurent212532b2014-07-21 15:43:18 -07004611 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004612 applyDeviceVolume_syncVSS(device);
Eric Laurent212532b2014-07-21 15:43:18 -07004613 }
4614 }
4615 }
4616 }
4617
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004618 private int getValidIndex(int index) {
John Spurlockb6e19e32015-03-10 21:33:44 -04004619 if (index < mIndexMin) {
4620 return mIndexMin;
John Spurlockee5ad722015-03-03 16:17:21 -05004621 } else if (mUseFixedVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07004622 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004623 }
4624
4625 return index;
4626 }
4627
Eric Laurentbffc3d12012-05-07 17:43:49 -07004628 private void dump(PrintWriter pw) {
RoboErik4197cb62015-01-21 15:45:32 -08004629 pw.print(" Muted: ");
4630 pw.println(mIsMuted);
John Spurlockb6e19e32015-03-10 21:33:44 -04004631 pw.print(" Min: ");
4632 pw.println((mIndexMin + 5) / 10);
John Spurlock2b29bc42014-08-26 16:40:35 -04004633 pw.print(" Max: ");
4634 pw.println((mIndexMax + 5) / 10);
Eric Laurentbffc3d12012-05-07 17:43:49 -07004635 pw.print(" Current: ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05004636 for (int i = 0; i < mIndexMap.size(); i++) {
4637 if (i > 0) {
4638 pw.print(", ");
4639 }
4640 final int device = mIndexMap.keyAt(i);
John Spurlock2b29bc42014-08-26 16:40:35 -04004641 pw.print(Integer.toHexString(device));
4642 final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
4643 : AudioSystem.getOutputDeviceName(device);
4644 if (!deviceName.isEmpty()) {
4645 pw.print(" (");
4646 pw.print(deviceName);
4647 pw.print(")");
4648 }
4649 pw.print(": ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05004650 final int index = (mIndexMap.valueAt(i) + 5) / 10;
John Spurlock2b29bc42014-08-26 16:40:35 -04004651 pw.print(index);
Eric Laurentbffc3d12012-05-07 17:43:49 -07004652 }
John Spurlockb32fc972015-03-05 13:58:00 -05004653 pw.println();
4654 pw.print(" Devices: ");
John Spurlock8a52c442015-03-26 14:23:58 -04004655 final int devices = getDevicesForStream(mStreamType);
John Spurlockb32fc972015-03-05 13:58:00 -05004656 int device, i = 0, n = 0;
John Spurlock1ff1e6e2015-03-09 14:21:20 -04004657 // iterate all devices from 1 to DEVICE_OUT_DEFAULT exclusive
4658 // (the default device is not returned by getDevicesForStream)
4659 while ((device = 1 << i) != AudioSystem.DEVICE_OUT_DEFAULT) {
John Spurlockb32fc972015-03-05 13:58:00 -05004660 if ((devices & device) != 0) {
4661 if (n++ > 0) {
4662 pw.print(", ");
4663 }
4664 pw.print(AudioSystem.getOutputDeviceName(device));
4665 }
4666 i++;
4667 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07004668 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004669 }
4670
4671 /** Thread that handles native AudioSystem control. */
4672 private class AudioSystemThread extends Thread {
4673 AudioSystemThread() {
4674 super("AudioService");
4675 }
4676
4677 @Override
4678 public void run() {
4679 // Set this thread up so the handler will work on it
4680 Looper.prepare();
4681
4682 synchronized(AudioService.this) {
4683 mAudioHandler = new AudioHandler();
4684
4685 // Notify that the handler has been created
4686 AudioService.this.notify();
4687 }
4688
4689 // Listen for volume change requests that are set by VolumePanel
4690 Looper.loop();
4691 }
4692 }
4693
4694 /** Handles internal volume messages in separate volume thread. */
4695 private class AudioHandler extends Handler {
4696
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004697 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004698
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004699 synchronized (VolumeStreamState.class) {
4700 // Apply volume
4701 streamState.applyDeviceVolume_syncVSS(device);
Eric Laurenta553c252009-07-17 12:17:14 -07004702
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004703 // Apply change to all streams using this one as alias
4704 int numStreamTypes = AudioSystem.getNumStreamTypes();
4705 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4706 if (streamType != streamState.mStreamType &&
4707 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
4708 // Make sure volume is also maxed out on A2DP device for aliased stream
4709 // that may have a different device selected
4710 int streamDevice = getDeviceForStream(streamType);
4711 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
4712 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
4713 mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
4714 }
4715 mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
Eric Laurentcd772d02013-10-30 18:31:07 -07004716 }
Eric Laurenta553c252009-07-17 12:17:14 -07004717 }
4718 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004719 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08004720 sendMsg(mAudioHandler,
4721 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08004722 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004723 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07004724 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08004725 streamState,
4726 PERSIST_DELAY);
4727
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004728 }
4729
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004730 private void setAllVolumes(VolumeStreamState streamState) {
4731
4732 // Apply volume
4733 streamState.applyAllVolumes();
4734
4735 // Apply change to all streams using this one as alias
4736 int numStreamTypes = AudioSystem.getNumStreamTypes();
4737 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4738 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07004739 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004740 mStreamStates[streamType].applyAllVolumes();
4741 }
4742 }
4743 }
4744
Eric Laurent42b041e2013-03-29 11:36:03 -07004745 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07004746 if (mUseFixedVolume) {
4747 return;
4748 }
Muyuan Li1ed6df62016-06-18 11:16:52 -07004749 if (mIsSingleVolume && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
Eric Laurent212532b2014-07-21 15:43:18 -07004750 return;
4751 }
Jean-Michel Trivia53b7052017-04-12 18:27:01 -07004752 if (streamState.hasValidSettingsName()) {
4753 System.putIntForUser(mContentResolver,
4754 streamState.getSettingNameForDevice(device),
4755 (streamState.getIndex(device) + 5)/ 10,
4756 UserHandle.USER_CURRENT);
4757 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004758 }
4759
Glenn Kastenba195eb2011-12-13 09:30:40 -08004760 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07004761 if (mUseFixedVolume) {
4762 return;
4763 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07004764 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004765 }
4766
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004767 private boolean onLoadSoundEffects() {
4768 int status;
4769
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004770 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004771 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004772 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
4773 return false;
4774 }
4775
4776 if (mSoundPool != null) {
4777 return true;
4778 }
4779
4780 loadTouchSoundAssets();
4781
Jean-Michel Trivi55a30c42014-07-20 17:56:11 -07004782 mSoundPool = new SoundPool.Builder()
4783 .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
4784 .setAudioAttributes(new AudioAttributes.Builder()
4785 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
4786 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
4787 .build())
4788 .build();
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004789 mSoundPoolCallBack = null;
4790 mSoundPoolListenerThread = new SoundPoolListenerThread();
4791 mSoundPoolListenerThread.start();
4792 int attempts = 3;
4793 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
4794 try {
4795 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07004796 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004797 } catch (InterruptedException e) {
4798 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
4799 }
4800 }
4801
4802 if (mSoundPoolCallBack == null) {
4803 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
4804 if (mSoundPoolLooper != null) {
4805 mSoundPoolLooper.quit();
4806 mSoundPoolLooper = null;
4807 }
4808 mSoundPoolListenerThread = null;
4809 mSoundPool.release();
4810 mSoundPool = null;
4811 return false;
4812 }
4813 /*
4814 * poolId table: The value -1 in this table indicates that corresponding
4815 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
4816 * Once loaded, the value in poolId is the sample ID and the same
4817 * sample can be reused for another effect using the same file.
4818 */
4819 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4820 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4821 poolId[fileIdx] = -1;
4822 }
4823 /*
4824 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
4825 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
4826 * this indicates we have a valid sample loaded for this effect.
4827 */
4828
4829 int numSamples = 0;
4830 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4831 // Do not load sample if this effect uses the MediaPlayer
4832 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
4833 continue;
4834 }
4835 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
4836 String filePath = Environment.getRootDirectory()
4837 + SOUND_EFFECTS_PATH
4838 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
4839 int sampleId = mSoundPool.load(filePath, 0);
4840 if (sampleId <= 0) {
4841 Log.w(TAG, "Soundpool could not load file: "+filePath);
4842 } else {
4843 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
4844 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
4845 numSamples++;
4846 }
4847 } else {
4848 SOUND_EFFECT_FILES_MAP[effect][1] =
4849 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
4850 }
4851 }
4852 // wait for all samples to be loaded
4853 if (numSamples > 0) {
4854 mSoundPoolCallBack.setSamples(poolId);
4855
4856 attempts = 3;
4857 status = 1;
4858 while ((status == 1) && (attempts-- > 0)) {
4859 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07004860 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004861 status = mSoundPoolCallBack.status();
4862 } catch (InterruptedException e) {
4863 Log.w(TAG, "Interrupted while waiting sound pool callback.");
4864 }
4865 }
4866 } else {
4867 status = -1;
4868 }
4869
4870 if (mSoundPoolLooper != null) {
4871 mSoundPoolLooper.quit();
4872 mSoundPoolLooper = null;
4873 }
4874 mSoundPoolListenerThread = null;
4875 if (status != 0) {
4876 Log.w(TAG,
4877 "onLoadSoundEffects(), Error "+status+ " while loading samples");
4878 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4879 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
4880 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4881 }
4882 }
4883
4884 mSoundPool.release();
4885 mSoundPool = null;
4886 }
4887 }
4888 return (status == 0);
4889 }
4890
4891 /**
4892 * Unloads samples from the sound pool.
4893 * This method can be called to free some memory when
4894 * sound effects are disabled.
4895 */
4896 private void onUnloadSoundEffects() {
4897 synchronized (mSoundEffectsLock) {
4898 if (mSoundPool == null) {
4899 return;
4900 }
4901
4902 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4903 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4904 poolId[fileIdx] = 0;
4905 }
4906
4907 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4908 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
4909 continue;
4910 }
4911 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
4912 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
4913 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4914 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
4915 }
4916 }
4917 mSoundPool.release();
4918 mSoundPool = null;
4919 }
4920 }
4921
4922 private void onPlaySoundEffect(int effectType, int volume) {
4923 synchronized (mSoundEffectsLock) {
4924
4925 onLoadSoundEffects();
4926
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004927 if (mSoundPool == null) {
4928 return;
4929 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004930 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08004931 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004932 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07004933 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004934 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07004935 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004936 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004937
4938 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004939 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
4940 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004941 } else {
4942 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004943 try {
Eric Laurente78fced2013-03-15 16:03:47 -07004944 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
4945 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004946 mediaPlayer.setDataSource(filePath);
4947 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
4948 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08004949 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004950 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
4951 public void onCompletion(MediaPlayer mp) {
4952 cleanupPlayer(mp);
4953 }
4954 });
4955 mediaPlayer.setOnErrorListener(new OnErrorListener() {
4956 public boolean onError(MediaPlayer mp, int what, int extra) {
4957 cleanupPlayer(mp);
4958 return true;
4959 }
4960 });
4961 mediaPlayer.start();
4962 } catch (IOException ex) {
4963 Log.w(TAG, "MediaPlayer IOException: "+ex);
4964 } catch (IllegalArgumentException ex) {
4965 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
4966 } catch (IllegalStateException ex) {
4967 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004968 }
4969 }
4970 }
4971 }
4972
4973 private void cleanupPlayer(MediaPlayer mp) {
4974 if (mp != null) {
4975 try {
4976 mp.stop();
4977 mp.release();
4978 } catch (IllegalStateException ex) {
4979 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
4980 }
4981 }
4982 }
4983
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07004984 private void setForceUse(int usage, int config, String eventSource) {
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004985 synchronized (mConnectedDevices) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07004986 setForceUseInt_SyncDevices(usage, config, eventSource);
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004987 }
Eric Laurentfa640152011-03-12 15:59:51 -08004988 }
4989
Eric Laurent05274f32012-11-29 12:48:18 -08004990 private void onPersistSafeVolumeState(int state) {
4991 Settings.Global.putInt(mContentResolver,
4992 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
4993 state);
4994 }
4995
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004996 @Override
4997 public void handleMessage(Message msg) {
Eric Laurentafbb0472011-12-15 09:04:23 -08004998 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004999
Eric Laurent9bc8358d2011-11-18 16:43:31 -08005000 case MSG_SET_DEVICE_VOLUME:
5001 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
5002 break;
5003
5004 case MSG_SET_ALL_VOLUMES:
5005 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005006 break;
5007
5008 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07005009 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005010 break;
5011
5012 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08005013 // note that the value persisted is the current ringer mode, not the
5014 // value of ringer mode as of the time the request was made to persist
John Spurlock661f2cf2014-11-17 10:29:10 -05005015 persistRingerMode(getRingerModeInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005016 break;
5017
Andy Hunged0ea402015-10-30 14:11:46 -07005018 case MSG_AUDIO_SERVER_DIED:
5019 onAudioServerDied();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005020 break;
5021
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07005022 case MSG_UNLOAD_SOUND_EFFECTS:
5023 onUnloadSoundEffects();
5024 break;
5025
Eric Laurent117b7bb2011-01-16 17:07:27 -08005026 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07005027 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
5028 // can take several dozens of milliseconds to complete
5029 boolean loaded = onLoadSoundEffects();
5030 if (msg.obj != null) {
5031 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
5032 synchronized (reply) {
5033 reply.mStatus = loaded ? 0 : -1;
5034 reply.notify();
5035 }
5036 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08005037 break;
5038
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005039 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07005040 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005041 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005042
5043 case MSG_BTA2DP_DOCK_TIMEOUT:
5044 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005045 synchronized (mConnectedDevices) {
5046 makeA2dpDeviceUnavailableNow( (String) msg.obj );
5047 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005048 break;
Eric Laurentfa640152011-03-12 15:59:51 -08005049
5050 case MSG_SET_FORCE_USE:
Sungsoocf09fe62016-09-28 16:21:48 +09005051 case MSG_SET_FORCE_BT_A2DP_USE:
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005052 setForceUse(msg.arg1, msg.arg2, (String) msg.obj);
Eric Laurentfa640152011-03-12 15:59:51 -08005053 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07005054
Eric Laurentdc03c612011-04-01 10:59:41 -07005055 case MSG_BT_HEADSET_CNCT_FAILED:
5056 resetBluetoothSco();
5057 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005058
5059 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
Paul McLean10804eb2015-01-28 11:16:35 -08005060 { WiredDeviceConnectionState connectState =
5061 (WiredDeviceConnectionState)msg.obj;
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005062 mWiredDevLogger.log(new WiredDevConnectEvent(connectState));
Paul McLean10804eb2015-01-28 11:16:35 -08005063 onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
John Spurlock90874332015-03-10 16:00:54 -04005064 connectState.mAddress, connectState.mName, connectState.mCaller);
Paul McLean10804eb2015-01-28 11:16:35 -08005065 mAudioEventWakeLock.release();
5066 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005067 break;
5068
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005069 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
5070 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
5071 mAudioEventWakeLock.release();
5072 break;
5073
5074 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
5075 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005076 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005077 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07005078
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005079 case MSG_A2DP_DEVICE_CONFIG_CHANGE:
5080 onBluetoothA2dpDeviceConfigChange((BluetoothDevice)msg.obj);
5081 mAudioEventWakeLock.release();
5082 break;
5083
Jean-Michel Trivi92ed7bf2017-06-26 19:32:38 -07005084 case MSG_DISABLE_AUDIO_FOR_UID:
5085 mPlaybackMonitor.disableAudioForUid( msg.arg1 == 1 /* disable */,
5086 msg.arg2 /* uid */);
5087 mAudioEventWakeLock.release();
5088 break;
5089
Dianne Hackborn632ca412012-06-14 19:34:10 -07005090 case MSG_REPORT_NEW_ROUTES: {
5091 int N = mRoutesObservers.beginBroadcast();
5092 if (N > 0) {
5093 AudioRoutesInfo routes;
5094 synchronized (mCurAudioRoutes) {
5095 routes = new AudioRoutesInfo(mCurAudioRoutes);
5096 }
5097 while (N > 0) {
5098 N--;
5099 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
5100 try {
5101 obs.dispatchAudioRoutesChanged(routes);
5102 } catch (RemoteException e) {
5103 }
5104 }
5105 }
5106 mRoutesObservers.finishBroadcast();
John Spurlock8a52c442015-03-26 14:23:58 -04005107 observeDevicesForStreams(-1);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005108 break;
5109 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005110
Eric Laurentc34dcc12012-09-10 13:51:52 -07005111 case MSG_CHECK_MUSIC_ACTIVE:
John Spurlock90874332015-03-10 16:00:54 -04005112 onCheckMusicActive((String) msg.obj);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005113 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07005114
5115 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
5116 onSendBecomingNoisyIntent();
5117 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07005118
5119 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
5120 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
John Spurlock90874332015-03-10 16:00:54 -04005121 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED),
5122 (String) msg.obj);
Eric Laurentd640bd32012-09-28 18:01:48 -07005123 break;
Eric Laurent05274f32012-11-29 12:48:18 -08005124 case MSG_PERSIST_SAFE_VOLUME_STATE:
5125 onPersistSafeVolumeState(msg.arg1);
5126 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08005127
Eric Laurent2a57ca92013-03-07 17:29:27 -08005128 case MSG_BROADCAST_BT_CONNECTION_STATE:
5129 onBroadcastScoConnectionState(msg.arg1);
5130 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07005131
5132 case MSG_SYSTEM_READY:
5133 onSystemReady();
5134 break;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005135
Eric Laurent0867bed2015-05-20 14:49:08 -07005136 case MSG_INDICATE_SYSTEM_READY:
5137 onIndicateSystemReady();
5138 break;
5139
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07005140 case MSG_ACCESSORY_PLUG_MEDIA_UNMUTE:
5141 onAccessoryPlugMediaUnmute(msg.arg1);
5142 break;
5143
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005144 case MSG_PERSIST_MUSIC_ACTIVE_MS:
5145 final int musicActiveMs = msg.arg1;
5146 Settings.Secure.putIntForUser(mContentResolver,
5147 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
5148 UserHandle.USER_CURRENT);
5149 break;
Eric Laurentc0232482016-03-15 18:19:23 -07005150
RoboErik5452e252015-02-06 15:33:53 -08005151 case MSG_UNMUTE_STREAM:
5152 onUnmuteStream(msg.arg1, msg.arg2);
5153 break;
Eric Laurentc0232482016-03-15 18:19:23 -07005154
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07005155 case MSG_DYN_POLICY_MIX_STATE_UPDATE:
5156 onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1);
5157 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005158 }
5159 }
5160 }
5161
Jason Parekhb1096152009-03-24 17:48:25 -07005162 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07005163
Phil Burked43bf52016-03-01 17:01:35 -08005164 private int mEncodedSurroundMode;
5165
Jason Parekhb1096152009-03-24 17:48:25 -07005166 SettingsObserver() {
5167 super(new Handler());
5168 mContentResolver.registerContentObserver(Settings.System.getUriFor(
5169 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07005170 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
5171 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Andy Hung7b98e9a2016-02-25 18:34:50 -08005172 mContentResolver.registerContentObserver(Settings.System.getUriFor(
5173 Settings.System.MASTER_MONO), false, this);
Phil Burked43bf52016-03-01 17:01:35 -08005174
5175 mEncodedSurroundMode = Settings.Global.getInt(
5176 mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT,
5177 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
5178 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
5179 Settings.Global.ENCODED_SURROUND_OUTPUT), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07005180 }
5181
5182 @Override
5183 public void onChange(boolean selfChange) {
5184 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08005185 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
5186 // However there appear to be some missing locks around mRingerModeMutedStreams
5187 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
5188 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07005189 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07005190 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07005191 /*
5192 * Ensure all stream types that should be affected by ringer mode
5193 * are in the proper state.
5194 */
John Spurlock661f2cf2014-11-17 10:29:10 -05005195 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurenta553c252009-07-17 12:17:14 -07005196 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07005197 readDockAudioSettings(mContentResolver);
Andy Hung7b98e9a2016-02-25 18:34:50 -08005198 updateMasterMono(mContentResolver);
Phil Burked43bf52016-03-01 17:01:35 -08005199 updateEncodedSurroundOutput();
5200 }
5201 }
5202
5203 private void updateEncodedSurroundOutput() {
5204 int newSurroundMode = Settings.Global.getInt(
5205 mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT,
5206 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
5207 // Did it change?
5208 if (mEncodedSurroundMode != newSurroundMode) {
5209 // Send to AudioPolicyManager
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005210 sendEncodedSurroundMode(newSurroundMode, "SettingsObserver");
Phil Burked43bf52016-03-01 17:01:35 -08005211 synchronized(mConnectedDevices) {
5212 // Is HDMI connected?
5213 String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_HDMI, "");
5214 DeviceListSpec deviceSpec = mConnectedDevices.get(key);
5215 if (deviceSpec != null) {
5216 // Toggle HDMI to retrigger broadcast with proper formats.
5217 setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
5218 AudioSystem.DEVICE_STATE_UNAVAILABLE, "", "",
5219 "android"); // disconnect
5220 setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
5221 AudioSystem.DEVICE_STATE_AVAILABLE, "", "",
5222 "android"); // reconnect
5223 }
5224 }
5225 mEncodedSurroundMode = newSurroundMode;
Eric Laurenta553c252009-07-17 12:17:14 -07005226 }
Jason Parekhb1096152009-03-24 17:48:25 -07005227 }
Jason Parekhb1096152009-03-24 17:48:25 -07005228 }
Eric Laurenta553c252009-07-17 12:17:14 -07005229
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005230 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005231 private void makeA2dpDeviceAvailable(String address, String name, String eventSource) {
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07005232 // enable A2DP before notifying A2DP connection to avoid unnecessary processing in
Eric Laurent78472112012-05-21 08:57:21 -07005233 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07005234 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
5235 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
5236 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005237 setBluetoothA2dpOnInt(true, eventSource);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005238 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07005239 AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005240 // Reset A2DP suspend state each time a new sink is connected
5241 AudioSystem.setParameters("A2dpSuspended=false");
Paul McLean394a8e12015-03-03 10:29:19 -07005242 mConnectedDevices.put(
5243 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
Paul McLean20eec5b2015-05-09 13:02:18 -07005244 new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
Paul McLean394a8e12015-03-03 10:29:19 -07005245 address));
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07005246 sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
5247 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, null, 0);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005248 }
5249
Eric Laurent5bfaeae2012-09-21 18:44:48 -07005250 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005251 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07005252 }
5253
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005254 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005255 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07005256 synchronized (mA2dpAvrcpLock) {
5257 mAvrcpAbsVolSupported = false;
5258 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005259 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07005260 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07005261 mConnectedDevices.remove(
5262 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
RoboErik5535ea82014-09-25 14:53:16 -07005263 synchronized (mCurAudioRoutes) {
5264 // Remove A2DP routes as well
John Spurlock61560172015-02-06 19:46:04 -05005265 if (mCurAudioRoutes.bluetoothName != null) {
5266 mCurAudioRoutes.bluetoothName = null;
RoboErik5535ea82014-09-25 14:53:16 -07005267 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
5268 SENDMSG_NOOP, 0, 0, null, 0);
5269 }
5270 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005271 }
5272
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005273 // must be called synchronized on mConnectedDevices
Eric Laurentd138e4e2015-05-15 16:41:15 -07005274 private void makeA2dpDeviceUnavailableLater(String address, int delayMs) {
Eric Laurent3b591262010-04-20 07:01:00 -07005275 // prevent any activity on the A2DP audio output to avoid unwanted
5276 // reconnection of the sink.
5277 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005278 // the device will be made unavailable later, so consider it disconnected right away
Paul McLean394a8e12015-03-03 10:29:19 -07005279 mConnectedDevices.remove(
5280 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005281 // send the delayed message to make the device unavailable later
5282 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
Eric Laurentd138e4e2015-05-15 16:41:15 -07005283 mAudioHandler.sendMessageDelayed(msg, delayMs);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005284
5285 }
5286
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005287 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005288 private void makeA2dpSrcAvailable(String address) {
5289 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07005290 AudioSystem.DEVICE_STATE_AVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07005291 mConnectedDevices.put(
5292 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
Paul McLean20eec5b2015-05-09 13:02:18 -07005293 new DeviceListSpec(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "",
Paul McLean394a8e12015-03-03 10:29:19 -07005294 address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005295 }
5296
5297 // must be called synchronized on mConnectedDevices
5298 private void makeA2dpSrcUnavailable(String address) {
5299 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07005300 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07005301 mConnectedDevices.remove(
5302 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005303 }
5304
5305 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07005306 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07005307 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
5308 }
5309
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005310 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07005311 private boolean hasScheduledA2dpDockTimeout() {
5312 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
5313 }
5314
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005315 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005316 {
Eric Laurent4724ea72017-05-23 10:39:38 -07005317 if (DEBUG_DEVICES) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005318 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice+"state=" + state);
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005319 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005320 if (btDevice == null) {
5321 return;
5322 }
5323 String address = btDevice.getAddress();
5324 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
5325 address = "";
5326 }
John Du5a0cf7a2013-07-19 11:30:34 -07005327
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005328 synchronized (mConnectedDevices) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005329 final String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
5330 btDevice.getAddress());
5331 final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
Paul McLean394a8e12015-03-03 10:29:19 -07005332 boolean isConnected = deviceSpec != null;
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005333
5334 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
5335 if (btDevice.isBluetoothDock()) {
5336 if (state == BluetoothProfile.STATE_DISCONNECTED) {
5337 // introduction of a delay for transient disconnections of docks when
5338 // power is rapidly turned off/on, this message will be canceled if
5339 // we reconnect the dock under a preset delay
Eric Laurentd138e4e2015-05-15 16:41:15 -07005340 makeA2dpDeviceUnavailableLater(address, BTA2DP_DOCK_TIMEOUT_MILLIS);
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005341 // the next time isConnected is evaluated, it will be false for the dock
5342 }
5343 } else {
5344 makeA2dpDeviceUnavailableNow(address);
5345 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07005346 synchronized (mCurAudioRoutes) {
John Spurlock61560172015-02-06 19:46:04 -05005347 if (mCurAudioRoutes.bluetoothName != null) {
5348 mCurAudioRoutes.bluetoothName = null;
Dianne Hackborn632ca412012-06-14 19:34:10 -07005349 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
5350 SENDMSG_NOOP, 0, 0, null, 0);
5351 }
5352 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005353 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
5354 if (btDevice.isBluetoothDock()) {
5355 // this could be a reconnection after a transient disconnection
5356 cancelA2dpDeviceTimeout();
5357 mDockAddress = address;
5358 } else {
5359 // this could be a connection of another A2DP device before the timeout of
5360 // a dock: cancel the dock timeout, and make the dock unavailable now
5361 if(hasScheduledA2dpDockTimeout()) {
5362 cancelA2dpDeviceTimeout();
5363 makeA2dpDeviceUnavailableNow(mDockAddress);
5364 }
5365 }
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005366 makeA2dpDeviceAvailable(address, btDevice.getName(),
5367 "onSetA2dpSinkConnectionState");
Dianne Hackborn632ca412012-06-14 19:34:10 -07005368 synchronized (mCurAudioRoutes) {
5369 String name = btDevice.getAliasName();
John Spurlock61560172015-02-06 19:46:04 -05005370 if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
5371 mCurAudioRoutes.bluetoothName = name;
Dianne Hackborn632ca412012-06-14 19:34:10 -07005372 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
5373 SENDMSG_NOOP, 0, 0, null, 0);
5374 }
5375 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08005376 }
5377 }
5378 }
5379
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005380 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
5381 {
5382 if (DEBUG_VOL) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005383 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice=" + btDevice + " state=" + state);
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005384 }
5385 if (btDevice == null) {
5386 return;
5387 }
5388 String address = btDevice.getAddress();
5389 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
5390 address = "";
5391 }
5392
5393 synchronized (mConnectedDevices) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005394 final String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
5395 final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
Paul McLean394a8e12015-03-03 10:29:19 -07005396 boolean isConnected = deviceSpec != null;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005397
5398 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
5399 makeA2dpSrcUnavailable(address);
5400 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
5401 makeA2dpSrcAvailable(address);
5402 }
5403 }
5404 }
5405
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005406 private void onBluetoothA2dpDeviceConfigChange(BluetoothDevice btDevice)
5407 {
Eric Laurent5205a352017-04-27 18:31:22 -07005408 if (DEBUG_DEVICES) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005409 Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice);
5410 }
5411 if (btDevice == null) {
5412 return;
5413 }
5414 String address = btDevice.getAddress();
5415 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
5416 address = "";
5417 }
5418
5419 int device = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
5420 synchronized (mConnectedDevices) {
Eric Laurent4724ea72017-05-23 10:39:38 -07005421 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, btDevice)) {
Eric Laurentcdae4762017-04-28 18:00:04 -07005422 return;
5423 }
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005424 final String key = makeDeviceListKey(device, address);
5425 final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
5426 if (deviceSpec != null) {
5427 // Device is connected
Eric Laurentcdae4762017-04-28 18:00:04 -07005428 int musicDevice = getDeviceForStream(AudioSystem.STREAM_MUSIC);
Eric Laurent5205a352017-04-27 18:31:22 -07005429 if (AudioSystem.handleDeviceConfigChange(device, address,
5430 btDevice.getName()) != AudioSystem.AUDIO_STATUS_OK) {
5431 // force A2DP device disconnection in case of error so that AudioService state is
5432 // consistent with audio policy manager state
Eric Laurentcdae4762017-04-28 18:00:04 -07005433 setBluetoothA2dpDeviceConnectionStateInt(
5434 btDevice, BluetoothA2dp.STATE_DISCONNECTED, BluetoothProfile.A2DP,
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005435 false /* suppressNoisyIntent */, musicDevice);
Eric Laurent5205a352017-04-27 18:31:22 -07005436 }
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005437 }
5438 }
5439 }
5440
John Du5a0cf7a2013-07-19 11:30:34 -07005441 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
5442 // address is not used for now, but may be used when multiple a2dp devices are supported
5443 synchronized (mA2dpAvrcpLock) {
5444 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07005445 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07005446 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
5447 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
5448 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
5449 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
5450 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07005451 }
5452 }
5453
Paul McLean394a8e12015-03-03 10:29:19 -07005454 private boolean handleDeviceConnection(boolean connect, int device, String address,
5455 String deviceName) {
5456 if (DEBUG_DEVICES) {
5457 Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device)
5458 + " address:" + address + " name:" + deviceName + ")");
5459 }
Eric Laurent59f48272012-04-05 19:42:21 -07005460 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07005461 String deviceKey = makeDeviceListKey(device, address);
5462 if (DEBUG_DEVICES) {
5463 Slog.i(TAG, "deviceKey:" + deviceKey);
5464 }
5465 DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
5466 boolean isConnected = deviceSpec != null;
5467 if (DEBUG_DEVICES) {
5468 Slog.i(TAG, "deviceSpec:" + deviceSpec + " is(already)Connected:" + isConnected);
5469 }
5470 if (connect && !isConnected) {
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07005471 final int res = AudioSystem.setDeviceConnectionState(device,
5472 AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);
5473 if (res != AudioSystem.AUDIO_STATUS_OK) {
5474 Slog.e(TAG, "not connecting device 0x" + Integer.toHexString(device) +
5475 " due to command error " + res );
5476 return false;
5477 }
Paul McLean394a8e12015-03-03 10:29:19 -07005478 mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07005479 sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
5480 device, 0, null, 0);
Paul McLean394a8e12015-03-03 10:29:19 -07005481 return true;
5482 } else if (!connect && isConnected) {
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07005483 AudioSystem.setDeviceConnectionState(device,
5484 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName);
5485 // always remove even if disconnection failed
Paul McLean394a8e12015-03-03 10:29:19 -07005486 mConnectedDevices.remove(deviceKey);
5487 return true;
Eric Laurent59f48272012-04-05 19:42:21 -07005488 }
5489 }
5490 return false;
5491 }
5492
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005493 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
Eric Laurent9a5b2622017-04-18 18:20:56 -07005494 // sent if:
5495 // - none of these devices are connected anymore after one is disconnected AND
5496 // - the device being disconnected is actually used for music.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005497 // Access synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005498 int mBecomingNoisyIntentDevices =
5499 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07005500 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07005501 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Jon Eklund43cc8bb2014-07-28 16:07:24 -05005502 AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005503
5504 // must be called before removing the device from mConnectedDevices
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005505 // Called synchronized on mConnectedDevices
Eric Laurentcdae4762017-04-28 18:00:04 -07005506 // musicDevice argument is used when not AudioSystem.DEVICE_NONE instead of querying
5507 // from AudioSystem
5508 private int checkSendBecomingNoisyIntent(int device, int state, int musicDevice) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005509 int delay = 0;
5510 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
5511 int devices = 0;
John Spurlock8c3dc852015-04-23 21:32:37 -04005512 for (int i = 0; i < mConnectedDevices.size(); i++) {
5513 int dev = mConnectedDevices.valueAt(i).mDeviceType;
Paul McLean394a8e12015-03-03 10:29:19 -07005514 if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
5515 && ((dev & mBecomingNoisyIntentDevices) != 0)) {
5516 devices |= dev;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005517 }
5518 }
Eric Laurentcdae4762017-04-28 18:00:04 -07005519 if (musicDevice == AudioSystem.DEVICE_NONE) {
5520 musicDevice = getDeviceForStream(AudioSystem.STREAM_MUSIC);
5521 }
5522 // ignore condition on device being actually used for music when in communication
5523 // because music routing is altered in this case.
5524 if (((device == musicDevice) || isInCommunication()) && (device == devices)) {
5525 mAudioHandler.removeMessages(MSG_BROADCAST_AUDIO_BECOMING_NOISY);
Eric Laurent5bfaeae2012-09-21 18:44:48 -07005526 sendMsg(mAudioHandler,
5527 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
5528 SENDMSG_REPLACE,
5529 0,
5530 0,
5531 null,
5532 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005533 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005534 }
5535 }
5536
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005537 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
5538 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005539 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
Eric Laurentadbe8bf2014-11-03 18:26:32 -08005540 synchronized (mLastDeviceConnectMsgTime) {
5541 long time = SystemClock.uptimeMillis();
5542 if (mLastDeviceConnectMsgTime > time) {
Matthew Xiec525cf72015-01-22 20:13:17 -08005543 delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
Eric Laurentadbe8bf2014-11-03 18:26:32 -08005544 }
5545 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005546 }
5547 return delay;
5548 }
5549
Eric Laurenteab40d12017-06-09 12:45:21 -07005550 private void updateAudioRoutes(int device, int state)
5551 {
Dianne Hackborn632ca412012-06-14 19:34:10 -07005552 int connType = 0;
5553
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005554 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07005555 connType = AudioRoutesInfo.MAIN_HEADSET;
Jon Eklund43cc8bb2014-07-28 16:07:24 -05005556 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
5557 device == AudioSystem.DEVICE_OUT_LINE) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07005558 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurent6fa42452015-01-09 15:09:40 -08005559 } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
5560 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07005561 connType = AudioRoutesInfo.MAIN_HDMI;
Eric Laurenteab40d12017-06-09 12:45:21 -07005562 } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE||
5563 device == AudioSystem.DEVICE_OUT_USB_HEADSET) {
Paul McLean10804eb2015-01-28 11:16:35 -08005564 connType = AudioRoutesInfo.MAIN_USB;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005565 }
5566
Dianne Hackborn632ca412012-06-14 19:34:10 -07005567 synchronized (mCurAudioRoutes) {
5568 if (connType != 0) {
John Spurlock61560172015-02-06 19:46:04 -05005569 int newConn = mCurAudioRoutes.mainType;
Dianne Hackborn632ca412012-06-14 19:34:10 -07005570 if (state != 0) {
5571 newConn |= connType;
5572 } else {
5573 newConn &= ~connType;
5574 }
John Spurlock61560172015-02-06 19:46:04 -05005575 if (newConn != mCurAudioRoutes.mainType) {
5576 mCurAudioRoutes.mainType = newConn;
Dianne Hackborn632ca412012-06-14 19:34:10 -07005577 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
5578 SENDMSG_NOOP, 0, 0, null, 0);
5579 }
5580 }
5581 }
Eric Laurenteab40d12017-06-09 12:45:21 -07005582 }
5583
5584 private void sendDeviceConnectionIntent(int device, int state, String address,
5585 String deviceName) {
5586 if (DEBUG_DEVICES) {
5587 Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
5588 " state:0x" + Integer.toHexString(state) + " address:" + address +
5589 " name:" + deviceName + ");");
5590 }
5591 Intent intent = new Intent();
5592
5593 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
5594 intent.setAction(Intent.ACTION_HEADSET_PLUG);
5595 intent.putExtra("microphone", 1);
5596 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
5597 device == AudioSystem.DEVICE_OUT_LINE) {
5598 intent.setAction(Intent.ACTION_HEADSET_PLUG);
Jean-Michel Trivi87d31ec2017-08-11 18:28:20 -07005599 intent.putExtra("microphone", 0);
Paul McLean145c9532017-08-04 11:12:19 -06005600 } else if (device == AudioSystem.DEVICE_OUT_USB_HEADSET) {
5601 intent.setAction(Intent.ACTION_HEADSET_PLUG);
Jean-Michel Trivi87d31ec2017-08-11 18:28:20 -07005602 intent.putExtra("microphone",
5603 AudioSystem.getDeviceConnectionState(AudioSystem.DEVICE_IN_USB_HEADSET, "")
5604 == AudioSystem.DEVICE_STATE_AVAILABLE ? 1 : 0);
5605 } else if (device == AudioSystem.DEVICE_IN_USB_HEADSET) {
5606 if (AudioSystem.getDeviceConnectionState(AudioSystem.DEVICE_OUT_USB_HEADSET, "")
5607 == AudioSystem.DEVICE_STATE_AVAILABLE) {
5608 intent.setAction(Intent.ACTION_HEADSET_PLUG);
5609 intent.putExtra("microphone", 1);
5610 } else {
5611 // do not send ACTION_HEADSET_PLUG when only the input side is seen as changing
5612 return;
5613 }
Eric Laurenteab40d12017-06-09 12:45:21 -07005614 } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
5615 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
5616 configureHdmiPlugIntent(intent, state);
5617 }
5618
Jean-Michel Trivi87a264d2017-08-15 17:52:22 -07005619 if (intent.getAction() == null) {
5620 return;
5621 }
5622
Eric Laurenteab40d12017-06-09 12:45:21 -07005623 intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
5624 intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
5625 intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
5626
5627 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005628
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005629 final long ident = Binder.clearCallingIdentity();
5630 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -08005631 ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005632 } finally {
5633 Binder.restoreCallingIdentity(ident);
5634 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005635 }
5636
Eric Laurentbbe3e742017-04-28 18:11:50 -07005637 private static final int DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG =
5638 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
5639 AudioSystem.DEVICE_OUT_LINE |
5640 AudioSystem.DEVICE_OUT_ALL_USB;
5641
Paul McLean10804eb2015-01-28 11:16:35 -08005642 private void onSetWiredDeviceConnectionState(int device, int state, String address,
John Spurlock90874332015-03-10 16:00:54 -04005643 String deviceName, String caller) {
Paul McLean394a8e12015-03-03 10:29:19 -07005644 if (DEBUG_DEVICES) {
John Spurlock90874332015-03-10 16:00:54 -04005645 Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
5646 + " state:" + Integer.toHexString(state)
5647 + " address:" + address
5648 + " deviceName:" + deviceName
5649 + " caller: " + caller + ");");
Paul McLean394a8e12015-03-03 10:29:19 -07005650 }
Paul McLean10804eb2015-01-28 11:16:35 -08005651
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005652 synchronized (mConnectedDevices) {
Eric Laurentbbe3e742017-04-28 18:11:50 -07005653 if ((state == 0) && ((device & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0)) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005654 setBluetoothA2dpOnInt(true, "onSetWiredDeviceConnectionState state 0");
Sungsoocf09fe62016-09-28 16:21:48 +09005655 }
Paul McLean145c9532017-08-04 11:12:19 -06005656
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07005657 if (!handleDeviceConnection(state == 1, device, address, deviceName)) {
5658 // change of connection state failed, bailout
5659 return;
5660 }
Eric Laurentf1a457d2012-09-20 16:27:23 -07005661 if (state != 0) {
Eric Laurentbbe3e742017-04-28 18:11:50 -07005662 if ((device & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005663 setBluetoothA2dpOnInt(false, "onSetWiredDeviceConnectionState state not 0");
Sungsoocf09fe62016-09-28 16:21:48 +09005664 }
Eric Laurentf1a457d2012-09-20 16:27:23 -07005665 if ((device & mSafeMediaVolumeDevices) != 0) {
5666 sendMsg(mAudioHandler,
5667 MSG_CHECK_MUSIC_ACTIVE,
5668 SENDMSG_REPLACE,
5669 0,
5670 0,
John Spurlock90874332015-03-10 16:00:54 -04005671 caller,
Eric Laurentf1a457d2012-09-20 16:27:23 -07005672 MUSIC_ACTIVE_POLL_PERIOD_MS);
5673 }
Eric Laurent212532b2014-07-21 15:43:18 -07005674 // Television devices without CEC service apply software volume on HDMI output
5675 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
5676 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
5677 checkAllFixedVolumeDevices();
5678 if (mHdmiManager != null) {
5679 synchronized (mHdmiManager) {
5680 if (mHdmiPlaybackClient != null) {
5681 mHdmiCecSink = false;
5682 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
5683 }
5684 }
5685 }
5686 }
5687 } else {
5688 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
5689 if (mHdmiManager != null) {
5690 synchronized (mHdmiManager) {
5691 mHdmiCecSink = false;
5692 }
5693 }
5694 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005695 }
Jean-Michel Trivi87a264d2017-08-15 17:52:22 -07005696 sendDeviceConnectionIntent(device, state, address, deviceName);
Eric Laurenteab40d12017-06-09 12:45:21 -07005697 updateAudioRoutes(device, state);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005698 }
5699 }
5700
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005701 private void configureHdmiPlugIntent(Intent intent, int state) {
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005702 intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
5703 intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005704 if (state == 1) {
5705 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
5706 int[] portGeneration = new int[1];
5707 int status = AudioSystem.listAudioPorts(ports, portGeneration);
5708 if (status == AudioManager.SUCCESS) {
5709 for (AudioPort port : ports) {
5710 if (port instanceof AudioDevicePort) {
5711 final AudioDevicePort devicePort = (AudioDevicePort) port;
Eric Laurent6fa42452015-01-09 15:09:40 -08005712 if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
5713 devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005714 // format the list of supported encodings
Eric Laurentcae34662015-05-19 16:46:52 -07005715 int[] formats = AudioFormat.filterPublicFormats(devicePort.formats());
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005716 if (formats.length > 0) {
5717 ArrayList<Integer> encodingList = new ArrayList(1);
5718 for (int format : formats) {
5719 // a format in the list can be 0, skip it
5720 if (format != AudioFormat.ENCODING_INVALID) {
5721 encodingList.add(format);
5722 }
5723 }
5724 int[] encodingArray = new int[encodingList.size()];
5725 for (int i = 0 ; i < encodingArray.length ; i++) {
5726 encodingArray[i] = encodingList.get(i);
5727 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005728 intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005729 }
5730 // find the maximum supported number of channels
5731 int maxChannels = 0;
5732 for (int mask : devicePort.channelMasks()) {
5733 int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
5734 if (channelCount > maxChannels) {
5735 maxChannels = channelCount;
5736 }
5737 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005738 intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005739 }
5740 }
5741 }
5742 }
5743 }
5744 }
5745
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07005746 /* cache of the address of the last dock the device was connected to */
5747 private String mDockAddress;
5748
Eric Laurenta553c252009-07-17 12:17:14 -07005749 /**
5750 * Receiver for misc intent broadcasts the Phone app cares about.
5751 */
5752 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
5753 @Override
5754 public void onReceive(Context context, Intent intent) {
5755 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07005756 int outDevice;
5757 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07005758 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07005759
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08005760 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
5761 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
5762 Intent.EXTRA_DOCK_STATE_UNDOCKED);
5763 int config;
5764 switch (dockState) {
5765 case Intent.EXTRA_DOCK_STATE_DESK:
5766 config = AudioSystem.FORCE_BT_DESK_DOCK;
5767 break;
5768 case Intent.EXTRA_DOCK_STATE_CAR:
5769 config = AudioSystem.FORCE_BT_CAR_DOCK;
5770 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05005771 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08005772 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05005773 break;
5774 case Intent.EXTRA_DOCK_STATE_HE_DESK:
5775 config = AudioSystem.FORCE_DIGITAL_DOCK;
5776 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08005777 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
5778 default:
5779 config = AudioSystem.FORCE_NONE;
5780 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08005781 // Low end docks have a menu to enable or disable audio
5782 // (see mDockAudioMediaEnabled)
5783 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
5784 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
5785 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07005786 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_DOCK, config,
5787 "ACTION_DOCK_EVENT intent"));
Eric Laurent08ed1b92012-11-05 14:54:12 -08005788 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
5789 }
5790 mDockState = dockState;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07005791 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
Eric Laurent59f48272012-04-05 19:42:21 -07005792 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07005793 BluetoothProfile.STATE_DISCONNECTED);
Eric Laurentdca56b92011-09-02 14:20:56 -07005794 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Eric Laurent98859b22015-06-12 14:35:59 -07005795 setBtScoDeviceConnectionState(btDevice, state);
Paul McLeandf361462014-04-10 16:02:55 -07005796 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005797 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07005798 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005799 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005800 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07005801 // broadcast intent if the connection was initated by AudioService
5802 if (!mScoClients.isEmpty() &&
5803 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
5804 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
5805 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005806 broadcast = true;
5807 }
5808 switch (btState) {
5809 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07005810 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07005811 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5812 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5813 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005814 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005815 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005816 break;
5817 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07005818 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08005819 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07005820 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08005821 break;
5822 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07005823 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5824 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5825 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005826 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005827 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005828 default:
5829 // do not broadcast CONNECTING or invalid state
5830 broadcast = false;
5831 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005832 }
5833 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005834 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07005835 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07005836 //FIXME: this is to maintain compatibility with deprecated intent
5837 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08005838 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07005839 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005840 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08005841 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005842 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06005843 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005844 RotationHelper.enable();
Jon Eklund318f0fe2014-01-23 17:53:48 -06005845 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005846 AudioSystem.setParameters("screen_state=on");
5847 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06005848 if (mMonitorRotation) {
5849 //reduce wakeups (save current) by only listening when display is on
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005850 RotationHelper.disable();
Jon Eklund318f0fe2014-01-23 17:53:48 -06005851 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005852 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07005853 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005854 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07005855 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Yasuhiro Matsuda4ced7192015-07-10 22:08:44 +09005856 if (mUserSwitchedReceived) {
5857 // attempt to stop music playback for background user except on first user
5858 // switch (i.e. first boot)
5859 sendMsg(mAudioHandler,
5860 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
5861 SENDMSG_REPLACE,
5862 0,
5863 0,
5864 null,
5865 0);
5866 }
5867 mUserSwitchedReceived = true;
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07005868 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005869 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07005870
Eric Laurent5bfaeae2012-09-21 18:44:48 -07005871 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07005872 readAudioSettings(true /*userSwitch*/);
5873 // preserve STREAM_MUSIC volume from one user to the next.
5874 sendMsg(mAudioHandler,
5875 MSG_SET_ALL_VOLUMES,
5876 SENDMSG_QUEUE,
5877 0,
5878 0,
5879 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005880 } else if (action.equals(Intent.ACTION_USER_BACKGROUND)) {
5881 // Disable audio recording for the background user/profile
5882 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
5883 if (userId >= 0) {
5884 // TODO Kill recording streams instead of killing processes holding permission
5885 UserInfo userInfo = UserManagerService.getInstance().getUserInfo(userId);
5886 killBackgroundUserProcessesWithRecordAudioPermission(userInfo);
5887 }
Makoto Onukiac65e1e2015-11-20 15:33:17 -08005888 UserManagerService.getInstance().setUserRestriction(
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005889 UserManager.DISALLOW_RECORD_AUDIO, true, userId);
5890 } else if (action.equals(Intent.ACTION_USER_FOREGROUND)) {
5891 // Enable audio recording for foreground user/profile
5892 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Makoto Onukiac65e1e2015-11-20 15:33:17 -08005893 UserManagerService.getInstance().setUserRestriction(
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005894 UserManager.DISALLOW_RECORD_AUDIO, false, userId);
Eric Laurentb70b78a2016-01-13 19:16:04 -08005895 } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
5896 state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
5897 if (state == BluetoothAdapter.STATE_OFF ||
5898 state == BluetoothAdapter.STATE_TURNING_OFF) {
5899 disconnectAllBluetoothProfiles();
5900 }
Marco Nelissenfb6df0b2017-02-15 15:25:24 -08005901 } else if (action.equals(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION) ||
5902 action.equals(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION)) {
5903 handleAudioEffectBroadcast(context, intent);
Eric Laurenta553c252009-07-17 12:17:14 -07005904 }
5905 }
Paul McLeanc837a452014-04-09 09:04:43 -07005906 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005907
Makoto Onukid45a4a22015-11-02 17:17:38 -08005908 private class AudioServiceUserRestrictionsListener implements UserRestrictionsListener {
5909
5910 @Override
5911 public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
5912 Bundle prevRestrictions) {
5913 // Update mic mute state.
5914 {
5915 final boolean wasRestricted =
5916 prevRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
5917 final boolean isRestricted =
5918 newRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
5919 if (wasRestricted != isRestricted) {
5920 setMicrophoneMuteNoCallerCheck(isRestricted, userId);
5921 }
5922 }
5923
5924 // Update speaker mute state.
5925 {
5926 final boolean wasRestricted =
Tony Makc1205112016-07-22 16:02:59 +01005927 prevRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)
Esteban Talavera492b4722017-02-13 14:59:45 +00005928 || prevRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_DEVICE);
Makoto Onukid45a4a22015-11-02 17:17:38 -08005929 final boolean isRestricted =
Tony Makc1205112016-07-22 16:02:59 +01005930 newRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)
Esteban Talavera492b4722017-02-13 14:59:45 +00005931 || newRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_DEVICE);
Makoto Onukid45a4a22015-11-02 17:17:38 -08005932 if (wasRestricted != isRestricted) {
5933 setMasterMuteInternalNoCallerCheck(isRestricted, /* flags =*/ 0, userId);
5934 }
5935 }
5936 }
5937 } // end class AudioServiceUserRestrictionsListener
5938
Marco Nelissenfb6df0b2017-02-15 15:25:24 -08005939 private void handleAudioEffectBroadcast(Context context, Intent intent) {
5940 String target = intent.getPackage();
5941 if (target != null) {
5942 Log.w(TAG, "effect broadcast already targeted to " + target);
5943 return;
5944 }
5945 intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
5946 // TODO this should target a user-selected panel
5947 List<ResolveInfo> ril = context.getPackageManager().queryBroadcastReceivers(
5948 intent, 0 /* flags */);
5949 if (ril != null && ril.size() != 0) {
5950 ResolveInfo ri = ril.get(0);
5951 if (ri != null && ri.activityInfo != null && ri.activityInfo.packageName != null) {
5952 intent.setPackage(ri.activityInfo.packageName);
5953 context.sendBroadcastAsUser(intent, UserHandle.ALL);
5954 return;
5955 }
5956 }
5957 Log.w(TAG, "couldn't find receiver package for effect intent");
5958 }
5959
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005960 private void killBackgroundUserProcessesWithRecordAudioPermission(UserInfo oldUser) {
5961 PackageManager pm = mContext.getPackageManager();
5962 // Find the home activity of the user. It should not be killed to avoid expensive restart,
5963 // when the user switches back. For managed profiles, we should kill all recording apps
5964 ComponentName homeActivityName = null;
5965 if (!oldUser.isManagedProfile()) {
Sudheer Shankafc46e9b2016-10-21 17:55:27 -07005966 homeActivityName = mActivityManagerInternal.getHomeActivityForUser(oldUser.id);
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005967 }
5968 final String[] permissions = { Manifest.permission.RECORD_AUDIO };
5969 List<PackageInfo> packages;
5970 try {
5971 packages = AppGlobals.getPackageManager()
5972 .getPackagesHoldingPermissions(permissions, 0, oldUser.id).getList();
5973 } catch (RemoteException e) {
5974 throw new AndroidRuntimeException(e);
5975 }
5976 for (int j = packages.size() - 1; j >= 0; j--) {
5977 PackageInfo pkg = packages.get(j);
Fyodor Kupolovbcb6c1e2015-05-11 12:05:15 -07005978 // Skip system processes
5979 if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
5980 continue;
5981 }
Amith Yamasanic1cbaab2015-07-21 11:46:14 -07005982 // Skip packages that have permission to interact across users
5983 if (pm.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS, pkg.packageName)
5984 == PackageManager.PERMISSION_GRANTED) {
5985 continue;
5986 }
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005987 if (homeActivityName != null
5988 && pkg.packageName.equals(homeActivityName.getPackageName())
5989 && pkg.applicationInfo.isSystemApp()) {
5990 continue;
5991 }
5992 try {
Svetoslavaa41add2015-08-06 15:03:55 -07005993 final int uid = pkg.applicationInfo.uid;
Sudheer Shankadc589ac2016-11-10 15:30:17 -08005994 ActivityManager.getService().killUid(UserHandle.getAppId(uid),
Svetoslavaa41add2015-08-06 15:03:55 -07005995 UserHandle.getUserId(uid),
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005996 "killBackgroundUserProcessesWithAudioRecordPermission");
5997 } catch (RemoteException e) {
5998 Log.w(TAG, "Error calling killUid", e);
5999 }
6000 }
6001 }
6002
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07006003
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07006004 //==========================================================================================
6005 // Audio Focus
6006 //==========================================================================================
Jean-Michel Trivi9228af62018-01-05 17:06:17 -08006007 /**
6008 * Returns whether a focus request is eligible to force ducking.
6009 * Will return true if:
6010 * - the AudioAttributes have a usage of USAGE_ASSISTANCE_ACCESSIBILITY,
6011 * - the focus request is AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
6012 * - the associated Bundle has KEY_ACCESSIBILITY_FORCE_FOCUS_DUCKING set to true,
6013 * - the uid of the requester is a known accessibility service or root.
6014 * @param aa AudioAttributes of the focus request
6015 * @param uid uid of the focus requester
6016 * @return true if ducking is to be forced
6017 */
6018 private boolean forceFocusDuckingForAccessibility(@Nullable AudioAttributes aa,
6019 int request, int uid) {
6020 if (aa == null || aa.getUsage() != AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY
6021 || request != AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK) {
6022 return false;
6023 }
6024 final Bundle extraInfo = aa.getBundle();
6025 if (extraInfo == null ||
6026 !extraInfo.getBoolean(AudioFocusRequest.KEY_ACCESSIBILITY_FORCE_FOCUS_DUCKING)) {
6027 return false;
6028 }
6029 if (uid == 0) {
6030 return true;
6031 }
6032 synchronized (mAccessibilityServiceUidsLock) {
6033 if (mAccessibilityServiceUids != null) {
6034 int callingUid = Binder.getCallingUid();
6035 for (int i = 0; i < mAccessibilityServiceUids.length; i++) {
6036 if (mAccessibilityServiceUids[i] == callingUid) {
6037 return true;
6038 }
6039 }
6040 }
6041 }
6042 return false;
6043 }
6044
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08006045 public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006046 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07006047 IAudioPolicyCallback pcb, int sdk) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006048 // permission checks
6049 if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
John Spurlock61560172015-02-06 19:46:04 -05006050 if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006051 if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
6052 android.Manifest.permission.MODIFY_PHONE_STATE)) {
6053 Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
6054 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
6055 }
6056 } else {
6057 // only a registered audio policy can be used to lock focus
6058 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006059 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
6060 Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006061 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
6062 }
6063 }
6064 }
6065 }
6066
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08006067 return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
Jean-Michel Trivi9228af62018-01-05 17:06:17 -08006068 clientId, callingPackageName, flags, sdk,
6069 forceFocusDuckingForAccessibility(aa, durationHint, Binder.getCallingUid()));
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07006070 }
6071
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07006072 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa,
6073 String callingPackageName) {
6074 return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa, callingPackageName);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07006075 }
6076
6077 public void unregisterAudioFocusClient(String clientId) {
6078 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07006079 }
6080
Jean-Michel Trivi23805662013-07-31 14:19:18 -07006081 public int getCurrentAudioFocus() {
6082 return mMediaFocusControl.getCurrentAudioFocus();
6083 }
6084
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08006085 public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) {
6086 return mMediaFocusControl.getFocusRampTimeMs(focusGain, attr);
6087 }
6088
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07006089 //==========================================================================================
John Spurlock5e783732015-02-19 10:28:59 -05006090 private boolean readCameraSoundForced() {
6091 return SystemProperties.getBoolean("audio.camerasound.force", false) ||
6092 mContext.getResources().getBoolean(
6093 com.android.internal.R.bool.config_camera_sound_forced);
6094 }
6095
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07006096 //==========================================================================================
6097 // Device orientation
6098 //==========================================================================================
6099 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07006100 * Handles device configuration changes that may map to a change in the orientation
6101 * or orientation.
6102 * Monitoring orientation and rotation is optional, and is defined by the definition and value
6103 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07006104 */
6105 private void handleConfigurationChanged(Context context) {
6106 try {
6107 // reading new orientation "safely" (i.e. under try catch) in case anything
6108 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07006109 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07006110 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07006111 if (mMonitorOrientation) {
6112 int newOrientation = config.orientation;
6113 if (newOrientation != mDeviceOrientation) {
6114 mDeviceOrientation = newOrientation;
6115 setOrientationForAudioSystem();
6116 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07006117 }
Eric Laurentd640bd32012-09-28 18:01:48 -07006118 sendMsg(mAudioHandler,
6119 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
6120 SENDMSG_REPLACE,
6121 0,
6122 0,
John Spurlock90874332015-03-10 16:00:54 -04006123 TAG,
Eric Laurentd640bd32012-09-28 18:01:48 -07006124 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07006125
John Spurlock5e783732015-02-19 10:28:59 -05006126 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -07006127 synchronized (mSettingsLock) {
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08006128 final boolean cameraSoundForcedChanged = (cameraSoundForced != mCameraSoundForced);
6129 mCameraSoundForced = cameraSoundForced;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07006130 if (cameraSoundForcedChanged) {
Muyuan Li1ed6df62016-06-18 11:16:52 -07006131 if (!mIsSingleVolume) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07006132 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
6133 if (cameraSoundForced) {
6134 s.setAllIndexesToMax();
6135 mRingerModeAffectedStreams &=
6136 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
6137 } else {
John Spurlock90874332015-03-10 16:00:54 -04006138 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07006139 mRingerModeAffectedStreams |=
6140 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
6141 }
6142 // take new state into account for streams muted by ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05006143 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07006144 }
6145
6146 sendMsg(mAudioHandler,
6147 MSG_SET_FORCE_USE,
6148 SENDMSG_QUEUE,
6149 AudioSystem.FOR_SYSTEM,
6150 cameraSoundForced ?
6151 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006152 new String("handleConfigurationChanged"),
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07006153 0);
6154
6155 sendMsg(mAudioHandler,
6156 MSG_SET_ALL_VOLUMES,
6157 SENDMSG_QUEUE,
6158 0,
6159 0,
6160 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
6161 }
Eric Laurentdd45d012012-10-08 09:04:34 -07006162 }
John Spurlock3346a802014-05-20 16:25:37 -04006163 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07006164 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07006165 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07006166 }
6167 }
6168
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07006169 //TODO move to an external "orientation helper" class
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07006170 private void setOrientationForAudioSystem() {
6171 switch (mDeviceOrientation) {
6172 case Configuration.ORIENTATION_LANDSCAPE:
6173 //Log.i(TAG, "orientation is landscape");
6174 AudioSystem.setParameters("orientation=landscape");
6175 break;
6176 case Configuration.ORIENTATION_PORTRAIT:
6177 //Log.i(TAG, "orientation is portrait");
6178 AudioSystem.setParameters("orientation=portrait");
6179 break;
6180 case Configuration.ORIENTATION_SQUARE:
6181 //Log.i(TAG, "orientation is square");
6182 AudioSystem.setParameters("orientation=square");
6183 break;
6184 case Configuration.ORIENTATION_UNDEFINED:
6185 //Log.i(TAG, "orientation is undefined");
6186 AudioSystem.setParameters("orientation=undefined");
6187 break;
6188 default:
6189 Log.e(TAG, "Unknown orientation");
6190 }
6191 }
6192
Sungsoocf09fe62016-09-28 16:21:48 +09006193 // Handles request to override default use of A2DP for media.
6194 // Must be called synchronized on mConnectedDevices
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006195 public void setBluetoothA2dpOnInt(boolean on, String eventSource) {
Sungsoocf09fe62016-09-28 16:21:48 +09006196 synchronized (mBluetoothA2dpEnabledLock) {
6197 mBluetoothA2dpEnabled = on;
6198 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
6199 setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006200 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
6201 eventSource);
Sungsoocf09fe62016-09-28 16:21:48 +09006202 }
6203 }
6204
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08006205 // Must be called synchronized on mConnectedDevices
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006206 private void setForceUseInt_SyncDevices(int usage, int config, String eventSource) {
Eric Laurent9a5b2622017-04-18 18:20:56 -07006207 if (usage == AudioSystem.FOR_MEDIA) {
6208 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
6209 SENDMSG_NOOP, 0, 0, null, 0);
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08006210 }
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006211 mForceUseLogger.log(new ForceUseEvent(usage, config, eventSource));
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08006212 AudioSystem.setForceUse(usage, config);
6213 }
6214
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08006215 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07006216 public void setRingtonePlayer(IRingtonePlayer player) {
6217 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
6218 mRingtonePlayer = player;
6219 }
6220
6221 @Override
6222 public IRingtonePlayer getRingtonePlayer() {
6223 return mRingtonePlayer;
6224 }
6225
6226 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07006227 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
6228 synchronized (mCurAudioRoutes) {
6229 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
6230 mRoutesObservers.register(observer);
6231 return routes;
6232 }
6233 }
6234
Eric Laurentc34dcc12012-09-10 13:51:52 -07006235
6236 //==========================================================================================
6237 // Safe media volume management.
6238 // MUSIC stream volume level is limited when headphones are connected according to safety
6239 // regulation. When the user attempts to raise the volume above the limit, a warning is
6240 // displayed and the user has to acknowlegde before the volume is actually changed.
6241 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
6242 // property. Platforms with a different limit must set this property accordingly in their
6243 // overlay.
6244 //==========================================================================================
6245
Eric Laurentd640bd32012-09-28 18:01:48 -07006246 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
6247 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
6248 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
6249 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
6250 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
6251 // (when user opts out).
John Spurlock35134602014-07-24 18:10:48 -04006252 private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
6253 private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
6254 private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed
6255 private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
Eric Laurentd640bd32012-09-28 18:01:48 -07006256 private Integer mSafeMediaVolumeState;
6257
6258 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07006259 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07006260 private int mSafeMediaVolumeIndex;
Eric Laurentb378a13a2017-07-11 14:08:11 -07006261 // mSafeUsbMediaVolumeIndex is used for USB Headsets and is the music volume UI index
6262 // corresponding to a gain of -30 dBFS in audio flinger mixer.
Eric Laurent0e5deb32017-09-01 15:12:42 -07006263 // We remove -22 dBs from the theoretical -15dB to account for the EQ + bass boost
6264 // amplification when both effects are on with all band gains at maximum.
Eric Laurentb378a13a2017-07-11 14:08:11 -07006265 // This level corresponds to a loudness of 85 dB SPL for the warning to be displayed when
6266 // the headset is compliant to EN 60950 with a max loudness of 100dB SPL.
Eric Laurenteab40d12017-06-09 12:45:21 -07006267 private int mSafeUsbMediaVolumeIndex;
Eric Laurent0e5deb32017-09-01 15:12:42 -07006268 private static final float SAFE_VOLUME_GAIN_DBFS = -37.0f;
Eric Laurentc34dcc12012-09-10 13:51:52 -07006269 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
6270 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
Eric Laurenteab40d12017-06-09 12:45:21 -07006271 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
6272 AudioSystem.DEVICE_OUT_USB_HEADSET;
Eric Laurentc34dcc12012-09-10 13:51:52 -07006273 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
6274 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
6275 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
6276 private int mMusicActiveMs;
6277 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
6278 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07006279 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07006280
Eric Laurenteab40d12017-06-09 12:45:21 -07006281 private int safeMediaVolumeIndex(int device) {
6282 if ((device & mSafeMediaVolumeDevices) == 0) {
6283 return MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC];
6284 }
6285 if (device == AudioSystem.DEVICE_OUT_USB_HEADSET) {
6286 return mSafeUsbMediaVolumeIndex;
6287 } else {
6288 return mSafeMediaVolumeIndex;
6289 }
6290 }
6291
John Spurlock90874332015-03-10 16:00:54 -04006292 private void setSafeMediaVolumeEnabled(boolean on, String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07006293 synchronized (mSafeMediaVolumeState) {
6294 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
6295 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
6296 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
6297 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
John Spurlock90874332015-03-10 16:00:54 -04006298 enforceSafeMediaVolume(caller);
Eric Laurentd640bd32012-09-28 18:01:48 -07006299 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
6300 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04006301 mMusicActiveMs = 1; // nonzero = confirmed
6302 saveMusicActiveMs();
Eric Laurentd640bd32012-09-28 18:01:48 -07006303 sendMsg(mAudioHandler,
6304 MSG_CHECK_MUSIC_ACTIVE,
6305 SENDMSG_REPLACE,
6306 0,
6307 0,
John Spurlock90874332015-03-10 16:00:54 -04006308 caller,
Eric Laurentd640bd32012-09-28 18:01:48 -07006309 MUSIC_ACTIVE_POLL_PERIOD_MS);
6310 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07006311 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07006312 }
6313 }
6314
John Spurlock90874332015-03-10 16:00:54 -04006315 private void enforceSafeMediaVolume(String caller) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07006316 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07006317 int devices = mSafeMediaVolumeDevices;
6318 int i = 0;
6319
6320 while (devices != 0) {
6321 int device = 1 << i++;
6322 if ((device & devices) == 0) {
6323 continue;
6324 }
Eric Laurent42b041e2013-03-29 11:36:03 -07006325 int index = streamState.getIndex(device);
Eric Laurenteab40d12017-06-09 12:45:21 -07006326 if (index > safeMediaVolumeIndex(device)) {
6327 streamState.setIndex(safeMediaVolumeIndex(device), device, caller);
Eric Laurent42b041e2013-03-29 11:36:03 -07006328 sendMsg(mAudioHandler,
6329 MSG_SET_DEVICE_VOLUME,
6330 SENDMSG_QUEUE,
6331 device,
6332 0,
6333 streamState,
6334 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07006335 }
6336 devices &= ~device;
6337 }
6338 }
6339
6340 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07006341 synchronized (mSafeMediaVolumeState) {
6342 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07006343 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
6344 ((device & mSafeMediaVolumeDevices) != 0) &&
Eric Laurenteab40d12017-06-09 12:45:21 -07006345 (index > safeMediaVolumeIndex(device))) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07006346 return false;
6347 }
6348 return true;
6349 }
6350 }
6351
John Spurlock3346a802014-05-20 16:25:37 -04006352 @Override
John Spurlock90874332015-03-10 16:00:54 -04006353 public void disableSafeMediaVolume(String callingPackage) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05006354 enforceVolumeController("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07006355 synchronized (mSafeMediaVolumeState) {
John Spurlock90874332015-03-10 16:00:54 -04006356 setSafeMediaVolumeEnabled(false, callingPackage);
Eric Laurentfde16d52012-12-03 14:42:39 -08006357 if (mPendingVolumeCommand != null) {
6358 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
6359 mPendingVolumeCommand.mIndex,
6360 mPendingVolumeCommand.mFlags,
John Spurlock90874332015-03-10 16:00:54 -04006361 mPendingVolumeCommand.mDevice,
6362 callingPackage);
Eric Laurentfde16d52012-12-03 14:42:39 -08006363 mPendingVolumeCommand = null;
6364 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07006365 }
6366 }
6367
Jungshik Jang41d97462014-06-30 22:26:29 +09006368 //==========================================================================================
6369 // Hdmi Cec system audio mode.
John Spurlockbc82b122015-03-02 16:12:38 -05006370 // If Hdmi Cec's system audio mode is on, audio service should send the volume change
6371 // to HdmiControlService so that the audio receiver can handle it.
Jungshik Jang41d97462014-06-30 22:26:29 +09006372 //==========================================================================================
6373
Eric Laurent212532b2014-07-21 15:43:18 -07006374 private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
6375 public void onComplete(int status) {
6376 if (mHdmiManager != null) {
6377 synchronized (mHdmiManager) {
6378 mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
6379 // Television devices without CEC service apply software volume on HDMI output
6380 if (isPlatformTelevision() && !mHdmiCecSink) {
6381 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
6382 }
6383 checkAllFixedVolumeDevices();
6384 }
6385 }
6386 }
6387 };
6388
Jungshik Jang41d97462014-06-30 22:26:29 +09006389 // If HDMI-CEC system audio is supported
6390 private boolean mHdmiSystemAudioSupported = false;
6391 // Set only when device is tv.
6392 private HdmiTvClient mHdmiTvClient;
Eric Laurent0b03f992014-11-18 18:08:02 -08006393 // true if the device has system feature PackageManager.FEATURE_LEANBACK.
Eric Laurent212532b2014-07-21 15:43:18 -07006394 // cached HdmiControlManager interface
6395 private HdmiControlManager mHdmiManager;
6396 // Set only when device is a set-top box.
6397 private HdmiPlaybackClient mHdmiPlaybackClient;
6398 // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
6399 private boolean mHdmiCecSink;
6400
6401 private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
Jungshik Jang41d97462014-06-30 22:26:29 +09006402
6403 @Override
Jungshik Jang12307ca2014-07-15 19:27:56 +09006404 public int setHdmiSystemAudioSupported(boolean on) {
Eric Laurent212532b2014-07-21 15:43:18 -07006405 int device = AudioSystem.DEVICE_NONE;
6406 if (mHdmiManager != null) {
6407 synchronized (mHdmiManager) {
6408 if (mHdmiTvClient == null) {
6409 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
6410 return device;
6411 }
Jungshik Jang41d97462014-06-30 22:26:29 +09006412
Eric Laurent212532b2014-07-21 15:43:18 -07006413 synchronized (mHdmiTvClient) {
6414 if (mHdmiSystemAudioSupported != on) {
6415 mHdmiSystemAudioSupported = on;
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006416 final int config = on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
6417 AudioSystem.FORCE_NONE;
6418 mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
6419 config, "setHdmiSystemAudioSupported"));
6420 AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO, config);
Eric Laurent212532b2014-07-21 15:43:18 -07006421 }
John Spurlock8a52c442015-03-26 14:23:58 -04006422 device = getDevicesForStream(AudioSystem.STREAM_MUSIC);
Eric Laurent212532b2014-07-21 15:43:18 -07006423 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09006424 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09006425 }
Eric Laurent212532b2014-07-21 15:43:18 -07006426 return device;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09006427 }
Jungshik Jang41d97462014-06-30 22:26:29 +09006428
Terry Heoe7d6d972014-09-04 21:05:28 +09006429 @Override
6430 public boolean isHdmiSystemAudioSupported() {
6431 return mHdmiSystemAudioSupported;
6432 }
6433
Eric Laurentdd45d012012-10-08 09:04:34 -07006434 //==========================================================================================
Jean-Michel Triviac487672016-11-11 10:05:18 -08006435 // Accessibility
6436
Jean-Michel Trivicfa55532017-01-18 11:17:51 -08006437 private void initA11yMonitoring() {
6438 final AccessibilityManager accessibilityManager =
6439 (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
Jean-Michel Triviac487672016-11-11 10:05:18 -08006440 updateDefaultStreamOverrideDelay(accessibilityManager.isTouchExplorationEnabled());
Jean-Michel Trivi7592b982017-02-01 15:12:15 -08006441 updateA11yVolumeAlias(accessibilityManager.isAccessibilityVolumeStreamActive());
Phil Weaver26d709f2017-04-20 17:19:14 -07006442 accessibilityManager.addTouchExplorationStateChangeListener(this, null);
6443 accessibilityManager.addAccessibilityServicesStateChangeListener(this, null);
Jean-Michel Triviac487672016-11-11 10:05:18 -08006444 }
6445
6446 //---------------------------------------------------------------------------------
6447 // A11y: taking touch exploration into account for selecting the default
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07006448 // stream override timeout when adjusting volume
Jean-Michel Triviac487672016-11-11 10:05:18 -08006449 //---------------------------------------------------------------------------------
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07006450
Jean-Michel Triviac487672016-11-11 10:05:18 -08006451 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
Julia Reynoldsd9e96e22017-11-07 10:33:08 -05006452 // - STREAM_RING on phones during this period after a notification stopped
6453 // - STREAM_MUSIC otherwise
6454
Jean-Michel Triviac487672016-11-11 10:05:18 -08006455 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 0;
6456 private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07006457
Jean-Michel Triviac487672016-11-11 10:05:18 -08006458 private static int sStreamOverrideDelayMs;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07006459
Jean-Michel Triviac487672016-11-11 10:05:18 -08006460 @Override
6461 public void onTouchExplorationStateChanged(boolean enabled) {
6462 updateDefaultStreamOverrideDelay(enabled);
6463 }
6464
6465 private void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
6466 if (touchExploreEnabled) {
6467 sStreamOverrideDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
6468 } else {
6469 sStreamOverrideDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07006470 }
Jean-Michel Triviac487672016-11-11 10:05:18 -08006471 if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
6472 + " stream override delay is now " + sStreamOverrideDelayMs + " ms");
6473 }
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07006474
Jean-Michel Triviac487672016-11-11 10:05:18 -08006475 //---------------------------------------------------------------------------------
6476 // A11y: taking a11y state into account for the handling of a11y prompts volume
6477 //---------------------------------------------------------------------------------
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07006478
Jean-Michel Triviac487672016-11-11 10:05:18 -08006479 private static boolean sIndependentA11yVolume = false;
6480
Jean-Michel Trivicfa55532017-01-18 11:17:51 -08006481 // implementation of AccessibilityServicesStateChangeListener
6482 @Override
Phil Weaver4cab9302017-03-30 15:27:39 -07006483 public void onAccessibilityServicesStateChanged(AccessibilityManager accessibilityManager) {
Jean-Michel Trivicfa55532017-01-18 11:17:51 -08006484 updateA11yVolumeAlias(accessibilityManager.isAccessibilityVolumeStreamActive());
6485 }
6486
6487 private void updateA11yVolumeAlias(boolean a11VolEnabled) {
6488 if (DEBUG_VOL) Log.d(TAG, "Accessibility volume enabled = " + a11VolEnabled);
6489 if (sIndependentA11yVolume != a11VolEnabled) {
6490 sIndependentA11yVolume = a11VolEnabled;
6491 // update the volume mapping scheme
6492 updateStreamVolumeAlias(true /*updateVolumes*/, TAG);
6493 // update the volume controller behavior
6494 mVolumeController.setA11yMode(sIndependentA11yVolume ?
6495 VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME :
6496 VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME);
Jean-Michel Trivia53b7052017-04-12 18:27:01 -07006497 mVolumeController.postVolumeChanged(AudioManager.STREAM_ACCESSIBILITY, 0);
Jean-Michel Trivicfa55532017-01-18 11:17:51 -08006498 }
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07006499 }
6500
6501 //==========================================================================================
Eric Laurentdd45d012012-10-08 09:04:34 -07006502 // Camera shutter sound policy.
6503 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
6504 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
6505 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
6506 //==========================================================================================
6507
6508 // cached value of com.android.internal.R.bool.config_camera_sound_forced
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08006509 @GuardedBy("mSettingsLock")
6510 private boolean mCameraSoundForced;
Eric Laurentdd45d012012-10-08 09:04:34 -07006511
6512 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
6513 public boolean isCameraSoundForced() {
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08006514 synchronized (mSettingsLock) {
Eric Laurentdd45d012012-10-08 09:04:34 -07006515 return mCameraSoundForced;
6516 }
6517 }
6518
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006519 //==========================================================================================
6520 // AudioService logging and dumpsys
6521 //==========================================================================================
6522 final int LOG_NB_EVENTS_PHONE_STATE = 20;
6523 final int LOG_NB_EVENTS_WIRED_DEV_CONNECTION = 30;
6524 final int LOG_NB_EVENTS_FORCE_USE = 20;
Jean-Michel Trivicf170362017-08-24 17:24:57 -07006525 final int LOG_NB_EVENTS_VOLUME = 40;
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006526
6527 final private AudioEventLogger mModeLogger = new AudioEventLogger(LOG_NB_EVENTS_PHONE_STATE,
6528 "phone state (logged after successfull call to AudioSystem.setPhoneState(int))");
6529
6530 final private AudioEventLogger mWiredDevLogger = new AudioEventLogger(
6531 LOG_NB_EVENTS_WIRED_DEV_CONNECTION,
6532 "wired device connection (logged before onSetWiredDeviceConnectionState() is executed)"
6533 );
6534
6535 final private AudioEventLogger mForceUseLogger = new AudioEventLogger(
6536 LOG_NB_EVENTS_FORCE_USE,
6537 "force use (logged before setForceUse() is executed)");
6538
Jean-Michel Trivicf170362017-08-24 17:24:57 -07006539 final private AudioEventLogger mVolumeLogger = new AudioEventLogger(LOG_NB_EVENTS_VOLUME,
6540 "volume changes (logged when command received by AudioService)");
6541
Eric Laurentdd45d012012-10-08 09:04:34 -07006542 private static final String[] RINGER_MODE_NAMES = new String[] {
6543 "SILENT",
6544 "VIBRATE",
6545 "NORMAL"
6546 };
6547
6548 private void dumpRingerMode(PrintWriter pw) {
6549 pw.println("\nRinger mode: ");
John Spurlock661f2cf2014-11-17 10:29:10 -05006550 pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
6551 pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
John Spurlock50ced3f2015-05-11 16:00:09 -04006552 dumpRingerModeStreams(pw, "affected", mRingerModeAffectedStreams);
6553 dumpRingerModeStreams(pw, "muted", mRingerModeMutedStreams);
John Spurlock661f2cf2014-11-17 10:29:10 -05006554 pw.print("- delegate = "); pw.println(mRingerModeDelegate);
Eric Laurentdd45d012012-10-08 09:04:34 -07006555 }
6556
John Spurlock50ced3f2015-05-11 16:00:09 -04006557 private void dumpRingerModeStreams(PrintWriter pw, String type, int streams) {
6558 pw.print("- ringer mode "); pw.print(type); pw.print(" streams = 0x");
6559 pw.print(Integer.toHexString(streams));
6560 if (streams != 0) {
6561 pw.print(" (");
6562 boolean first = true;
6563 for (int i = 0; i < AudioSystem.STREAM_NAMES.length; i++) {
6564 final int stream = (1 << i);
6565 if ((streams & stream) != 0) {
6566 if (!first) pw.print(',');
6567 pw.print(AudioSystem.STREAM_NAMES[i]);
6568 streams &= ~stream;
6569 first = false;
6570 }
6571 }
6572 if (streams != 0) {
6573 if (!first) pw.print(',');
6574 pw.print(streams);
6575 }
6576 pw.print(')');
6577 }
6578 pw.println();
6579 }
6580
Dianne Hackborn632ca412012-06-14 19:34:10 -07006581 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08006582 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06006583 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07006584
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07006585 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07006586 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07006587 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07006588 pw.println("\nAudio routes:");
John Spurlock61560172015-02-06 19:46:04 -05006589 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
6590 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
John Spurlock35134602014-07-24 18:10:48 -04006591
6592 pw.println("\nOther state:");
John Spurlock3346a802014-05-20 16:25:37 -04006593 pw.print(" mVolumeController="); pw.println(mVolumeController);
John Spurlock35134602014-07-24 18:10:48 -04006594 pw.print(" mSafeMediaVolumeState=");
6595 pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
6596 pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
Eric Laurenteab40d12017-06-09 12:45:21 -07006597 pw.print(" mSafeUsbMediaVolumeIndex="); pw.println(mSafeUsbMediaVolumeIndex);
Jean-Michel Trivi7592b982017-02-01 15:12:15 -08006598 pw.print(" sIndependentA11yVolume="); pw.println(sIndependentA11yVolume);
John Spurlock35134602014-07-24 18:10:48 -04006599 pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
6600 pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04006601 pw.print(" mMcc="); pw.println(mMcc);
John Spurlock5e783732015-02-19 10:28:59 -05006602 pw.print(" mCameraSoundForced="); pw.println(mCameraSoundForced);
John Spurlock661f2cf2014-11-17 10:29:10 -05006603 pw.print(" mHasVibrator="); pw.println(mHasVibrator);
John Spurlocka48d7792015-03-03 17:35:57 -05006604 pw.print(" mVolumePolicy="); pw.println(mVolumePolicy);
Jean-Michel Trivi1ab43f62017-04-27 15:37:34 -07006605 pw.print(" mAvrcpAbsVolSupported="); pw.println(mAvrcpAbsVolSupported);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006606
6607 dumpAudioPolicies(pw);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08006608
6609 mPlaybackMonitor.dump(pw);
Jean-Michel Trivi66ffacf2017-02-04 17:25:31 -08006610
6611 mRecordMonitor.dump(pw);
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006612
Jean-Michel Trivicf170362017-08-24 17:24:57 -07006613 pw.println("\n");
Jean-Michel Trivi011f39e2017-08-19 18:08:06 -07006614 pw.println("\nEvent logs:");
6615 mModeLogger.dump(pw);
6616 pw.println("\n");
6617 mWiredDevLogger.dump(pw);
6618 pw.println("\n");
6619 mForceUseLogger.dump(pw);
Jean-Michel Trivicf170362017-08-24 17:24:57 -07006620 pw.println("\n");
6621 mVolumeLogger.dump(pw);
John Spurlock35134602014-07-24 18:10:48 -04006622 }
6623
6624 private static String safeMediaVolumeStateToString(Integer state) {
6625 switch(state) {
6626 case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
6627 case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
6628 case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
6629 case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
6630 }
6631 return null;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08006632 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07006633
6634 // Inform AudioFlinger of our device's low RAM attribute
6635 private static void readAndSetLowRamDevice()
6636 {
6637 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
6638 if (status != 0) {
6639 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
6640 }
6641 }
John Spurlock3346a802014-05-20 16:25:37 -04006642
John Spurlockcdb57ae2015-02-11 19:04:11 -05006643 private void enforceVolumeController(String action) {
John Spurlock3346a802014-05-20 16:25:37 -04006644 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
6645 "Only SystemUI can " + action);
6646 }
6647
6648 @Override
6649 public void setVolumeController(final IVolumeController controller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05006650 enforceVolumeController("set the volume controller");
John Spurlock3346a802014-05-20 16:25:37 -04006651
6652 // return early if things are not actually changing
6653 if (mVolumeController.isSameBinder(controller)) {
6654 return;
6655 }
6656
6657 // dismiss the old volume controller
6658 mVolumeController.postDismiss();
6659 if (controller != null) {
6660 // we are about to register a new controller, listen for its death
6661 try {
6662 controller.asBinder().linkToDeath(new DeathRecipient() {
6663 @Override
6664 public void binderDied() {
6665 if (mVolumeController.isSameBinder(controller)) {
6666 Log.w(TAG, "Current remote volume controller died, unregistering");
6667 setVolumeController(null);
6668 }
6669 }
6670 }, 0);
6671 } catch (RemoteException e) {
6672 // noop
6673 }
6674 }
6675 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04006676 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
6677 }
6678
6679 @Override
6680 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05006681 enforceVolumeController("notify about volume controller visibility");
John Spurlock33f4e042014-07-11 13:10:58 -04006682
6683 // return early if the controller is not current
6684 if (!mVolumeController.isSameBinder(controller)) {
6685 return;
6686 }
6687
6688 mVolumeController.setVisible(visible);
6689 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04006690 }
RoboErikd09bd0c2014-06-24 17:45:19 -07006691
John Spurlocka48d7792015-03-03 17:35:57 -05006692 @Override
6693 public void setVolumePolicy(VolumePolicy policy) {
6694 enforceVolumeController("set volume policy");
John Spurlockb02c7442015-04-14 09:32:25 -04006695 if (policy != null && !policy.equals(mVolumePolicy)) {
John Spurlocka48d7792015-03-03 17:35:57 -05006696 mVolumePolicy = policy;
John Spurlockb02c7442015-04-14 09:32:25 -04006697 if (DEBUG_VOL) Log.d(TAG, "Volume policy changed: " + mVolumePolicy);
John Spurlocka48d7792015-03-03 17:35:57 -05006698 }
6699 }
6700
RoboErikd09bd0c2014-06-24 17:45:19 -07006701 public static class VolumeController {
6702 private static final String TAG = "VolumeController";
6703
6704 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04006705 private boolean mVisible;
6706 private long mNextLongPress;
6707 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07006708
6709 public void setController(IVolumeController controller) {
6710 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04006711 mVisible = false;
6712 }
6713
6714 public void loadSettings(ContentResolver cr) {
6715 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
6716 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
6717 }
6718
RoboErik4197cb62015-01-21 15:45:32 -08006719 public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
6720 if (isMute) {
6721 return false;
6722 }
John Spurlock33f4e042014-07-11 13:10:58 -04006723 boolean suppress = false;
6724 if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
6725 final long now = SystemClock.uptimeMillis();
6726 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
6727 // ui will become visible
6728 if (mNextLongPress < now) {
6729 mNextLongPress = now + mLongPressTimeout;
6730 }
6731 suppress = true;
6732 } else if (mNextLongPress > 0) { // in a long-press
6733 if (now > mNextLongPress) {
6734 // long press triggered, no more suppression
6735 mNextLongPress = 0;
6736 } else {
6737 // keep suppressing until the long press triggers
6738 suppress = true;
6739 }
6740 }
6741 }
6742 return suppress;
6743 }
6744
6745 public void setVisible(boolean visible) {
6746 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07006747 }
6748
6749 public boolean isSameBinder(IVolumeController controller) {
6750 return Objects.equals(asBinder(), binder(controller));
6751 }
6752
6753 public IBinder asBinder() {
6754 return binder(mController);
6755 }
6756
6757 private static IBinder binder(IVolumeController controller) {
6758 return controller == null ? null : controller.asBinder();
6759 }
6760
6761 @Override
6762 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04006763 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07006764 }
6765
6766 public void postDisplaySafeVolumeWarning(int flags) {
6767 if (mController == null)
6768 return;
6769 try {
6770 mController.displaySafeVolumeWarning(flags);
6771 } catch (RemoteException e) {
6772 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
6773 }
6774 }
6775
6776 public void postVolumeChanged(int streamType, int flags) {
6777 if (mController == null)
6778 return;
6779 try {
6780 mController.volumeChanged(streamType, flags);
6781 } catch (RemoteException e) {
6782 Log.w(TAG, "Error calling volumeChanged", e);
6783 }
6784 }
6785
RoboErikd09bd0c2014-06-24 17:45:19 -07006786 public void postMasterMuteChanged(int flags) {
6787 if (mController == null)
6788 return;
6789 try {
6790 mController.masterMuteChanged(flags);
6791 } catch (RemoteException e) {
6792 Log.w(TAG, "Error calling masterMuteChanged", e);
6793 }
6794 }
6795
6796 public void setLayoutDirection(int layoutDirection) {
6797 if (mController == null)
6798 return;
6799 try {
6800 mController.setLayoutDirection(layoutDirection);
6801 } catch (RemoteException e) {
6802 Log.w(TAG, "Error calling setLayoutDirection", e);
6803 }
6804 }
6805
6806 public void postDismiss() {
6807 if (mController == null)
6808 return;
6809 try {
6810 mController.dismiss();
6811 } catch (RemoteException e) {
6812 Log.w(TAG, "Error calling dismiss", e);
6813 }
6814 }
Jean-Michel Triviac487672016-11-11 10:05:18 -08006815
6816 public void setA11yMode(int a11yMode) {
6817 if (mController == null)
6818 return;
6819 try {
6820 mController.setA11yMode(a11yMode);
6821 } catch (RemoteException e) {
6822 Log.w(TAG, "Error calling setA11Mode", e);
6823 }
6824 }
RoboErikd09bd0c2014-06-24 17:45:19 -07006825 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006826
RoboErik0dac35a2014-08-12 15:48:49 -07006827 /**
6828 * Interface for system components to get some extra functionality through
6829 * LocalServices.
6830 */
6831 final class AudioServiceInternal extends AudioManagerInternal {
John Spurlock661f2cf2014-11-17 10:29:10 -05006832 @Override
6833 public void setRingerModeDelegate(RingerModeDelegate delegate) {
6834 mRingerModeDelegate = delegate;
6835 if (mRingerModeDelegate != null) {
Jean-Michel Trivi8719a1d2017-11-06 11:52:51 -08006836 synchronized (mSettingsLock) {
6837 updateRingerModeAffectedStreams();
6838 }
John Spurlock661f2cf2014-11-17 10:29:10 -05006839 setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
6840 }
6841 }
RoboErik272e1612014-09-05 11:39:29 -07006842
6843 @Override
6844 public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
6845 String callingPackage, int uid) {
6846 // direction and stream type swap here because the public
6847 // adjustSuggested has a different order than the other methods.
John Spurlock90874332015-03-10 16:00:54 -04006848 adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage,
6849 callingPackage, uid);
RoboErik272e1612014-09-05 11:39:29 -07006850 }
6851
RoboErik0dac35a2014-08-12 15:48:49 -07006852 @Override
6853 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
6854 String callingPackage, int uid) {
John Spurlock90874332015-03-10 16:00:54 -04006855 adjustStreamVolume(streamType, direction, flags, callingPackage,
6856 callingPackage, uid);
RoboErik0dac35a2014-08-12 15:48:49 -07006857 }
6858
6859 @Override
6860 public void setStreamVolumeForUid(int streamType, int direction, int flags,
6861 String callingPackage, int uid) {
John Spurlock90874332015-03-10 16:00:54 -04006862 setStreamVolume(streamType, direction, flags, callingPackage, callingPackage, uid);
RoboErik0dac35a2014-08-12 15:48:49 -07006863 }
RoboErik519c7742014-11-18 10:59:09 -08006864
6865 @Override
John Spurlock661f2cf2014-11-17 10:29:10 -05006866 public int getRingerModeInternal() {
6867 return AudioService.this.getRingerModeInternal();
6868 }
6869
6870 @Override
6871 public void setRingerModeInternal(int ringerMode, String caller) {
6872 AudioService.this.setRingerModeInternal(ringerMode, caller);
6873 }
John Spurlockcdb57ae2015-02-11 19:04:11 -05006874
6875 @Override
John Spurlock50ced3f2015-05-11 16:00:09 -04006876 public void updateRingerModeAffectedStreamsInternal() {
6877 synchronized (mSettingsLock) {
6878 if (updateRingerModeAffectedStreams()) {
6879 setRingerModeInt(getRingerModeInternal(), false);
6880 }
6881 }
6882 }
Phil Weaverf1a9aff2017-03-23 17:21:29 -07006883
6884 @Override
6885 public void setAccessibilityServiceUids(IntArray uids) {
6886 synchronized (mAccessibilityServiceUidsLock) {
6887 if (uids.size() == 0) {
6888 mAccessibilityServiceUids = null;
6889 } else {
6890 boolean changed = (mAccessibilityServiceUids == null)
6891 || (mAccessibilityServiceUids.length != uids.size());
6892 if (!changed) {
6893 for (int i = 0; i < mAccessibilityServiceUids.length; i++) {
6894 if (uids.get(i) != mAccessibilityServiceUids[i]) {
6895 changed = true;
6896 break;
6897 }
6898 }
6899 }
6900 if (changed) {
6901 mAccessibilityServiceUids = uids.toArray();
6902 }
6903 }
6904 }
6905 }
RoboErik0dac35a2014-08-12 15:48:49 -07006906 }
6907
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006908 //==========================================================================================
6909 // Audio policy management
6910 //==========================================================================================
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006911 public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07006912 boolean hasFocusListener, boolean isFocusPolicy) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006913 AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
6914
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006915 if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
6916 + " with config:" + policyConfig);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006917 String regId = null;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006918 // error handling
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006919 boolean hasPermissionForPolicy =
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006920 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006921 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
6922 if (!hasPermissionForPolicy) {
6923 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
6924 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006925 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006926 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006927
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006928 synchronized (mAudioPolicies) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006929 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006930 if (mAudioPolicies.containsKey(pcb.asBinder())) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006931 Slog.e(TAG, "Cannot re-register policy");
6932 return null;
6933 }
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07006934 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener,
6935 isFocusPolicy);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006936 pcb.asBinder().linkToDeath(app, 0/*flags*/);
6937 regId = app.getRegistrationId();
6938 mAudioPolicies.put(pcb.asBinder(), app);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006939 } catch (RemoteException e) {
6940 // audio policy owner has already died!
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006941 Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006942 " binder death", e);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006943 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006944 }
6945 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006946 return regId;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006947 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006948
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006949 public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
6950 if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006951 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006952 AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006953 if (app == null) {
6954 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
6955 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006956 return;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006957 } else {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006958 pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006959 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006960 app.release();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006961 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006962 // TODO implement clearing mix attribute matching info in native audio policy
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006963 }
6964
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006965 public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
6966 if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
6967 + " policy " + pcb.asBinder());
6968 // error handling
6969 boolean hasPermissionForPolicy =
6970 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
6971 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
6972 if (!hasPermissionForPolicy) {
6973 Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
6974 + Binder.getCallingPid() + " / uid "
6975 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
6976 return AudioManager.ERROR;
6977 }
6978
6979 synchronized (mAudioPolicies) {
6980 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
6981 Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
6982 return AudioManager.ERROR;
6983 }
6984 final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
6985 if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6986 // is there already one policy managing ducking?
Eric Laurent0867bed2015-05-20 14:49:08 -07006987 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006988 if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6989 Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
6990 return AudioManager.ERROR;
6991 }
6992 }
6993 }
6994 app.mFocusDuckBehavior = duckingBehavior;
6995 mMediaFocusControl.setDuckingInExtPolicyAvailable(
6996 duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
6997 }
6998 return AudioManager.SUCCESS;
6999 }
7000
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08007001 private void dumpAudioPolicies(PrintWriter pw) {
7002 pw.println("\nAudio policies:");
7003 synchronized (mAudioPolicies) {
Eric Laurent0867bed2015-05-20 14:49:08 -07007004 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08007005 pw.println(policy.toLogFriendlyString());
7006 }
7007 }
7008 }
7009
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08007010 //======================
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08007011 // Audio policy callbacks from AudioSystem for dynamic policies
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007012 //======================
7013 private final AudioSystem.DynamicPolicyCallback mDynPolicyCallback =
7014 new AudioSystem.DynamicPolicyCallback() {
7015 public void onDynamicPolicyMixStateUpdate(String regId, int state) {
7016 if (!TextUtils.isEmpty(regId)) {
7017 sendMsg(mAudioHandler, MSG_DYN_POLICY_MIX_STATE_UPDATE, SENDMSG_QUEUE,
7018 state /*arg1*/, 0 /*arg2 ignored*/, regId /*obj*/, 0 /*delay*/);
7019 }
7020 }
7021 };
7022
7023 private void onDynPolicyMixStateUpdate(String regId, int state) {
7024 if (DEBUG_AP) Log.d(TAG, "onDynamicPolicyMixStateUpdate("+ regId + ", " + state +")");
7025 synchronized (mAudioPolicies) {
7026 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
7027 for (AudioMix mix : policy.getMixes()) {
7028 if (mix.getRegistration().equals(regId)) {
7029 try {
7030 policy.mPolicyCallback.notifyMixStateUpdate(regId, state);
7031 } catch (RemoteException e) {
7032 Log.e(TAG, "Can't call notifyMixStateUpdate() on IAudioPolicyCallback "
7033 + policy.mPolicyCallback.asBinder(), e);
7034 }
7035 return;
7036 }
7037 }
7038 }
7039 }
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08007040 }
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007041
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08007042 //======================
7043 // Audio policy callbacks from AudioSystem for recording configuration updates
7044 //======================
Jean-Michel Trivi66ffacf2017-02-04 17:25:31 -08007045 private final RecordingActivityMonitor mRecordMonitor;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08007046
7047 public void registerRecordingCallback(IRecordingConfigDispatcher rcdb) {
Jean-Michel Trivi66ffacf2017-02-04 17:25:31 -08007048 final boolean isPrivileged =
7049 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
7050 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
7051 mRecordMonitor.registerRecordingCallback(rcdb, isPrivileged);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08007052 }
7053
7054 public void unregisterRecordingCallback(IRecordingConfigDispatcher rcdb) {
7055 mRecordMonitor.unregisterRecordingCallback(rcdb);
7056 }
7057
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07007058 public List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
Jean-Michel Trivi66ffacf2017-02-04 17:25:31 -08007059 final boolean isPrivileged =
7060 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
7061 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
7062 return mRecordMonitor.getActiveRecordingConfigurations(isPrivileged);
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007063 }
7064
Robin Lee7af9a742017-02-20 14:47:30 +00007065 public void disableRingtoneSync(final int userId) {
Andre Lago7bdc6d82016-09-22 18:00:41 +01007066 final int callingUserId = UserHandle.getCallingUserId();
Robin Lee7af9a742017-02-20 14:47:30 +00007067 if (callingUserId != userId) {
7068 mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
7069 "disable sound settings syncing for another profile");
7070 }
Andre Lago7bdc6d82016-09-22 18:00:41 +01007071 final long token = Binder.clearCallingIdentity();
7072 try {
Robin Lee7af9a742017-02-20 14:47:30 +00007073 // Disable the sync setting so the profile uses its own sound settings.
7074 Settings.Secure.putIntForUser(mContentResolver, Settings.Secure.SYNC_PARENT_SOUNDS,
7075 0 /* false */, userId);
Andre Lago7bdc6d82016-09-22 18:00:41 +01007076 } finally {
7077 Binder.restoreCallingIdentity(token);
7078 }
7079 }
7080
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007081 //======================
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -08007082 // Audio playback notification
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007083 //======================
Eric Laurente5a351c2017-09-27 20:11:51 -07007084 private final PlaybackActivityMonitor mPlaybackMonitor;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007085
7086 public void registerPlaybackCallback(IPlaybackConfigDispatcher pcdb) {
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -08007087 final boolean isPrivileged =
Jaewan Kim92dea332017-02-02 11:52:08 +09007088 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007089 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
7090 mPlaybackMonitor.registerPlaybackCallback(pcdb, isPrivileged);
7091 }
7092
7093 public void unregisterPlaybackCallback(IPlaybackConfigDispatcher pcdb) {
7094 mPlaybackMonitor.unregisterPlaybackCallback(pcdb);
7095 }
7096
7097 public List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() {
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -08007098 final boolean isPrivileged =
Jaewan Kim92dea332017-02-02 11:52:08 +09007099 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -08007100 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
7101 return mPlaybackMonitor.getActivePlaybackConfigurations(isPrivileged);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007102 }
7103
Jean-Michel Trivi44a8f532017-01-02 14:36:43 -08007104 public int trackPlayer(PlayerBase.PlayerIdCard pic) {
7105 return mPlaybackMonitor.trackPlayer(pic);
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007106 }
7107
7108 public void playerAttributes(int piid, AudioAttributes attr) {
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -08007109 mPlaybackMonitor.playerAttributes(piid, attr, Binder.getCallingUid());
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007110 }
7111
7112 public void playerEvent(int piid, int event) {
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -08007113 mPlaybackMonitor.playerEvent(piid, event, Binder.getCallingUid());
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007114 }
7115
Jean-Michel Trivi3120059d2017-08-28 12:40:55 -07007116 public void playerHasOpPlayAudio(int piid, boolean hasOpPlayAudio) {
7117 mPlaybackMonitor.playerHasOpPlayAudio(piid, hasOpPlayAudio, Binder.getCallingUid());
7118 }
7119
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007120 public void releasePlayer(int piid) {
Jean-Michel Trivi46e310b2017-01-04 15:58:02 -08007121 mPlaybackMonitor.releasePlayer(piid, Binder.getCallingUid());
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08007122 }
7123
7124 //======================
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08007125 // Audio policy proxy
7126 //======================
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007127 /**
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08007128 * This internal class inherits from AudioPolicyConfig, each instance contains all the
7129 * mixes of an AudioPolicy and their configurations.
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007130 */
7131 public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007132 private static final String TAG = "AudioPolicyProxy";
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007133 IAudioPolicyCallback mPolicyCallback;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007134 boolean mHasFocusListener;
7135 /**
7136 * Audio focus ducking behavior for an audio policy.
7137 * This variable reflects the value that was successfully set in
7138 * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
7139 * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
7140 * is handling ducking for audio focus.
7141 */
7142 int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07007143 boolean mIsFocusPolicy = false;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007144
7145 AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07007146 boolean hasFocusListener, boolean isFocusPolicy) {
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007147 super(config);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08007148 setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007149 mPolicyCallback = token;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007150 mHasFocusListener = hasFocusListener;
7151 if (mHasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007152 mMediaFocusControl.addFocusFollower(mPolicyCallback);
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07007153 // can only ever be true if there is a focus listener
7154 if (isFocusPolicy) {
7155 mIsFocusPolicy = true;
7156 mMediaFocusControl.setFocusPolicy(mPolicyCallback);
7157 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007158 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08007159 connectMixes();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007160 }
7161
7162 public void binderDied() {
7163 synchronized (mAudioPolicies) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007164 Log.i(TAG, "audio policy " + mPolicyCallback + " died");
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007165 release();
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007166 mAudioPolicies.remove(mPolicyCallback.asBinder());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007167 }
7168 }
7169
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007170 String getRegistrationId() {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08007171 return getRegistration();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007172 }
7173
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007174 void release() {
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07007175 if (mIsFocusPolicy) {
7176 mMediaFocusControl.unsetFocusPolicy(mPolicyCallback);
7177 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007178 if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
7179 mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
7180 }
7181 if (mHasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07007182 mMediaFocusControl.removeFocusFollower(mPolicyCallback);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08007183 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08007184 AudioSystem.registerPolicyMixes(mMixes, false);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007185 }
7186
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08007187 void connectMixes() {
7188 AudioSystem.registerPolicyMixes(mMixes, true);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007189 }
7190 };
7191
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07007192 //======================
7193 // Audio policy: focus
7194 //======================
7195 /** */
7196 public int dispatchFocusChange(AudioFocusInfo afi, int focusChange, IAudioPolicyCallback pcb) {
7197 synchronized (mAudioPolicies) {
7198 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
7199 throw new IllegalStateException("Unregistered AudioPolicy for focus dispatch");
7200 }
7201 return mMediaFocusControl.dispatchFocusChange(afi, focusChange);
7202 }
7203 }
7204
7205 //======================
7206 // misc
7207 //======================
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07007208 private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
7209 new HashMap<IBinder, AudioPolicyProxy>();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07007210 private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
Phil Burkac0f7042016-02-24 12:19:08 -08007211}