blob: 2a631b562fc4f1f20d139f1fd76f20b895e16e53 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
John Spurlock61560172015-02-06 19:46:04 -050017package com.android.server.audio;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Jeff Sharkey098d5802012-04-26 17:30:34 -070019import static android.Manifest.permission.REMOTE_AUDIO_PLAYBACK;
Amith Yamasanic696a532011-10-28 17:02:37 -070020import static android.media.AudioManager.RINGER_MODE_NORMAL;
21import static android.media.AudioManager.RINGER_MODE_SILENT;
22import static android.media.AudioManager.RINGER_MODE_VIBRATE;
Fyodor Kupolovbcb6c1e2015-05-11 12:05:15 -070023import static android.os.Process.FIRST_APPLICATION_UID;
Amith Yamasanic696a532011-10-28 17:02:37 -070024
Fyodor Kupolovb5013302015-04-17 17:59:14 -070025import android.Manifest;
Glenn Kastenfd116ad2013-07-12 17:10:39 -070026import android.app.ActivityManager;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070027import android.app.ActivityManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.app.ActivityManagerNative;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070029import android.app.AppGlobals;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -070030import android.app.AppOpsManager;
Julia Reynolds48034f82016-03-09 10:15:16 -050031import android.app.NotificationManager;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070032import android.bluetooth.BluetoothA2dp;
33import android.bluetooth.BluetoothAdapter;
34import android.bluetooth.BluetoothClass;
35import android.bluetooth.BluetoothDevice;
36import android.bluetooth.BluetoothHeadset;
37import android.bluetooth.BluetoothProfile;
Nick Pellybd022f42009-08-14 18:33:38 -070038import android.content.BroadcastReceiver;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070039import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.content.ContentResolver;
41import android.content.Context;
42import android.content.Intent;
Eric Laurenta553c252009-07-17 12:17:14 -070043import android.content.IntentFilter;
Julia Reynolds48034f82016-03-09 10:15:16 -050044import android.content.pm.ApplicationInfo;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070045import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.content.pm.PackageManager;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070047import android.content.pm.UserInfo;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -070048import android.content.res.Configuration;
Eric Laurente78fced2013-03-15 16:03:47 -070049import android.content.res.Resources;
50import android.content.res.XmlResourceParser;
Jason Parekhb1096152009-03-24 17:48:25 -070051import android.database.ContentObserver;
Jungshik Jang41d97462014-06-30 22:26:29 +090052import android.hardware.hdmi.HdmiControlManager;
Eric Laurent212532b2014-07-21 15:43:18 -070053import android.hardware.hdmi.HdmiPlaybackClient;
Jungshik Jang41d97462014-06-30 22:26:29 +090054import android.hardware.hdmi.HdmiTvClient;
Paul McLeanc837a452014-04-09 09:04:43 -070055import android.hardware.usb.UsbManager;
John Spurlock61560172015-02-06 19:46:04 -050056import android.media.AudioAttributes;
57import android.media.AudioDevicePort;
58import android.media.AudioSystem;
59import android.media.AudioFormat;
60import android.media.AudioManager;
61import android.media.AudioManagerInternal;
62import android.media.AudioPort;
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -080063import android.media.AudioRecordingConfiguration;
John Spurlock61560172015-02-06 19:46:04 -050064import android.media.AudioRoutesInfo;
John Spurlock61560172015-02-06 19:46:04 -050065import android.media.IAudioFocusDispatcher;
66import android.media.IAudioRoutesObserver;
67import android.media.IAudioService;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -080068import android.media.IRecordingConfigDispatcher;
John Spurlock61560172015-02-06 19:46:04 -050069import android.media.IRingtonePlayer;
70import android.media.IVolumeController;
71import android.media.MediaPlayer;
72import android.media.SoundPool;
John Spurlocka48d7792015-03-03 17:35:57 -050073import android.media.VolumePolicy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074import android.media.MediaPlayer.OnCompletionListener;
75import android.media.MediaPlayer.OnErrorListener;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -070076import android.media.audiopolicy.AudioMix;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -080077import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070078import android.media.audiopolicy.AudioPolicyConfig;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -080079import android.media.audiopolicy.IAudioPolicyCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080import android.os.Binder;
Eric Laurentc18c9132013-04-12 17:24:56 -070081import android.os.Build;
Makoto Onukid45a4a22015-11-02 17:17:38 -080082import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083import android.os.Environment;
84import android.os.Handler;
85import android.os.IBinder;
86import android.os.Looper;
87import android.os.Message;
Jean-Michel Trivic6802222012-04-30 11:15:03 -070088import android.os.PowerManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070089import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090import android.os.RemoteException;
John Spurlock33f4e042014-07-11 13:10:58 -040091import android.os.SystemClock;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070092import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070093import android.os.UserHandle;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070094import android.os.UserManager;
Makoto Onukid45a4a22015-11-02 17:17:38 -080095import android.os.UserManagerInternal;
96import android.os.UserManagerInternal.UserRestrictionsListener;
Eric Laurentbffc3d12012-05-07 17:43:49 -070097import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098import android.provider.Settings;
99import android.provider.Settings.System;
Tyler Gunnef9f6f92014-09-12 22:16:17 -0700100import android.telecom.TelecomManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -0700101import android.text.TextUtils;
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700102import android.util.AndroidRuntimeException;
John Spurlock8c3dc852015-04-23 21:32:37 -0400103import android.util.ArrayMap;
104import android.util.ArraySet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105import android.util.Log;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400106import android.util.MathUtils;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -0700107import android.util.Slog;
John Spurlock2bb02ec2015-03-02 13:13:06 -0500108import android.util.SparseIntArray;
Jean-Michel Trivid327f212010-03-16 21:44:33 -0700109import android.view.KeyEvent;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700110import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111
Eric Laurente78fced2013-03-15 16:03:47 -0700112import com.android.internal.util.XmlUtils;
John Spurlock90874332015-03-10 16:00:54 -0400113import com.android.server.EventLogTags;
RoboErik0dac35a2014-08-12 15:48:49 -0700114import com.android.server.LocalServices;
Makoto Onukie1aef852015-10-15 17:28:35 -0700115import com.android.server.SystemService;
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700116import com.android.server.pm.UserManagerService;
Eric Laurente78fced2013-03-15 16:03:47 -0700117
118import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800120import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121import java.io.IOException;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800122import java.io.PrintWriter;
Eric Laurente78fced2013-03-15 16:03:47 -0700123import java.lang.reflect.Field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124import java.util.ArrayList;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700125import java.util.HashMap;
126import java.util.Iterator;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -0700127import java.util.List;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700128import java.util.NoSuchElementException;
RoboErikd09bd0c2014-06-24 17:45:19 -0700129import java.util.Objects;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130
131/**
132 * The implementation of the volume manager service.
133 * <p>
134 * This implementation focuses on delivering a responsive UI. Most methods are
135 * asynchronous to external calls. For example, the task of setting a volume
136 * will update our internal state, but in a separate thread will set the system
137 * volume and later persist to the database. Similarly, setting the ringer mode
138 * will update the state and broadcast a change and in a separate thread later
139 * persist the ringer mode.
140 *
141 * @hide
142 */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700143public class AudioService extends IAudioService.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144
145 private static final String TAG = "AudioService";
146
Jean-Michel Trivi339567d2014-07-29 09:53:34 -0700147 /** Debug audio mode */
148 protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -0700149
150 /** Debug audio policy feature */
151 protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);
152
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700153 /** Debug volumes */
John Spurlockae641c92014-06-30 18:11:40 -0400154 protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700155
Paul McLean394a8e12015-03-03 10:29:19 -0700156 /** debug calls to devices APIs */
157 protected static final boolean DEBUG_DEVICES = Log.isLoggable(TAG + ".DEVICES", Log.DEBUG);
158
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 /** How long to delay before persisting a change in volume/ringer mode. */
RoboErik45edba12012-03-27 17:54:36 -0700160 private static final int PERSIST_DELAY = 500;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161
RoboErik5452e252015-02-06 15:33:53 -0800162 /** How long to delay after a volume down event before unmuting a stream */
163 private static final int UNMUTE_STREAM_DELAY = 350;
164
John Spurlock3346a802014-05-20 16:25:37 -0400165 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400166 * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
167 */
168 private static final int FLAG_ADJUST_VOLUME = 1;
169
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700170 private final Context mContext;
171 private final ContentResolver mContentResolver;
172 private final AppOpsManager mAppOps;
Eric Laurent212532b2014-07-21 15:43:18 -0700173
Eric Laurent212532b2014-07-21 15:43:18 -0700174 // the platform type affects volume and silent mode behavior
175 private final int mPlatformType;
176
177 private boolean isPlatformVoice() {
John Spurlock61560172015-02-06 19:46:04 -0500178 return mPlatformType == AudioSystem.PLATFORM_VOICE;
Eric Laurent212532b2014-07-21 15:43:18 -0700179 }
180
181 private boolean isPlatformTelevision() {
John Spurlock61560172015-02-06 19:46:04 -0500182 return mPlatformType == AudioSystem.PLATFORM_TELEVISION;
Eric Laurent212532b2014-07-21 15:43:18 -0700183 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800184
John Spurlock3346a802014-05-20 16:25:37 -0400185 /** The controller for the volume UI. */
186 private final VolumeController mVolumeController = new VolumeController();
John Spurlockcdb57ae2015-02-11 19:04:11 -0500187 private final ControllerService mControllerService = new ControllerService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188
189 // sendMsg() flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 /** If the msg is already queued, replace it with this one. */
191 private static final int SENDMSG_REPLACE = 0;
192 /** If the msg is already queued, ignore this one and leave the old. */
193 private static final int SENDMSG_NOOP = 1;
194 /** If the msg is already queued, queue this one and leave the old. */
195 private static final int SENDMSG_QUEUE = 2;
196
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700197 // AudioHandler messages
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800198 private static final int MSG_SET_DEVICE_VOLUME = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 private static final int MSG_PERSIST_VOLUME = 1;
200 private static final int MSG_PERSIST_RINGER_MODE = 3;
Andy Hunged0ea402015-10-30 14:11:46 -0700201 private static final int MSG_AUDIO_SERVER_DIED = 4;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700202 private static final int MSG_PLAY_SOUND_EFFECT = 5;
203 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
204 private static final int MSG_LOAD_SOUND_EFFECTS = 7;
205 private static final int MSG_SET_FORCE_USE = 8;
206 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
207 private static final int MSG_SET_ALL_VOLUMES = 10;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700208 private static final int MSG_REPORT_NEW_ROUTES = 12;
Sungsoocf09fe62016-09-28 16:21:48 +0900209 private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700210 private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
211 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
212 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
213 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
214 private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
215 private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
216 private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700217 private static final int MSG_SYSTEM_READY = 21;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400218 private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
RoboErik5452e252015-02-06 15:33:53 -0800219 private static final int MSG_UNMUTE_STREAM = 24;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -0700220 private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 25;
Eric Laurent0867bed2015-05-20 14:49:08 -0700221 private static final int MSG_INDICATE_SYSTEM_READY = 26;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700222 // start of messages handled under wakelock
223 // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
Jean-Michel Trivie12c39b2012-06-06 10:51:58 -0700224 // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700225 private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
Mike Lockwood0a40ec22014-05-21 10:08:50 -0700226 private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
227 private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -0800228 private static final int MSG_A2DP_DEVICE_CONFIG_CHANGE = 103;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700229 // end of messages handled under wakelock
Eric Laurentafbb0472011-12-15 09:04:23 -0800230
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -0700231 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
Eric Laurentdc03c612011-04-01 10:59:41 -0700232 // Timeout for connection to bluetooth headset service
233 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
234
Eric Laurent0867bed2015-05-20 14:49:08 -0700235 // retry delay in case of failure to indicate system ready to AudioFlinger
236 private static final int INDICATE_SYSTEM_READY_RETRY_DELAY_MS = 1000;
237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238 /** @see AudioSystemThread */
239 private AudioSystemThread mAudioSystemThread;
240 /** @see AudioHandler */
241 private AudioHandler mAudioHandler;
242 /** @see VolumeStreamState */
243 private VolumeStreamState[] mStreamStates;
Jason Parekhb1096152009-03-24 17:48:25 -0700244 private SettingsObserver mSettingsObserver;
Eric Laurenta553c252009-07-17 12:17:14 -0700245
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700246 private int mMode = AudioSystem.MODE_NORMAL;
Glenn Kastenba195eb2011-12-13 09:30:40 -0800247 // protects mRingerMode
248 private final Object mSettingsLock = new Object();
Eric Laurent45c90ce2012-04-24 18:44:22 -0700249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 private SoundPool mSoundPool;
Glenn Kasten30c918c2011-11-10 17:56:41 -0800251 private final Object mSoundEffectsLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252 private static final int NUM_SOUNDPOOL_CHANNELS = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253
254 /* Sound effect file names */
255 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
Eric Laurente78fced2013-03-15 16:03:47 -0700256 private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257
258 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
259 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
260 * uses soundpool (second column) */
Eric Laurente78fced2013-03-15 16:03:47 -0700261 private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800262
John Spurlockb6e19e32015-03-10 21:33:44 -0400263 /** Maximum volume index values for audio streams */
Eric Laurent91377de2014-10-10 15:24:04 -0700264 private static int[] MAX_STREAM_VOLUME = new int[] {
Eric Laurent6ee99522009-08-25 06:30:59 -0700265 5, // STREAM_VOICE_CALL
266 7, // STREAM_SYSTEM
267 7, // STREAM_RING
268 15, // STREAM_MUSIC
269 7, // STREAM_ALARM
270 7, // STREAM_NOTIFICATION
271 15, // STREAM_BLUETOOTH_SCO
272 7, // STREAM_SYSTEM_ENFORCED
273 15, // STREAM_DTMF
274 15 // STREAM_TTS
Jared Suttles59820132009-08-13 21:50:52 -0500275 };
Eric Laurent91377de2014-10-10 15:24:04 -0700276
John Spurlockb6e19e32015-03-10 21:33:44 -0400277 /** Minimum volume index values for audio streams */
278 private static int[] MIN_STREAM_VOLUME = new int[] {
279 1, // STREAM_VOICE_CALL
280 0, // STREAM_SYSTEM
281 0, // STREAM_RING
282 0, // STREAM_MUSIC
283 0, // STREAM_ALARM
284 0, // STREAM_NOTIFICATION
Eric Laurente4381ec2015-10-29 17:52:48 -0700285 0, // STREAM_BLUETOOTH_SCO
John Spurlockb6e19e32015-03-10 21:33:44 -0400286 0, // STREAM_SYSTEM_ENFORCED
287 0, // STREAM_DTMF
288 0 // STREAM_TTS
289 };
290
Eric Laurent6d517662012-04-23 18:42:39 -0700291 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
Eric Laurenta553c252009-07-17 12:17:14 -0700292 * of another stream: This avoids multiplying the volume settings for hidden
293 * stream types that follow other stream behavior for volume settings
Eric Laurent6d517662012-04-23 18:42:39 -0700294 * NOTE: do not create loops in aliases!
295 * Some streams alias to different streams according to device category (phone or tablet) or
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700296 * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
Eric Laurent212532b2014-07-21 15:43:18 -0700297 * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
298 * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
299 * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
300 private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700301 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
302 AudioSystem.STREAM_RING, // STREAM_SYSTEM
303 AudioSystem.STREAM_RING, // STREAM_RING
304 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
305 AudioSystem.STREAM_ALARM, // STREAM_ALARM
306 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
307 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
308 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
309 AudioSystem.STREAM_RING, // STREAM_DTMF
310 AudioSystem.STREAM_MUSIC // STREAM_TTS
Eric Laurenta553c252009-07-17 12:17:14 -0700311 };
Eric Laurent212532b2014-07-21 15:43:18 -0700312 private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
313 AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL
314 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
315 AudioSystem.STREAM_MUSIC, // STREAM_RING
316 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
317 AudioSystem.STREAM_MUSIC, // STREAM_ALARM
318 AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
319 AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO
320 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
321 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
322 AudioSystem.STREAM_MUSIC // STREAM_TTS
323 };
324 private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700325 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
John Spurlock4f0f1202014-08-05 13:28:33 -0400326 AudioSystem.STREAM_RING, // STREAM_SYSTEM
Eric Laurent6d517662012-04-23 18:42:39 -0700327 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
John Spurlock4f0f1202014-08-05 13:28:33 -0400332 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
333 AudioSystem.STREAM_RING, // STREAM_DTMF
Eric Laurent6d517662012-04-23 18:42:39 -0700334 AudioSystem.STREAM_MUSIC // STREAM_TTS
335 };
336 private int[] mStreamVolumeAlias;
Eric Laurenta553c252009-07-17 12:17:14 -0700337
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700338 /**
339 * Map AudioSystem.STREAM_* constants to app ops. This should be used
340 * after mapping through mStreamVolumeAlias.
341 */
John Spurlock59dc9c12015-03-02 11:20:15 -0500342 private static final int[] STREAM_VOLUME_OPS = new int[] {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700343 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL
344 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM
345 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING
346 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC
347 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM
348 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION
349 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO
350 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED
351 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF
352 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS
353 };
354
Eric Laurent83a017b2013-03-19 18:15:31 -0700355 private final boolean mUseFixedVolume;
356
Glenn Kasten30c918c2011-11-10 17:56:41 -0800357 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 public void onError(int error) {
359 switch (error) {
360 case AudioSystem.AUDIO_STATUS_SERVER_DIED:
Andy Hunged0ea402015-10-30 14:11:46 -0700361 sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED,
Eric Laurentdfb881f2013-07-18 14:41:39 -0700362 SENDMSG_NOOP, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 break;
364 default:
365 break;
366 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700367 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 };
369
370 /**
371 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
372 * {@link AudioManager#RINGER_MODE_SILENT}, or
373 * {@link AudioManager#RINGER_MODE_VIBRATE}.
374 */
Glenn Kastenba195eb2011-12-13 09:30:40 -0800375 // protected by mSettingsLock
John Spurlock661f2cf2014-11-17 10:29:10 -0500376 private int mRingerMode; // internal ringer mode, affects muting of underlying streams
377 private int mRingerModeExternal = -1; // reported ringer mode to outside clients (AudioManager)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378
Eric Laurent9bcf4012009-06-12 06:09:28 -0700379 /** @see System#MODE_RINGER_STREAMS_AFFECTED */
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700380 private int mRingerModeAffectedStreams = 0;
Eric Laurent9bcf4012009-06-12 06:09:28 -0700381
Eric Laurent5b4e6542010-03-19 20:02:21 -0700382 // Streams currently muted by ringer mode
383 private int mRingerModeMutedStreams;
384
John Spurlock3ce37252015-02-17 13:20:45 -0500385 /** Streams that can be muted. Do not resolve to aliases when checking.
386 * @see System#MUTE_STREAMS_AFFECTED */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 private int mMuteAffectedStreams;
388
389 /**
Eric Laurentbffc3d12012-05-07 17:43:49 -0700390 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
391 * mVibrateSetting is just maintained during deprecation period but vibration policy is
392 * now only controlled by mHasVibrator and mRingerMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 */
394 private int mVibrateSetting;
395
Eric Laurentbffc3d12012-05-07 17:43:49 -0700396 // Is there a vibrator
397 private final boolean mHasVibrator;
398
Eric Laurenta553c252009-07-17 12:17:14 -0700399 // Broadcast receiver for device connections intent broadcasts
400 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
401
Makoto Onukid45a4a22015-11-02 17:17:38 -0800402 /** Interface for UserManagerService. */
403 private final UserManagerInternal mUserManagerInternal;
404
405 private final UserRestrictionsListener mUserRestrictionsListener =
406 new AudioServiceUserRestrictionsListener();
407
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700408 // Devices currently connected
Paul McLean394a8e12015-03-03 10:29:19 -0700409 // Use makeDeviceListKey() to make a unique key for this list.
410 private class DeviceListSpec {
411 int mDeviceType;
412 String mDeviceName;
413 String mDeviceAddress;
414
415 public DeviceListSpec(int deviceType, String deviceName, String deviceAddress) {
416 mDeviceType = deviceType;
417 mDeviceName = deviceName;
418 mDeviceAddress = deviceAddress;
419 }
420
421 public String toString() {
422 return "[type:0x" + Integer.toHexString(mDeviceType) + " name:" + mDeviceName
423 + " address:" + mDeviceAddress + "]";
424 }
425 }
426
427 // Generate a unique key for the mConnectedDevices List by composing the device "type"
428 // and the "address" associated with a specific instance of that device type
429 private String makeDeviceListKey(int device, String deviceAddress) {
430 return "0x" + Integer.toHexString(device) + ":" + deviceAddress;
431 }
432
John Spurlock8c3dc852015-04-23 21:32:37 -0400433 private final ArrayMap<String, DeviceListSpec> mConnectedDevices = new ArrayMap<>();
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700434
435 // Forced device usage for communications
436 private int mForcedUseForComm;
437
Eric Laurent9272b4b2010-01-23 17:12:59 -0800438 // List of binder death handlers for setMode() client processes.
439 // The last process to have called setMode() is at the top of the list.
Glenn Kasten30c918c2011-11-10 17:56:41 -0800440 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
Eric Laurenteb14a782009-12-17 03:12:59 -0800441
Eric Laurent3def1ee2010-03-17 23:26:26 -0700442 // List of clients having issued a SCO start request
Glenn Kasten30c918c2011-11-10 17:56:41 -0800443 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
Eric Laurent3def1ee2010-03-17 23:26:26 -0700444
445 // BluetoothHeadset API to control SCO connection
446 private BluetoothHeadset mBluetoothHeadset;
447
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700448 // Bluetooth headset device
449 private BluetoothDevice mBluetoothHeadsetDevice;
Eric Laurent3def1ee2010-03-17 23:26:26 -0700450
Eric Laurent62ef7672010-11-24 10:58:32 -0800451 // Indicate if SCO audio connection is currently active and if the initiator is
452 // audio service (internal) or bluetooth headset (external)
453 private int mScoAudioState;
454 // SCO audio state is not active
455 private static final int SCO_STATE_INACTIVE = 0;
Eric Laurentdc03c612011-04-01 10:59:41 -0700456 // SCO audio activation request waiting for headset service to connect
457 private static final int SCO_STATE_ACTIVATE_REQ = 1;
Eric Laurent25fc29b2013-04-05 12:13:54 -0700458 // SCO audio state is active or starting due to a request from AudioManager API
Eric Laurentdc03c612011-04-01 10:59:41 -0700459 private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
460 // SCO audio deactivation request waiting for headset service to connect
461 private static final int SCO_STATE_DEACTIVATE_REQ = 5;
462
Eric Laurent62ef7672010-11-24 10:58:32 -0800463 // SCO audio state is active due to an action in BT handsfree (either voice recognition or
464 // in call audio)
465 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
Eric Laurentdc03c612011-04-01 10:59:41 -0700466 // Deactivation request for all SCO connections (initiated by audio mode change)
467 // waiting for headset service to connect
468 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
469
Eric Laurentc18c9132013-04-12 17:24:56 -0700470 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
471 // originated from an app targeting an API version before JB MR2 and raw audio after that.
472 private int mScoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -0700473 // SCO audio mode is undefined
474 private static final int SCO_MODE_UNDEFINED = -1;
Eric Laurentc18c9132013-04-12 17:24:56 -0700475 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
476 private static final int SCO_MODE_VIRTUAL_CALL = 0;
477 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
478 private static final int SCO_MODE_RAW = 1;
Liejun Taof4e51d82014-07-16 11:18:29 -0700479 // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
480 private static final int SCO_MODE_VR = 2;
481
482 private static final int SCO_MODE_MAX = 2;
Eric Laurentc18c9132013-04-12 17:24:56 -0700483
Eric Laurentdc03c612011-04-01 10:59:41 -0700484 // Current connection state indicated by bluetooth headset
485 private int mScoConnectionState;
Eric Laurent62ef7672010-11-24 10:58:32 -0800486
Eric Laurenta60e2122010-12-28 16:49:07 -0800487 // true if boot sequence has been completed
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700488 private boolean mSystemReady;
Yasuhiro Matsuda4ced7192015-07-10 22:08:44 +0900489 // true if Intent.ACTION_USER_SWITCHED has ever been received
490 private boolean mUserSwitchedReceived;
Eric Laurenta60e2122010-12-28 16:49:07 -0800491 // listener for SoundPool sample load completion indication
492 private SoundPoolCallback mSoundPoolCallBack;
493 // thread for SoundPool listener
494 private SoundPoolListenerThread mSoundPoolListenerThread;
495 // message looper for SoundPool listener
496 private Looper mSoundPoolLooper = null;
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700497 // volume applied to sound played with playSoundEffect()
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700498 private static int sSoundEffectVolumeDb;
Eric Laurent25101b02011-02-02 09:33:30 -0800499 // previous volume adjustment direction received by checkForRingerModeChange()
500 private int mPrevVolDirection = AudioManager.ADJUST_SAME;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700501 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
502 // is controlled by Vol keys.
503 private int mVolumeControlStream = -1;
504 private final Object mForceControlStreamLock = new Object();
505 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
506 // server process so in theory it is not necessary to monitor the client death.
507 // However it is good to be ready for future evolutions.
508 private ForceControlStreamClient mForceControlStreamClient = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700509 // Used to play ringtones outside system_server
510 private volatile IRingtonePlayer mRingtonePlayer;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800511
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700512 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
513
Eric Laurent78472112012-05-21 08:57:21 -0700514 // Request to override default use of A2DP for media.
Sungsoo486f7d32016-09-28 16:20:52 +0900515 private boolean mBluetoothA2dpEnabled;
Eric Laurent78472112012-05-21 08:57:21 -0700516 private final Object mBluetoothA2dpEnabledLock = new Object();
517
Dianne Hackborn632ca412012-06-14 19:34:10 -0700518 // Monitoring of audio routes. Protected by mCurAudioRoutes.
519 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
520 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
521 = new RemoteCallbackList<IAudioRoutesObserver>();
522
Eric Laurent4bbcc652012-09-24 14:26:30 -0700523 // Devices for which the volume is fixed and VolumePanel slider should be disabled
Eric Laurent212532b2014-07-21 15:43:18 -0700524 int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700525 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Eric Laurent212532b2014-07-21 15:43:18 -0700526 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
527 AudioSystem.DEVICE_OUT_HDMI_ARC |
528 AudioSystem.DEVICE_OUT_SPDIF |
529 AudioSystem.DEVICE_OUT_AUX_LINE;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700530 int mFullVolumeDevices = 0;
Eric Laurent4bbcc652012-09-24 14:26:30 -0700531
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700532 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700533 private final boolean mMonitorOrientation;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700534 private final boolean mMonitorRotation;
Eric Laurentd640bd32012-09-28 18:01:48 -0700535
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700536 private boolean mDockAudioMediaEnabled = true;
537
Eric Laurent08ed1b92012-11-05 14:54:12 -0800538 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
539
Eric Laurentfde16d52012-12-03 14:42:39 -0800540 // Used when safe volume warning message display is requested by setStreamVolume(). In this
541 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
542 // and used later when/if disableSafeMediaVolume() is called.
543 private StreamVolumeCommand mPendingVolumeCommand;
544
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700545 private PowerManager.WakeLock mAudioEventWakeLock;
546
547 private final MediaFocusControl mMediaFocusControl;
548
John Du5a0cf7a2013-07-19 11:30:34 -0700549 // Reference to BluetoothA2dp to query for AbsoluteVolume.
550 private BluetoothA2dp mA2dp;
seunghwan.hong4fe77952014-10-29 17:43:20 +0900551 // lock always taken synchronized on mConnectedDevices
John Du5a0cf7a2013-07-19 11:30:34 -0700552 private final Object mA2dpAvrcpLock = new Object();
553 // If absolute volume is supported in AVRCP device
554 private boolean mAvrcpAbsVolSupported = false;
555
Eric Laurentadbe8bf2014-11-03 18:26:32 -0800556 private static Long mLastDeviceConnectMsgTime = new Long(0);
557
Julia Reynolds48034f82016-03-09 10:15:16 -0500558 private NotificationManager mNm;
John Spurlock661f2cf2014-11-17 10:29:10 -0500559 private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
John Spurlocka48d7792015-03-03 17:35:57 -0500560 private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
John Spurlock07e72432015-03-13 11:46:52 -0400561 private long mLoweredFromNormalToVibrateTime;
John Spurlock661f2cf2014-11-17 10:29:10 -0500562
Paul McLean10804eb2015-01-28 11:16:35 -0800563 // Intent "extra" data keys.
564 public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName";
565 public static final String CONNECT_INTENT_KEY_STATE = "state";
566 public static final String CONNECT_INTENT_KEY_ADDRESS = "address";
567 public static final String CONNECT_INTENT_KEY_HAS_PLAYBACK = "hasPlayback";
568 public static final String CONNECT_INTENT_KEY_HAS_CAPTURE = "hasCapture";
569 public static final String CONNECT_INTENT_KEY_HAS_MIDI = "hasMIDI";
570 public static final String CONNECT_INTENT_KEY_DEVICE_CLASS = "class";
571
572 // Defines the format for the connection "address" for ALSA devices
573 public static String makeAlsaAddressString(int card, int device) {
574 return "card=" + card + ";device=" + device + ";";
575 }
576
Makoto Onukie1aef852015-10-15 17:28:35 -0700577 public static final class Lifecycle extends SystemService {
578 private AudioService mService;
579
580 public Lifecycle(Context context) {
581 super(context);
582 mService = new AudioService(context);
583 }
584
585 @Override
586 public void onStart() {
587 publishBinderService(Context.AUDIO_SERVICE, mService);
588 }
589
590 @Override
591 public void onBootPhase(int phase) {
592 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
593 mService.systemReady();
594 }
595 }
596 }
597
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 ///////////////////////////////////////////////////////////////////////////
599 // Construction
600 ///////////////////////////////////////////////////////////////////////////
601
602 /** @hide */
603 public AudioService(Context context) {
604 mContext = context;
605 mContentResolver = context.getContentResolver();
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700606 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700607
John Spurlock61560172015-02-06 19:46:04 -0500608 mPlatformType = AudioSystem.getPlatformType(context);
Jared Suttles59820132009-08-13 21:50:52 -0500609
Makoto Onukid45a4a22015-11-02 17:17:38 -0800610 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
611
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700612 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700613 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700614
Eric Laurentbffc3d12012-05-07 17:43:49 -0700615 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
616 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
617
John Spurlockb6e19e32015-03-10 21:33:44 -0400618 // Initialize volume
Eric Laurent91377de2014-10-10 15:24:04 -0700619 int maxVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps",
620 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
621 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
622 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500623 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700624 }
625 maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
626 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
627 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
628 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500629 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700630 }
Jared Suttles59820132009-08-13 21:50:52 -0500631
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700632 sSoundEffectVolumeDb = context.getResources().getInteger(
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700633 com.android.internal.R.integer.config_soundEffectVolumeDb);
Eric Laurent25101b02011-02-02 09:33:30 -0800634
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700635 mForcedUseForComm = AudioSystem.FORCE_NONE;
Eric Laurentdd45d012012-10-08 09:04:34 -0700636
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 createAudioSystemThread();
Eric Laurentdd45d012012-10-08 09:04:34 -0700638
Eric Laurentdfb881f2013-07-18 14:41:39 -0700639 AudioSystem.setErrorCallback(mAudioSystemCallback);
640
John Spurlock5e783732015-02-19 10:28:59 -0500641 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -0700642 mCameraSoundForced = new Boolean(cameraSoundForced);
643 sendMsg(mAudioHandler,
644 MSG_SET_FORCE_USE,
645 SENDMSG_QUEUE,
646 AudioSystem.FOR_SYSTEM,
647 cameraSoundForced ?
648 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
649 null,
650 0);
651
Eric Laurent05274f32012-11-29 12:48:18 -0800652 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
653 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
654 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
655 // The default safe volume index read here will be replaced by the actual value when
656 // the mcc is read by onConfigureSafeVolume()
657 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
658 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
659
Eric Laurent83a017b2013-03-19 18:15:31 -0700660 mUseFixedVolume = mContext.getResources().getBoolean(
661 com.android.internal.R.bool.config_useFixedVolume);
662
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700663 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
664 // array initialized by updateStreamVolumeAlias()
John Spurlock90874332015-03-10 16:00:54 -0400665 updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 readPersistedSettings();
Eric Laurentc0232482016-03-15 18:19:23 -0700667 readUserRestrictions();
Eric Laurentc1d41662011-07-19 11:21:13 -0700668 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700669 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700670
Jean-Michel Trivid4de20d2015-11-04 14:45:54 -0800671 mMediaFocusControl = new MediaFocusControl(mContext);
John Spurlockb6e19e32015-03-10 21:33:44 -0400672
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700673 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700674
675 // Call setRingerModeInt() to apply correct mute
676 // state on streams affected by ringer mode.
677 mRingerModeMutedStreams = 0;
John Spurlock661f2cf2014-11-17 10:29:10 -0500678 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3891c4c2010-04-20 09:40:57 -0700679
Eric Laurenta553c252009-07-17 12:17:14 -0700680 // Register for device connection intent broadcasts.
681 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700682 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700683 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
684 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700685 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
686 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700687 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700688 intentFilter.addAction(Intent.ACTION_USER_BACKGROUND);
689 intentFilter.addAction(Intent.ACTION_USER_FOREGROUND);
Paul McLeanc837a452014-04-09 09:04:43 -0700690 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Eric Laurentb70b78a2016-01-13 19:16:04 -0800691 intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700692
Eric Laurentd640bd32012-09-28 18:01:48 -0700693 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700694 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700695 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
696 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700697 Log.v(TAG, "monitoring device orientation");
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700698 // initialize orientation in AudioSystem
699 setOrientationForAudioSystem();
700 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700701 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
702 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -0700703 RotationHelper.init(mContext, mAudioHandler);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700704 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700705
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700706 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null);
Jared Suttles59820132009-08-13 21:50:52 -0500707
RoboErik0dac35a2014-08-12 15:48:49 -0700708 LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
Makoto Onukid45a4a22015-11-02 17:17:38 -0800709
710 mUserManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -0800711
712 mRecordMonitor.initMonitor();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 }
714
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700715 public void systemReady() {
716 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
717 0, 0, null, 0);
718 }
719
720 public void onSystemReady() {
721 mSystemReady = true;
722 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
723 0, 0, null, 0);
724
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700725 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
726 resetBluetoothSco();
727 getBluetoothHeadset();
728 //FIXME: this is to maintain compatibility with deprecated intent
729 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
730 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
731 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
732 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
733 sendStickyBroadcastToAll(newIntent);
734
735 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
736 if (adapter != null) {
737 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
738 BluetoothProfile.A2DP);
739 }
740
Eric Laurent212532b2014-07-21 15:43:18 -0700741 mHdmiManager =
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900742 (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700743 if (mHdmiManager != null) {
744 synchronized (mHdmiManager) {
745 mHdmiTvClient = mHdmiManager.getTvClient();
Jungshik Jangc9ff9682014-09-15 17:41:06 +0900746 if (mHdmiTvClient != null) {
747 mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
748 }
Eric Laurent212532b2014-07-21 15:43:18 -0700749 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
750 mHdmiCecSink = false;
751 }
752 }
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900753
Julia Reynolds48034f82016-03-09 10:15:16 -0500754 mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
755
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700756 sendMsg(mAudioHandler,
757 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
758 SENDMSG_REPLACE,
759 0,
760 0,
John Spurlock90874332015-03-10 16:00:54 -0400761 TAG,
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700762 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700763
764 StreamOverride.init(mContext);
John Spurlockcdb57ae2015-02-11 19:04:11 -0500765 mControllerService.init();
Eric Laurent0867bed2015-05-20 14:49:08 -0700766 onIndicateSystemReady();
767 }
768
769 void onIndicateSystemReady() {
770 if (AudioSystem.systemReady() == AudioSystem.SUCCESS) {
771 return;
772 }
773 sendMsg(mAudioHandler,
774 MSG_INDICATE_SYSTEM_READY,
775 SENDMSG_REPLACE,
776 0,
777 0,
778 null,
779 INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
780 }
781
Andy Hunged0ea402015-10-30 14:11:46 -0700782 public void onAudioServerDied() {
Eric Laurent0867bed2015-05-20 14:49:08 -0700783 if (!mSystemReady ||
784 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Andy Hunged0ea402015-10-30 14:11:46 -0700785 Log.e(TAG, "Audioserver died.");
786 sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent0867bed2015-05-20 14:49:08 -0700787 null, 500);
788 return;
789 }
Andy Hunged0ea402015-10-30 14:11:46 -0700790 Log.e(TAG, "Audioserver started.");
Eric Laurent0867bed2015-05-20 14:49:08 -0700791
792 // indicate to audio HAL that we start the reconfiguration phase after a media
793 // server crash
794 // Note that we only execute this when the media server
795 // process restarts after a crash, not the first time it is started.
796 AudioSystem.setParameters("restarting=true");
797
798 readAndSetLowRamDevice();
799
800 // Restore device connection states
801 synchronized (mConnectedDevices) {
802 for (int i = 0; i < mConnectedDevices.size(); i++) {
803 DeviceListSpec spec = mConnectedDevices.valueAt(i);
804 AudioSystem.setDeviceConnectionState(
805 spec.mDeviceType,
806 AudioSystem.DEVICE_STATE_AVAILABLE,
807 spec.mDeviceAddress,
808 spec.mDeviceName);
809 }
810 }
811 // Restore call state
812 AudioSystem.setPhoneState(mMode);
813
814 // Restore forced usage for communcations and record
815 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
816 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
817 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
818 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
819
820 // Restore stream volumes
821 int numStreamTypes = AudioSystem.getNumStreamTypes();
822 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
823 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurente4381ec2015-10-29 17:52:48 -0700824 AudioSystem.initStreamVolume(
825 streamType, streamState.mIndexMin / 10, streamState.mIndexMax / 10);
Eric Laurent0867bed2015-05-20 14:49:08 -0700826
827 streamState.applyAllVolumes();
828 }
829
Andy Hungf04b84d2015-12-18 17:33:27 -0800830 // Restore mono mode
Andy Hung7b98e9a2016-02-25 18:34:50 -0800831 updateMasterMono(mContentResolver);
Andy Hungf04b84d2015-12-18 17:33:27 -0800832
Eric Laurent0867bed2015-05-20 14:49:08 -0700833 // Restore ringer mode
834 setRingerModeInt(getRingerModeInternal(), false);
835
836 // Reset device orientation (if monitored for this device)
837 if (mMonitorOrientation) {
838 setOrientationForAudioSystem();
839 }
840 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -0700841 RotationHelper.updateOrientation();
Eric Laurent0867bed2015-05-20 14:49:08 -0700842 }
843
Sungsoocf09fe62016-09-28 16:21:48 +0900844 synchronized (mBluetoothA2dpEnabledLock) {
845 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
846 mBluetoothA2dpEnabled ?
847 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
848 }
849
Eric Laurent0867bed2015-05-20 14:49:08 -0700850 synchronized (mSettingsLock) {
851 AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
852 mDockAudioMediaEnabled ?
853 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
Phil Burked43bf52016-03-01 17:01:35 -0800854 sendEncodedSurroundMode(mContentResolver);
Eric Laurent0867bed2015-05-20 14:49:08 -0700855 }
856 if (mHdmiManager != null) {
857 synchronized (mHdmiManager) {
858 if (mHdmiTvClient != null) {
859 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
860 }
861 }
862 }
863
864 synchronized (mAudioPolicies) {
865 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
866 policy.connectMixes();
867 }
868 }
869
870 onIndicateSystemReady();
871 // indicate the end of reconfiguration phase to audio HAL
872 AudioSystem.setParameters("restarting=false");
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700873 }
874
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 private void createAudioSystemThread() {
876 mAudioSystemThread = new AudioSystemThread();
877 mAudioSystemThread.start();
878 waitForAudioHandlerCreation();
879 }
880
881 /** Waits for the volume handler to be created by the other thread. */
882 private void waitForAudioHandlerCreation() {
883 synchronized(this) {
884 while (mAudioHandler == null) {
885 try {
886 // Wait for mAudioHandler to be set by the other thread
887 wait();
888 } catch (InterruptedException e) {
889 Log.e(TAG, "Interrupted while waiting on volume handler.");
890 }
891 }
892 }
893 }
894
Eric Laurent24482012012-05-10 09:41:17 -0700895 private void checkAllAliasStreamVolumes() {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700896 synchronized (VolumeStreamState.class) {
897 int numStreamTypes = AudioSystem.getNumStreamTypes();
898 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
899 if (streamType != mStreamVolumeAlias[streamType]) {
900 mStreamStates[streamType].
John Spurlock90874332015-03-10 16:00:54 -0400901 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]],
902 TAG);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700903 }
904 // apply stream volume
RoboErik4197cb62015-01-21 15:45:32 -0800905 if (!mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700906 mStreamStates[streamType].applyAllVolumes();
907 }
Eric Laurent24482012012-05-10 09:41:17 -0700908 }
909 }
910 }
911
Eric Laurent212532b2014-07-21 15:43:18 -0700912 private void checkAllFixedVolumeDevices()
913 {
914 int numStreamTypes = AudioSystem.getNumStreamTypes();
915 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
916 mStreamStates[streamType].checkFixedVolumeDevices();
917 }
918 }
919
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700920 private void checkAllFixedVolumeDevices(int streamType) {
921 mStreamStates[streamType].checkFixedVolumeDevices();
922 }
923
John Spurlockb6e19e32015-03-10 21:33:44 -0400924 private void checkMuteAffectedStreams() {
925 // any stream with a min level > 0 is not muteable by definition
926 for (int i = 0; i < mStreamStates.length; i++) {
927 final VolumeStreamState vss = mStreamStates[i];
928 if (vss.mIndexMin > 0) {
929 mMuteAffectedStreams &= ~(1 << vss.mStreamType);
930 }
931 }
932 }
933
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800934 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935 int numStreamTypes = AudioSystem.getNumStreamTypes();
936 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
937
938 for (int i = 0; i < numStreamTypes; i++) {
Eric Laurent6d517662012-04-23 18:42:39 -0700939 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -0700940 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941
Eric Laurent212532b2014-07-21 15:43:18 -0700942 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -0700943 checkAllAliasStreamVolumes();
John Spurlockb6e19e32015-03-10 21:33:44 -0400944 checkMuteAffectedStreams();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 }
946
Eric Laurentbffc3d12012-05-07 17:43:49 -0700947 private void dumpStreamStates(PrintWriter pw) {
948 pw.println("\nStream volumes (device: index)");
949 int numStreamTypes = AudioSystem.getNumStreamTypes();
950 for (int i = 0; i < numStreamTypes; i++) {
John Spurlock61560172015-02-06 19:46:04 -0500951 pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":");
Eric Laurentbffc3d12012-05-07 17:43:49 -0700952 mStreamStates[i].dump(pw);
953 pw.println("");
954 }
Eric Laurentdd45d012012-10-08 09:04:34 -0700955 pw.print("\n- mute affected streams = 0x");
956 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -0700957 }
958
John Spurlock90874332015-03-10 16:00:54 -0400959 private void updateStreamVolumeAlias(boolean updateVolumes, String caller) {
Eric Laurent6d517662012-04-23 18:42:39 -0700960 int dtmfStreamAlias;
Eric Laurent212532b2014-07-21 15:43:18 -0700961
962 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -0500963 case AudioSystem.PLATFORM_VOICE:
Eric Laurent212532b2014-07-21 15:43:18 -0700964 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
Eric Laurent6d517662012-04-23 18:42:39 -0700965 dtmfStreamAlias = AudioSystem.STREAM_RING;
Eric Laurent212532b2014-07-21 15:43:18 -0700966 break;
John Spurlock61560172015-02-06 19:46:04 -0500967 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -0700968 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
969 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
970 break;
971 default:
972 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
Eric Laurent6d517662012-04-23 18:42:39 -0700973 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
974 }
Eric Laurent212532b2014-07-21 15:43:18 -0700975
976 if (isPlatformTelevision()) {
977 mRingerModeAffectedStreams = 0;
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700978 } else {
Eric Laurent212532b2014-07-21 15:43:18 -0700979 if (isInCommunication()) {
980 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
981 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
982 } else {
983 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
984 }
Eric Laurent6d517662012-04-23 18:42:39 -0700985 }
Eric Laurent212532b2014-07-21 15:43:18 -0700986
Eric Laurent6d517662012-04-23 18:42:39 -0700987 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
988 if (updateVolumes) {
John Spurlock90874332015-03-10 16:00:54 -0400989 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
990 caller);
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700991 // apply stream mute states according to new value of mRingerModeAffectedStreams
John Spurlock661f2cf2014-11-17 10:29:10 -0500992 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent6d517662012-04-23 18:42:39 -0700993 sendMsg(mAudioHandler,
994 MSG_SET_ALL_VOLUMES,
995 SENDMSG_QUEUE,
996 0,
997 0,
998 mStreamStates[AudioSystem.STREAM_DTMF], 0);
999 }
1000 }
1001
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001002 private void readDockAudioSettings(ContentResolver cr)
1003 {
1004 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -07001005 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001006
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001007 sendMsg(mAudioHandler,
1008 MSG_SET_FORCE_USE,
1009 SENDMSG_QUEUE,
1010 AudioSystem.FOR_DOCK,
1011 mDockAudioMediaEnabled ?
1012 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
1013 null,
1014 0);
1015 }
1016
Phil Burkac0f7042016-02-24 12:19:08 -08001017
Andy Hung7b98e9a2016-02-25 18:34:50 -08001018 private void updateMasterMono(ContentResolver cr)
1019 {
1020 final boolean masterMono = System.getIntForUser(
1021 cr, System.MASTER_MONO, 0 /* default */, UserHandle.USER_CURRENT) == 1;
1022 if (DEBUG_VOL) {
1023 Log.d(TAG, String.format("Master mono %b", masterMono));
1024 }
1025 AudioSystem.setMasterMono(masterMono);
1026 }
1027
Phil Burked43bf52016-03-01 17:01:35 -08001028 private void sendEncodedSurroundMode(ContentResolver cr)
Phil Burkac0f7042016-02-24 12:19:08 -08001029 {
1030 int encodedSurroundMode = Settings.Global.getInt(
1031 cr, Settings.Global.ENCODED_SURROUND_OUTPUT,
1032 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
1033 sendEncodedSurroundMode(encodedSurroundMode);
1034 }
1035
1036 private void sendEncodedSurroundMode(int encodedSurroundMode)
1037 {
1038 // initialize to guaranteed bad value
1039 int forceSetting = AudioSystem.NUM_FORCE_CONFIG;
1040 switch (encodedSurroundMode) {
1041 case Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO:
1042 forceSetting = AudioSystem.FORCE_NONE;
1043 break;
1044 case Settings.Global.ENCODED_SURROUND_OUTPUT_NEVER:
1045 forceSetting = AudioSystem.FORCE_ENCODED_SURROUND_NEVER;
1046 break;
1047 case Settings.Global.ENCODED_SURROUND_OUTPUT_ALWAYS:
1048 forceSetting = AudioSystem.FORCE_ENCODED_SURROUND_ALWAYS;
1049 break;
1050 default:
1051 Log.e(TAG, "updateSurroundSoundSettings: illegal value "
1052 + encodedSurroundMode);
1053 break;
1054 }
1055 if (forceSetting != AudioSystem.NUM_FORCE_CONFIG) {
1056 sendMsg(mAudioHandler,
1057 MSG_SET_FORCE_USE,
1058 SENDMSG_QUEUE,
1059 AudioSystem.FOR_ENCODED_SURROUND,
1060 forceSetting,
1061 null,
1062 0);
1063 }
1064 }
1065
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066 private void readPersistedSettings() {
1067 final ContentResolver cr = mContentResolver;
1068
Eric Laurentbffc3d12012-05-07 17:43:49 -07001069 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07001070 Settings.Global.getInt(
1071 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -07001072 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -07001073 // sanity check in case the settings are restored from a device with incompatible
1074 // ringer modes
John Spurlock97559372014-10-24 16:27:36 -04001075 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001076 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -07001077 }
1078 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1079 ringerMode = AudioManager.RINGER_MODE_SILENT;
1080 }
1081 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07001082 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -08001083 }
Eric Laurent212532b2014-07-21 15:43:18 -07001084 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001085 ringerMode = AudioManager.RINGER_MODE_NORMAL;
1086 }
Glenn Kastenba195eb2011-12-13 09:30:40 -08001087 synchronized(mSettingsLock) {
1088 mRingerMode = ringerMode;
John Spurlock661f2cf2014-11-17 10:29:10 -05001089 if (mRingerModeExternal == -1) {
1090 mRingerModeExternal = mRingerMode;
1091 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001092
Eric Laurentdd45d012012-10-08 09:04:34 -07001093 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
1094 // are still needed while setVibrateSetting() and getVibrateSetting() are being
1095 // deprecated.
John Spurlock61560172015-02-06 19:46:04 -05001096 mVibrateSetting = AudioSystem.getValueForVibrateSetting(0,
Eric Laurentdd45d012012-10-08 09:04:34 -07001097 AudioManager.VIBRATE_TYPE_NOTIFICATION,
1098 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
1099 : AudioManager.VIBRATE_SETTING_OFF);
John Spurlock61560172015-02-06 19:46:04 -05001100 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting,
Eric Laurentdd45d012012-10-08 09:04:34 -07001101 AudioManager.VIBRATE_TYPE_RINGER,
1102 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
1103 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104
Eric Laurent24e0d9b2013-10-03 18:15:07 -07001105 updateRingerModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001106 readDockAudioSettings(cr);
Phil Burked43bf52016-03-01 17:01:35 -08001107 sendEncodedSurroundMode(cr);
Eric Laurent402f7f22011-02-04 12:30:32 -08001108 }
Eric Laurentc1d41662011-07-19 11:21:13 -07001109
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001110 mMuteAffectedStreams = System.getIntForUser(cr,
John Spurlock61560172015-02-06 19:46:04 -05001111 System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
John Spurlock24c05182015-02-05 12:30:36 -05001112 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001113
Andy Hung7b98e9a2016-02-25 18:34:50 -08001114 updateMasterMono(cr);
Andy Hungf04b84d2015-12-18 17:33:27 -08001115
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116 // Each stream will read its own persisted settings
1117
John Spurlockbcc10872014-11-28 15:29:21 -05001118 // Broadcast the sticky intents
1119 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
1120 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001121
1122 // Broadcast vibrate settings
1123 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
1124 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07001125
John Spurlock33f4e042014-07-11 13:10:58 -04001126 // Load settings for the volume controller
1127 mVolumeController.loadSettings(cr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 }
1129
Eric Laurentc0232482016-03-15 18:19:23 -07001130 private void readUserRestrictions() {
1131 final int currentUser = getCurrentUserId();
1132
1133 // Check the current user restriction.
Tony Makc1205112016-07-22 16:02:59 +01001134 boolean masterMute =
1135 mUserManagerInternal.getUserRestriction(currentUser,
1136 UserManager.DISALLLOW_UNMUTE_DEVICE)
1137 || mUserManagerInternal.getUserRestriction(currentUser,
1138 UserManager.DISALLOW_ADJUST_VOLUME);
Eric Laurentc0232482016-03-15 18:19:23 -07001139 if (mUseFixedVolume) {
1140 masterMute = false;
1141 AudioSystem.setMasterVolume(1.0f);
1142 }
1143 if (DEBUG_VOL) {
1144 Log.d(TAG, String.format("Master mute %s, user=%d", masterMute, currentUser));
1145 }
1146 setSystemAudioMute(masterMute);
1147 AudioSystem.setMasterMute(masterMute);
1148 broadcastMasterMuteStatus(masterMute);
1149
1150 boolean microphoneMute = mUserManagerInternal.getUserRestriction(
1151 currentUser, UserManager.DISALLOW_UNMUTE_MICROPHONE);
1152 if (DEBUG_VOL) {
1153 Log.d(TAG, String.format("Mic mute %s, user=%d", microphoneMute, currentUser));
1154 }
1155 AudioSystem.muteMicrophone(microphoneMute);
1156 }
1157
Eric Laurenta553c252009-07-17 12:17:14 -07001158 private int rescaleIndex(int index, int srcStream, int dstStream) {
1159 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
1160 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161
1162 ///////////////////////////////////////////////////////////////////////////
1163 // IPC methods
1164 ///////////////////////////////////////////////////////////////////////////
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001165 /** @see AudioManager#adjustVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001166 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001167 String callingPackage, String caller) {
RoboErik272e1612014-09-05 11:39:29 -07001168 adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
John Spurlock90874332015-03-10 16:00:54 -04001169 caller, Binder.getCallingUid());
RoboErik272e1612014-09-05 11:39:29 -07001170 }
1171
1172 private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001173 String callingPackage, String caller, int uid) {
1174 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType
1175 + ", flags=" + flags + ", caller=" + caller);
Eric Laurent402f7f22011-02-04 12:30:32 -08001176 int streamType;
RoboErik4197cb62015-01-21 15:45:32 -08001177 boolean isMute = isMuteAdjust(direction);
Eric Laurent45c90ce2012-04-24 18:44:22 -07001178 if (mVolumeControlStream != -1) {
1179 streamType = mVolumeControlStream;
Eric Laurent402f7f22011-02-04 12:30:32 -08001180 } else {
1181 streamType = getActiveStreamType(suggestedStreamType);
1182 }
John Spurlock0a376af2015-03-26 16:24:12 -04001183 ensureValidStreamType(streamType);
John Spurlock33f4e042014-07-11 13:10:58 -04001184 final int resolvedStream = mStreamVolumeAlias[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001185
RoboErik2811dd32014-08-12 09:48:13 -07001186 // Play sounds on STREAM_RING only.
1187 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
John Spurlock33f4e042014-07-11 13:10:58 -04001188 resolvedStream != AudioSystem.STREAM_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189 flags &= ~AudioManager.FLAG_PLAY_SOUND;
1190 }
1191
John Spurlock33f4e042014-07-11 13:10:58 -04001192 // For notifications/ring, show the ui before making any adjustments
RoboErik4197cb62015-01-21 15:45:32 -08001193 // Don't suppress mute/unmute requests
1194 if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
John Spurlock33f4e042014-07-11 13:10:58 -04001195 direction = 0;
1196 flags &= ~AudioManager.FLAG_PLAY_SOUND;
1197 flags &= ~AudioManager.FLAG_VIBRATE;
1198 if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
1199 }
1200
John Spurlock90874332015-03-10 16:00:54 -04001201 adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 }
1203
1204 /** @see AudioManager#adjustStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001205 public void adjustStreamVolume(int streamType, int direction, int flags,
1206 String callingPackage) {
John Spurlock90874332015-03-10 16:00:54 -04001207 adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage,
1208 Binder.getCallingUid());
RoboErik0dac35a2014-08-12 15:48:49 -07001209 }
1210
1211 private void adjustStreamVolume(int streamType, int direction, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001212 String callingPackage, String caller, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001213 if (mUseFixedVolume) {
1214 return;
1215 }
John Spurlock90874332015-03-10 16:00:54 -04001216 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream=" + streamType + ", dir=" + direction
1217 + ", flags=" + flags + ", caller=" + caller);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07001218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001219 ensureValidDirection(direction);
1220 ensureValidStreamType(streamType);
1221
RoboErik4197cb62015-01-21 15:45:32 -08001222 boolean isMuteAdjust = isMuteAdjust(direction);
1223
John Spurlock3ce37252015-02-17 13:20:45 -05001224 if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
1225 return;
1226 }
1227
Eric Laurent96a33d12011-11-08 10:31:57 -08001228 // use stream type alias here so that streams with same alias have the same behavior,
1229 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
1230 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
Eric Laurent6d517662012-04-23 18:42:39 -07001231 int streamTypeAlias = mStreamVolumeAlias[streamType];
RoboErik4197cb62015-01-21 15:45:32 -08001232
Eric Laurentb024c302011-10-14 17:19:27 -07001233 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001234
1235 final int device = getDeviceForStream(streamTypeAlias);
Eric Laurent3ef75492012-11-28 12:12:23 -08001236
Eric Laurent42b041e2013-03-29 11:36:03 -07001237 int aliasIndex = streamState.getIndex(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001238 boolean adjustVolume = true;
Eric Laurent3ef75492012-11-28 12:12:23 -08001239 int step;
Eric Laurent24482012012-05-10 09:41:17 -07001240
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001241 // skip a2dp absolute volume control request when the device
1242 // is not an a2dp device
1243 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1244 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1245 return;
1246 }
1247
Kenny Guy70e0c582015-06-30 19:18:28 +01001248 // If we are being called by the system (e.g. hardware keys) check for current user
1249 // so we handle user restrictions correctly.
1250 if (uid == android.os.Process.SYSTEM_UID) {
1251 uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
1252 }
John Spurlock59dc9c12015-03-02 11:20:15 -05001253 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001254 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001255 return;
1256 }
1257
Eric Laurentfde16d52012-12-03 14:42:39 -08001258 // reset any pending volume command
1259 synchronized (mSafeMediaVolumeState) {
1260 mPendingVolumeCommand = null;
1261 }
1262
Eric Laurent3ef75492012-11-28 12:12:23 -08001263 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1264 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1265 ((device & mFixedVolumeDevices) != 0)) {
1266 flags |= AudioManager.FLAG_FIXED_VOLUME;
1267
1268 // Always toggle between max safe volume and 0 for fixed volume devices where safe
1269 // volume is enforced, and max and 0 for the others.
1270 // This is simulated by stepping by the full allowed volume range
1271 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1272 (device & mSafeMediaVolumeDevices) != 0) {
1273 step = mSafeMediaVolumeIndex;
1274 } else {
1275 step = streamState.getMaxIndex();
1276 }
1277 if (aliasIndex != 0) {
1278 aliasIndex = step;
1279 }
1280 } else {
1281 // convert one UI step (+/-1) into a number of internal units on the stream alias
1282 step = rescaleIndex(10, streamType, streamTypeAlias);
1283 }
1284
Eric Laurent42b041e2013-03-29 11:36:03 -07001285 // If either the client forces allowing ringer modes for this adjustment,
1286 // or the stream type is one that is affected by ringer modes
1287 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlockee5ad722015-03-03 16:17:21 -05001288 (streamTypeAlias == getUiSoundsStreamType())) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001289 int ringerMode = getRingerModeInternal();
Eric Laurent42b041e2013-03-29 11:36:03 -07001290 // do not vibrate if already in vibrate mode
1291 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
1292 flags &= ~AudioManager.FLAG_VIBRATE;
Eric Laurent3ef75492012-11-28 12:12:23 -08001293 }
RoboErik5452e252015-02-06 15:33:53 -08001294 // Check if the ringer mode handles this adjustment. If it does we don't
1295 // need to adjust the volume further.
John Spurlock50ced3f2015-05-11 16:00:09 -04001296 final int result = checkForRingerModeChange(aliasIndex, direction, step,
Julia Reynoldsed783792016-04-08 15:27:35 -04001297 streamState.mIsMuted, callingPackage, flags);
John Spurlocka11b4af2014-06-01 11:52:23 -04001298 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
1299 // If suppressing a volume adjustment in silent mode, display the UI hint
1300 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
1301 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
1302 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001303 // If suppressing a volume down adjustment in vibrate mode, display the UI hint
1304 if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
1305 flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
1306 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001307 }
John Spurlock50ced3f2015-05-11 16:00:09 -04001308 // If the ringermode is suppressing media, prevent changes
Julia Reynoldsed783792016-04-08 15:27:35 -04001309 if (!volumeAdjustmentAllowedByDnd(streamTypeAlias, flags)) {
John Spurlock50ced3f2015-05-11 16:00:09 -04001310 adjustVolume = false;
1311 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001312 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001313
Eric Laurent42b041e2013-03-29 11:36:03 -07001314 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
RoboErik5452e252015-02-06 15:33:53 -08001315 mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001316
John Du5a0cf7a2013-07-19 11:30:34 -07001317 // Check if volume update should be send to AVRCP
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001318 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1319 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1320 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1321 synchronized (mA2dpAvrcpLock) {
1322 if (mA2dp != null && mAvrcpAbsVolSupported) {
1323 mA2dp.adjustAvrcpAbsoluteVolume(direction);
1324 }
John Du5a0cf7a2013-07-19 11:30:34 -07001325 }
1326 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001327
RoboErik4197cb62015-01-21 15:45:32 -08001328 if (isMuteAdjust) {
1329 boolean state;
1330 if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
1331 state = !streamState.mIsMuted;
1332 } else {
1333 state = direction == AudioManager.ADJUST_MUTE;
1334 }
1335 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1336 setSystemAudioMute(state);
1337 }
1338 for (int stream = 0; stream < mStreamStates.length; stream++) {
1339 if (streamTypeAlias == mStreamVolumeAlias[stream]) {
Sungmin Choi841ed0a2015-07-26 23:09:49 -07001340 if (!(readCameraSoundForced()
1341 && (mStreamStates[stream].getStreamType()
1342 == AudioSystem.STREAM_SYSTEM_ENFORCED))) {
1343 mStreamStates[stream].mute(state);
1344 }
RoboErik4197cb62015-01-21 15:45:32 -08001345 }
1346 }
1347 } else if ((direction == AudioManager.ADJUST_RAISE) &&
Eric Laurent42b041e2013-03-29 11:36:03 -07001348 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
RoboErik4197cb62015-01-21 15:45:32 -08001349 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -04001350 mVolumeController.postDisplaySafeVolumeWarning(flags);
John Spurlock90874332015-03-10 16:00:54 -04001351 } else if (streamState.adjustIndex(direction * step, device, caller)
1352 || streamState.mIsMuted) {
RoboErik4197cb62015-01-21 15:45:32 -08001353 // Post message to set system volume (it in turn will post a
1354 // message to persist).
1355 if (streamState.mIsMuted) {
1356 // Unmute the stream if it was previously muted
RoboErik5452e252015-02-06 15:33:53 -08001357 if (direction == AudioManager.ADJUST_RAISE) {
1358 // unmute immediately for volume up
1359 streamState.mute(false);
1360 } else if (direction == AudioManager.ADJUST_LOWER) {
John Spurlocka48d7792015-03-03 17:35:57 -05001361 if (mPlatformType == AudioSystem.PLATFORM_TELEVISION) {
1362 sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
1363 streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
1364 }
RoboErik5452e252015-02-06 15:33:53 -08001365 }
RoboErik4197cb62015-01-21 15:45:32 -08001366 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001367 sendMsg(mAudioHandler,
1368 MSG_SET_DEVICE_VOLUME,
1369 SENDMSG_QUEUE,
1370 device,
1371 0,
1372 streamState,
1373 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001374 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001375
RoboErik4197cb62015-01-21 15:45:32 -08001376 // Check if volume update should be sent to Hdmi system audio.
Jungshik Jang41d97462014-06-30 22:26:29 +09001377 int newIndex = mStreamStates[streamType].getIndex(device);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001378 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1379 setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
1380 }
Eric Laurent212532b2014-07-21 15:43:18 -07001381 if (mHdmiManager != null) {
1382 synchronized (mHdmiManager) {
Eric Laurent212532b2014-07-21 15:43:18 -07001383 // mHdmiCecSink true => mHdmiPlaybackClient != null
1384 if (mHdmiCecSink &&
1385 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1386 oldIndex != newIndex) {
1387 synchronized (mHdmiPlaybackClient) {
1388 int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
RoboErik4197cb62015-01-21 15:45:32 -08001389 KeyEvent.KEYCODE_VOLUME_UP;
Donghyun Cho5f6d404e2016-03-17 20:39:25 +09001390 final long ident = Binder.clearCallingIdentity();
1391 try {
1392 mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1393 mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1394 } finally {
1395 Binder.restoreCallingIdentity(ident);
1396 }
Eric Laurent212532b2014-07-21 15:43:18 -07001397 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001398 }
1399 }
1400 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001401 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001402 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001403 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 }
1405
RoboErik5452e252015-02-06 15:33:53 -08001406 // Called after a delay when volume down is pressed while muted
1407 private void onUnmuteStream(int stream, int flags) {
1408 VolumeStreamState streamState = mStreamStates[stream];
1409 streamState.mute(false);
1410
1411 final int device = getDeviceForStream(stream);
1412 final int index = mStreamStates[stream].getIndex(device);
1413 sendVolumeUpdate(stream, index, index, flags);
1414 }
1415
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001416 private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
1417 if (mHdmiManager == null
1418 || mHdmiTvClient == null
1419 || oldVolume == newVolume
1420 || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
1421
1422 // Sets the audio volume of AVR when we are in system audio mode. The new volume info
1423 // is tranformed to HDMI-CEC commands and passed through CEC bus.
1424 synchronized (mHdmiManager) {
1425 if (!mHdmiSystemAudioSupported) return;
1426 synchronized (mHdmiTvClient) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001427 final long token = Binder.clearCallingIdentity();
1428 try {
Jinsuk Kim7a9ba422015-02-16 16:47:38 +09001429 mHdmiTvClient.setSystemAudioVolume(oldVolume, newVolume, maxVolume);
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001430 } finally {
1431 Binder.restoreCallingIdentity(token);
1432 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001433 }
1434 }
1435 }
1436
Eric Laurentfde16d52012-12-03 14:42:39 -08001437 // StreamVolumeCommand contains the information needed to defer the process of
1438 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1439 class StreamVolumeCommand {
1440 public final int mStreamType;
1441 public final int mIndex;
1442 public final int mFlags;
1443 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001444
Eric Laurentfde16d52012-12-03 14:42:39 -08001445 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1446 mStreamType = streamType;
1447 mIndex = index;
1448 mFlags = flags;
1449 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001450 }
John Spurlock35134602014-07-24 18:10:48 -04001451
1452 @Override
1453 public String toString() {
1454 return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1455 .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1456 .append(mDevice).append('}').toString();
1457 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001458 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001459
Julia Reynolds48034f82016-03-09 10:15:16 -05001460 private int getNewRingerMode(int stream, int index, int flags) {
John Spurlockee5ad722015-03-03 16:17:21 -05001461 // setting volume on ui sounds stream type also controls silent mode
Eric Laurent3ef75492012-11-28 12:12:23 -08001462 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlock75ae23c2015-06-02 16:26:43 -04001463 (stream == getUiSoundsStreamType())) {
Eric Laurent3ef75492012-11-28 12:12:23 -08001464 int newRingerMode;
1465 if (index == 0) {
1466 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlocka48d7792015-03-03 17:35:57 -05001467 : mVolumePolicy.volumeDownToEnterSilent ? AudioManager.RINGER_MODE_SILENT
Julia Reynolds48034f82016-03-09 10:15:16 -05001468 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001469 } else {
1470 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1471 }
Julia Reynolds48034f82016-03-09 10:15:16 -05001472 return newRingerMode;
1473 }
1474 return getRingerModeExternal();
1475 }
1476
1477 private boolean isAndroidNPlus(String caller) {
1478 try {
1479 final ApplicationInfo applicationInfo =
1480 mContext.getPackageManager().getApplicationInfoAsUser(
1481 caller, 0, UserHandle.getUserId(Binder.getCallingUid()));
1482 if (applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
1483 return true;
1484 }
1485 return false;
1486 } catch (PackageManager.NameNotFoundException e) {
1487 return true;
1488 }
1489 }
1490
1491 private boolean wouldToggleZenMode(int newMode) {
1492 if (getRingerModeExternal() == AudioManager.RINGER_MODE_SILENT
1493 && newMode != AudioManager.RINGER_MODE_SILENT) {
1494 return true;
1495 } else if (getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT
1496 && newMode == AudioManager.RINGER_MODE_SILENT) {
1497 return true;
1498 }
1499 return false;
1500 }
1501
1502 private void onSetStreamVolume(int streamType, int index, int flags, int device,
1503 String caller) {
1504 final int stream = mStreamVolumeAlias[streamType];
1505 setStreamVolumeInt(stream, index, device, false, caller);
1506 // setting volume on ui sounds stream type also controls silent mode
1507 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1508 (stream == getUiSoundsStreamType())) {
1509 setRingerMode(getNewRingerMode(stream, index, flags),
1510 TAG + ".onSetStreamVolume", false /*external*/);
Eric Laurent3ef75492012-11-28 12:12:23 -08001511 }
John Spurlock75ae23c2015-06-02 16:26:43 -04001512 // setting non-zero volume for a muted stream unmutes the stream and vice versa
1513 mStreamStates[stream].mute(index == 0);
Eric Laurentfde16d52012-12-03 14:42:39 -08001514 }
1515
1516 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001517 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
John Spurlock90874332015-03-10 16:00:54 -04001518 setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
1519 Binder.getCallingUid());
RoboErik0dac35a2014-08-12 15:48:49 -07001520 }
1521
1522 private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
John Spurlock90874332015-03-10 16:00:54 -04001523 String caller, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001524 if (mUseFixedVolume) {
1525 return;
1526 }
1527
Eric Laurentfde16d52012-12-03 14:42:39 -08001528 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001529 int streamTypeAlias = mStreamVolumeAlias[streamType];
1530 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001531
1532 final int device = getDeviceForStream(streamType);
1533 int oldIndex;
1534
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001535 // skip a2dp absolute volume control request when the device
1536 // is not an a2dp device
1537 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1538 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1539 return;
1540 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001541 // If we are being called by the system (e.g. hardware keys) check for current user
1542 // so we handle user restrictions correctly.
1543 if (uid == android.os.Process.SYSTEM_UID) {
1544 uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
1545 }
John Spurlock59dc9c12015-03-02 11:20:15 -05001546 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001547 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001548 return;
1549 }
1550
Julia Reynolds48034f82016-03-09 10:15:16 -05001551 if (isAndroidNPlus(callingPackage)
1552 && wouldToggleZenMode(getNewRingerMode(streamTypeAlias, index, flags))
1553 && !mNm.isNotificationPolicyAccessGrantedForPackage(callingPackage)) {
1554 throw new SecurityException("Not allowed to change Do Not Disturb state");
1555 }
1556
Julia Reynoldsed783792016-04-08 15:27:35 -04001557 if (!volumeAdjustmentAllowedByDnd(streamTypeAlias, flags)) {
1558 return;
1559 }
1560
Eric Laurentfde16d52012-12-03 14:42:39 -08001561 synchronized (mSafeMediaVolumeState) {
1562 // reset any pending volume command
1563 mPendingVolumeCommand = null;
1564
Eric Laurent42b041e2013-03-29 11:36:03 -07001565 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001566
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001567 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001568
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001569 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1570 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1571 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1572 synchronized (mA2dpAvrcpLock) {
1573 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001574 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001575 }
John Du5a0cf7a2013-07-19 11:30:34 -07001576 }
1577 }
1578
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001579 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1580 setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
Jungshik Jang41d97462014-06-30 22:26:29 +09001581 }
1582
Eric Laurentfde16d52012-12-03 14:42:39 -08001583 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001584 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001585 ((device & mFixedVolumeDevices) != 0)) {
1586 flags |= AudioManager.FLAG_FIXED_VOLUME;
1587
1588 // volume is either 0 or max allowed for fixed volume devices
1589 if (index != 0) {
1590 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1591 (device & mSafeMediaVolumeDevices) != 0) {
1592 index = mSafeMediaVolumeIndex;
1593 } else {
1594 index = streamState.getMaxIndex();
1595 }
1596 }
1597 }
1598
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001599 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001600 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001601 mPendingVolumeCommand = new StreamVolumeCommand(
1602 streamType, index, flags, device);
1603 } else {
John Spurlock90874332015-03-10 16:00:54 -04001604 onSetStreamVolume(streamType, index, flags, device, caller);
Eric Laurent42b041e2013-03-29 11:36:03 -07001605 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001606 }
1607 }
Eric Laurent25101b02011-02-02 09:33:30 -08001608 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001609 }
1610
Julia Reynoldsed783792016-04-08 15:27:35 -04001611 // No ringer affected streams can be changed in total silence mode except those that
1612 // will cause the device to exit total silence mode.
1613 private boolean volumeAdjustmentAllowedByDnd(int streamTypeAlias, int flags) {
1614 if (mNm.getZenMode() == Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
1615 && isStreamMutedByRingerMode(streamTypeAlias)) {
1616 if (!(((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1617 (streamTypeAlias == getUiSoundsStreamType()))) {
1618 return false;
1619 }
1620 }
1621 return true;
1622 }
1623
Eric Laurent45c90ce2012-04-24 18:44:22 -07001624 /** @see AudioManager#forceVolumeControlStream(int) */
1625 public void forceVolumeControlStream(int streamType, IBinder cb) {
1626 synchronized(mForceControlStreamLock) {
1627 mVolumeControlStream = streamType;
1628 if (mVolumeControlStream == -1) {
1629 if (mForceControlStreamClient != null) {
1630 mForceControlStreamClient.release();
1631 mForceControlStreamClient = null;
1632 }
1633 } else {
1634 mForceControlStreamClient = new ForceControlStreamClient(cb);
1635 }
1636 }
1637 }
1638
1639 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1640 private IBinder mCb; // To be notified of client's death
1641
1642 ForceControlStreamClient(IBinder cb) {
1643 if (cb != null) {
1644 try {
1645 cb.linkToDeath(this, 0);
1646 } catch (RemoteException e) {
1647 // Client has died!
1648 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1649 cb = null;
1650 }
1651 }
1652 mCb = cb;
1653 }
1654
1655 public void binderDied() {
1656 synchronized(mForceControlStreamLock) {
1657 Log.w(TAG, "SCO client died");
1658 if (mForceControlStreamClient != this) {
1659 Log.w(TAG, "unregistered control stream client died");
1660 } else {
1661 mForceControlStreamClient = null;
1662 mVolumeControlStream = -1;
1663 }
1664 }
1665 }
1666
1667 public void release() {
1668 if (mCb != null) {
1669 mCb.unlinkToDeath(this, 0);
1670 mCb = null;
1671 }
1672 }
1673 }
1674
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001675 private void sendBroadcastToAll(Intent intent) {
Christopher Tate267603f2015-01-20 14:21:21 -08001676 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
John Spurlock86490862015-02-25 11:22:52 -05001677 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001678 final long ident = Binder.clearCallingIdentity();
1679 try {
1680 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1681 } finally {
1682 Binder.restoreCallingIdentity(ident);
1683 }
1684 }
1685
1686 private void sendStickyBroadcastToAll(Intent intent) {
John Spurlock86490862015-02-25 11:22:52 -05001687 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001688 final long ident = Binder.clearCallingIdentity();
1689 try {
1690 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1691 } finally {
1692 Binder.restoreCallingIdentity(ident);
1693 }
1694 }
1695
Kenny Guy70e0c582015-06-30 19:18:28 +01001696 private int getCurrentUserId() {
1697 final long ident = Binder.clearCallingIdentity();
1698 try {
1699 UserInfo currentUser = ActivityManagerNative.getDefault().getCurrentUser();
1700 return currentUser.id;
1701 } catch (RemoteException e) {
1702 // Activity manager not running, nothing we can do assume user 0.
1703 } finally {
1704 Binder.restoreCallingIdentity(ident);
1705 }
Xiaohui Chen7c696362015-09-16 09:56:14 -07001706 return UserHandle.USER_SYSTEM;
Kenny Guy70e0c582015-06-30 19:18:28 +01001707 }
1708
Eric Laurent25101b02011-02-02 09:33:30 -08001709 // UI update and Broadcast Intent
1710 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
John Spurlock72966d62015-06-18 15:45:07 -04001711 streamType = mStreamVolumeAlias[streamType];
Eric Laurent25101b02011-02-02 09:33:30 -08001712
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001713 if (streamType == AudioSystem.STREAM_MUSIC) {
1714 flags = updateFlagsForSystemAudio(flags);
Jungshik Jang1a6be6e2014-09-16 11:04:54 +09001715 }
John Spurlock3346a802014-05-20 16:25:37 -04001716 mVolumeController.postVolumeChanged(streamType, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 }
1718
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001719 // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
1720 // receives volume notification from Audio Receiver.
1721 private int updateFlagsForSystemAudio(int flags) {
1722 if (mHdmiTvClient != null) {
1723 synchronized (mHdmiTvClient) {
1724 if (mHdmiSystemAudioSupported &&
1725 ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
1726 flags &= ~AudioManager.FLAG_SHOW_UI;
1727 }
1728 }
1729 }
1730 return flags;
1731 }
1732
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001733 // UI update and Broadcast Intent
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001734 private void sendMasterMuteUpdate(boolean muted, int flags) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001735 mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
Justin Koh57978ed2012-04-03 17:37:58 -07001736 broadcastMasterMuteStatus(muted);
1737 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001738
Justin Koh57978ed2012-04-03 17:37:58 -07001739 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001740 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1741 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001742 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1743 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001744 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001745 }
1746
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001747 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001748 * Sets the stream state's index, and posts a message to set system volume.
1749 * This will not call out to the UI. Assumes a valid stream type.
1750 *
1751 * @param streamType Type of the stream
1752 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001753 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001754 * @param force If true, set the volume even if the desired volume is same
1755 * as the current volume.
1756 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001757 private void setStreamVolumeInt(int streamType,
1758 int index,
1759 int device,
John Spurlock90874332015-03-10 16:00:54 -04001760 boolean force,
1761 String caller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001762 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07001763
John Spurlock90874332015-03-10 16:00:54 -04001764 if (streamState.setIndex(index, device, caller) || force) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001765 // Post message to set system volume (it in turn will post a message
1766 // to persist).
1767 sendMsg(mAudioHandler,
1768 MSG_SET_DEVICE_VOLUME,
1769 SENDMSG_QUEUE,
1770 device,
1771 0,
1772 streamState,
1773 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001774 }
1775 }
1776
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001777 private void setSystemAudioMute(boolean state) {
1778 if (mHdmiManager == null || mHdmiTvClient == null) return;
1779 synchronized (mHdmiManager) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001780 if (!mHdmiSystemAudioSupported) return;
1781 synchronized (mHdmiTvClient) {
1782 final long token = Binder.clearCallingIdentity();
1783 try {
1784 mHdmiTvClient.setSystemAudioMute(state);
1785 } finally {
1786 Binder.restoreCallingIdentity(token);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001787 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001788 }
1789 }
1790 }
1791
Eric Laurent25101b02011-02-02 09:33:30 -08001792 /** get stream mute state. */
1793 public boolean isStreamMute(int streamType) {
RoboErik7c82ced2014-12-04 17:39:08 -08001794 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1795 streamType = getActiveStreamType(streamType);
1796 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001797 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08001798 return mStreamStates[streamType].mIsMuted;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001799 }
Eric Laurent25101b02011-02-02 09:33:30 -08001800 }
1801
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07001802 private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
1803 private IBinder mICallback; // To be notified of client's death
1804
1805 RmtSbmxFullVolDeathHandler(IBinder cb) {
1806 mICallback = cb;
1807 try {
1808 cb.linkToDeath(this, 0/*flags*/);
1809 } catch (RemoteException e) {
1810 Log.e(TAG, "can't link to death", e);
1811 }
1812 }
1813
1814 boolean isHandlerFor(IBinder cb) {
1815 return mICallback.equals(cb);
1816 }
1817
1818 void forget() {
1819 try {
1820 mICallback.unlinkToDeath(this, 0/*flags*/);
1821 } catch (NoSuchElementException e) {
1822 Log.e(TAG, "error unlinking to death", e);
1823 }
1824 }
1825
1826 public void binderDied() {
1827 Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
1828 forceRemoteSubmixFullVolume(false, mICallback);
1829 }
1830 }
1831
1832 /**
1833 * call must be synchronized on mRmtSbmxFullVolDeathHandlers
1834 * @return true if there is a registered death handler, false otherwise */
1835 private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1836 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1837 while (it.hasNext()) {
1838 final RmtSbmxFullVolDeathHandler handler = it.next();
1839 if (handler.isHandlerFor(cb)) {
1840 handler.forget();
1841 mRmtSbmxFullVolDeathHandlers.remove(handler);
1842 return true;
1843 }
1844 }
1845 return false;
1846 }
1847
1848 /** call synchronized on mRmtSbmxFullVolDeathHandlers */
1849 private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1850 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1851 while (it.hasNext()) {
1852 if (it.next().isHandlerFor(cb)) {
1853 return true;
1854 }
1855 }
1856 return false;
1857 }
1858
1859 private int mRmtSbmxFullVolRefCount = 0;
1860 private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
1861 new ArrayList<RmtSbmxFullVolDeathHandler>();
1862
1863 public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
1864 if (cb == null) {
1865 return;
1866 }
1867 if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
1868 android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
1869 Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
1870 return;
1871 }
1872 synchronized(mRmtSbmxFullVolDeathHandlers) {
1873 boolean applyRequired = false;
1874 if (startForcing) {
1875 if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
1876 mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
1877 if (mRmtSbmxFullVolRefCount == 0) {
1878 mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1879 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1880 applyRequired = true;
1881 }
1882 mRmtSbmxFullVolRefCount++;
1883 }
1884 } else {
1885 if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
1886 mRmtSbmxFullVolRefCount--;
1887 if (mRmtSbmxFullVolRefCount == 0) {
1888 mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1889 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1890 applyRequired = true;
1891 }
1892 }
1893 }
1894 if (applyRequired) {
1895 // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
1896 checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
1897 mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
1898 }
1899 }
1900 }
1901
Kenny Guy70e0c582015-06-30 19:18:28 +01001902 private void setMasterMuteInternal(boolean mute, int flags, String callingPackage, int uid,
1903 int userId) {
1904 // If we are being called by the system check for user we are going to change
1905 // so we handle user restrictions correctly.
1906 if (uid == android.os.Process.SYSTEM_UID) {
1907 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
1908 }
Makoto Onuki4f160732015-10-27 17:15:38 -07001909 // If OP_AUDIO_MASTER_VOLUME is set, disallow unmuting.
1910 if (!mute && mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
RoboErik7c82ced2014-12-04 17:39:08 -08001911 != AppOpsManager.MODE_ALLOWED) {
Julia Reynolds4a21b252014-06-04 11:11:43 -04001912 return;
1913 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001914 if (userId != UserHandle.getCallingUserId() &&
1915 mContext.checkCallingOrSelfPermission(
1916 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1917 != PackageManager.PERMISSION_GRANTED) {
1918 return;
1919 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08001920 setMasterMuteInternalNoCallerCheck(mute, flags, userId);
1921 }
1922
1923 private void setMasterMuteInternalNoCallerCheck(boolean mute, int flags, int userId) {
1924 if (DEBUG_VOL) {
1925 Log.d(TAG, String.format("Master mute %s, %d, user=%d", mute, flags, userId));
1926 }
1927 if (mUseFixedVolume) {
1928 return; // If using fixed volume, we don't mute.
1929 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001930 if (getCurrentUserId() == userId) {
1931 if (mute != AudioSystem.getMasterMute()) {
1932 setSystemAudioMute(mute);
1933 AudioSystem.setMasterMute(mute);
Kenny Guy70e0c582015-06-30 19:18:28 +01001934 sendMasterMuteUpdate(mute, flags);
RoboErik7c82ced2014-12-04 17:39:08 -08001935
Kenny Guy70e0c582015-06-30 19:18:28 +01001936 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1937 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute);
1938 sendBroadcastToAll(intent);
1939 }
Jason Simmons1ce5b262012-02-02 13:00:17 -08001940 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08001941 }
1942
1943 /** get master mute state. */
1944 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08001945 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001946 }
1947
Kenny Guy70e0c582015-06-30 19:18:28 +01001948 public void setMasterMute(boolean mute, int flags, String callingPackage, int userId) {
1949 setMasterMuteInternal(mute, flags, callingPackage, Binder.getCallingUid(),
1950 userId);
John Spurlockee5ad722015-03-03 16:17:21 -05001951 }
1952
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001953 /** @see AudioManager#getStreamVolume(int) */
1954 public int getStreamVolume(int streamType) {
1955 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001956 int device = getDeviceForStream(streamType);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001957 synchronized (VolumeStreamState.class) {
1958 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001959
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001960 // by convention getStreamVolume() returns 0 when a stream is muted.
RoboErik4197cb62015-01-21 15:45:32 -08001961 if (mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001962 index = 0;
1963 }
1964 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
1965 (device & mFixedVolumeDevices) != 0) {
1966 index = mStreamStates[streamType].getMaxIndex();
1967 }
1968 return (index + 5) / 10;
Eric Laurent42b041e2013-03-29 11:36:03 -07001969 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001970 }
1971
1972 /** @see AudioManager#getStreamMaxVolume(int) */
1973 public int getStreamMaxVolume(int streamType) {
1974 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07001975 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001976 }
1977
John Spurlockb6e19e32015-03-10 21:33:44 -04001978 /** @see AudioManager#getStreamMinVolume(int) */
1979 public int getStreamMinVolume(int streamType) {
1980 ensureValidStreamType(streamType);
1981 return (mStreamStates[streamType].getMinIndex() + 5) / 10;
1982 }
1983
Eric Laurent25101b02011-02-02 09:33:30 -08001984 /** Get last audible volume before stream was muted. */
1985 public int getLastAudibleStreamVolume(int streamType) {
1986 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001987 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001988 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08001989 }
1990
John Spurlockee5ad722015-03-03 16:17:21 -05001991 /** @see AudioManager#getUiSoundsStreamType() */
1992 public int getUiSoundsStreamType() {
John Spurlock4f0f1202014-08-05 13:28:33 -04001993 return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
Eric Laurent6d517662012-04-23 18:42:39 -07001994 }
1995
Makoto Onukid45a4a22015-11-02 17:17:38 -08001996 /** @see AudioManager#setMicrophoneMute(boolean) */
1997 @Override
Kenny Guy70e0c582015-06-30 19:18:28 +01001998 public void setMicrophoneMute(boolean on, String callingPackage, int userId) {
1999 // If we are being called by the system check for user we are going to change
2000 // so we handle user restrictions correctly.
2001 int uid = Binder.getCallingUid();
2002 if (uid == android.os.Process.SYSTEM_UID) {
2003 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
2004 }
Makoto Onuki4f160732015-10-27 17:15:38 -07002005 // If OP_MUTE_MICROPHONE is set, disallow unmuting.
2006 if (!on && mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, uid, callingPackage)
Kenny Guy70e0c582015-06-30 19:18:28 +01002007 != AppOpsManager.MODE_ALLOWED) {
Emily Bernier22c921a2014-05-28 11:01:32 -04002008 return;
2009 }
Jean-Michel Trivi4a4fea02014-08-29 18:14:09 -07002010 if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
2011 return;
2012 }
Kenny Guy70e0c582015-06-30 19:18:28 +01002013 if (userId != UserHandle.getCallingUserId() &&
2014 mContext.checkCallingOrSelfPermission(
2015 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
2016 != PackageManager.PERMISSION_GRANTED) {
2017 return;
2018 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08002019 setMicrophoneMuteNoCallerCheck(on, userId);
2020 }
Emily Bernier22c921a2014-05-28 11:01:32 -04002021
Makoto Onukid45a4a22015-11-02 17:17:38 -08002022 private void setMicrophoneMuteNoCallerCheck(boolean on, int userId) {
2023 if (DEBUG_VOL) {
2024 Log.d(TAG, String.format("Mic mute %s, user=%d", on, userId));
2025 }
Kenny Guy70e0c582015-06-30 19:18:28 +01002026 // If mute is for current user actually mute, else just persist the setting
2027 // which will be loaded on user switch.
2028 if (getCurrentUserId() == userId) {
2029 AudioSystem.muteMicrophone(on);
2030 }
Julia Reynoldsb53453f2014-08-22 11:42:43 -04002031 // Post a persist microphone msg.
Emily Bernier22c921a2014-05-28 11:01:32 -04002032 }
2033
John Spurlock661f2cf2014-11-17 10:29:10 -05002034 @Override
2035 public int getRingerModeExternal() {
2036 synchronized(mSettingsLock) {
2037 return mRingerModeExternal;
2038 }
2039 }
2040
2041 @Override
2042 public int getRingerModeInternal() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08002043 synchronized(mSettingsLock) {
2044 return mRingerMode;
2045 }
2046 }
2047
2048 private void ensureValidRingerMode(int ringerMode) {
John Spurlock97559372014-10-24 16:27:36 -04002049 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08002050 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
2051 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002052 }
2053
John Spurlock97559372014-10-24 16:27:36 -04002054 /** @see AudioManager#isValidRingerMode(int) */
2055 public boolean isValidRingerMode(int ringerMode) {
2056 return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
2057 }
2058
John Spurlock661f2cf2014-11-17 10:29:10 -05002059 public void setRingerModeExternal(int ringerMode, String caller) {
Julia Reynolds48034f82016-03-09 10:15:16 -05002060 if (isAndroidNPlus(caller) && wouldToggleZenMode(ringerMode)
2061 && !mNm.isNotificationPolicyAccessGrantedForPackage(caller)) {
2062 throw new SecurityException("Not allowed to change Do Not Disturb state");
2063 }
2064
John Spurlockaf88a192014-12-23 16:14:44 -05002065 setRingerMode(ringerMode, caller, true /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05002066 }
2067
2068 public void setRingerModeInternal(int ringerMode, String caller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05002069 enforceVolumeController("setRingerModeInternal");
John Spurlockaf88a192014-12-23 16:14:44 -05002070 setRingerMode(ringerMode, caller, false /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05002071 }
2072
2073 private void setRingerMode(int ringerMode, String caller, boolean external) {
Eric Laurent212532b2014-07-21 15:43:18 -07002074 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07002075 return;
2076 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002077 if (caller == null || caller.length() == 0) {
2078 throw new IllegalArgumentException("Bad caller: " + caller);
2079 }
John Spurlock97559372014-10-24 16:27:36 -04002080 ensureValidRingerMode(ringerMode);
Eric Laurent24482012012-05-10 09:41:17 -07002081 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
2082 ringerMode = AudioManager.RINGER_MODE_SILENT;
2083 }
John Spurlockaf88a192014-12-23 16:14:44 -05002084 final long identity = Binder.clearCallingIdentity();
2085 try {
2086 synchronized (mSettingsLock) {
2087 final int ringerModeInternal = getRingerModeInternal();
2088 final int ringerModeExternal = getRingerModeExternal();
2089 if (external) {
2090 setRingerModeExt(ringerMode);
2091 if (mRingerModeDelegate != null) {
2092 ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
John Spurlocka48d7792015-03-03 17:35:57 -05002093 ringerMode, caller, ringerModeInternal, mVolumePolicy);
John Spurlockaf88a192014-12-23 16:14:44 -05002094 }
2095 if (ringerMode != ringerModeInternal) {
2096 setRingerModeInt(ringerMode, true /*persist*/);
2097 }
2098 } else /*internal*/ {
2099 if (ringerMode != ringerModeInternal) {
2100 setRingerModeInt(ringerMode, true /*persist*/);
2101 }
2102 if (mRingerModeDelegate != null) {
2103 ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
John Spurlocka48d7792015-03-03 17:35:57 -05002104 ringerMode, caller, ringerModeExternal, mVolumePolicy);
John Spurlockaf88a192014-12-23 16:14:44 -05002105 }
2106 setRingerModeExt(ringerMode);
John Spurlock57627792014-12-11 11:29:54 -05002107 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002108 }
John Spurlockaf88a192014-12-23 16:14:44 -05002109 } finally {
2110 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002111 }
2112 }
2113
John Spurlock661f2cf2014-11-17 10:29:10 -05002114 private void setRingerModeExt(int ringerMode) {
2115 synchronized(mSettingsLock) {
2116 if (ringerMode == mRingerModeExternal) return;
2117 mRingerModeExternal = ringerMode;
John Spurlocke5b42d92014-10-15 12:03:48 -04002118 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002119 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05002120 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
John Spurlocke5b42d92014-10-15 12:03:48 -04002121 }
2122
John Spurlock50ced3f2015-05-11 16:00:09 -04002123 private void muteRingerModeStreams() {
Eric Laurent5b4e6542010-03-19 20:02:21 -07002124 // Mute stream if not previously muted by ringer mode and ringer mode
2125 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
2126 // Unmute stream if previously muted by ringer mode and ringer mode
2127 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07002128 int numStreamTypes = AudioSystem.getNumStreamTypes();
John Spurlock50ced3f2015-05-11 16:00:09 -04002129 final boolean ringerModeMute = mRingerMode == AudioManager.RINGER_MODE_VIBRATE
2130 || mRingerMode == AudioManager.RINGER_MODE_SILENT;
Eric Laurent5b4e6542010-03-19 20:02:21 -07002131 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002132 final boolean isMuted = isStreamMutedByRingerMode(streamType);
2133 final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
2134 if (isMuted == shouldMute) continue;
2135 if (!shouldMute) {
2136 // unmute
2137 // ring and notifications volume should never be 0 when not silenced
John Spurlockd9c75db2015-04-28 11:19:13 -04002138 if (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002139 synchronized (VolumeStreamState.class) {
John Spurlocka48d7792015-03-03 17:35:57 -05002140 final VolumeStreamState vss = mStreamStates[streamType];
2141 for (int i = 0; i < vss.mIndexMap.size(); i++) {
2142 int device = vss.mIndexMap.keyAt(i);
2143 int value = vss.mIndexMap.valueAt(i);
John Spurlock2bb02ec2015-03-02 13:13:06 -05002144 if (value == 0) {
John Spurlocka48d7792015-03-03 17:35:57 -05002145 vss.setIndex(10, device, TAG);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002146 }
2147 }
Eric Laurent9e0d25f2015-02-12 17:28:53 -08002148 // Persist volume for stream ring when it is changed here
2149 final int device = getDeviceForStream(streamType);
2150 sendMsg(mAudioHandler,
2151 MSG_PERSIST_VOLUME,
2152 SENDMSG_QUEUE,
2153 device,
2154 0,
2155 mStreamStates[streamType],
2156 PERSIST_DELAY);
Eric Laurentb024c302011-10-14 17:19:27 -07002157 }
Eric Laurent9bcf4012009-06-12 06:09:28 -07002158 }
RoboErik4197cb62015-01-21 15:45:32 -08002159 mStreamStates[streamType].mute(false);
John Spurlock661f2cf2014-11-17 10:29:10 -05002160 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent5b4e6542010-03-19 20:02:21 -07002161 } else {
John Spurlock661f2cf2014-11-17 10:29:10 -05002162 // mute
RoboErik4197cb62015-01-21 15:45:32 -08002163 mStreamStates[streamType].mute(true);
John Spurlock661f2cf2014-11-17 10:29:10 -05002164 mRingerModeMutedStreams |= (1 << streamType);
Jason Parekhb1096152009-03-24 17:48:25 -07002165 }
2166 }
John Spurlock50ced3f2015-05-11 16:00:09 -04002167 }
2168
2169 private void setRingerModeInt(int ringerMode, boolean persist) {
2170 final boolean change;
2171 synchronized(mSettingsLock) {
2172 change = mRingerMode != ringerMode;
2173 mRingerMode = ringerMode;
2174 }
2175
2176 muteRingerModeStreams();
Eric Laurenta553c252009-07-17 12:17:14 -07002177
Jason Parekhb1096152009-03-24 17:48:25 -07002178 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07002179 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002180 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07002181 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
2182 }
John Spurlockbcc10872014-11-28 15:29:21 -05002183 if (change) {
2184 // Send sticky broadcast
2185 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
2186 }
Jason Parekhb1096152009-03-24 17:48:25 -07002187 }
2188
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002189 /** @see AudioManager#shouldVibrate(int) */
2190 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002191 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002192
2193 switch (getVibrateSetting(vibrateType)) {
2194
2195 case AudioManager.VIBRATE_SETTING_ON:
John Spurlock57627792014-12-11 11:29:54 -05002196 return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002197
2198 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
John Spurlock57627792014-12-11 11:29:54 -05002199 return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002200
2201 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04002202 // return false, even for incoming calls
2203 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002204
2205 default:
2206 return false;
2207 }
2208 }
2209
2210 /** @see AudioManager#getVibrateSetting(int) */
2211 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002212 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002213 return (mVibrateSetting >> (vibrateType * 2)) & 3;
2214 }
2215
2216 /** @see AudioManager#setVibrateSetting(int, int) */
2217 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
2218
Eric Laurentbffc3d12012-05-07 17:43:49 -07002219 if (!mHasVibrator) return;
2220
John Spurlock61560172015-02-06 19:46:04 -05002221 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
2222 vibrateSetting);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002223
2224 // Broadcast change
2225 broadcastVibrateSetting(vibrateType);
2226
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002227 }
2228
Eric Laurent9272b4b2010-01-23 17:12:59 -08002229 private class SetModeDeathHandler implements IBinder.DeathRecipient {
2230 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002231 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002232 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
2233
Eric Laurent9f103de2011-09-08 15:04:23 -07002234 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08002235 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07002236 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002237 }
2238
2239 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07002240 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002241 synchronized(mSetModeDeathHandlers) {
2242 Log.w(TAG, "setMode() client died");
2243 int index = mSetModeDeathHandlers.indexOf(this);
2244 if (index < 0) {
2245 Log.w(TAG, "unregistered setMode() client died");
2246 } else {
John Spurlock90874332015-03-10 16:00:54 -04002247 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid, TAG);
Eric Laurent9272b4b2010-01-23 17:12:59 -08002248 }
2249 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002250 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2251 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002252 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07002253 final long ident = Binder.clearCallingIdentity();
2254 disconnectBluetoothSco(newModeOwnerPid);
2255 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07002256 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08002257 }
2258
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002259 public int getPid() {
2260 return mPid;
2261 }
2262
Eric Laurent9272b4b2010-01-23 17:12:59 -08002263 public void setMode(int mode) {
2264 mMode = mode;
2265 }
2266
2267 public int getMode() {
2268 return mMode;
2269 }
2270
2271 public IBinder getBinder() {
2272 return mCb;
2273 }
2274 }
2275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002276 /** @see AudioManager#setMode(int) */
John Spurlock90874332015-03-10 16:00:54 -04002277 public void setMode(int mode, IBinder cb, String callingPackage) {
2278 if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ", callingPackage=" + callingPackage + ")"); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002279 if (!checkAudioSettingsPermission("setMode()")) {
2280 return;
2281 }
Eric Laurenta553c252009-07-17 12:17:14 -07002282
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07002283 if ( (mode == AudioSystem.MODE_IN_CALL) &&
2284 (mContext.checkCallingOrSelfPermission(
2285 android.Manifest.permission.MODIFY_PHONE_STATE)
2286 != PackageManager.PERMISSION_GRANTED)) {
2287 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
2288 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
2289 return;
2290 }
2291
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08002292 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07002293 return;
2294 }
2295
Eric Laurentd7454be2011-09-14 08:45:58 -07002296 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002297 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07002298 if (mode == AudioSystem.MODE_CURRENT) {
2299 mode = mMode;
2300 }
John Spurlock90874332015-03-10 16:00:54 -04002301 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid(), callingPackage);
Eric Laurent9f103de2011-09-08 15:04:23 -07002302 }
2303 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2304 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002305 if (newModeOwnerPid != 0) {
2306 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07002307 }
2308 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002309
Eric Laurent9f103de2011-09-08 15:04:23 -07002310 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07002311 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07002312 // any mode other than NORMAL.
John Spurlock90874332015-03-10 16:00:54 -04002313 private int setModeInt(int mode, IBinder cb, int pid, String caller) {
2314 if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ", caller="
2315 + caller + ")"); }
Eric Laurentd7454be2011-09-14 08:45:58 -07002316 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002317 if (cb == null) {
2318 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07002319 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07002320 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002321
Eric Laurent9f103de2011-09-08 15:04:23 -07002322 SetModeDeathHandler hdlr = null;
2323 Iterator iter = mSetModeDeathHandlers.iterator();
2324 while (iter.hasNext()) {
2325 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
2326 if (h.getPid() == pid) {
2327 hdlr = h;
2328 // Remove from client list so that it is re-inserted at top of list
2329 iter.remove();
2330 hdlr.getBinder().unlinkToDeath(hdlr, 0);
2331 break;
2332 }
2333 }
2334 int status = AudioSystem.AUDIO_STATUS_OK;
2335 do {
2336 if (mode == AudioSystem.MODE_NORMAL) {
2337 // get new mode from client at top the list if any
2338 if (!mSetModeDeathHandlers.isEmpty()) {
2339 hdlr = mSetModeDeathHandlers.get(0);
2340 cb = hdlr.getBinder();
2341 mode = hdlr.getMode();
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002342 if (DEBUG_MODE) {
2343 Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
2344 + hdlr.mPid);
2345 }
Eric Laurentb9c9d262009-05-06 08:13:20 -07002346 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002347 } else {
2348 if (hdlr == null) {
2349 hdlr = new SetModeDeathHandler(cb, pid);
2350 }
2351 // Register for client death notification
2352 try {
2353 cb.linkToDeath(hdlr, 0);
2354 } catch (RemoteException e) {
2355 // Client has died!
2356 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
2357 }
2358
2359 // Last client to call setMode() is always at top of client list
2360 // as required by SetModeDeathHandler.binderDied()
2361 mSetModeDeathHandlers.add(0, hdlr);
2362 hdlr.setMode(mode);
2363 }
2364
2365 if (mode != mMode) {
2366 status = AudioSystem.setPhoneState(mode);
2367 if (status == AudioSystem.AUDIO_STATUS_OK) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002368 if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002369 mMode = mode;
2370 } else {
2371 if (hdlr != null) {
2372 mSetModeDeathHandlers.remove(hdlr);
2373 cb.unlinkToDeath(hdlr, 0);
2374 }
2375 // force reading new top of mSetModeDeathHandlers stack
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002376 if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002377 mode = AudioSystem.MODE_NORMAL;
2378 }
2379 } else {
2380 status = AudioSystem.AUDIO_STATUS_OK;
2381 }
2382 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
2383
2384 if (status == AudioSystem.AUDIO_STATUS_OK) {
2385 if (mode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002386 if (mSetModeDeathHandlers.isEmpty()) {
2387 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
2388 } else {
2389 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2390 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002391 }
2392 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002393 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07002394 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
John Spurlock90874332015-03-10 16:00:54 -04002395 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, caller);
Eric Laurent6d517662012-04-23 18:42:39 -07002396
John Spurlock90874332015-03-10 16:00:54 -04002397 updateStreamVolumeAlias(true /*updateVolumes*/, caller);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002398 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002399 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002400 }
2401
2402 /** @see AudioManager#getMode() */
2403 public int getMode() {
2404 return mMode;
2405 }
2406
Eric Laurente78fced2013-03-15 16:03:47 -07002407 //==========================================================================================
2408 // Sound Effects
2409 //==========================================================================================
2410
2411 private static final String TAG_AUDIO_ASSETS = "audio_assets";
2412 private static final String ATTR_VERSION = "version";
2413 private static final String TAG_GROUP = "group";
2414 private static final String ATTR_GROUP_NAME = "name";
2415 private static final String TAG_ASSET = "asset";
2416 private static final String ATTR_ASSET_ID = "id";
2417 private static final String ATTR_ASSET_FILE = "file";
2418
2419 private static final String ASSET_FILE_VERSION = "1.0";
2420 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
2421
Glenn Kasten167d1a22013-07-23 16:24:41 -07002422 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002423
2424 class LoadSoundEffectReply {
2425 public int mStatus = 1;
2426 };
2427
Eric Laurente78fced2013-03-15 16:03:47 -07002428 private void loadTouchSoundAssetDefaults() {
2429 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
2430 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
2431 SOUND_EFFECT_FILES_MAP[i][0] = 0;
2432 SOUND_EFFECT_FILES_MAP[i][1] = -1;
2433 }
2434 }
2435
2436 private void loadTouchSoundAssets() {
2437 XmlResourceParser parser = null;
2438
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002439 // only load assets once.
2440 if (!SOUND_EFFECT_FILES.isEmpty()) {
2441 return;
2442 }
2443
Eric Laurente78fced2013-03-15 16:03:47 -07002444 loadTouchSoundAssetDefaults();
2445
2446 try {
2447 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
2448
2449 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
2450 String version = parser.getAttributeValue(null, ATTR_VERSION);
2451 boolean inTouchSoundsGroup = false;
2452
2453 if (ASSET_FILE_VERSION.equals(version)) {
2454 while (true) {
2455 XmlUtils.nextElement(parser);
2456 String element = parser.getName();
2457 if (element == null) {
2458 break;
2459 }
2460 if (element.equals(TAG_GROUP)) {
2461 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
2462 if (GROUP_TOUCH_SOUNDS.equals(name)) {
2463 inTouchSoundsGroup = true;
2464 break;
2465 }
2466 }
2467 }
2468 while (inTouchSoundsGroup) {
2469 XmlUtils.nextElement(parser);
2470 String element = parser.getName();
2471 if (element == null) {
2472 break;
2473 }
2474 if (element.equals(TAG_ASSET)) {
2475 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
2476 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
2477 int fx;
2478
2479 try {
2480 Field field = AudioManager.class.getField(id);
2481 fx = field.getInt(null);
2482 } catch (Exception e) {
2483 Log.w(TAG, "Invalid touch sound ID: "+id);
2484 continue;
2485 }
2486
2487 int i = SOUND_EFFECT_FILES.indexOf(file);
2488 if (i == -1) {
2489 i = SOUND_EFFECT_FILES.size();
2490 SOUND_EFFECT_FILES.add(file);
2491 }
2492 SOUND_EFFECT_FILES_MAP[fx][0] = i;
2493 } else {
2494 break;
2495 }
2496 }
2497 }
2498 } catch (Resources.NotFoundException e) {
2499 Log.w(TAG, "audio assets file not found", e);
2500 } catch (XmlPullParserException e) {
2501 Log.w(TAG, "XML parser exception reading touch sound assets", e);
2502 } catch (IOException e) {
2503 Log.w(TAG, "I/O exception reading touch sound assets", e);
2504 } finally {
2505 if (parser != null) {
2506 parser.close();
2507 }
2508 }
2509 }
2510
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002511 /** @see AudioManager#playSoundEffect(int) */
2512 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002513 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002514 }
2515
2516 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002517 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07002518 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
2519 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
2520 return;
2521 }
2522
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002523 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002524 effectType, (int) (volume * 1000), null, 0);
2525 }
2526
2527 /**
2528 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08002529 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002530 */
2531 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002532 int attempts = 3;
2533 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08002534
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002535 synchronized (reply) {
2536 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
2537 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08002538 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07002539 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002540 } catch (InterruptedException e) {
2541 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08002542 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002543 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002544 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002545 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002546 }
2547
2548 /**
2549 * Unloads samples from the sound pool.
2550 * This method can be called to free some memory when
2551 * sound effects are disabled.
2552 */
2553 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002554 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002555 }
2556
Eric Laurenta60e2122010-12-28 16:49:07 -08002557 class SoundPoolListenerThread extends Thread {
2558 public SoundPoolListenerThread() {
2559 super("SoundPoolListenerThread");
2560 }
2561
2562 @Override
2563 public void run() {
2564
2565 Looper.prepare();
2566 mSoundPoolLooper = Looper.myLooper();
2567
2568 synchronized (mSoundEffectsLock) {
2569 if (mSoundPool != null) {
2570 mSoundPoolCallBack = new SoundPoolCallback();
2571 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2572 }
2573 mSoundEffectsLock.notify();
2574 }
2575 Looper.loop();
2576 }
2577 }
2578
2579 private final class SoundPoolCallback implements
2580 android.media.SoundPool.OnLoadCompleteListener {
2581
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002582 int mStatus = 1; // 1 means neither error nor last sample loaded yet
2583 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08002584
2585 public int status() {
2586 return mStatus;
2587 }
2588
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002589 public void setSamples(int[] samples) {
2590 for (int i = 0; i < samples.length; i++) {
2591 // do not wait ack for samples rejected upfront by SoundPool
2592 if (samples[i] > 0) {
2593 mSamples.add(samples[i]);
2594 }
2595 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002596 }
2597
2598 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2599 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002600 int i = mSamples.indexOf(sampleId);
2601 if (i >= 0) {
2602 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08002603 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002604 if ((status != 0) || mSamples. isEmpty()) {
2605 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08002606 mSoundEffectsLock.notify();
2607 }
2608 }
2609 }
2610 }
2611
Eric Laurent4050c932009-07-08 02:52:14 -07002612 /** @see AudioManager#reloadAudioSettings() */
2613 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002614 readAudioSettings(false /*userSwitch*/);
2615 }
2616
2617 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07002618 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2619 readPersistedSettings();
Eric Laurentc0232482016-03-15 18:19:23 -07002620 readUserRestrictions();
Eric Laurent4050c932009-07-08 02:52:14 -07002621
2622 // restore volume settings
2623 int numStreamTypes = AudioSystem.getNumStreamTypes();
2624 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2625 VolumeStreamState streamState = mStreamStates[streamType];
2626
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002627 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2628 continue;
2629 }
2630
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002631 streamState.readSettings();
2632 synchronized (VolumeStreamState.class) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002633 // unmute stream that was muted but is not affect by mute anymore
RoboErik4197cb62015-01-21 15:45:32 -08002634 if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07002635 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
RoboErik4197cb62015-01-21 15:45:32 -08002636 streamState.mIsMuted = false;
Eric Laurent4050c932009-07-08 02:52:14 -07002637 }
Eric Laurent4050c932009-07-08 02:52:14 -07002638 }
2639 }
2640
Eric Laurent33902db2012-10-07 16:15:07 -07002641 // apply new ringer mode before checking volume for alias streams so that streams
2642 // muted by ringer mode have the correct volume
John Spurlock661f2cf2014-11-17 10:29:10 -05002643 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent33902db2012-10-07 16:15:07 -07002644
Eric Laurent212532b2014-07-21 15:43:18 -07002645 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07002646 checkAllAliasStreamVolumes();
John Spurlockb6e19e32015-03-10 21:33:44 -04002647 checkMuteAffectedStreams();
Eric Laurent24482012012-05-10 09:41:17 -07002648
Eric Laurentd640bd32012-09-28 18:01:48 -07002649 synchronized (mSafeMediaVolumeState) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002650 mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2651 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2652 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
Eric Laurentd640bd32012-09-28 18:01:48 -07002653 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
John Spurlock90874332015-03-10 16:00:54 -04002654 enforceSafeMediaVolume(TAG);
Eric Laurentf1a457d2012-09-20 16:27:23 -07002655 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07002656 }
Eric Laurent4050c932009-07-08 02:52:14 -07002657 }
2658
Dianne Hackborn961cae92013-03-20 14:59:43 -07002659 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002660 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002661 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2662 return;
2663 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002664
2665 if (on) {
2666 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2667 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2668 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
2669 }
2670 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2671 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2672 mForcedUseForComm = AudioSystem.FORCE_NONE;
2673 }
Eric Laurentfa640152011-03-12 15:59:51 -08002674
Eric Laurentafbb0472011-12-15 09:04:23 -08002675 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002676 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002677 }
2678
2679 /** @see AudioManager#isSpeakerphoneOn() */
2680 public boolean isSpeakerphoneOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002681 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002682 }
2683
Dianne Hackborn961cae92013-03-20 14:59:43 -07002684 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurent48221252015-09-24 18:41:48 -07002685 public void setBluetoothScoOn(boolean on) {
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002686 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2687 return;
2688 }
Eric Laurent48221252015-09-24 18:41:48 -07002689 setBluetoothScoOnInt(on);
2690 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002691
Eric Laurent48221252015-09-24 18:41:48 -07002692 public void setBluetoothScoOnInt(boolean on) {
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002693 if (on) {
2694 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2695 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2696 mForcedUseForComm = AudioSystem.FORCE_NONE;
2697 }
Eric Laurentfa640152011-03-12 15:59:51 -08002698
Eric Laurentafbb0472011-12-15 09:04:23 -08002699 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002700 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08002701 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002702 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002703 }
2704
2705 /** @see AudioManager#isBluetoothScoOn() */
2706 public boolean isBluetoothScoOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002707 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002708 }
2709
Sungsoocf09fe62016-09-28 16:21:48 +09002710 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07002711 public void setBluetoothA2dpOn(boolean on) {
Sungsoocf09fe62016-09-28 16:21:48 +09002712 synchronized (mBluetoothA2dpEnabledLock) {
2713 mBluetoothA2dpEnabled = on;
2714 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2715 AudioSystem.FOR_MEDIA,
2716 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2717 null, 0);
2718 }
Eric Laurent78472112012-05-21 08:57:21 -07002719 }
2720
Sungsoocf09fe62016-09-28 16:21:48 +09002721 /** @see AudioManager#isBluetoothA2dpOn() */
Eric Laurent78472112012-05-21 08:57:21 -07002722 public boolean isBluetoothA2dpOn() {
Sungsoocf09fe62016-09-28 16:21:48 +09002723 synchronized (mBluetoothA2dpEnabledLock) {
2724 return mBluetoothA2dpEnabled;
2725 }
Eric Laurent78472112012-05-21 08:57:21 -07002726 }
2727
Eric Laurent3def1ee2010-03-17 23:26:26 -07002728 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07002729 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
2730 int scoAudioMode =
2731 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
Liejun Taof4e51d82014-07-16 11:18:29 -07002732 SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
Eric Laurent83900752014-05-15 15:14:22 -07002733 startBluetoothScoInt(cb, scoAudioMode);
2734 }
2735
2736 /** @see AudioManager#startBluetoothScoVirtualCall() */
2737 public void startBluetoothScoVirtualCall(IBinder cb) {
2738 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
2739 }
2740
2741 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07002742 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002743 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002744 return;
2745 }
Eric Laurent854938a2011-02-22 12:05:20 -08002746 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002747 // The calling identity must be cleared before calling ScoClient.incCount().
2748 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2749 // and this must be done on behalf of system server to make sure permissions are granted.
2750 // The caller identity must be cleared after getScoClient() because it is needed if a new
2751 // client is created.
2752 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07002753 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08002754 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002755 }
2756
2757 /** @see AudioManager#stopBluetoothSco() */
2758 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07002759 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002760 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002761 return;
2762 }
Eric Laurent854938a2011-02-22 12:05:20 -08002763 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002764 // The calling identity must be cleared before calling ScoClient.decCount().
2765 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2766 // and this must be done on behalf of system server to make sure permissions are granted.
2767 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08002768 if (client != null) {
2769 client.decCount();
2770 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08002771 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002772 }
2773
Eric Laurent78472112012-05-21 08:57:21 -07002774
Eric Laurent3def1ee2010-03-17 23:26:26 -07002775 private class ScoClient implements IBinder.DeathRecipient {
2776 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002777 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002778 private int mStartcount; // number of SCO connections started by this client
2779
2780 ScoClient(IBinder cb) {
2781 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002782 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002783 mStartcount = 0;
2784 }
2785
2786 public void binderDied() {
2787 synchronized(mScoClients) {
2788 Log.w(TAG, "SCO client died");
2789 int index = mScoClients.indexOf(this);
2790 if (index < 0) {
2791 Log.w(TAG, "unregistered SCO client died");
2792 } else {
2793 clearCount(true);
2794 mScoClients.remove(this);
2795 }
2796 }
2797 }
2798
Eric Laurent83900752014-05-15 15:14:22 -07002799 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002800 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07002801 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002802 if (mStartcount == 0) {
2803 try {
2804 mCb.linkToDeath(this, 0);
2805 } catch (RemoteException e) {
2806 // client has already died!
2807 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
2808 }
2809 }
2810 mStartcount++;
2811 }
2812 }
2813
2814 public void decCount() {
2815 synchronized(mScoClients) {
2816 if (mStartcount == 0) {
2817 Log.w(TAG, "ScoClient.decCount() already 0");
2818 } else {
2819 mStartcount--;
2820 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002821 try {
2822 mCb.unlinkToDeath(this, 0);
2823 } catch (NoSuchElementException e) {
2824 Log.w(TAG, "decCount() going to 0 but not registered to binder");
2825 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002826 }
Eric Laurentc18c9132013-04-12 17:24:56 -07002827 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002828 }
2829 }
2830 }
2831
2832 public void clearCount(boolean stopSco) {
2833 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002834 if (mStartcount != 0) {
2835 try {
2836 mCb.unlinkToDeath(this, 0);
2837 } catch (NoSuchElementException e) {
2838 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2839 }
2840 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002841 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002842 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002843 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002844 }
2845 }
2846 }
2847
2848 public int getCount() {
2849 return mStartcount;
2850 }
2851
2852 public IBinder getBinder() {
2853 return mCb;
2854 }
2855
Eric Laurentd7454be2011-09-14 08:45:58 -07002856 public int getPid() {
2857 return mCreatorPid;
2858 }
2859
Eric Laurent3def1ee2010-03-17 23:26:26 -07002860 public int totalCount() {
2861 synchronized(mScoClients) {
2862 int count = 0;
2863 int size = mScoClients.size();
2864 for (int i = 0; i < size; i++) {
2865 count += mScoClients.get(i).getCount();
2866 }
2867 return count;
2868 }
2869 }
2870
Eric Laurent83900752014-05-15 15:14:22 -07002871 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08002872 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07002873 if (totalCount() == 0) {
2874 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2875 // Make sure that the state transitions to CONNECTING even if we cannot initiate
2876 // the connection.
2877 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2878 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002879 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07002880 synchronized(mSetModeDeathHandlers) {
2881 if ((mSetModeDeathHandlers.isEmpty() ||
2882 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2883 (mScoAudioState == SCO_STATE_INACTIVE ||
2884 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2885 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07002886 mScoAudioMode = scoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -07002887 if (scoAudioMode == SCO_MODE_UNDEFINED) {
Andre Eisenbach570cc532014-10-28 17:03:18 -07002888 if (mBluetoothHeadsetDevice != null) {
2889 mScoAudioMode = new Integer(Settings.Global.getInt(
2890 mContentResolver,
2891 "bluetooth_sco_channel_"+
2892 mBluetoothHeadsetDevice.getAddress(),
2893 SCO_MODE_VIRTUAL_CALL));
2894 if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2895 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2896 }
2897 } else {
2898 mScoAudioMode = SCO_MODE_RAW;
Liejun Taof4e51d82014-07-16 11:18:29 -07002899 }
2900 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002901 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002902 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002903 if (mScoAudioMode == SCO_MODE_RAW) {
2904 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002905 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002906 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2907 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002908 } else if (mScoAudioMode == SCO_MODE_VR) {
2909 status = mBluetoothHeadset.startVoiceRecognition(
2910 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002911 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002912
Eric Laurentc18c9132013-04-12 17:24:56 -07002913 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07002914 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2915 } else {
2916 broadcastScoConnectionState(
2917 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2918 }
2919 } else if (getBluetoothHeadset()) {
2920 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07002921 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002922 } else {
2923 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2924 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002925 }
2926 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07002927 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002928 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002929 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002930 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002931 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2932 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2933 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07002934 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002935 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002936 if (mScoAudioMode == SCO_MODE_RAW) {
2937 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002938 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002939 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2940 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002941 } else if (mScoAudioMode == SCO_MODE_VR) {
2942 status = mBluetoothHeadset.stopVoiceRecognition(
2943 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002944 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002945
Eric Laurentc18c9132013-04-12 17:24:56 -07002946 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002947 mScoAudioState = SCO_STATE_INACTIVE;
2948 broadcastScoConnectionState(
2949 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2950 }
2951 } else if (getBluetoothHeadset()) {
2952 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2953 }
2954 } else {
2955 mScoAudioState = SCO_STATE_INACTIVE;
2956 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2957 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002958 }
2959 }
2960 }
2961 }
2962
Eric Laurent62ef7672010-11-24 10:58:32 -08002963 private void checkScoAudioState() {
2964 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002965 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08002966 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2967 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2968 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2969 }
2970 }
2971
Eric Laurent854938a2011-02-22 12:05:20 -08002972 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002973 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002974 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002975 int size = mScoClients.size();
2976 for (int i = 0; i < size; i++) {
2977 client = mScoClients.get(i);
2978 if (client.getBinder() == cb)
2979 return client;
2980 }
Eric Laurent854938a2011-02-22 12:05:20 -08002981 if (create) {
2982 client = new ScoClient(cb);
2983 mScoClients.add(client);
2984 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002985 return client;
2986 }
2987 }
2988
Eric Laurentd7454be2011-09-14 08:45:58 -07002989 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002990 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002991 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002992 int size = mScoClients.size();
2993 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08002994 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07002995 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08002996 cl.clearCount(stopSco);
2997 } else {
2998 savedClient = cl;
2999 }
3000 }
3001 mScoClients.clear();
3002 if (savedClient != null) {
3003 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003004 }
3005 }
3006 }
3007
Eric Laurentdc03c612011-04-01 10:59:41 -07003008 private boolean getBluetoothHeadset() {
3009 boolean result = false;
3010 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
3011 if (adapter != null) {
3012 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
3013 BluetoothProfile.HEADSET);
3014 }
3015 // If we could not get a bluetooth headset proxy, send a failure message
3016 // without delay to reset the SCO audio state and clear SCO clients.
3017 // If we could get a proxy, send a delayed failure message that will reset our state
3018 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08003019 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07003020 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
3021 return result;
3022 }
3023
Eric Laurentd7454be2011-09-14 08:45:58 -07003024 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07003025 synchronized(mScoClients) {
3026 checkScoAudioState();
3027 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
3028 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
3029 if (mBluetoothHeadsetDevice != null) {
3030 if (mBluetoothHeadset != null) {
3031 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07003032 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08003033 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07003034 SENDMSG_REPLACE, 0, 0, null, 0);
3035 }
3036 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
3037 getBluetoothHeadset()) {
3038 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
3039 }
3040 }
3041 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07003042 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07003043 }
3044 }
3045 }
3046
3047 private void resetBluetoothSco() {
3048 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07003049 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07003050 mScoAudioState = SCO_STATE_INACTIVE;
3051 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3052 }
Eric Laurent48221252015-09-24 18:41:48 -07003053 AudioSystem.setParameters("A2dpSuspended=false");
3054 setBluetoothScoOnInt(false);
Eric Laurentdc03c612011-04-01 10:59:41 -07003055 }
3056
3057 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08003058 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
3059 SENDMSG_QUEUE, state, 0, null, 0);
3060 }
3061
3062 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07003063 if (state != mScoConnectionState) {
3064 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
3065 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
3066 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
3067 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003068 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07003069 mScoConnectionState = state;
3070 }
3071 }
3072
Eric Laurent98859b22015-06-12 14:35:59 -07003073 void setBtScoDeviceConnectionState(BluetoothDevice btDevice, int state) {
3074 if (btDevice == null) {
3075 return;
3076 }
3077
3078 String address = btDevice.getAddress();
3079 BluetoothClass btClass = btDevice.getBluetoothClass();
3080 int outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
3081 int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
3082 if (btClass != null) {
3083 switch (btClass.getDeviceClass()) {
3084 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
3085 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
3086 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
3087 break;
3088 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
3089 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
3090 break;
3091 }
3092 }
3093
3094 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
3095 address = "";
3096 }
3097
3098 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
3099
3100 String btDeviceName = btDevice.getName();
3101 boolean success =
3102 handleDeviceConnection(connected, outDevice, address, btDeviceName) &&
3103 handleDeviceConnection(connected, inDevice, address, btDeviceName);
Satish Kodishala29809802016-01-18 14:23:12 +05303104
3105 if (!success) {
3106 return;
3107 }
3108
3109 /* When one BT headset is disconnected while another BT headset
3110 * is connected, don't mess with the headset device.
3111 */
3112 if ((state == BluetoothProfile.STATE_DISCONNECTED ||
3113 state == BluetoothProfile.STATE_DISCONNECTING) &&
3114 mBluetoothHeadset != null &&
3115 mBluetoothHeadset.getAudioState(btDevice) == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
3116 Log.w(TAG, "SCO connected through another device, returning");
3117 return;
3118 }
3119
3120 synchronized (mScoClients) {
3121 if (connected) {
3122 mBluetoothHeadsetDevice = btDevice;
3123 } else {
3124 mBluetoothHeadsetDevice = null;
3125 resetBluetoothSco();
Eric Laurent98859b22015-06-12 14:35:59 -07003126 }
3127 }
3128 }
3129
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07003130 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
3131 new BluetoothProfile.ServiceListener() {
3132 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003133 BluetoothDevice btDevice;
3134 List<BluetoothDevice> deviceList;
3135 switch(profile) {
3136 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09003137 synchronized (mConnectedDevices) {
3138 synchronized (mA2dpAvrcpLock) {
3139 mA2dp = (BluetoothA2dp) proxy;
3140 deviceList = mA2dp.getConnectedDevices();
3141 if (deviceList.size() > 0) {
3142 btDevice = deviceList.get(0);
John Du5a0cf7a2013-07-19 11:30:34 -07003143 int state = mA2dp.getConnectionState(btDevice);
3144 int delay = checkSendBecomingNoisyIntent(
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003145 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3146 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
John Du5a0cf7a2013-07-19 11:30:34 -07003147 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003148 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07003149 state,
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08003150 0 /* arg2 unused */,
John Du5a0cf7a2013-07-19 11:30:34 -07003151 btDevice,
3152 delay);
3153 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003154 }
Eric Laurent62ef7672010-11-24 10:58:32 -08003155 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003156 break;
3157
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003158 case BluetoothProfile.A2DP_SINK:
3159 deviceList = proxy.getConnectedDevices();
3160 if (deviceList.size() > 0) {
3161 btDevice = deviceList.get(0);
3162 synchronized (mConnectedDevices) {
3163 int state = proxy.getConnectionState(btDevice);
3164 queueMsgUnderWakeLock(mAudioHandler,
3165 MSG_SET_A2DP_SRC_CONNECTION_STATE,
3166 state,
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08003167 0 /* arg2 unused */,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003168 btDevice,
3169 0 /* delay */);
3170 }
3171 }
3172 break;
3173
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003174 case BluetoothProfile.HEADSET:
3175 synchronized (mScoClients) {
3176 // Discard timeout message
3177 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
3178 mBluetoothHeadset = (BluetoothHeadset) proxy;
3179 deviceList = mBluetoothHeadset.getConnectedDevices();
3180 if (deviceList.size() > 0) {
3181 mBluetoothHeadsetDevice = deviceList.get(0);
3182 } else {
3183 mBluetoothHeadsetDevice = null;
3184 }
3185 // Refresh SCO audio state
3186 checkScoAudioState();
3187 // Continue pending action if any
3188 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
3189 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
3190 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
3191 boolean status = false;
3192 if (mBluetoothHeadsetDevice != null) {
3193 switch (mScoAudioState) {
3194 case SCO_STATE_ACTIVATE_REQ:
3195 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07003196 if (mScoAudioMode == SCO_MODE_RAW) {
3197 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003198 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003199 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
3200 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003201 } else if (mScoAudioMode == SCO_MODE_VR) {
3202 status = mBluetoothHeadset.startVoiceRecognition(
3203 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003204 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003205 break;
3206 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07003207 if (mScoAudioMode == SCO_MODE_RAW) {
3208 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003209 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003210 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
3211 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003212 } else if (mScoAudioMode == SCO_MODE_VR) {
3213 status = mBluetoothHeadset.stopVoiceRecognition(
3214 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003215 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003216 break;
3217 case SCO_STATE_DEACTIVATE_EXT_REQ:
3218 status = mBluetoothHeadset.stopVoiceRecognition(
3219 mBluetoothHeadsetDevice);
3220 }
3221 }
3222 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08003223 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003224 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07003225 }
3226 }
Eric Laurentdc03c612011-04-01 10:59:41 -07003227 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003228 break;
3229
3230 default:
3231 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003232 }
3233 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07003234 public void onServiceDisconnected(int profile) {
Eric Laurentb70b78a2016-01-13 19:16:04 -08003235
Paul McLean394a8e12015-03-03 10:29:19 -07003236 switch (profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003237 case BluetoothProfile.A2DP:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003238 disconnectA2dp();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003239 break;
3240
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003241 case BluetoothProfile.A2DP_SINK:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003242 disconnectA2dpSink();
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003243 break;
3244
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003245 case BluetoothProfile.HEADSET:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003246 disconnectHeadset();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003247 break;
3248
3249 default:
3250 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003251 }
3252 }
3253 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003254
Eric Laurentb70b78a2016-01-13 19:16:04 -08003255 void disconnectAllBluetoothProfiles() {
3256 disconnectA2dp();
3257 disconnectA2dpSink();
3258 disconnectHeadset();
3259 }
3260
3261 void disconnectA2dp() {
3262 synchronized (mConnectedDevices) {
3263 synchronized (mA2dpAvrcpLock) {
3264 ArraySet<String> toRemove = null;
3265 // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
3266 for (int i = 0; i < mConnectedDevices.size(); i++) {
3267 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
3268 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
3269 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
3270 toRemove.add(deviceSpec.mDeviceAddress);
3271 }
3272 }
3273 if (toRemove != null) {
3274 int delay = checkSendBecomingNoisyIntent(
3275 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3276 0);
3277 for (int i = 0; i < toRemove.size(); i++) {
3278 makeA2dpDeviceUnavailableLater(toRemove.valueAt(i), delay);
3279 }
3280 }
3281 }
3282 }
3283 }
3284
3285 void disconnectA2dpSink() {
3286 synchronized (mConnectedDevices) {
3287 ArraySet<String> toRemove = null;
3288 // Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
3289 for(int i = 0; i < mConnectedDevices.size(); i++) {
3290 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
3291 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) {
3292 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
3293 toRemove.add(deviceSpec.mDeviceAddress);
3294 }
3295 }
3296 if (toRemove != null) {
3297 for (int i = 0; i < toRemove.size(); i++) {
3298 makeA2dpSrcUnavailable(toRemove.valueAt(i));
3299 }
3300 }
3301 }
3302 }
3303
3304 void disconnectHeadset() {
3305 synchronized (mScoClients) {
3306 if (mBluetoothHeadsetDevice != null) {
3307 setBtScoDeviceConnectionState(mBluetoothHeadsetDevice,
3308 BluetoothProfile.STATE_DISCONNECTED);
3309 }
3310 mBluetoothHeadset = null;
3311 }
3312 }
3313
John Spurlock90874332015-03-10 16:00:54 -04003314 private void onCheckMusicActive(String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07003315 synchronized (mSafeMediaVolumeState) {
3316 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07003317 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
3318
3319 if ((device & mSafeMediaVolumeDevices) != 0) {
3320 sendMsg(mAudioHandler,
3321 MSG_CHECK_MUSIC_ACTIVE,
3322 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07003323 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07003324 0,
John Spurlock90874332015-03-10 16:00:54 -04003325 caller,
Eric Laurentc34dcc12012-09-10 13:51:52 -07003326 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07003327 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07003328 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
3329 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07003330 // Approximate cumulative active music time
3331 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
3332 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
John Spurlock90874332015-03-10 16:00:54 -04003333 setSafeMediaVolumeEnabled(true, caller);
Eric Laurentc34dcc12012-09-10 13:51:52 -07003334 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07003335 }
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003336 saveMusicActiveMs();
Eric Laurentc34dcc12012-09-10 13:51:52 -07003337 }
3338 }
3339 }
3340 }
3341 }
3342
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003343 private void saveMusicActiveMs() {
3344 mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
3345 }
3346
John Spurlock90874332015-03-10 16:00:54 -04003347 private void onConfigureSafeVolume(boolean force, String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07003348 synchronized (mSafeMediaVolumeState) {
3349 int mcc = mContext.getResources().getConfiguration().mcc;
3350 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
3351 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
3352 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
John Spurlock35134602014-07-24 18:10:48 -04003353 boolean safeMediaVolumeEnabled =
3354 SystemProperties.getBoolean("audio.safemedia.force", false)
3355 || mContext.getResources().getBoolean(
3356 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08003357
Ricardo Garcia3a30a762015-06-23 15:54:45 -07003358 boolean safeMediaVolumeBypass =
3359 SystemProperties.getBoolean("audio.safemedia.bypass", false);
3360
Eric Laurent05274f32012-11-29 12:48:18 -08003361 // The persisted state is either "disabled" or "active": this is the state applied
3362 // next time we boot and cannot be "inactive"
3363 int persistedState;
Ricardo Garcia3a30a762015-06-23 15:54:45 -07003364 if (safeMediaVolumeEnabled && !safeMediaVolumeBypass) {
Eric Laurent05274f32012-11-29 12:48:18 -08003365 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
3366 // The state can already be "inactive" here if the user has forced it before
3367 // the 30 seconds timeout for forced configuration. In this case we don't reset
3368 // it to "active".
3369 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003370 if (mMusicActiveMs == 0) {
3371 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
John Spurlock90874332015-03-10 16:00:54 -04003372 enforceSafeMediaVolume(caller);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003373 } else {
3374 // We have existing playback time recorded, already confirmed.
3375 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
3376 }
Eric Laurent05274f32012-11-29 12:48:18 -08003377 }
Eric Laurentd640bd32012-09-28 18:01:48 -07003378 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08003379 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07003380 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
3381 }
3382 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08003383 sendMsg(mAudioHandler,
3384 MSG_PERSIST_SAFE_VOLUME_STATE,
3385 SENDMSG_QUEUE,
3386 persistedState,
3387 0,
3388 null,
3389 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07003390 }
3391 }
3392 }
3393
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003394 ///////////////////////////////////////////////////////////////////////////
3395 // Internal methods
3396 ///////////////////////////////////////////////////////////////////////////
3397
3398 /**
3399 * Checks if the adjustment should change ringer mode instead of just
3400 * adjusting volume. If so, this will set the proper ringer mode and volume
3401 * indices on the stream states.
3402 */
Julia Reynoldsed783792016-04-08 15:27:35 -04003403 private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted,
3404 String caller, int flags) {
John Spurlocka48d7792015-03-03 17:35:57 -05003405 final boolean isTv = mPlatformType == AudioSystem.PLATFORM_TELEVISION;
John Spurlocka11b4af2014-06-01 11:52:23 -04003406 int result = FLAG_ADJUST_VOLUME;
John Spurlock661f2cf2014-11-17 10:29:10 -05003407 int ringerMode = getRingerModeInternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003408
Eric Laurentbffc3d12012-05-07 17:43:49 -07003409 switch (ringerMode) {
3410 case RINGER_MODE_NORMAL:
3411 if (direction == AudioManager.ADJUST_LOWER) {
3412 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07003413 // "step" is the delta in internal index units corresponding to a
3414 // change of 1 in UI index units.
3415 // Because of rounding when rescaling from one stream index range to its alias
3416 // index range, we cannot simply test oldIndex == step:
3417 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
3418 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003419 ringerMode = RINGER_MODE_VIBRATE;
John Spurlock07e72432015-03-13 11:46:52 -04003420 mLoweredFromNormalToVibrateTime = SystemClock.uptimeMillis();
Eric Laurentbffc3d12012-05-07 17:43:49 -07003421 }
3422 } else {
John Spurlockd9c75db2015-04-28 11:19:13 -04003423 if (oldIndex == step && mVolumePolicy.volumeDownToEnterSilent) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003424 ringerMode = RINGER_MODE_SILENT;
3425 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07003426 }
John Spurlocka48d7792015-03-03 17:35:57 -05003427 } else if (isTv && (direction == AudioManager.ADJUST_TOGGLE_MUTE
3428 || direction == AudioManager.ADJUST_MUTE)) {
RoboErik5452e252015-02-06 15:33:53 -08003429 if (mHasVibrator) {
3430 ringerMode = RINGER_MODE_VIBRATE;
3431 } else {
3432 ringerMode = RINGER_MODE_SILENT;
3433 }
3434 // Setting the ringer mode will toggle mute
3435 result &= ~FLAG_ADJUST_VOLUME;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003436 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003437 break;
3438 case RINGER_MODE_VIBRATE:
3439 if (!mHasVibrator) {
3440 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
3441 "but no vibrator is present");
3442 break;
3443 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003444 if ((direction == AudioManager.ADJUST_LOWER)) {
RoboErik5452e252015-02-06 15:33:53 -08003445 // This is the case we were muted with the volume turned up
John Spurlocka48d7792015-03-03 17:35:57 -05003446 if (isTv && oldIndex >= 2 * step && isMuted) {
RoboErik5452e252015-02-06 15:33:53 -08003447 ringerMode = RINGER_MODE_NORMAL;
3448 } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
John Spurlocka48d7792015-03-03 17:35:57 -05003449 if (mVolumePolicy.volumeDownToEnterSilent) {
John Spurlock07e72432015-03-13 11:46:52 -04003450 final long diff = SystemClock.uptimeMillis()
3451 - mLoweredFromNormalToVibrateTime;
John Spurlockd9c75db2015-04-28 11:19:13 -04003452 if (diff > mVolumePolicy.vibrateToSilentDebounce
3453 && mRingerModeDelegate.canVolumeDownEnterSilent()) {
John Spurlock07e72432015-03-13 11:46:52 -04003454 ringerMode = RINGER_MODE_SILENT;
3455 }
John Spurlock795a5142014-12-08 14:09:35 -05003456 } else {
3457 result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
3458 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003459 }
RoboErik5452e252015-02-06 15:33:53 -08003460 } else if (direction == AudioManager.ADJUST_RAISE
3461 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3462 || direction == AudioManager.ADJUST_UNMUTE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003463 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07003464 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003465 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003466 break;
3467 case RINGER_MODE_SILENT:
John Spurlocka48d7792015-03-03 17:35:57 -05003468 if (isTv && direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
RoboErik5452e252015-02-06 15:33:53 -08003469 // This is the case we were muted with the volume turned up
3470 ringerMode = RINGER_MODE_NORMAL;
3471 } else if (direction == AudioManager.ADJUST_RAISE
3472 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3473 || direction == AudioManager.ADJUST_UNMUTE) {
John Spurlocka48d7792015-03-03 17:35:57 -05003474 if (!mVolumePolicy.volumeUpToExitSilent) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003475 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003476 } else {
RoboErik5452e252015-02-06 15:33:53 -08003477 if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003478 ringerMode = RINGER_MODE_VIBRATE;
3479 } else {
RoboErik5452e252015-02-06 15:33:53 -08003480 // If we don't have a vibrator or they were toggling mute
3481 // go straight back to normal.
John Spurlocka11b4af2014-06-01 11:52:23 -04003482 ringerMode = RINGER_MODE_NORMAL;
3483 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003484 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05003485 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003486 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003487 break;
3488 default:
3489 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
3490 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003491 }
3492
Julia Reynoldsed783792016-04-08 15:27:35 -04003493 if (isAndroidNPlus(caller) && wouldToggleZenMode(ringerMode)
3494 && !mNm.isNotificationPolicyAccessGrantedForPackage(caller)
3495 && (flags & AudioManager.FLAG_FROM_KEY) == 0) {
3496 throw new SecurityException("Not allowed to change Do Not Disturb state");
3497 }
3498
John Spurlock661f2cf2014-11-17 10:29:10 -05003499 setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003500
Eric Laurent25101b02011-02-02 09:33:30 -08003501 mPrevVolDirection = direction;
3502
John Spurlocka11b4af2014-06-01 11:52:23 -04003503 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003504 }
3505
John Spurlock3346a802014-05-20 16:25:37 -04003506 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003507 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07003508 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003509 }
3510
Eric Laurent5b4e6542010-03-19 20:02:21 -07003511 private boolean isStreamMutedByRingerMode(int streamType) {
3512 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
3513 }
3514
John Spurlock50ced3f2015-05-11 16:00:09 -04003515 private boolean updateRingerModeAffectedStreams() {
3516 int ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003517 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3518 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
3519 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
3520 UserHandle.USER_CURRENT);
3521
John Spurlock50ced3f2015-05-11 16:00:09 -04003522 if (mPlatformType == AudioSystem.PLATFORM_TELEVISION) {
3523 ringerModeAffectedStreams = 0;
3524 } else if (mRingerModeDelegate != null) {
3525 ringerModeAffectedStreams = mRingerModeDelegate
3526 .getRingerModeAffectedStreams(ringerModeAffectedStreams);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003527 }
3528 synchronized (mCameraSoundForced) {
3529 if (mCameraSoundForced) {
3530 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3531 } else {
3532 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3533 }
3534 }
3535 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
3536 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
3537 } else {
3538 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
3539 }
3540
3541 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3542 Settings.System.putIntForUser(mContentResolver,
3543 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3544 ringerModeAffectedStreams,
3545 UserHandle.USER_CURRENT);
3546 mRingerModeAffectedStreams = ringerModeAffectedStreams;
3547 return true;
3548 }
3549 return false;
3550 }
3551
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05003552 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003553 public boolean isStreamAffectedByMute(int streamType) {
3554 return (mMuteAffectedStreams & (1 << streamType)) != 0;
3555 }
3556
3557 private void ensureValidDirection(int direction) {
RoboErik4197cb62015-01-21 15:45:32 -08003558 switch (direction) {
3559 case AudioManager.ADJUST_LOWER:
3560 case AudioManager.ADJUST_RAISE:
3561 case AudioManager.ADJUST_SAME:
3562 case AudioManager.ADJUST_MUTE:
3563 case AudioManager.ADJUST_UNMUTE:
3564 case AudioManager.ADJUST_TOGGLE_MUTE:
3565 break;
3566 default:
3567 throw new IllegalArgumentException("Bad direction " + direction);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003568 }
3569 }
3570
3571 private void ensureValidStreamType(int streamType) {
3572 if (streamType < 0 || streamType >= mStreamStates.length) {
3573 throw new IllegalArgumentException("Bad stream type " + streamType);
3574 }
3575 }
3576
RoboErik4197cb62015-01-21 15:45:32 -08003577 private boolean isMuteAdjust(int adjust) {
3578 return adjust == AudioManager.ADJUST_MUTE || adjust == AudioManager.ADJUST_UNMUTE
3579 || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
3580 }
3581
Eric Laurent6d517662012-04-23 18:42:39 -07003582 private boolean isInCommunication() {
Nancy Chen0eb1e402014-08-21 22:52:29 -07003583 boolean IsInCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003584
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003585 TelecomManager telecomManager =
3586 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
Eric Laurent38edfda2014-12-18 17:38:04 -08003587
3588 final long ident = Binder.clearCallingIdentity();
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003589 IsInCall = telecomManager.isInCall();
Eric Laurent38edfda2014-12-18 17:38:04 -08003590 Binder.restoreCallingIdentity(ident);
Santos Cordon9eb45932014-06-27 12:28:43 -07003591
Nancy Chen0eb1e402014-08-21 22:52:29 -07003592 return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
Eric Laurent6d517662012-04-23 18:42:39 -07003593 }
Eric Laurent25101b02011-02-02 09:33:30 -08003594
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003595 /**
3596 * For code clarity for getActiveStreamType(int)
3597 * @param delay_ms max time since last STREAM_MUSIC activity to consider
3598 * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
3599 * in the last "delay_ms" ms.
3600 */
3601 private boolean isAfMusicActiveRecently(int delay_ms) {
3602 return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
3603 || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
3604 }
3605
Eric Laurent6d517662012-04-23 18:42:39 -07003606 private int getActiveStreamType(int suggestedStreamType) {
Eric Laurent212532b2014-07-21 15:43:18 -07003607 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003608 case AudioSystem.PLATFORM_VOICE:
Eric Laurent6d517662012-04-23 18:42:39 -07003609 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003610 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3611 == AudioSystem.FORCE_BT_SCO) {
3612 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
3613 return AudioSystem.STREAM_BLUETOOTH_SCO;
3614 } else {
3615 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
3616 return AudioSystem.STREAM_VOICE_CALL;
3617 }
Eric Laurent25101b02011-02-02 09:33:30 -08003618 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003619 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003620 if (DEBUG_VOL)
3621 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3622 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003623 } else {
3624 if (DEBUG_VOL)
3625 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
3626 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003627 }
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003628 } else if (isAfMusicActiveRecently(0)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003629 if (DEBUG_VOL)
3630 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3631 return AudioSystem.STREAM_MUSIC;
Eric Laurent25101b02011-02-02 09:33:30 -08003632 }
Eric Laurent212532b2014-07-21 15:43:18 -07003633 break;
John Spurlock61560172015-02-06 19:46:04 -05003634 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -07003635 if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
RoboErik2811dd32014-08-12 09:48:13 -07003636 // TV always defaults to STREAM_MUSIC
Eric Laurent212532b2014-07-21 15:43:18 -07003637 return AudioSystem.STREAM_MUSIC;
Eric Laurent212532b2014-07-21 15:43:18 -07003638 }
3639 break;
3640 default:
Eric Laurent6d517662012-04-23 18:42:39 -07003641 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003642 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3643 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003644 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08003645 return AudioSystem.STREAM_BLUETOOTH_SCO;
3646 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003647 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08003648 return AudioSystem.STREAM_VOICE_CALL;
3649 }
3650 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003651 StreamOverride.sDelayMs) ||
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003652 AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003653 StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003654 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08003655 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003656 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003657 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003658 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
3659 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003660 } else {
John Spurlockeb1d88d2014-07-19 14:49:19 -04003661 if (DEBUG_VOL) Log.v(TAG,
3662 "getActiveStreamType: using STREAM_NOTIFICATION as default");
3663 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003664 }
Joe Onoratoc7fcba42011-01-05 16:53:11 -08003665 }
Eric Laurent212532b2014-07-21 15:43:18 -07003666 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003667 }
Eric Laurent212532b2014-07-21 15:43:18 -07003668 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
3669 + suggestedStreamType);
3670 return suggestedStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003671 }
3672
John Spurlockbcc10872014-11-28 15:29:21 -05003673 private void broadcastRingerMode(String action, int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003674 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05003675 Intent broadcast = new Intent(action);
Glenn Kastenba195eb2011-12-13 09:30:40 -08003676 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003677 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
3678 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003679 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003680 }
3681
3682 private void broadcastVibrateSetting(int vibrateType) {
3683 // Send broadcast
3684 if (ActivityManagerNative.isSystemReady()) {
3685 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
3686 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
3687 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003688 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003689 }
3690 }
3691
3692 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003693 /**
3694 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
3695 * Note that the wake lock needs to be released after the message has been handled.
3696 */
3697 private void queueMsgUnderWakeLock(Handler handler, int msg,
3698 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003699 final long ident = Binder.clearCallingIdentity();
3700 // Always acquire the wake lock as AudioService because it is released by the
3701 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003702 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003703 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003704 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
3705 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003706
Eric Laurentafbb0472011-12-15 09:04:23 -08003707 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003708 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003709
3710 if (existingMsgPolicy == SENDMSG_REPLACE) {
3711 handler.removeMessages(msg);
3712 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
3713 return;
3714 }
Eric Laurentadbe8bf2014-11-03 18:26:32 -08003715 synchronized (mLastDeviceConnectMsgTime) {
3716 long time = SystemClock.uptimeMillis() + delay;
3717 handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
3718 if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
3719 msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
3720 msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
3721 mLastDeviceConnectMsgTime = time;
3722 }
3723 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003724 }
3725
3726 boolean checkAudioSettingsPermission(String method) {
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07003727 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003728 == PackageManager.PERMISSION_GRANTED) {
3729 return true;
3730 }
3731 String msg = "Audio Settings Permission Denial: " + method + " from pid="
3732 + Binder.getCallingPid()
3733 + ", uid=" + Binder.getCallingUid();
3734 Log.w(TAG, msg);
3735 return false;
3736 }
3737
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003738 private int getDeviceForStream(int stream) {
John Spurlock8a52c442015-03-26 14:23:58 -04003739 int device = getDevicesForStream(stream);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003740 if ((device & (device - 1)) != 0) {
3741 // Multiple device selection is either:
3742 // - speaker + one other device: give priority to speaker in this case.
3743 // - one A2DP device + another device: happens with duplicated output. In this case
3744 // retain the device on the A2DP output as the other must not correspond to an active
3745 // selection if not the speaker.
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003746 // - HDMI-CEC system audio mode only output: give priority to available item in order.
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003747 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
3748 device = AudioSystem.DEVICE_OUT_SPEAKER;
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003749 } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
3750 device = AudioSystem.DEVICE_OUT_HDMI_ARC;
3751 } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
3752 device = AudioSystem.DEVICE_OUT_SPDIF;
3753 } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
3754 device = AudioSystem.DEVICE_OUT_AUX_LINE;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003755 } else {
3756 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
3757 }
3758 }
3759 return device;
3760 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003761
John Spurlock8a52c442015-03-26 14:23:58 -04003762 private int getDevicesForStream(int stream) {
3763 return getDevicesForStream(stream, true /*checkOthers*/);
3764 }
3765
3766 private int getDevicesForStream(int stream, boolean checkOthers) {
3767 ensureValidStreamType(stream);
3768 synchronized (VolumeStreamState.class) {
3769 return mStreamStates[stream].observeDevicesForStream_syncVSS(checkOthers);
3770 }
3771 }
3772
3773 private void observeDevicesForStreams(int skipStream) {
3774 synchronized (VolumeStreamState.class) {
3775 for (int stream = 0; stream < mStreamStates.length; stream++) {
3776 if (stream != skipStream) {
3777 mStreamStates[stream].observeDevicesForStream_syncVSS(false /*checkOthers*/);
3778 }
3779 }
3780 }
3781 }
3782
Paul McLean10804eb2015-01-28 11:16:35 -08003783 /*
3784 * A class just for packaging up a set of connection parameters.
3785 */
3786 private class WiredDeviceConnectionState {
John Spurlock90874332015-03-10 16:00:54 -04003787 public final int mType;
3788 public final int mState;
3789 public final String mAddress;
3790 public final String mName;
3791 public final String mCaller;
Paul McLean10804eb2015-01-28 11:16:35 -08003792
John Spurlock90874332015-03-10 16:00:54 -04003793 public WiredDeviceConnectionState(int type, int state, String address, String name,
3794 String caller) {
Paul McLean10804eb2015-01-28 11:16:35 -08003795 mType = type;
3796 mState = state;
3797 mAddress = address;
3798 mName = name;
John Spurlock90874332015-03-10 16:00:54 -04003799 mCaller = caller;
Paul McLean10804eb2015-01-28 11:16:35 -08003800 }
3801 }
3802
John Spurlock90874332015-03-10 16:00:54 -04003803 public void setWiredDeviceConnectionState(int type, int state, String address, String name,
3804 String caller) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003805 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07003806 if (DEBUG_DEVICES) {
3807 Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
3808 + address + ")");
3809 }
Paul McLean10804eb2015-01-28 11:16:35 -08003810 int delay = checkSendBecomingNoisyIntent(type, state);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003811 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003812 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08003813 0 /* arg1 unused */,
3814 0 /* arg2 unused */,
John Spurlock90874332015-03-10 16:00:54 -04003815 new WiredDeviceConnectionState(type, state, address, name, caller),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003816 delay);
3817 }
3818 }
3819
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003820 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003821 {
3822 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003823 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
3824 throw new IllegalArgumentException("invalid profile " + profile);
3825 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003826 synchronized (mConnectedDevices) {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003827 if (profile == BluetoothProfile.A2DP) {
3828 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3829 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
3830 } else {
3831 delay = 0;
3832 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003833 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003834 (profile == BluetoothProfile.A2DP ?
3835 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003836 state,
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08003837 0 /* arg2 unused */,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003838 device,
3839 delay);
3840 }
3841 return delay;
3842 }
3843
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08003844 public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device)
3845 {
3846 synchronized (mConnectedDevices) {
3847 queueMsgUnderWakeLock(mAudioHandler,
3848 MSG_A2DP_DEVICE_CONFIG_CHANGE,
3849 0 /* arg1 unused */,
3850 0 /* arg1 unused */,
3851 device,
3852 0 /* delay */);
3853 }
3854 }
3855
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003856 ///////////////////////////////////////////////////////////////////////////
3857 // Inner classes
3858 ///////////////////////////////////////////////////////////////////////////
3859
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003860 // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
3861 // 1 mScoclient OR mSafeMediaVolumeState
3862 // 2 mSetModeDeathHandlers
3863 // 3 mSettingsLock
3864 // 4 VolumeStreamState.class
3865 // 5 mCameraSoundForced
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003866 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003867 private final int mStreamType;
John Spurlockb6e19e32015-03-10 21:33:44 -04003868 private final int mIndexMin;
3869 private final int mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003870
RoboErik4197cb62015-01-21 15:45:32 -08003871 private boolean mIsMuted;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003872 private String mVolumeIndexSettingName;
John Spurlock8a52c442015-03-26 14:23:58 -04003873 private int mObservedDevices;
John Spurlockb6e19e32015-03-10 21:33:44 -04003874
John Spurlock2bb02ec2015-03-02 13:13:06 -05003875 private final SparseIntArray mIndexMap = new SparseIntArray(8);
John Spurlockf63860c2015-02-19 09:46:27 -05003876 private final Intent mVolumeChanged;
John Spurlock8a52c442015-03-26 14:23:58 -04003877 private final Intent mStreamDevicesChanged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003878
Eric Laurenta553c252009-07-17 12:17:14 -07003879 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003880
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003881 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003882
3883 mStreamType = streamType;
John Spurlockb6e19e32015-03-10 21:33:44 -04003884 mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;
3885 mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;
3886 AudioSystem.initStreamVolume(streamType, mIndexMin / 10, mIndexMax / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003887
Eric Laurent33902db2012-10-07 16:15:07 -07003888 readSettings();
John Spurlockf63860c2015-02-19 09:46:27 -05003889 mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
3890 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
John Spurlock8a52c442015-03-26 14:23:58 -04003891 mStreamDevicesChanged = new Intent(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
3892 mStreamDevicesChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
3893 }
3894
3895 public int observeDevicesForStream_syncVSS(boolean checkOthers) {
3896 final int devices = AudioSystem.getDevicesForStream(mStreamType);
3897 if (devices == mObservedDevices) {
3898 return devices;
3899 }
3900 final int prevDevices = mObservedDevices;
3901 mObservedDevices = devices;
3902 if (checkOthers) {
3903 // one stream's devices have changed, check the others
3904 observeDevicesForStreams(mStreamType);
3905 }
3906 // log base stream changes to the event log
3907 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
3908 EventLogTags.writeStreamDevicesChanged(mStreamType, prevDevices, devices);
3909 }
3910 sendBroadcastToAll(mStreamDevicesChanged
3911 .putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, prevDevices)
3912 .putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, devices));
3913 return devices;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003914 }
3915
Eric Laurent42b041e2013-03-29 11:36:03 -07003916 public String getSettingNameForDevice(int device) {
3917 String name = mVolumeIndexSettingName;
Eric Laurent948d3272014-05-16 15:18:45 -07003918 String suffix = AudioSystem.getOutputDeviceName(device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003919 if (suffix.isEmpty()) {
3920 return name;
3921 }
3922 return name + "_" + suffix;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003923 }
3924
Eric Laurentfdbee862014-05-12 15:26:12 -07003925 public void readSettings() {
3926 synchronized (VolumeStreamState.class) {
John Spurlockee5ad722015-03-03 16:17:21 -05003927 // force maximum volume on all streams if fixed volume property is set
3928 if (mUseFixedVolume) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003929 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07003930 return;
3931 }
3932 // do not read system stream volume from settings: this stream is always aliased
3933 // to another stream type and its volume is never persisted. Values in settings can
3934 // only be stale values
3935 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3936 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
John Spurlock61560172015-02-06 19:46:04 -05003937 int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
Eric Laurentfdbee862014-05-12 15:26:12 -07003938 synchronized (mCameraSoundForced) {
3939 if (mCameraSoundForced) {
3940 index = mIndexMax;
3941 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003942 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003943 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003944 return;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003945 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003946
Eric Laurentfdbee862014-05-12 15:26:12 -07003947 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
3948
3949 for (int i = 0; remainingDevices != 0; i++) {
3950 int device = (1 << i);
3951 if ((device & remainingDevices) == 0) {
3952 continue;
3953 }
3954 remainingDevices &= ~device;
3955
3956 // retrieve current volume for device
3957 String name = getSettingNameForDevice(device);
3958 // if no volume stored for current stream and device, use default volume if default
3959 // device, continue otherwise
3960 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
John Spurlock61560172015-02-06 19:46:04 -05003961 AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
Eric Laurentfdbee862014-05-12 15:26:12 -07003962 int index = Settings.System.getIntForUser(
3963 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3964 if (index == -1) {
3965 continue;
3966 }
3967
John Spurlock2bb02ec2015-03-02 13:13:06 -05003968 mIndexMap.put(device, getValidIndex(10 * index));
Eric Laurentdd45d012012-10-08 09:04:34 -07003969 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003970 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003971 }
3972
Liejun Tao39fb5672016-03-09 15:52:13 -06003973 private int getAbsoluteVolumeIndex(int index) {
3974 /* Special handling for Bluetooth Absolute Volume scenario
3975 * If we send full audio gain, some accessories are too loud even at its lowest
3976 * volume. We are not able to enumerate all such accessories, so here is the
3977 * workaround from phone side.
3978 * Pre-scale volume at lowest volume steps 1 2 and 3.
3979 * For volume step 0, set audio gain to 0 as some accessories won't mute on their end.
3980 */
3981 if (index == 0) {
3982 // 0% for volume 0
3983 index = 0;
3984 } else if (index == 1) {
3985 // 50% for volume 1
3986 index = (int)(mIndexMax * 0.5) /10;
3987 } else if (index == 2) {
3988 // 70% for volume 2
3989 index = (int)(mIndexMax * 0.70) /10;
3990 } else if (index == 3) {
3991 // 85% for volume 3
3992 index = (int)(mIndexMax * 0.85) /10;
3993 } else {
3994 // otherwise, full gain
3995 index = (mIndexMax + 5)/10;
3996 }
3997 return index;
3998 }
3999
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004000 // must be called while synchronized VolumeStreamState.class
4001 public void applyDeviceVolume_syncVSS(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07004002 int index;
RoboErik4197cb62015-01-21 15:45:32 -08004003 if (mIsMuted) {
Eric Laurent42b041e2013-03-29 11:36:03 -07004004 index = 0;
Liejun Tao4565a472016-01-20 17:52:20 -06004005 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) {
Liejun Tao39fb5672016-03-09 15:52:13 -06004006 index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
Liejun Tao4565a472016-01-20 17:52:20 -06004007 } else if ((device & mFullVolumeDevices) != 0) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004008 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07004009 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07004010 index = (getIndex(device) + 5)/10;
4011 }
4012 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004013 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004014
Eric Laurentfdbee862014-05-12 15:26:12 -07004015 public void applyAllVolumes() {
4016 synchronized (VolumeStreamState.class) {
Eric Laurentd9ac2be2016-04-07 14:04:23 -07004017 // apply device specific volumes first
Eric Laurentfdbee862014-05-12 15:26:12 -07004018 int index;
John Spurlock2bb02ec2015-03-02 13:13:06 -05004019 for (int i = 0; i < mIndexMap.size(); i++) {
Eric Laurentd9ac2be2016-04-07 14:04:23 -07004020 final int device = mIndexMap.keyAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07004021 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
RoboErik4197cb62015-01-21 15:45:32 -08004022 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004023 index = 0;
Liejun Tao39fb5672016-03-09 15:52:13 -06004024 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
4025 mAvrcpAbsVolSupported) {
4026 index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
4027 } else if ((device & mFullVolumeDevices) != 0) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004028 index = (mIndexMax + 5)/10;
4029 } else {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004030 index = (mIndexMap.valueAt(i) + 5)/10;
Eric Laurentfdbee862014-05-12 15:26:12 -07004031 }
4032 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07004033 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004034 }
Eric Laurentd9ac2be2016-04-07 14:04:23 -07004035 // apply default volume last: by convention , default device volume will be used
4036 // by audio policy manager if no explicit volume is present for a given device type
4037 if (mIsMuted) {
4038 index = 0;
4039 } else {
4040 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
4041 }
4042 AudioSystem.setStreamVolumeIndex(
4043 mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004044 }
4045 }
4046
John Spurlock90874332015-03-10 16:00:54 -04004047 public boolean adjustIndex(int deltaIndex, int device, String caller) {
4048 return setIndex(getIndex(device) + deltaIndex, device, caller);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004049 }
4050
John Spurlock90874332015-03-10 16:00:54 -04004051 public boolean setIndex(int index, int device, String caller) {
John Spurlockf63860c2015-02-19 09:46:27 -05004052 boolean changed = false;
4053 int oldIndex;
Eric Laurentfdbee862014-05-12 15:26:12 -07004054 synchronized (VolumeStreamState.class) {
John Spurlockf63860c2015-02-19 09:46:27 -05004055 oldIndex = getIndex(device);
Eric Laurentfdbee862014-05-12 15:26:12 -07004056 index = getValidIndex(index);
4057 synchronized (mCameraSoundForced) {
4058 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
4059 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07004060 }
4061 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05004062 mIndexMap.put(device, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07004063
John Spurlockf63860c2015-02-19 09:46:27 -05004064 changed = oldIndex != index;
Eric Laurent825a5ea2016-11-03 16:27:40 -07004065 // Apply change to all streams using this one as alias if:
4066 // - the index actually changed OR
4067 // - there is no volume index stored for this device on alias stream.
4068 // If changing volume of current device, also change volume of current
4069 // device on aliased stream
4070 final boolean currentDevice = (device == getDeviceForStream(mStreamType));
4071 final int numStreamTypes = AudioSystem.getNumStreamTypes();
4072 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4073 final VolumeStreamState aliasStreamState = mStreamStates[streamType];
4074 if (streamType != mStreamType &&
4075 mStreamVolumeAlias[streamType] == mStreamType &&
4076 (changed || !aliasStreamState.hasIndexForDevice(device))) {
4077 final int scaledIndex = rescaleIndex(index, mStreamType, streamType);
4078 aliasStreamState.setIndex(scaledIndex, device, caller);
4079 if (currentDevice) {
4080 aliasStreamState.setIndex(scaledIndex,
4081 getDeviceForStream(streamType), caller);
Eric Laurentfdbee862014-05-12 15:26:12 -07004082 }
4083 }
Eric Laurentfdbee862014-05-12 15:26:12 -07004084 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004085 }
John Spurlockf63860c2015-02-19 09:46:27 -05004086 if (changed) {
4087 oldIndex = (oldIndex + 5) / 10;
4088 index = (index + 5) / 10;
John Spurlock90874332015-03-10 16:00:54 -04004089 // log base stream changes to the event log
4090 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
4091 if (caller == null) {
4092 Log.w(TAG, "No caller for volume_changed event", new Throwable());
4093 }
4094 EventLogTags.writeVolumeChanged(mStreamType, oldIndex, index, mIndexMax / 10,
4095 caller);
4096 }
4097 // fire changed intents for all streams
John Spurlockf63860c2015-02-19 09:46:27 -05004098 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
4099 mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
Jean-Michel Trivi560877d2015-06-25 17:38:35 -07004100 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
4101 mStreamVolumeAlias[mStreamType]);
John Spurlockf63860c2015-02-19 09:46:27 -05004102 sendBroadcastToAll(mVolumeChanged);
4103 }
4104 return changed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004105 }
4106
Eric Laurentfdbee862014-05-12 15:26:12 -07004107 public int getIndex(int device) {
4108 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004109 int index = mIndexMap.get(device, -1);
4110 if (index == -1) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004111 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
John Spurlock2bb02ec2015-03-02 13:13:06 -05004112 index = mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurentfdbee862014-05-12 15:26:12 -07004113 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05004114 return index;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004115 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07004116 }
4117
Eric Laurent825a5ea2016-11-03 16:27:40 -07004118 public boolean hasIndexForDevice(int device) {
4119 synchronized (VolumeStreamState.class) {
4120 return (mIndexMap.get(device, -1) != -1);
4121 }
4122 }
4123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004124 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07004125 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004126 }
4127
John Spurlockb6e19e32015-03-10 21:33:44 -04004128 public int getMinIndex() {
4129 return mIndexMin;
4130 }
4131
John Spurlock90874332015-03-10 16:00:54 -04004132 public void setAllIndexes(VolumeStreamState srcStream, String caller) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004133 synchronized (VolumeStreamState.class) {
4134 int srcStreamType = srcStream.getStreamType();
4135 // apply default device volume from source stream to all devices first in case
4136 // some devices are present in this stream state but not in source stream state
4137 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004138 index = rescaleIndex(index, srcStreamType, mStreamType);
John Spurlock2bb02ec2015-03-02 13:13:06 -05004139 for (int i = 0; i < mIndexMap.size(); i++) {
4140 mIndexMap.put(mIndexMap.keyAt(i), index);
Eric Laurentfdbee862014-05-12 15:26:12 -07004141 }
4142 // Now apply actual volume for devices in source stream state
John Spurlock2bb02ec2015-03-02 13:13:06 -05004143 SparseIntArray srcMap = srcStream.mIndexMap;
4144 for (int i = 0; i < srcMap.size(); i++) {
4145 int device = srcMap.keyAt(i);
4146 index = srcMap.valueAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07004147 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07004148
John Spurlock90874332015-03-10 16:00:54 -04004149 setIndex(index, device, caller);
Eric Laurentfdbee862014-05-12 15:26:12 -07004150 }
Eric Laurent6d517662012-04-23 18:42:39 -07004151 }
4152 }
4153
Eric Laurentfdbee862014-05-12 15:26:12 -07004154 public void setAllIndexesToMax() {
4155 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004156 for (int i = 0; i < mIndexMap.size(); i++) {
4157 mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07004158 }
Eric Laurentdd45d012012-10-08 09:04:34 -07004159 }
Eric Laurentdd45d012012-10-08 09:04:34 -07004160 }
4161
RoboErik4197cb62015-01-21 15:45:32 -08004162 public void mute(boolean state) {
John Spurlock22b9ee12015-02-18 22:51:44 -05004163 boolean changed = false;
Eric Laurentfdbee862014-05-12 15:26:12 -07004164 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08004165 if (state != mIsMuted) {
John Spurlock22b9ee12015-02-18 22:51:44 -05004166 changed = true;
RoboErik4197cb62015-01-21 15:45:32 -08004167 mIsMuted = state;
John Spurlock22b9ee12015-02-18 22:51:44 -05004168
RoboErik4197cb62015-01-21 15:45:32 -08004169 // Set the new mute volume. This propagates the values to
4170 // the audio system, otherwise the volume won't be changed
4171 // at the lower level.
4172 sendMsg(mAudioHandler,
4173 MSG_SET_ALL_VOLUMES,
4174 SENDMSG_QUEUE,
4175 0,
4176 0,
4177 this, 0);
Eric Laurentfdbee862014-05-12 15:26:12 -07004178 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004179 }
John Spurlock22b9ee12015-02-18 22:51:44 -05004180 if (changed) {
4181 // Stream mute changed, fire the intent.
4182 Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
4183 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
4184 intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
4185 sendBroadcastToAll(intent);
4186 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004187 }
4188
Eric Laurent6d517662012-04-23 18:42:39 -07004189 public int getStreamType() {
4190 return mStreamType;
4191 }
4192
Eric Laurent212532b2014-07-21 15:43:18 -07004193 public void checkFixedVolumeDevices() {
4194 synchronized (VolumeStreamState.class) {
4195 // ignore settings for fixed volume devices: volume should always be at max or 0
4196 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004197 for (int i = 0; i < mIndexMap.size(); i++) {
4198 int device = mIndexMap.keyAt(i);
4199 int index = mIndexMap.valueAt(i);
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07004200 if (((device & mFullVolumeDevices) != 0)
4201 || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004202 mIndexMap.put(device, mIndexMax);
Eric Laurent212532b2014-07-21 15:43:18 -07004203 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004204 applyDeviceVolume_syncVSS(device);
Eric Laurent212532b2014-07-21 15:43:18 -07004205 }
4206 }
4207 }
4208 }
4209
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004210 private int getValidIndex(int index) {
John Spurlockb6e19e32015-03-10 21:33:44 -04004211 if (index < mIndexMin) {
4212 return mIndexMin;
John Spurlockee5ad722015-03-03 16:17:21 -05004213 } else if (mUseFixedVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07004214 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004215 }
4216
4217 return index;
4218 }
4219
Eric Laurentbffc3d12012-05-07 17:43:49 -07004220 private void dump(PrintWriter pw) {
RoboErik4197cb62015-01-21 15:45:32 -08004221 pw.print(" Muted: ");
4222 pw.println(mIsMuted);
John Spurlockb6e19e32015-03-10 21:33:44 -04004223 pw.print(" Min: ");
4224 pw.println((mIndexMin + 5) / 10);
John Spurlock2b29bc42014-08-26 16:40:35 -04004225 pw.print(" Max: ");
4226 pw.println((mIndexMax + 5) / 10);
Eric Laurentbffc3d12012-05-07 17:43:49 -07004227 pw.print(" Current: ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05004228 for (int i = 0; i < mIndexMap.size(); i++) {
4229 if (i > 0) {
4230 pw.print(", ");
4231 }
4232 final int device = mIndexMap.keyAt(i);
John Spurlock2b29bc42014-08-26 16:40:35 -04004233 pw.print(Integer.toHexString(device));
4234 final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
4235 : AudioSystem.getOutputDeviceName(device);
4236 if (!deviceName.isEmpty()) {
4237 pw.print(" (");
4238 pw.print(deviceName);
4239 pw.print(")");
4240 }
4241 pw.print(": ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05004242 final int index = (mIndexMap.valueAt(i) + 5) / 10;
John Spurlock2b29bc42014-08-26 16:40:35 -04004243 pw.print(index);
Eric Laurentbffc3d12012-05-07 17:43:49 -07004244 }
John Spurlockb32fc972015-03-05 13:58:00 -05004245 pw.println();
4246 pw.print(" Devices: ");
John Spurlock8a52c442015-03-26 14:23:58 -04004247 final int devices = getDevicesForStream(mStreamType);
John Spurlockb32fc972015-03-05 13:58:00 -05004248 int device, i = 0, n = 0;
John Spurlock1ff1e6e2015-03-09 14:21:20 -04004249 // iterate all devices from 1 to DEVICE_OUT_DEFAULT exclusive
4250 // (the default device is not returned by getDevicesForStream)
4251 while ((device = 1 << i) != AudioSystem.DEVICE_OUT_DEFAULT) {
John Spurlockb32fc972015-03-05 13:58:00 -05004252 if ((devices & device) != 0) {
4253 if (n++ > 0) {
4254 pw.print(", ");
4255 }
4256 pw.print(AudioSystem.getOutputDeviceName(device));
4257 }
4258 i++;
4259 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07004260 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004261 }
4262
4263 /** Thread that handles native AudioSystem control. */
4264 private class AudioSystemThread extends Thread {
4265 AudioSystemThread() {
4266 super("AudioService");
4267 }
4268
4269 @Override
4270 public void run() {
4271 // Set this thread up so the handler will work on it
4272 Looper.prepare();
4273
4274 synchronized(AudioService.this) {
4275 mAudioHandler = new AudioHandler();
4276
4277 // Notify that the handler has been created
4278 AudioService.this.notify();
4279 }
4280
4281 // Listen for volume change requests that are set by VolumePanel
4282 Looper.loop();
4283 }
4284 }
4285
4286 /** Handles internal volume messages in separate volume thread. */
4287 private class AudioHandler extends Handler {
4288
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004289 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004290
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004291 synchronized (VolumeStreamState.class) {
4292 // Apply volume
4293 streamState.applyDeviceVolume_syncVSS(device);
Eric Laurenta553c252009-07-17 12:17:14 -07004294
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004295 // Apply change to all streams using this one as alias
4296 int numStreamTypes = AudioSystem.getNumStreamTypes();
4297 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4298 if (streamType != streamState.mStreamType &&
4299 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
4300 // Make sure volume is also maxed out on A2DP device for aliased stream
4301 // that may have a different device selected
4302 int streamDevice = getDeviceForStream(streamType);
4303 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
4304 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
4305 mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
4306 }
4307 mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
Eric Laurentcd772d02013-10-30 18:31:07 -07004308 }
Eric Laurenta553c252009-07-17 12:17:14 -07004309 }
4310 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004311 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08004312 sendMsg(mAudioHandler,
4313 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08004314 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004315 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07004316 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08004317 streamState,
4318 PERSIST_DELAY);
4319
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004320 }
4321
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004322 private void setAllVolumes(VolumeStreamState streamState) {
4323
4324 // Apply volume
4325 streamState.applyAllVolumes();
4326
4327 // Apply change to all streams using this one as alias
4328 int numStreamTypes = AudioSystem.getNumStreamTypes();
4329 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4330 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07004331 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004332 mStreamStates[streamType].applyAllVolumes();
4333 }
4334 }
4335 }
4336
Eric Laurent42b041e2013-03-29 11:36:03 -07004337 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07004338 if (mUseFixedVolume) {
4339 return;
4340 }
Eric Laurent212532b2014-07-21 15:43:18 -07004341 if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
4342 return;
4343 }
Eric Laurent42b041e2013-03-29 11:36:03 -07004344 System.putIntForUser(mContentResolver,
4345 streamState.getSettingNameForDevice(device),
4346 (streamState.getIndex(device) + 5)/ 10,
4347 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004348 }
4349
Glenn Kastenba195eb2011-12-13 09:30:40 -08004350 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07004351 if (mUseFixedVolume) {
4352 return;
4353 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07004354 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004355 }
4356
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004357 private boolean onLoadSoundEffects() {
4358 int status;
4359
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004360 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004361 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004362 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
4363 return false;
4364 }
4365
4366 if (mSoundPool != null) {
4367 return true;
4368 }
4369
4370 loadTouchSoundAssets();
4371
Jean-Michel Trivi55a30c42014-07-20 17:56:11 -07004372 mSoundPool = new SoundPool.Builder()
4373 .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
4374 .setAudioAttributes(new AudioAttributes.Builder()
4375 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
4376 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
4377 .build())
4378 .build();
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004379 mSoundPoolCallBack = null;
4380 mSoundPoolListenerThread = new SoundPoolListenerThread();
4381 mSoundPoolListenerThread.start();
4382 int attempts = 3;
4383 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
4384 try {
4385 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07004386 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004387 } catch (InterruptedException e) {
4388 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
4389 }
4390 }
4391
4392 if (mSoundPoolCallBack == null) {
4393 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
4394 if (mSoundPoolLooper != null) {
4395 mSoundPoolLooper.quit();
4396 mSoundPoolLooper = null;
4397 }
4398 mSoundPoolListenerThread = null;
4399 mSoundPool.release();
4400 mSoundPool = null;
4401 return false;
4402 }
4403 /*
4404 * poolId table: The value -1 in this table indicates that corresponding
4405 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
4406 * Once loaded, the value in poolId is the sample ID and the same
4407 * sample can be reused for another effect using the same file.
4408 */
4409 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4410 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4411 poolId[fileIdx] = -1;
4412 }
4413 /*
4414 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
4415 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
4416 * this indicates we have a valid sample loaded for this effect.
4417 */
4418
4419 int numSamples = 0;
4420 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4421 // Do not load sample if this effect uses the MediaPlayer
4422 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
4423 continue;
4424 }
4425 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
4426 String filePath = Environment.getRootDirectory()
4427 + SOUND_EFFECTS_PATH
4428 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
4429 int sampleId = mSoundPool.load(filePath, 0);
4430 if (sampleId <= 0) {
4431 Log.w(TAG, "Soundpool could not load file: "+filePath);
4432 } else {
4433 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
4434 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
4435 numSamples++;
4436 }
4437 } else {
4438 SOUND_EFFECT_FILES_MAP[effect][1] =
4439 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
4440 }
4441 }
4442 // wait for all samples to be loaded
4443 if (numSamples > 0) {
4444 mSoundPoolCallBack.setSamples(poolId);
4445
4446 attempts = 3;
4447 status = 1;
4448 while ((status == 1) && (attempts-- > 0)) {
4449 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07004450 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004451 status = mSoundPoolCallBack.status();
4452 } catch (InterruptedException e) {
4453 Log.w(TAG, "Interrupted while waiting sound pool callback.");
4454 }
4455 }
4456 } else {
4457 status = -1;
4458 }
4459
4460 if (mSoundPoolLooper != null) {
4461 mSoundPoolLooper.quit();
4462 mSoundPoolLooper = null;
4463 }
4464 mSoundPoolListenerThread = null;
4465 if (status != 0) {
4466 Log.w(TAG,
4467 "onLoadSoundEffects(), Error "+status+ " while loading samples");
4468 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4469 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
4470 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4471 }
4472 }
4473
4474 mSoundPool.release();
4475 mSoundPool = null;
4476 }
4477 }
4478 return (status == 0);
4479 }
4480
4481 /**
4482 * Unloads samples from the sound pool.
4483 * This method can be called to free some memory when
4484 * sound effects are disabled.
4485 */
4486 private void onUnloadSoundEffects() {
4487 synchronized (mSoundEffectsLock) {
4488 if (mSoundPool == null) {
4489 return;
4490 }
4491
4492 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4493 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4494 poolId[fileIdx] = 0;
4495 }
4496
4497 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4498 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
4499 continue;
4500 }
4501 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
4502 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
4503 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4504 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
4505 }
4506 }
4507 mSoundPool.release();
4508 mSoundPool = null;
4509 }
4510 }
4511
4512 private void onPlaySoundEffect(int effectType, int volume) {
4513 synchronized (mSoundEffectsLock) {
4514
4515 onLoadSoundEffects();
4516
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004517 if (mSoundPool == null) {
4518 return;
4519 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004520 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08004521 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004522 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07004523 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004524 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07004525 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004526 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004527
4528 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004529 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
4530 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004531 } else {
4532 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004533 try {
Eric Laurente78fced2013-03-15 16:03:47 -07004534 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
4535 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004536 mediaPlayer.setDataSource(filePath);
4537 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
4538 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08004539 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004540 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
4541 public void onCompletion(MediaPlayer mp) {
4542 cleanupPlayer(mp);
4543 }
4544 });
4545 mediaPlayer.setOnErrorListener(new OnErrorListener() {
4546 public boolean onError(MediaPlayer mp, int what, int extra) {
4547 cleanupPlayer(mp);
4548 return true;
4549 }
4550 });
4551 mediaPlayer.start();
4552 } catch (IOException ex) {
4553 Log.w(TAG, "MediaPlayer IOException: "+ex);
4554 } catch (IllegalArgumentException ex) {
4555 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
4556 } catch (IllegalStateException ex) {
4557 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004558 }
4559 }
4560 }
4561 }
4562
4563 private void cleanupPlayer(MediaPlayer mp) {
4564 if (mp != null) {
4565 try {
4566 mp.stop();
4567 mp.release();
4568 } catch (IllegalStateException ex) {
4569 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
4570 }
4571 }
4572 }
4573
Eric Laurentfa640152011-03-12 15:59:51 -08004574 private void setForceUse(int usage, int config) {
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004575 synchronized (mConnectedDevices) {
4576 setForceUseInt_SyncDevices(usage, config);
4577 }
Eric Laurentfa640152011-03-12 15:59:51 -08004578 }
4579
Eric Laurent05274f32012-11-29 12:48:18 -08004580 private void onPersistSafeVolumeState(int state) {
4581 Settings.Global.putInt(mContentResolver,
4582 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
4583 state);
4584 }
4585
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004586 @Override
4587 public void handleMessage(Message msg) {
Eric Laurentafbb0472011-12-15 09:04:23 -08004588 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004589
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004590 case MSG_SET_DEVICE_VOLUME:
4591 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
4592 break;
4593
4594 case MSG_SET_ALL_VOLUMES:
4595 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004596 break;
4597
4598 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07004599 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004600 break;
4601
4602 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08004603 // note that the value persisted is the current ringer mode, not the
4604 // value of ringer mode as of the time the request was made to persist
John Spurlock661f2cf2014-11-17 10:29:10 -05004605 persistRingerMode(getRingerModeInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004606 break;
4607
Andy Hunged0ea402015-10-30 14:11:46 -07004608 case MSG_AUDIO_SERVER_DIED:
4609 onAudioServerDied();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004610 break;
4611
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004612 case MSG_UNLOAD_SOUND_EFFECTS:
4613 onUnloadSoundEffects();
4614 break;
4615
Eric Laurent117b7bb2011-01-16 17:07:27 -08004616 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004617 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
4618 // can take several dozens of milliseconds to complete
4619 boolean loaded = onLoadSoundEffects();
4620 if (msg.obj != null) {
4621 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
4622 synchronized (reply) {
4623 reply.mStatus = loaded ? 0 : -1;
4624 reply.notify();
4625 }
4626 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08004627 break;
4628
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004629 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004630 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004631 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004632
4633 case MSG_BTA2DP_DOCK_TIMEOUT:
4634 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004635 synchronized (mConnectedDevices) {
4636 makeA2dpDeviceUnavailableNow( (String) msg.obj );
4637 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004638 break;
Eric Laurentfa640152011-03-12 15:59:51 -08004639
4640 case MSG_SET_FORCE_USE:
Sungsoocf09fe62016-09-28 16:21:48 +09004641 case MSG_SET_FORCE_BT_A2DP_USE:
Eric Laurentfa640152011-03-12 15:59:51 -08004642 setForceUse(msg.arg1, msg.arg2);
4643 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07004644
Eric Laurentdc03c612011-04-01 10:59:41 -07004645 case MSG_BT_HEADSET_CNCT_FAILED:
4646 resetBluetoothSco();
4647 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004648
4649 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
Paul McLean10804eb2015-01-28 11:16:35 -08004650 { WiredDeviceConnectionState connectState =
4651 (WiredDeviceConnectionState)msg.obj;
4652 onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
John Spurlock90874332015-03-10 16:00:54 -04004653 connectState.mAddress, connectState.mName, connectState.mCaller);
Paul McLean10804eb2015-01-28 11:16:35 -08004654 mAudioEventWakeLock.release();
4655 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004656 break;
4657
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004658 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
4659 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
4660 mAudioEventWakeLock.release();
4661 break;
4662
4663 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
4664 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004665 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004666 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004667
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08004668 case MSG_A2DP_DEVICE_CONFIG_CHANGE:
4669 onBluetoothA2dpDeviceConfigChange((BluetoothDevice)msg.obj);
4670 mAudioEventWakeLock.release();
4671 break;
4672
Dianne Hackborn632ca412012-06-14 19:34:10 -07004673 case MSG_REPORT_NEW_ROUTES: {
4674 int N = mRoutesObservers.beginBroadcast();
4675 if (N > 0) {
4676 AudioRoutesInfo routes;
4677 synchronized (mCurAudioRoutes) {
4678 routes = new AudioRoutesInfo(mCurAudioRoutes);
4679 }
4680 while (N > 0) {
4681 N--;
4682 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
4683 try {
4684 obs.dispatchAudioRoutesChanged(routes);
4685 } catch (RemoteException e) {
4686 }
4687 }
4688 }
4689 mRoutesObservers.finishBroadcast();
John Spurlock8a52c442015-03-26 14:23:58 -04004690 observeDevicesForStreams(-1);
Dianne Hackborn632ca412012-06-14 19:34:10 -07004691 break;
4692 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004693
Eric Laurentc34dcc12012-09-10 13:51:52 -07004694 case MSG_CHECK_MUSIC_ACTIVE:
John Spurlock90874332015-03-10 16:00:54 -04004695 onCheckMusicActive((String) msg.obj);
Eric Laurentc34dcc12012-09-10 13:51:52 -07004696 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004697
4698 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
4699 onSendBecomingNoisyIntent();
4700 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07004701
4702 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
4703 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
John Spurlock90874332015-03-10 16:00:54 -04004704 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED),
4705 (String) msg.obj);
Eric Laurentd640bd32012-09-28 18:01:48 -07004706 break;
Eric Laurent05274f32012-11-29 12:48:18 -08004707 case MSG_PERSIST_SAFE_VOLUME_STATE:
4708 onPersistSafeVolumeState(msg.arg1);
4709 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08004710
Eric Laurent2a57ca92013-03-07 17:29:27 -08004711 case MSG_BROADCAST_BT_CONNECTION_STATE:
4712 onBroadcastScoConnectionState(msg.arg1);
4713 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004714
4715 case MSG_SYSTEM_READY:
4716 onSystemReady();
4717 break;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004718
Eric Laurent0867bed2015-05-20 14:49:08 -07004719 case MSG_INDICATE_SYSTEM_READY:
4720 onIndicateSystemReady();
4721 break;
4722
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004723 case MSG_PERSIST_MUSIC_ACTIVE_MS:
4724 final int musicActiveMs = msg.arg1;
4725 Settings.Secure.putIntForUser(mContentResolver,
4726 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
4727 UserHandle.USER_CURRENT);
4728 break;
Eric Laurentc0232482016-03-15 18:19:23 -07004729
RoboErik5452e252015-02-06 15:33:53 -08004730 case MSG_UNMUTE_STREAM:
4731 onUnmuteStream(msg.arg1, msg.arg2);
4732 break;
Eric Laurentc0232482016-03-15 18:19:23 -07004733
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07004734 case MSG_DYN_POLICY_MIX_STATE_UPDATE:
4735 onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1);
4736 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004737 }
4738 }
4739 }
4740
Jason Parekhb1096152009-03-24 17:48:25 -07004741 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07004742
Phil Burked43bf52016-03-01 17:01:35 -08004743 private int mEncodedSurroundMode;
4744
Jason Parekhb1096152009-03-24 17:48:25 -07004745 SettingsObserver() {
4746 super(new Handler());
4747 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4748 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004749 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4750 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Andy Hung7b98e9a2016-02-25 18:34:50 -08004751 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4752 Settings.System.MASTER_MONO), false, this);
Phil Burked43bf52016-03-01 17:01:35 -08004753
4754 mEncodedSurroundMode = Settings.Global.getInt(
4755 mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT,
4756 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
4757 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4758 Settings.Global.ENCODED_SURROUND_OUTPUT), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07004759 }
4760
4761 @Override
4762 public void onChange(boolean selfChange) {
4763 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08004764 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
4765 // However there appear to be some missing locks around mRingerModeMutedStreams
4766 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
4767 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07004768 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004769 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07004770 /*
4771 * Ensure all stream types that should be affected by ringer mode
4772 * are in the proper state.
4773 */
John Spurlock661f2cf2014-11-17 10:29:10 -05004774 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurenta553c252009-07-17 12:17:14 -07004775 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004776 readDockAudioSettings(mContentResolver);
Andy Hung7b98e9a2016-02-25 18:34:50 -08004777 updateMasterMono(mContentResolver);
Phil Burked43bf52016-03-01 17:01:35 -08004778 updateEncodedSurroundOutput();
4779 }
4780 }
4781
4782 private void updateEncodedSurroundOutput() {
4783 int newSurroundMode = Settings.Global.getInt(
4784 mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT,
4785 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
4786 // Did it change?
4787 if (mEncodedSurroundMode != newSurroundMode) {
4788 // Send to AudioPolicyManager
4789 sendEncodedSurroundMode(newSurroundMode);
4790 synchronized(mConnectedDevices) {
4791 // Is HDMI connected?
4792 String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_HDMI, "");
4793 DeviceListSpec deviceSpec = mConnectedDevices.get(key);
4794 if (deviceSpec != null) {
4795 // Toggle HDMI to retrigger broadcast with proper formats.
4796 setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
4797 AudioSystem.DEVICE_STATE_UNAVAILABLE, "", "",
4798 "android"); // disconnect
4799 setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
4800 AudioSystem.DEVICE_STATE_AVAILABLE, "", "",
4801 "android"); // reconnect
4802 }
4803 }
4804 mEncodedSurroundMode = newSurroundMode;
Eric Laurenta553c252009-07-17 12:17:14 -07004805 }
Jason Parekhb1096152009-03-24 17:48:25 -07004806 }
Jason Parekhb1096152009-03-24 17:48:25 -07004807 }
Eric Laurenta553c252009-07-17 12:17:14 -07004808
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004809 // must be called synchronized on mConnectedDevices
Paul McLean20eec5b2015-05-09 13:02:18 -07004810 private void makeA2dpDeviceAvailable(String address, String name) {
Eric Laurent78472112012-05-21 08:57:21 -07004811 // enable A2DP before notifying A2DP connection to avoid unecessary processing in
4812 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004813 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4814 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4815 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Sungsoocf09fe62016-09-28 16:21:48 +09004816 setBluetoothA2dpOnInt(true);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004817 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004818 AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004819 // Reset A2DP suspend state each time a new sink is connected
4820 AudioSystem.setParameters("A2dpSuspended=false");
Paul McLean394a8e12015-03-03 10:29:19 -07004821 mConnectedDevices.put(
4822 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
Paul McLean20eec5b2015-05-09 13:02:18 -07004823 new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
Paul McLean394a8e12015-03-03 10:29:19 -07004824 address));
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004825 }
4826
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004827 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004828 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07004829 }
4830
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004831 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004832 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004833 synchronized (mA2dpAvrcpLock) {
4834 mAvrcpAbsVolSupported = false;
4835 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004836 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004837 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004838 mConnectedDevices.remove(
4839 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
RoboErik5535ea82014-09-25 14:53:16 -07004840 synchronized (mCurAudioRoutes) {
4841 // Remove A2DP routes as well
John Spurlock61560172015-02-06 19:46:04 -05004842 if (mCurAudioRoutes.bluetoothName != null) {
4843 mCurAudioRoutes.bluetoothName = null;
RoboErik5535ea82014-09-25 14:53:16 -07004844 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4845 SENDMSG_NOOP, 0, 0, null, 0);
4846 }
4847 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004848 }
4849
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004850 // must be called synchronized on mConnectedDevices
Eric Laurentd138e4e2015-05-15 16:41:15 -07004851 private void makeA2dpDeviceUnavailableLater(String address, int delayMs) {
Eric Laurent3b591262010-04-20 07:01:00 -07004852 // prevent any activity on the A2DP audio output to avoid unwanted
4853 // reconnection of the sink.
4854 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004855 // the device will be made unavailable later, so consider it disconnected right away
Paul McLean394a8e12015-03-03 10:29:19 -07004856 mConnectedDevices.remove(
4857 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004858 // send the delayed message to make the device unavailable later
4859 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
Eric Laurentd138e4e2015-05-15 16:41:15 -07004860 mAudioHandler.sendMessageDelayed(msg, delayMs);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004861
4862 }
4863
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004864 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004865 private void makeA2dpSrcAvailable(String address) {
4866 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004867 AudioSystem.DEVICE_STATE_AVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004868 mConnectedDevices.put(
4869 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
Paul McLean20eec5b2015-05-09 13:02:18 -07004870 new DeviceListSpec(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "",
Paul McLean394a8e12015-03-03 10:29:19 -07004871 address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004872 }
4873
4874 // must be called synchronized on mConnectedDevices
4875 private void makeA2dpSrcUnavailable(String address) {
4876 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004877 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004878 mConnectedDevices.remove(
4879 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004880 }
4881
4882 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004883 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004884 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4885 }
4886
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004887 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004888 private boolean hasScheduledA2dpDockTimeout() {
4889 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4890 }
4891
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004892 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004893 {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004894 if (DEBUG_VOL) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08004895 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice+"state=" + state);
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004896 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004897 if (btDevice == null) {
4898 return;
4899 }
4900 String address = btDevice.getAddress();
4901 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4902 address = "";
4903 }
John Du5a0cf7a2013-07-19 11:30:34 -07004904
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004905 synchronized (mConnectedDevices) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08004906 final String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4907 btDevice.getAddress());
4908 final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
Paul McLean394a8e12015-03-03 10:29:19 -07004909 boolean isConnected = deviceSpec != null;
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004910
4911 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4912 if (btDevice.isBluetoothDock()) {
4913 if (state == BluetoothProfile.STATE_DISCONNECTED) {
4914 // introduction of a delay for transient disconnections of docks when
4915 // power is rapidly turned off/on, this message will be canceled if
4916 // we reconnect the dock under a preset delay
Eric Laurentd138e4e2015-05-15 16:41:15 -07004917 makeA2dpDeviceUnavailableLater(address, BTA2DP_DOCK_TIMEOUT_MILLIS);
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004918 // the next time isConnected is evaluated, it will be false for the dock
4919 }
4920 } else {
4921 makeA2dpDeviceUnavailableNow(address);
4922 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07004923 synchronized (mCurAudioRoutes) {
John Spurlock61560172015-02-06 19:46:04 -05004924 if (mCurAudioRoutes.bluetoothName != null) {
4925 mCurAudioRoutes.bluetoothName = null;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004926 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4927 SENDMSG_NOOP, 0, 0, null, 0);
4928 }
4929 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004930 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4931 if (btDevice.isBluetoothDock()) {
4932 // this could be a reconnection after a transient disconnection
4933 cancelA2dpDeviceTimeout();
4934 mDockAddress = address;
4935 } else {
4936 // this could be a connection of another A2DP device before the timeout of
4937 // a dock: cancel the dock timeout, and make the dock unavailable now
4938 if(hasScheduledA2dpDockTimeout()) {
4939 cancelA2dpDeviceTimeout();
4940 makeA2dpDeviceUnavailableNow(mDockAddress);
4941 }
4942 }
Paul McLean20eec5b2015-05-09 13:02:18 -07004943 makeA2dpDeviceAvailable(address, btDevice.getName());
Dianne Hackborn632ca412012-06-14 19:34:10 -07004944 synchronized (mCurAudioRoutes) {
4945 String name = btDevice.getAliasName();
John Spurlock61560172015-02-06 19:46:04 -05004946 if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
4947 mCurAudioRoutes.bluetoothName = name;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004948 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4949 SENDMSG_NOOP, 0, 0, null, 0);
4950 }
4951 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004952 }
4953 }
4954 }
4955
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004956 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
4957 {
4958 if (DEBUG_VOL) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08004959 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice=" + btDevice + " state=" + state);
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004960 }
4961 if (btDevice == null) {
4962 return;
4963 }
4964 String address = btDevice.getAddress();
4965 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4966 address = "";
4967 }
4968
4969 synchronized (mConnectedDevices) {
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08004970 final String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
4971 final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
Paul McLean394a8e12015-03-03 10:29:19 -07004972 boolean isConnected = deviceSpec != null;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004973
4974 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4975 makeA2dpSrcUnavailable(address);
4976 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4977 makeA2dpSrcAvailable(address);
4978 }
4979 }
4980 }
4981
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08004982 private void onBluetoothA2dpDeviceConfigChange(BluetoothDevice btDevice)
4983 {
4984 if (DEBUG_VOL) {
4985 Log.d(TAG, "onBluetoothA2dpDeviceConfigChange btDevice=" + btDevice);
4986 }
4987 if (btDevice == null) {
4988 return;
4989 }
4990 String address = btDevice.getAddress();
4991 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4992 address = "";
4993 }
4994
4995 int device = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
4996 synchronized (mConnectedDevices) {
4997 final String key = makeDeviceListKey(device, address);
4998 final DeviceListSpec deviceSpec = mConnectedDevices.get(key);
4999 if (deviceSpec != null) {
5000 // Device is connected
5001 AudioSystem.handleDeviceConfigChange(device, address,
5002 btDevice.getName());
5003 }
5004 }
5005 }
5006
John Du5a0cf7a2013-07-19 11:30:34 -07005007 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
5008 // address is not used for now, but may be used when multiple a2dp devices are supported
5009 synchronized (mA2dpAvrcpLock) {
5010 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07005011 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07005012 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
5013 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
5014 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
5015 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
5016 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07005017 }
5018 }
5019
Paul McLean394a8e12015-03-03 10:29:19 -07005020 private boolean handleDeviceConnection(boolean connect, int device, String address,
5021 String deviceName) {
5022 if (DEBUG_DEVICES) {
5023 Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device)
5024 + " address:" + address + " name:" + deviceName + ")");
5025 }
Eric Laurent59f48272012-04-05 19:42:21 -07005026 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07005027 String deviceKey = makeDeviceListKey(device, address);
5028 if (DEBUG_DEVICES) {
5029 Slog.i(TAG, "deviceKey:" + deviceKey);
5030 }
5031 DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
5032 boolean isConnected = deviceSpec != null;
5033 if (DEBUG_DEVICES) {
5034 Slog.i(TAG, "deviceSpec:" + deviceSpec + " is(already)Connected:" + isConnected);
5035 }
5036 if (connect && !isConnected) {
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07005037 final int res = AudioSystem.setDeviceConnectionState(device,
5038 AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);
5039 if (res != AudioSystem.AUDIO_STATUS_OK) {
5040 Slog.e(TAG, "not connecting device 0x" + Integer.toHexString(device) +
5041 " due to command error " + res );
5042 return false;
5043 }
Paul McLean394a8e12015-03-03 10:29:19 -07005044 mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
5045 return true;
5046 } else if (!connect && isConnected) {
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07005047 AudioSystem.setDeviceConnectionState(device,
5048 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName);
5049 // always remove even if disconnection failed
Paul McLean394a8e12015-03-03 10:29:19 -07005050 mConnectedDevices.remove(deviceKey);
5051 return true;
Eric Laurent59f48272012-04-05 19:42:21 -07005052 }
5053 }
5054 return false;
5055 }
5056
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005057 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
5058 // sent if none of these devices is connected.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005059 // Access synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005060 int mBecomingNoisyIntentDevices =
5061 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07005062 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07005063 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Jon Eklund43cc8bb2014-07-28 16:07:24 -05005064 AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005065
5066 // must be called before removing the device from mConnectedDevices
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005067 // Called synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005068 private int checkSendBecomingNoisyIntent(int device, int state) {
5069 int delay = 0;
5070 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
5071 int devices = 0;
John Spurlock8c3dc852015-04-23 21:32:37 -04005072 for (int i = 0; i < mConnectedDevices.size(); i++) {
5073 int dev = mConnectedDevices.valueAt(i).mDeviceType;
Paul McLean394a8e12015-03-03 10:29:19 -07005074 if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
5075 && ((dev & mBecomingNoisyIntentDevices) != 0)) {
5076 devices |= dev;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005077 }
5078 }
5079 if (devices == device) {
Eric Laurent5bfaeae2012-09-21 18:44:48 -07005080 sendMsg(mAudioHandler,
5081 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
5082 SENDMSG_REPLACE,
5083 0,
5084 0,
5085 null,
5086 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005087 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005088 }
5089 }
5090
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005091 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
5092 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005093 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
Eric Laurentadbe8bf2014-11-03 18:26:32 -08005094 synchronized (mLastDeviceConnectMsgTime) {
5095 long time = SystemClock.uptimeMillis();
5096 if (mLastDeviceConnectMsgTime > time) {
Matthew Xiec525cf72015-01-22 20:13:17 -08005097 delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
Eric Laurentadbe8bf2014-11-03 18:26:32 -08005098 }
5099 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005100 }
5101 return delay;
5102 }
5103
Paul McLean394a8e12015-03-03 10:29:19 -07005104 private void sendDeviceConnectionIntent(int device, int state, String address,
5105 String deviceName) {
5106 if (DEBUG_DEVICES) {
5107 Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
5108 " state:0x" + Integer.toHexString(state) + " address:" + address +
5109 " name:" + deviceName + ");");
5110 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005111 Intent intent = new Intent();
5112
Paul McLean10804eb2015-01-28 11:16:35 -08005113 intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
5114 intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
5115 intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
5116
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005117 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
5118
Dianne Hackborn632ca412012-06-14 19:34:10 -07005119 int connType = 0;
5120
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005121 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07005122 connType = AudioRoutesInfo.MAIN_HEADSET;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005123 intent.setAction(Intent.ACTION_HEADSET_PLUG);
5124 intent.putExtra("microphone", 1);
Jon Eklund43cc8bb2014-07-28 16:07:24 -05005125 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
5126 device == AudioSystem.DEVICE_OUT_LINE) {
5127 /*do apps care about line-out vs headphones?*/
Dianne Hackborn632ca412012-06-14 19:34:10 -07005128 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005129 intent.setAction(Intent.ACTION_HEADSET_PLUG);
5130 intent.putExtra("microphone", 0);
Eric Laurent6fa42452015-01-09 15:09:40 -08005131 } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
5132 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07005133 connType = AudioRoutesInfo.MAIN_HDMI;
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005134 configureHdmiPlugIntent(intent, state);
Paul McLean10804eb2015-01-28 11:16:35 -08005135 } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE) {
5136 connType = AudioRoutesInfo.MAIN_USB;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005137 }
5138
Dianne Hackborn632ca412012-06-14 19:34:10 -07005139 synchronized (mCurAudioRoutes) {
5140 if (connType != 0) {
John Spurlock61560172015-02-06 19:46:04 -05005141 int newConn = mCurAudioRoutes.mainType;
Dianne Hackborn632ca412012-06-14 19:34:10 -07005142 if (state != 0) {
5143 newConn |= connType;
5144 } else {
5145 newConn &= ~connType;
5146 }
John Spurlock61560172015-02-06 19:46:04 -05005147 if (newConn != mCurAudioRoutes.mainType) {
5148 mCurAudioRoutes.mainType = newConn;
Dianne Hackborn632ca412012-06-14 19:34:10 -07005149 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
5150 SENDMSG_NOOP, 0, 0, null, 0);
5151 }
5152 }
5153 }
5154
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005155 final long ident = Binder.clearCallingIdentity();
5156 try {
5157 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
5158 } finally {
5159 Binder.restoreCallingIdentity(ident);
5160 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005161 }
5162
Paul McLean10804eb2015-01-28 11:16:35 -08005163 private void onSetWiredDeviceConnectionState(int device, int state, String address,
John Spurlock90874332015-03-10 16:00:54 -04005164 String deviceName, String caller) {
Paul McLean394a8e12015-03-03 10:29:19 -07005165 if (DEBUG_DEVICES) {
John Spurlock90874332015-03-10 16:00:54 -04005166 Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
5167 + " state:" + Integer.toHexString(state)
5168 + " address:" + address
5169 + " deviceName:" + deviceName
5170 + " caller: " + caller + ");");
Paul McLean394a8e12015-03-03 10:29:19 -07005171 }
Paul McLean10804eb2015-01-28 11:16:35 -08005172
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005173 synchronized (mConnectedDevices) {
Sungsoocf09fe62016-09-28 16:21:48 +09005174 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
5175 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
5176 (device == AudioSystem.DEVICE_OUT_LINE))) {
5177 setBluetoothA2dpOnInt(true);
5178 }
Eric Laurentae4506e2014-05-29 16:04:32 -07005179 boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
5180 (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
5181 ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07005182 if (!handleDeviceConnection(state == 1, device, address, deviceName)) {
5183 // change of connection state failed, bailout
5184 return;
5185 }
Eric Laurentf1a457d2012-09-20 16:27:23 -07005186 if (state != 0) {
Sungsoocf09fe62016-09-28 16:21:48 +09005187 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
5188 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
5189 (device == AudioSystem.DEVICE_OUT_LINE)) {
5190 setBluetoothA2dpOnInt(false);
5191 }
Eric Laurentf1a457d2012-09-20 16:27:23 -07005192 if ((device & mSafeMediaVolumeDevices) != 0) {
5193 sendMsg(mAudioHandler,
5194 MSG_CHECK_MUSIC_ACTIVE,
5195 SENDMSG_REPLACE,
5196 0,
5197 0,
John Spurlock90874332015-03-10 16:00:54 -04005198 caller,
Eric Laurentf1a457d2012-09-20 16:27:23 -07005199 MUSIC_ACTIVE_POLL_PERIOD_MS);
5200 }
Eric Laurent212532b2014-07-21 15:43:18 -07005201 // Television devices without CEC service apply software volume on HDMI output
5202 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
5203 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
5204 checkAllFixedVolumeDevices();
5205 if (mHdmiManager != null) {
5206 synchronized (mHdmiManager) {
5207 if (mHdmiPlaybackClient != null) {
5208 mHdmiCecSink = false;
5209 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
5210 }
5211 }
5212 }
5213 }
5214 } else {
5215 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
5216 if (mHdmiManager != null) {
5217 synchronized (mHdmiManager) {
5218 mHdmiCecSink = false;
5219 }
5220 }
5221 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005222 }
Paul McLean10804eb2015-01-28 11:16:35 -08005223 if (!isUsb && device != AudioSystem.DEVICE_IN_WIRED_HEADSET) {
5224 sendDeviceConnectionIntent(device, state, address, deviceName);
Mike Lockwooddb454842012-09-18 11:16:57 -07005225 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005226 }
5227 }
5228
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005229 private void configureHdmiPlugIntent(Intent intent, int state) {
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005230 intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
5231 intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005232 if (state == 1) {
5233 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
5234 int[] portGeneration = new int[1];
5235 int status = AudioSystem.listAudioPorts(ports, portGeneration);
5236 if (status == AudioManager.SUCCESS) {
5237 for (AudioPort port : ports) {
5238 if (port instanceof AudioDevicePort) {
5239 final AudioDevicePort devicePort = (AudioDevicePort) port;
Eric Laurent6fa42452015-01-09 15:09:40 -08005240 if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
5241 devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005242 // format the list of supported encodings
Eric Laurentcae34662015-05-19 16:46:52 -07005243 int[] formats = AudioFormat.filterPublicFormats(devicePort.formats());
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005244 if (formats.length > 0) {
5245 ArrayList<Integer> encodingList = new ArrayList(1);
5246 for (int format : formats) {
5247 // a format in the list can be 0, skip it
5248 if (format != AudioFormat.ENCODING_INVALID) {
5249 encodingList.add(format);
5250 }
5251 }
5252 int[] encodingArray = new int[encodingList.size()];
5253 for (int i = 0 ; i < encodingArray.length ; i++) {
5254 encodingArray[i] = encodingList.get(i);
5255 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005256 intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005257 }
5258 // find the maximum supported number of channels
5259 int maxChannels = 0;
5260 for (int mask : devicePort.channelMasks()) {
5261 int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
5262 if (channelCount > maxChannels) {
5263 maxChannels = channelCount;
5264 }
5265 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005266 intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005267 }
5268 }
5269 }
5270 }
5271 }
5272 }
5273
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07005274 /* cache of the address of the last dock the device was connected to */
5275 private String mDockAddress;
5276
Eric Laurenta553c252009-07-17 12:17:14 -07005277 /**
5278 * Receiver for misc intent broadcasts the Phone app cares about.
5279 */
5280 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
5281 @Override
5282 public void onReceive(Context context, Intent intent) {
5283 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07005284 int outDevice;
5285 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07005286 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07005287
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08005288 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
5289 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
5290 Intent.EXTRA_DOCK_STATE_UNDOCKED);
5291 int config;
5292 switch (dockState) {
5293 case Intent.EXTRA_DOCK_STATE_DESK:
5294 config = AudioSystem.FORCE_BT_DESK_DOCK;
5295 break;
5296 case Intent.EXTRA_DOCK_STATE_CAR:
5297 config = AudioSystem.FORCE_BT_CAR_DOCK;
5298 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05005299 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08005300 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05005301 break;
5302 case Intent.EXTRA_DOCK_STATE_HE_DESK:
5303 config = AudioSystem.FORCE_DIGITAL_DOCK;
5304 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08005305 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
5306 default:
5307 config = AudioSystem.FORCE_NONE;
5308 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08005309 // Low end docks have a menu to enable or disable audio
5310 // (see mDockAudioMediaEnabled)
5311 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
5312 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
5313 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
5314 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
5315 }
5316 mDockState = dockState;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07005317 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
Eric Laurent59f48272012-04-05 19:42:21 -07005318 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07005319 BluetoothProfile.STATE_DISCONNECTED);
Eric Laurentdca56b92011-09-02 14:20:56 -07005320 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Eric Laurent98859b22015-06-12 14:35:59 -07005321 setBtScoDeviceConnectionState(btDevice, state);
Paul McLeandf361462014-04-10 16:02:55 -07005322 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005323 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07005324 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005325 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005326 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07005327 // broadcast intent if the connection was initated by AudioService
5328 if (!mScoClients.isEmpty() &&
5329 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
5330 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
5331 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005332 broadcast = true;
5333 }
5334 switch (btState) {
5335 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07005336 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07005337 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5338 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5339 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005340 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005341 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005342 break;
5343 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07005344 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08005345 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07005346 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08005347 break;
5348 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07005349 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5350 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5351 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005352 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005353 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005354 default:
5355 // do not broadcast CONNECTING or invalid state
5356 broadcast = false;
5357 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005358 }
5359 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005360 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07005361 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07005362 //FIXME: this is to maintain compatibility with deprecated intent
5363 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08005364 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07005365 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005366 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08005367 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005368 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06005369 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005370 RotationHelper.enable();
Jon Eklund318f0fe2014-01-23 17:53:48 -06005371 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005372 AudioSystem.setParameters("screen_state=on");
5373 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06005374 if (mMonitorRotation) {
5375 //reduce wakeups (save current) by only listening when display is on
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005376 RotationHelper.disable();
Jon Eklund318f0fe2014-01-23 17:53:48 -06005377 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005378 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07005379 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005380 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07005381 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Yasuhiro Matsuda4ced7192015-07-10 22:08:44 +09005382 if (mUserSwitchedReceived) {
5383 // attempt to stop music playback for background user except on first user
5384 // switch (i.e. first boot)
5385 sendMsg(mAudioHandler,
5386 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
5387 SENDMSG_REPLACE,
5388 0,
5389 0,
5390 null,
5391 0);
5392 }
5393 mUserSwitchedReceived = true;
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07005394 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005395 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07005396
Eric Laurent5bfaeae2012-09-21 18:44:48 -07005397 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07005398 readAudioSettings(true /*userSwitch*/);
5399 // preserve STREAM_MUSIC volume from one user to the next.
5400 sendMsg(mAudioHandler,
5401 MSG_SET_ALL_VOLUMES,
5402 SENDMSG_QUEUE,
5403 0,
5404 0,
5405 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005406 } else if (action.equals(Intent.ACTION_USER_BACKGROUND)) {
5407 // Disable audio recording for the background user/profile
5408 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
5409 if (userId >= 0) {
5410 // TODO Kill recording streams instead of killing processes holding permission
5411 UserInfo userInfo = UserManagerService.getInstance().getUserInfo(userId);
5412 killBackgroundUserProcessesWithRecordAudioPermission(userInfo);
5413 }
Makoto Onukiac65e1e2015-11-20 15:33:17 -08005414 UserManagerService.getInstance().setUserRestriction(
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005415 UserManager.DISALLOW_RECORD_AUDIO, true, userId);
5416 } else if (action.equals(Intent.ACTION_USER_FOREGROUND)) {
5417 // Enable audio recording for foreground user/profile
5418 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Makoto Onukiac65e1e2015-11-20 15:33:17 -08005419 UserManagerService.getInstance().setUserRestriction(
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005420 UserManager.DISALLOW_RECORD_AUDIO, false, userId);
Eric Laurentb70b78a2016-01-13 19:16:04 -08005421 } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
5422 state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
5423 if (state == BluetoothAdapter.STATE_OFF ||
5424 state == BluetoothAdapter.STATE_TURNING_OFF) {
5425 disconnectAllBluetoothProfiles();
5426 }
Eric Laurenta553c252009-07-17 12:17:14 -07005427 }
5428 }
Paul McLeanc837a452014-04-09 09:04:43 -07005429 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005430
Makoto Onukid45a4a22015-11-02 17:17:38 -08005431 private class AudioServiceUserRestrictionsListener implements UserRestrictionsListener {
5432
5433 @Override
5434 public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
5435 Bundle prevRestrictions) {
5436 // Update mic mute state.
5437 {
5438 final boolean wasRestricted =
5439 prevRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
5440 final boolean isRestricted =
5441 newRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
5442 if (wasRestricted != isRestricted) {
5443 setMicrophoneMuteNoCallerCheck(isRestricted, userId);
5444 }
5445 }
5446
5447 // Update speaker mute state.
5448 {
5449 final boolean wasRestricted =
Tony Makc1205112016-07-22 16:02:59 +01005450 prevRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)
5451 || prevRestrictions.getBoolean(UserManager.DISALLLOW_UNMUTE_DEVICE);
Makoto Onukid45a4a22015-11-02 17:17:38 -08005452 final boolean isRestricted =
Tony Makc1205112016-07-22 16:02:59 +01005453 newRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)
5454 || newRestrictions.getBoolean(UserManager.DISALLLOW_UNMUTE_DEVICE);
Makoto Onukid45a4a22015-11-02 17:17:38 -08005455 if (wasRestricted != isRestricted) {
5456 setMasterMuteInternalNoCallerCheck(isRestricted, /* flags =*/ 0, userId);
5457 }
5458 }
5459 }
5460 } // end class AudioServiceUserRestrictionsListener
5461
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005462 private void killBackgroundUserProcessesWithRecordAudioPermission(UserInfo oldUser) {
5463 PackageManager pm = mContext.getPackageManager();
5464 // Find the home activity of the user. It should not be killed to avoid expensive restart,
5465 // when the user switches back. For managed profiles, we should kill all recording apps
5466 ComponentName homeActivityName = null;
5467 if (!oldUser.isManagedProfile()) {
5468 homeActivityName = LocalServices.getService(ActivityManagerInternal.class)
5469 .getHomeActivityForUser(oldUser.id);
5470 }
5471 final String[] permissions = { Manifest.permission.RECORD_AUDIO };
5472 List<PackageInfo> packages;
5473 try {
5474 packages = AppGlobals.getPackageManager()
5475 .getPackagesHoldingPermissions(permissions, 0, oldUser.id).getList();
5476 } catch (RemoteException e) {
5477 throw new AndroidRuntimeException(e);
5478 }
5479 for (int j = packages.size() - 1; j >= 0; j--) {
5480 PackageInfo pkg = packages.get(j);
Fyodor Kupolovbcb6c1e2015-05-11 12:05:15 -07005481 // Skip system processes
5482 if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
5483 continue;
5484 }
Amith Yamasanic1cbaab2015-07-21 11:46:14 -07005485 // Skip packages that have permission to interact across users
5486 if (pm.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS, pkg.packageName)
5487 == PackageManager.PERMISSION_GRANTED) {
5488 continue;
5489 }
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005490 if (homeActivityName != null
5491 && pkg.packageName.equals(homeActivityName.getPackageName())
5492 && pkg.applicationInfo.isSystemApp()) {
5493 continue;
5494 }
5495 try {
Svetoslavaa41add2015-08-06 15:03:55 -07005496 final int uid = pkg.applicationInfo.uid;
5497 ActivityManagerNative.getDefault().killUid(UserHandle.getAppId(uid),
5498 UserHandle.getUserId(uid),
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005499 "killBackgroundUserProcessesWithAudioRecordPermission");
5500 } catch (RemoteException e) {
5501 Log.w(TAG, "Error calling killUid", e);
5502 }
5503 }
5504 }
5505
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005506
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005507 //==========================================================================================
5508 // Audio Focus
5509 //==========================================================================================
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005510 public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005511 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005512 IAudioPolicyCallback pcb) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005513 // permission checks
5514 if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
John Spurlock61560172015-02-06 19:46:04 -05005515 if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005516 if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
5517 android.Manifest.permission.MODIFY_PHONE_STATE)) {
5518 Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
5519 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5520 }
5521 } else {
5522 // only a registered audio policy can be used to lock focus
5523 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005524 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
5525 Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005526 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5527 }
5528 }
5529 }
5530 }
5531
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005532 return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
5533 clientId, callingPackageName, flags);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005534 }
5535
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005536 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
5537 return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005538 }
5539
5540 public void unregisterAudioFocusClient(String clientId) {
5541 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005542 }
5543
Jean-Michel Trivi23805662013-07-31 14:19:18 -07005544 public int getCurrentAudioFocus() {
5545 return mMediaFocusControl.getCurrentAudioFocus();
5546 }
5547
John Spurlock5e783732015-02-19 10:28:59 -05005548 private boolean readCameraSoundForced() {
5549 return SystemProperties.getBoolean("audio.camerasound.force", false) ||
5550 mContext.getResources().getBoolean(
5551 com.android.internal.R.bool.config_camera_sound_forced);
5552 }
5553
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005554 //==========================================================================================
5555 // Device orientation
5556 //==========================================================================================
5557 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005558 * Handles device configuration changes that may map to a change in the orientation
5559 * or orientation.
5560 * Monitoring orientation and rotation is optional, and is defined by the definition and value
5561 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005562 */
5563 private void handleConfigurationChanged(Context context) {
5564 try {
5565 // reading new orientation "safely" (i.e. under try catch) in case anything
5566 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07005567 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005568 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07005569 if (mMonitorOrientation) {
5570 int newOrientation = config.orientation;
5571 if (newOrientation != mDeviceOrientation) {
5572 mDeviceOrientation = newOrientation;
5573 setOrientationForAudioSystem();
5574 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005575 }
Eric Laurentd640bd32012-09-28 18:01:48 -07005576 sendMsg(mAudioHandler,
5577 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
5578 SENDMSG_REPLACE,
5579 0,
5580 0,
John Spurlock90874332015-03-10 16:00:54 -04005581 TAG,
Eric Laurentd640bd32012-09-28 18:01:48 -07005582 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07005583
John Spurlock5e783732015-02-19 10:28:59 -05005584 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -07005585 synchronized (mSettingsLock) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005586 boolean cameraSoundForcedChanged = false;
Eric Laurentdd45d012012-10-08 09:04:34 -07005587 synchronized (mCameraSoundForced) {
5588 if (cameraSoundForced != mCameraSoundForced) {
5589 mCameraSoundForced = cameraSoundForced;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005590 cameraSoundForcedChanged = true;
Eric Laurentdd45d012012-10-08 09:04:34 -07005591 }
5592 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005593 if (cameraSoundForcedChanged) {
5594 if (!isPlatformTelevision()) {
5595 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
5596 if (cameraSoundForced) {
5597 s.setAllIndexesToMax();
5598 mRingerModeAffectedStreams &=
5599 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5600 } else {
John Spurlock90874332015-03-10 16:00:54 -04005601 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005602 mRingerModeAffectedStreams |=
5603 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5604 }
5605 // take new state into account for streams muted by ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05005606 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005607 }
5608
5609 sendMsg(mAudioHandler,
5610 MSG_SET_FORCE_USE,
5611 SENDMSG_QUEUE,
5612 AudioSystem.FOR_SYSTEM,
5613 cameraSoundForced ?
5614 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
5615 null,
5616 0);
5617
5618 sendMsg(mAudioHandler,
5619 MSG_SET_ALL_VOLUMES,
5620 SENDMSG_QUEUE,
5621 0,
5622 0,
5623 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
5624 }
Eric Laurentdd45d012012-10-08 09:04:34 -07005625 }
John Spurlock3346a802014-05-20 16:25:37 -04005626 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005627 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005628 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005629 }
5630 }
5631
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005632 //TODO move to an external "orientation helper" class
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005633 private void setOrientationForAudioSystem() {
5634 switch (mDeviceOrientation) {
5635 case Configuration.ORIENTATION_LANDSCAPE:
5636 //Log.i(TAG, "orientation is landscape");
5637 AudioSystem.setParameters("orientation=landscape");
5638 break;
5639 case Configuration.ORIENTATION_PORTRAIT:
5640 //Log.i(TAG, "orientation is portrait");
5641 AudioSystem.setParameters("orientation=portrait");
5642 break;
5643 case Configuration.ORIENTATION_SQUARE:
5644 //Log.i(TAG, "orientation is square");
5645 AudioSystem.setParameters("orientation=square");
5646 break;
5647 case Configuration.ORIENTATION_UNDEFINED:
5648 //Log.i(TAG, "orientation is undefined");
5649 AudioSystem.setParameters("orientation=undefined");
5650 break;
5651 default:
5652 Log.e(TAG, "Unknown orientation");
5653 }
5654 }
5655
Sungsoocf09fe62016-09-28 16:21:48 +09005656 // Handles request to override default use of A2DP for media.
5657 // Must be called synchronized on mConnectedDevices
5658 public void setBluetoothA2dpOnInt(boolean on) {
5659 synchronized (mBluetoothA2dpEnabledLock) {
5660 mBluetoothA2dpEnabled = on;
5661 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
5662 setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
5663 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
5664 }
5665 }
5666
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005667 // Must be called synchronized on mConnectedDevices
5668 private void setForceUseInt_SyncDevices(int usage, int config) {
5669 switch (usage) {
Sungsoocf09fe62016-09-28 16:21:48 +09005670 case AudioSystem.FOR_MEDIA:
5671 if (config == AudioSystem.FORCE_NO_BT_A2DP) {
5672 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ALL_A2DP;
5673 } else { // config == AudioSystem.FORCE_NONE
5674 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
5675 }
Sungsoo71f35632016-09-28 16:26:49 +09005676 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
5677 SENDMSG_NOOP, 0, 0, null, 0);
Sungsoocf09fe62016-09-28 16:21:48 +09005678 break;
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005679 case AudioSystem.FOR_DOCK:
5680 if (config == AudioSystem.FORCE_ANALOG_DOCK) {
5681 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5682 } else { // config == AudioSystem.FORCE_NONE
5683 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5684 }
5685 break;
5686 default:
5687 // usage doesn't affect the broadcast of ACTION_AUDIO_BECOMING_NOISY
5688 }
5689 AudioSystem.setForceUse(usage, config);
5690 }
5691
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005692 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07005693 public void setRingtonePlayer(IRingtonePlayer player) {
5694 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5695 mRingtonePlayer = player;
5696 }
5697
5698 @Override
5699 public IRingtonePlayer getRingtonePlayer() {
5700 return mRingtonePlayer;
5701 }
5702
5703 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07005704 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5705 synchronized (mCurAudioRoutes) {
5706 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5707 mRoutesObservers.register(observer);
5708 return routes;
5709 }
5710 }
5711
Eric Laurentc34dcc12012-09-10 13:51:52 -07005712
5713 //==========================================================================================
5714 // Safe media volume management.
5715 // MUSIC stream volume level is limited when headphones are connected according to safety
5716 // regulation. When the user attempts to raise the volume above the limit, a warning is
5717 // displayed and the user has to acknowlegde before the volume is actually changed.
5718 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
5719 // property. Platforms with a different limit must set this property accordingly in their
5720 // overlay.
5721 //==========================================================================================
5722
Eric Laurentd640bd32012-09-28 18:01:48 -07005723 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
5724 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
5725 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
5726 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
5727 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
5728 // (when user opts out).
John Spurlock35134602014-07-24 18:10:48 -04005729 private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
5730 private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
5731 private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed
5732 private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
Eric Laurentd640bd32012-09-28 18:01:48 -07005733 private Integer mSafeMediaVolumeState;
5734
5735 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005736 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07005737 private int mSafeMediaVolumeIndex;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005738 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
5739 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
5740 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
5741 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
5742 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
5743 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
5744 private int mMusicActiveMs;
5745 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
5746 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07005747 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07005748
John Spurlock90874332015-03-10 16:00:54 -04005749 private void setSafeMediaVolumeEnabled(boolean on, String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005750 synchronized (mSafeMediaVolumeState) {
5751 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
5752 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
5753 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
5754 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
John Spurlock90874332015-03-10 16:00:54 -04005755 enforceSafeMediaVolume(caller);
Eric Laurentd640bd32012-09-28 18:01:48 -07005756 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
5757 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005758 mMusicActiveMs = 1; // nonzero = confirmed
5759 saveMusicActiveMs();
Eric Laurentd640bd32012-09-28 18:01:48 -07005760 sendMsg(mAudioHandler,
5761 MSG_CHECK_MUSIC_ACTIVE,
5762 SENDMSG_REPLACE,
5763 0,
5764 0,
John Spurlock90874332015-03-10 16:00:54 -04005765 caller,
Eric Laurentd640bd32012-09-28 18:01:48 -07005766 MUSIC_ACTIVE_POLL_PERIOD_MS);
5767 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005768 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005769 }
5770 }
5771
John Spurlock90874332015-03-10 16:00:54 -04005772 private void enforceSafeMediaVolume(String caller) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005773 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07005774 int devices = mSafeMediaVolumeDevices;
5775 int i = 0;
5776
5777 while (devices != 0) {
5778 int device = 1 << i++;
5779 if ((device & devices) == 0) {
5780 continue;
5781 }
Eric Laurent42b041e2013-03-29 11:36:03 -07005782 int index = streamState.getIndex(device);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005783 if (index > mSafeMediaVolumeIndex) {
John Spurlock90874332015-03-10 16:00:54 -04005784 streamState.setIndex(mSafeMediaVolumeIndex, device, caller);
Eric Laurent42b041e2013-03-29 11:36:03 -07005785 sendMsg(mAudioHandler,
5786 MSG_SET_DEVICE_VOLUME,
5787 SENDMSG_QUEUE,
5788 device,
5789 0,
5790 streamState,
5791 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005792 }
5793 devices &= ~device;
5794 }
5795 }
5796
5797 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005798 synchronized (mSafeMediaVolumeState) {
5799 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07005800 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
5801 ((device & mSafeMediaVolumeDevices) != 0) &&
5802 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005803 return false;
5804 }
5805 return true;
5806 }
5807 }
5808
John Spurlock3346a802014-05-20 16:25:37 -04005809 @Override
John Spurlock90874332015-03-10 16:00:54 -04005810 public void disableSafeMediaVolume(String callingPackage) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005811 enforceVolumeController("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07005812 synchronized (mSafeMediaVolumeState) {
John Spurlock90874332015-03-10 16:00:54 -04005813 setSafeMediaVolumeEnabled(false, callingPackage);
Eric Laurentfde16d52012-12-03 14:42:39 -08005814 if (mPendingVolumeCommand != null) {
5815 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
5816 mPendingVolumeCommand.mIndex,
5817 mPendingVolumeCommand.mFlags,
John Spurlock90874332015-03-10 16:00:54 -04005818 mPendingVolumeCommand.mDevice,
5819 callingPackage);
Eric Laurentfde16d52012-12-03 14:42:39 -08005820 mPendingVolumeCommand = null;
5821 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005822 }
5823 }
5824
Jungshik Jang41d97462014-06-30 22:26:29 +09005825 //==========================================================================================
5826 // Hdmi Cec system audio mode.
John Spurlockbc82b122015-03-02 16:12:38 -05005827 // If Hdmi Cec's system audio mode is on, audio service should send the volume change
5828 // to HdmiControlService so that the audio receiver can handle it.
Jungshik Jang41d97462014-06-30 22:26:29 +09005829 //==========================================================================================
5830
Eric Laurent212532b2014-07-21 15:43:18 -07005831 private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
5832 public void onComplete(int status) {
5833 if (mHdmiManager != null) {
5834 synchronized (mHdmiManager) {
5835 mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
5836 // Television devices without CEC service apply software volume on HDMI output
5837 if (isPlatformTelevision() && !mHdmiCecSink) {
5838 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5839 }
5840 checkAllFixedVolumeDevices();
5841 }
5842 }
5843 }
5844 };
5845
Jungshik Jang41d97462014-06-30 22:26:29 +09005846 // If HDMI-CEC system audio is supported
5847 private boolean mHdmiSystemAudioSupported = false;
5848 // Set only when device is tv.
5849 private HdmiTvClient mHdmiTvClient;
Eric Laurent0b03f992014-11-18 18:08:02 -08005850 // true if the device has system feature PackageManager.FEATURE_LEANBACK.
Eric Laurent212532b2014-07-21 15:43:18 -07005851 // cached HdmiControlManager interface
5852 private HdmiControlManager mHdmiManager;
5853 // Set only when device is a set-top box.
5854 private HdmiPlaybackClient mHdmiPlaybackClient;
5855 // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5856 private boolean mHdmiCecSink;
5857
5858 private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
Jungshik Jang41d97462014-06-30 22:26:29 +09005859
5860 @Override
Jungshik Jang12307ca2014-07-15 19:27:56 +09005861 public int setHdmiSystemAudioSupported(boolean on) {
Eric Laurent212532b2014-07-21 15:43:18 -07005862 int device = AudioSystem.DEVICE_NONE;
5863 if (mHdmiManager != null) {
5864 synchronized (mHdmiManager) {
5865 if (mHdmiTvClient == null) {
5866 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5867 return device;
5868 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005869
Eric Laurent212532b2014-07-21 15:43:18 -07005870 synchronized (mHdmiTvClient) {
5871 if (mHdmiSystemAudioSupported != on) {
5872 mHdmiSystemAudioSupported = on;
5873 AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5874 on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5875 AudioSystem.FORCE_NONE);
5876 }
John Spurlock8a52c442015-03-26 14:23:58 -04005877 device = getDevicesForStream(AudioSystem.STREAM_MUSIC);
Eric Laurent212532b2014-07-21 15:43:18 -07005878 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005879 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005880 }
Eric Laurent212532b2014-07-21 15:43:18 -07005881 return device;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005882 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005883
Terry Heoe7d6d972014-09-04 21:05:28 +09005884 @Override
5885 public boolean isHdmiSystemAudioSupported() {
5886 return mHdmiSystemAudioSupported;
5887 }
5888
Eric Laurentdd45d012012-10-08 09:04:34 -07005889 //==========================================================================================
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005890 // Accessibility: taking touch exploration into account for selecting the default
5891 // stream override timeout when adjusting volume
5892 //==========================================================================================
5893 private static class StreamOverride
5894 implements AccessibilityManager.TouchExplorationStateChangeListener {
5895
5896 // AudioService.getActiveStreamType() will return:
5897 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
5898 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
5899 // stopped
Jean-Michel Triviccffda82015-05-21 18:23:57 -07005900 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 0;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005901 private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
5902
5903 static int sDelayMs;
5904
5905 static void init(Context ctxt) {
5906 AccessibilityManager accessibilityManager =
5907 (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
5908 updateDefaultStreamOverrideDelay(
5909 accessibilityManager.isTouchExplorationEnabled());
5910 accessibilityManager.addTouchExplorationStateChangeListener(
5911 new StreamOverride());
5912 }
5913
5914 @Override
5915 public void onTouchExplorationStateChanged(boolean enabled) {
5916 updateDefaultStreamOverrideDelay(enabled);
5917 }
5918
5919 private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
5920 if (touchExploreEnabled) {
5921 sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
5922 } else {
5923 sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
5924 }
5925 if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
5926 + " stream override delay is now " + sDelayMs + " ms");
5927 }
5928 }
5929
5930 //==========================================================================================
Eric Laurentdd45d012012-10-08 09:04:34 -07005931 // Camera shutter sound policy.
5932 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5933 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5934 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5935 //==========================================================================================
5936
5937 // cached value of com.android.internal.R.bool.config_camera_sound_forced
5938 private Boolean mCameraSoundForced;
5939
5940 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5941 public boolean isCameraSoundForced() {
5942 synchronized (mCameraSoundForced) {
5943 return mCameraSoundForced;
5944 }
5945 }
5946
5947 private static final String[] RINGER_MODE_NAMES = new String[] {
5948 "SILENT",
5949 "VIBRATE",
5950 "NORMAL"
5951 };
5952
5953 private void dumpRingerMode(PrintWriter pw) {
5954 pw.println("\nRinger mode: ");
John Spurlock661f2cf2014-11-17 10:29:10 -05005955 pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
5956 pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
John Spurlock50ced3f2015-05-11 16:00:09 -04005957 dumpRingerModeStreams(pw, "affected", mRingerModeAffectedStreams);
5958 dumpRingerModeStreams(pw, "muted", mRingerModeMutedStreams);
John Spurlock661f2cf2014-11-17 10:29:10 -05005959 pw.print("- delegate = "); pw.println(mRingerModeDelegate);
Eric Laurentdd45d012012-10-08 09:04:34 -07005960 }
5961
John Spurlock50ced3f2015-05-11 16:00:09 -04005962 private void dumpRingerModeStreams(PrintWriter pw, String type, int streams) {
5963 pw.print("- ringer mode "); pw.print(type); pw.print(" streams = 0x");
5964 pw.print(Integer.toHexString(streams));
5965 if (streams != 0) {
5966 pw.print(" (");
5967 boolean first = true;
5968 for (int i = 0; i < AudioSystem.STREAM_NAMES.length; i++) {
5969 final int stream = (1 << i);
5970 if ((streams & stream) != 0) {
5971 if (!first) pw.print(',');
5972 pw.print(AudioSystem.STREAM_NAMES[i]);
5973 streams &= ~stream;
5974 first = false;
5975 }
5976 }
5977 if (streams != 0) {
5978 if (!first) pw.print(',');
5979 pw.print(streams);
5980 }
5981 pw.print(')');
5982 }
5983 pw.println();
5984 }
5985
Dianne Hackborn632ca412012-06-14 19:34:10 -07005986 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005987 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07005988 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5989
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005990 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07005991 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07005992 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005993 pw.println("\nAudio routes:");
John Spurlock61560172015-02-06 19:46:04 -05005994 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
5995 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
John Spurlock35134602014-07-24 18:10:48 -04005996
5997 pw.println("\nOther state:");
John Spurlock3346a802014-05-20 16:25:37 -04005998 pw.print(" mVolumeController="); pw.println(mVolumeController);
John Spurlock35134602014-07-24 18:10:48 -04005999 pw.print(" mSafeMediaVolumeState=");
6000 pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
6001 pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
6002 pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
6003 pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04006004 pw.print(" mMcc="); pw.println(mMcc);
John Spurlock5e783732015-02-19 10:28:59 -05006005 pw.print(" mCameraSoundForced="); pw.println(mCameraSoundForced);
John Spurlock661f2cf2014-11-17 10:29:10 -05006006 pw.print(" mHasVibrator="); pw.println(mHasVibrator);
John Spurlockcdb57ae2015-02-11 19:04:11 -05006007 pw.print(" mControllerService="); pw.println(mControllerService);
John Spurlocka48d7792015-03-03 17:35:57 -05006008 pw.print(" mVolumePolicy="); pw.println(mVolumePolicy);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006009
6010 dumpAudioPolicies(pw);
John Spurlock35134602014-07-24 18:10:48 -04006011 }
6012
6013 private static String safeMediaVolumeStateToString(Integer state) {
6014 switch(state) {
6015 case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
6016 case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
6017 case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
6018 case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
6019 }
6020 return null;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08006021 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07006022
6023 // Inform AudioFlinger of our device's low RAM attribute
6024 private static void readAndSetLowRamDevice()
6025 {
6026 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
6027 if (status != 0) {
6028 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
6029 }
6030 }
John Spurlock3346a802014-05-20 16:25:37 -04006031
John Spurlockcdb57ae2015-02-11 19:04:11 -05006032 private void enforceVolumeController(String action) {
6033 if (mControllerService.mUid != 0 && Binder.getCallingUid() == mControllerService.mUid) {
6034 return;
6035 }
John Spurlock3346a802014-05-20 16:25:37 -04006036 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
6037 "Only SystemUI can " + action);
6038 }
6039
6040 @Override
6041 public void setVolumeController(final IVolumeController controller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05006042 enforceVolumeController("set the volume controller");
John Spurlock3346a802014-05-20 16:25:37 -04006043
6044 // return early if things are not actually changing
6045 if (mVolumeController.isSameBinder(controller)) {
6046 return;
6047 }
6048
6049 // dismiss the old volume controller
6050 mVolumeController.postDismiss();
6051 if (controller != null) {
6052 // we are about to register a new controller, listen for its death
6053 try {
6054 controller.asBinder().linkToDeath(new DeathRecipient() {
6055 @Override
6056 public void binderDied() {
6057 if (mVolumeController.isSameBinder(controller)) {
6058 Log.w(TAG, "Current remote volume controller died, unregistering");
6059 setVolumeController(null);
6060 }
6061 }
6062 }, 0);
6063 } catch (RemoteException e) {
6064 // noop
6065 }
6066 }
6067 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04006068 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
6069 }
6070
6071 @Override
6072 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05006073 enforceVolumeController("notify about volume controller visibility");
John Spurlock33f4e042014-07-11 13:10:58 -04006074
6075 // return early if the controller is not current
6076 if (!mVolumeController.isSameBinder(controller)) {
6077 return;
6078 }
6079
6080 mVolumeController.setVisible(visible);
6081 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04006082 }
RoboErikd09bd0c2014-06-24 17:45:19 -07006083
John Spurlocka48d7792015-03-03 17:35:57 -05006084 @Override
6085 public void setVolumePolicy(VolumePolicy policy) {
6086 enforceVolumeController("set volume policy");
John Spurlockb02c7442015-04-14 09:32:25 -04006087 if (policy != null && !policy.equals(mVolumePolicy)) {
John Spurlocka48d7792015-03-03 17:35:57 -05006088 mVolumePolicy = policy;
John Spurlockb02c7442015-04-14 09:32:25 -04006089 if (DEBUG_VOL) Log.d(TAG, "Volume policy changed: " + mVolumePolicy);
John Spurlocka48d7792015-03-03 17:35:57 -05006090 }
6091 }
6092
RoboErikd09bd0c2014-06-24 17:45:19 -07006093 public static class VolumeController {
6094 private static final String TAG = "VolumeController";
6095
6096 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04006097 private boolean mVisible;
6098 private long mNextLongPress;
6099 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07006100
6101 public void setController(IVolumeController controller) {
6102 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04006103 mVisible = false;
6104 }
6105
6106 public void loadSettings(ContentResolver cr) {
6107 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
6108 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
6109 }
6110
RoboErik4197cb62015-01-21 15:45:32 -08006111 public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
6112 if (isMute) {
6113 return false;
6114 }
John Spurlock33f4e042014-07-11 13:10:58 -04006115 boolean suppress = false;
6116 if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
6117 final long now = SystemClock.uptimeMillis();
6118 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
6119 // ui will become visible
6120 if (mNextLongPress < now) {
6121 mNextLongPress = now + mLongPressTimeout;
6122 }
6123 suppress = true;
6124 } else if (mNextLongPress > 0) { // in a long-press
6125 if (now > mNextLongPress) {
6126 // long press triggered, no more suppression
6127 mNextLongPress = 0;
6128 } else {
6129 // keep suppressing until the long press triggers
6130 suppress = true;
6131 }
6132 }
6133 }
6134 return suppress;
6135 }
6136
6137 public void setVisible(boolean visible) {
6138 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07006139 }
6140
6141 public boolean isSameBinder(IVolumeController controller) {
6142 return Objects.equals(asBinder(), binder(controller));
6143 }
6144
6145 public IBinder asBinder() {
6146 return binder(mController);
6147 }
6148
6149 private static IBinder binder(IVolumeController controller) {
6150 return controller == null ? null : controller.asBinder();
6151 }
6152
6153 @Override
6154 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04006155 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07006156 }
6157
6158 public void postDisplaySafeVolumeWarning(int flags) {
6159 if (mController == null)
6160 return;
6161 try {
6162 mController.displaySafeVolumeWarning(flags);
6163 } catch (RemoteException e) {
6164 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
6165 }
6166 }
6167
6168 public void postVolumeChanged(int streamType, int flags) {
6169 if (mController == null)
6170 return;
6171 try {
6172 mController.volumeChanged(streamType, flags);
6173 } catch (RemoteException e) {
6174 Log.w(TAG, "Error calling volumeChanged", e);
6175 }
6176 }
6177
RoboErikd09bd0c2014-06-24 17:45:19 -07006178 public void postMasterMuteChanged(int flags) {
6179 if (mController == null)
6180 return;
6181 try {
6182 mController.masterMuteChanged(flags);
6183 } catch (RemoteException e) {
6184 Log.w(TAG, "Error calling masterMuteChanged", e);
6185 }
6186 }
6187
6188 public void setLayoutDirection(int layoutDirection) {
6189 if (mController == null)
6190 return;
6191 try {
6192 mController.setLayoutDirection(layoutDirection);
6193 } catch (RemoteException e) {
6194 Log.w(TAG, "Error calling setLayoutDirection", e);
6195 }
6196 }
6197
6198 public void postDismiss() {
6199 if (mController == null)
6200 return;
6201 try {
6202 mController.dismiss();
6203 } catch (RemoteException e) {
6204 Log.w(TAG, "Error calling dismiss", e);
6205 }
6206 }
6207 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006208
RoboErik0dac35a2014-08-12 15:48:49 -07006209 /**
6210 * Interface for system components to get some extra functionality through
6211 * LocalServices.
6212 */
6213 final class AudioServiceInternal extends AudioManagerInternal {
John Spurlock661f2cf2014-11-17 10:29:10 -05006214 @Override
6215 public void setRingerModeDelegate(RingerModeDelegate delegate) {
6216 mRingerModeDelegate = delegate;
6217 if (mRingerModeDelegate != null) {
John Spurlock50ced3f2015-05-11 16:00:09 -04006218 updateRingerModeAffectedStreams();
John Spurlock661f2cf2014-11-17 10:29:10 -05006219 setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
6220 }
6221 }
RoboErik272e1612014-09-05 11:39:29 -07006222
6223 @Override
6224 public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
6225 String callingPackage, int uid) {
6226 // direction and stream type swap here because the public
6227 // adjustSuggested has a different order than the other methods.
John Spurlock90874332015-03-10 16:00:54 -04006228 adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage,
6229 callingPackage, uid);
RoboErik272e1612014-09-05 11:39:29 -07006230 }
6231
RoboErik0dac35a2014-08-12 15:48:49 -07006232 @Override
6233 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
6234 String callingPackage, int uid) {
John Spurlock90874332015-03-10 16:00:54 -04006235 adjustStreamVolume(streamType, direction, flags, callingPackage,
6236 callingPackage, uid);
RoboErik0dac35a2014-08-12 15:48:49 -07006237 }
6238
6239 @Override
6240 public void setStreamVolumeForUid(int streamType, int direction, int flags,
6241 String callingPackage, int uid) {
John Spurlock90874332015-03-10 16:00:54 -04006242 setStreamVolume(streamType, direction, flags, callingPackage, callingPackage, uid);
RoboErik0dac35a2014-08-12 15:48:49 -07006243 }
RoboErik519c7742014-11-18 10:59:09 -08006244
6245 @Override
John Spurlock661f2cf2014-11-17 10:29:10 -05006246 public int getRingerModeInternal() {
6247 return AudioService.this.getRingerModeInternal();
6248 }
6249
6250 @Override
6251 public void setRingerModeInternal(int ringerMode, String caller) {
6252 AudioService.this.setRingerModeInternal(ringerMode, caller);
6253 }
John Spurlockcdb57ae2015-02-11 19:04:11 -05006254
6255 @Override
6256 public int getVolumeControllerUid() {
6257 return mControllerService.mUid;
6258 }
John Spurlock50ced3f2015-05-11 16:00:09 -04006259
6260 @Override
6261 public void updateRingerModeAffectedStreamsInternal() {
6262 synchronized (mSettingsLock) {
6263 if (updateRingerModeAffectedStreams()) {
6264 setRingerModeInt(getRingerModeInternal(), false);
6265 }
6266 }
6267 }
RoboErik0dac35a2014-08-12 15:48:49 -07006268 }
6269
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006270 //==========================================================================================
6271 // Audio policy management
6272 //==========================================================================================
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006273 public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
6274 boolean hasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006275 AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
6276
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006277 if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
6278 + " with config:" + policyConfig);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006279 String regId = null;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006280 // error handling
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006281 boolean hasPermissionForPolicy =
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006282 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006283 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
6284 if (!hasPermissionForPolicy) {
6285 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
6286 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006287 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006288 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006289
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006290 synchronized (mAudioPolicies) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006291 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006292 if (mAudioPolicies.containsKey(pcb.asBinder())) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006293 Slog.e(TAG, "Cannot re-register policy");
6294 return null;
6295 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006296 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
6297 pcb.asBinder().linkToDeath(app, 0/*flags*/);
6298 regId = app.getRegistrationId();
6299 mAudioPolicies.put(pcb.asBinder(), app);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006300 } catch (RemoteException e) {
6301 // audio policy owner has already died!
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006302 Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006303 " binder death", e);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006304 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006305 }
6306 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006307 return regId;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006308 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006309
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006310 public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
6311 if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006312 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006313 AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006314 if (app == null) {
6315 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
6316 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006317 return;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006318 } else {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006319 pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006320 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006321 app.release();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006322 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006323 // TODO implement clearing mix attribute matching info in native audio policy
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006324 }
6325
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006326 public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
6327 if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
6328 + " policy " + pcb.asBinder());
6329 // error handling
6330 boolean hasPermissionForPolicy =
6331 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
6332 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
6333 if (!hasPermissionForPolicy) {
6334 Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
6335 + Binder.getCallingPid() + " / uid "
6336 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
6337 return AudioManager.ERROR;
6338 }
6339
6340 synchronized (mAudioPolicies) {
6341 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
6342 Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
6343 return AudioManager.ERROR;
6344 }
6345 final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
6346 if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6347 // is there already one policy managing ducking?
Eric Laurent0867bed2015-05-20 14:49:08 -07006348 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006349 if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6350 Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
6351 return AudioManager.ERROR;
6352 }
6353 }
6354 }
6355 app.mFocusDuckBehavior = duckingBehavior;
6356 mMediaFocusControl.setDuckingInExtPolicyAvailable(
6357 duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
6358 }
6359 return AudioManager.SUCCESS;
6360 }
6361
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006362 private void dumpAudioPolicies(PrintWriter pw) {
6363 pw.println("\nAudio policies:");
6364 synchronized (mAudioPolicies) {
Eric Laurent0867bed2015-05-20 14:49:08 -07006365 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006366 pw.println(policy.toLogFriendlyString());
6367 }
6368 }
6369 }
6370
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006371 //======================
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08006372 // Audio policy callbacks from AudioSystem for dynamic policies
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006373 //======================
6374 private final AudioSystem.DynamicPolicyCallback mDynPolicyCallback =
6375 new AudioSystem.DynamicPolicyCallback() {
6376 public void onDynamicPolicyMixStateUpdate(String regId, int state) {
6377 if (!TextUtils.isEmpty(regId)) {
6378 sendMsg(mAudioHandler, MSG_DYN_POLICY_MIX_STATE_UPDATE, SENDMSG_QUEUE,
6379 state /*arg1*/, 0 /*arg2 ignored*/, regId /*obj*/, 0 /*delay*/);
6380 }
6381 }
6382 };
6383
6384 private void onDynPolicyMixStateUpdate(String regId, int state) {
6385 if (DEBUG_AP) Log.d(TAG, "onDynamicPolicyMixStateUpdate("+ regId + ", " + state +")");
6386 synchronized (mAudioPolicies) {
6387 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
6388 for (AudioMix mix : policy.getMixes()) {
6389 if (mix.getRegistration().equals(regId)) {
6390 try {
6391 policy.mPolicyCallback.notifyMixStateUpdate(regId, state);
6392 } catch (RemoteException e) {
6393 Log.e(TAG, "Can't call notifyMixStateUpdate() on IAudioPolicyCallback "
6394 + policy.mPolicyCallback.asBinder(), e);
6395 }
6396 return;
6397 }
6398 }
6399 }
6400 }
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08006401 }
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006402
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08006403 //======================
6404 // Audio policy callbacks from AudioSystem for recording configuration updates
6405 //======================
6406 private final RecordingActivityMonitor mRecordMonitor = new RecordingActivityMonitor();
6407
6408 public void registerRecordingCallback(IRecordingConfigDispatcher rcdb) {
6409 mRecordMonitor.registerRecordingCallback(rcdb);
6410 }
6411
6412 public void unregisterRecordingCallback(IRecordingConfigDispatcher rcdb) {
6413 mRecordMonitor.unregisterRecordingCallback(rcdb);
6414 }
6415
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07006416 public List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08006417 return mRecordMonitor.getActiveRecordingConfigurations();
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006418 }
6419
6420 //======================
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006421 // Audio policy proxy
6422 //======================
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006423 /**
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006424 * This internal class inherits from AudioPolicyConfig, each instance contains all the
6425 * mixes of an AudioPolicy and their configurations.
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006426 */
6427 public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006428 private static final String TAG = "AudioPolicyProxy";
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006429 IAudioPolicyCallback mPolicyCallback;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006430 boolean mHasFocusListener;
6431 /**
6432 * Audio focus ducking behavior for an audio policy.
6433 * This variable reflects the value that was successfully set in
6434 * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
6435 * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
6436 * is handling ducking for audio focus.
6437 */
6438 int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
6439
6440 AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
6441 boolean hasFocusListener) {
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006442 super(config);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006443 setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006444 mPolicyCallback = token;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006445 mHasFocusListener = hasFocusListener;
6446 if (mHasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006447 mMediaFocusControl.addFocusFollower(mPolicyCallback);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006448 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006449 connectMixes();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006450 }
6451
6452 public void binderDied() {
6453 synchronized (mAudioPolicies) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006454 Log.i(TAG, "audio policy " + mPolicyCallback + " died");
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006455 release();
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006456 mAudioPolicies.remove(mPolicyCallback.asBinder());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006457 }
6458 }
6459
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006460 String getRegistrationId() {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006461 return getRegistration();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006462 }
6463
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006464 void release() {
6465 if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6466 mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
6467 }
6468 if (mHasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006469 mMediaFocusControl.removeFocusFollower(mPolicyCallback);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006470 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006471 AudioSystem.registerPolicyMixes(mMixes, false);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006472 }
6473
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006474 void connectMixes() {
6475 AudioSystem.registerPolicyMixes(mMixes, true);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006476 }
6477 };
6478
6479 private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
6480 new HashMap<IBinder, AudioPolicyProxy>();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006481 private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
John Spurlockcdb57ae2015-02-11 19:04:11 -05006482
6483 private class ControllerService extends ContentObserver {
6484 private int mUid;
6485 private ComponentName mComponent;
6486
6487 public ControllerService() {
6488 super(null);
6489 }
6490
6491 @Override
6492 public String toString() {
6493 return String.format("{mUid=%d,mComponent=%s}", mUid, mComponent);
6494 }
6495
6496 public void init() {
6497 onChange(true);
6498 mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
6499 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT), false, this);
6500 }
6501
6502 @Override
6503 public void onChange(boolean selfChange) {
6504 mUid = 0;
6505 mComponent = null;
6506 final String setting = Settings.Secure.getString(mContentResolver,
6507 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
6508 if (setting == null) return;
6509 try {
6510 mComponent = ComponentName.unflattenFromString(setting);
6511 if (mComponent == null) return;
6512 mUid = mContext.getPackageManager()
6513 .getApplicationInfo(mComponent.getPackageName(), 0).uid;
6514 } catch (Exception e) {
6515 Log.w(TAG, "Error loading controller service", e);
6516 }
6517 if (DEBUG_VOL) Log.d(TAG, "Reloaded controller service: " + this);
6518 }
6519 }
Phil Burkac0f7042016-02-24 12:19:08 -08006520}