blob: c70a87c36d225b2f4f713e5baf233577edef9ecd [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;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700228 // end of messages handled under wakelock
Eric Laurentafbb0472011-12-15 09:04:23 -0800229
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -0700230 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
Eric Laurentdc03c612011-04-01 10:59:41 -0700231 // Timeout for connection to bluetooth headset service
232 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
233
Eric Laurent0867bed2015-05-20 14:49:08 -0700234 // retry delay in case of failure to indicate system ready to AudioFlinger
235 private static final int INDICATE_SYSTEM_READY_RETRY_DELAY_MS = 1000;
236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 /** @see AudioSystemThread */
238 private AudioSystemThread mAudioSystemThread;
239 /** @see AudioHandler */
240 private AudioHandler mAudioHandler;
241 /** @see VolumeStreamState */
242 private VolumeStreamState[] mStreamStates;
Jason Parekhb1096152009-03-24 17:48:25 -0700243 private SettingsObserver mSettingsObserver;
Eric Laurenta553c252009-07-17 12:17:14 -0700244
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700245 private int mMode = AudioSystem.MODE_NORMAL;
Glenn Kastenba195eb2011-12-13 09:30:40 -0800246 // protects mRingerMode
247 private final Object mSettingsLock = new Object();
Eric Laurent45c90ce2012-04-24 18:44:22 -0700248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 private SoundPool mSoundPool;
Glenn Kasten30c918c2011-11-10 17:56:41 -0800250 private final Object mSoundEffectsLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 private static final int NUM_SOUNDPOOL_CHANNELS = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252
253 /* Sound effect file names */
254 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
Eric Laurente78fced2013-03-15 16:03:47 -0700255 private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256
257 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
258 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
259 * uses soundpool (second column) */
Eric Laurente78fced2013-03-15 16:03:47 -0700260 private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261
John Spurlockb6e19e32015-03-10 21:33:44 -0400262 /** Maximum volume index values for audio streams */
Eric Laurent91377de2014-10-10 15:24:04 -0700263 private static int[] MAX_STREAM_VOLUME = new int[] {
Eric Laurent6ee99522009-08-25 06:30:59 -0700264 5, // STREAM_VOICE_CALL
265 7, // STREAM_SYSTEM
266 7, // STREAM_RING
267 15, // STREAM_MUSIC
268 7, // STREAM_ALARM
269 7, // STREAM_NOTIFICATION
270 15, // STREAM_BLUETOOTH_SCO
271 7, // STREAM_SYSTEM_ENFORCED
272 15, // STREAM_DTMF
273 15 // STREAM_TTS
Jared Suttles59820132009-08-13 21:50:52 -0500274 };
Eric Laurent91377de2014-10-10 15:24:04 -0700275
John Spurlockb6e19e32015-03-10 21:33:44 -0400276 /** Minimum volume index values for audio streams */
277 private static int[] MIN_STREAM_VOLUME = new int[] {
278 1, // STREAM_VOICE_CALL
279 0, // STREAM_SYSTEM
280 0, // STREAM_RING
281 0, // STREAM_MUSIC
282 0, // STREAM_ALARM
283 0, // STREAM_NOTIFICATION
Eric Laurente4381ec2015-10-29 17:52:48 -0700284 0, // STREAM_BLUETOOTH_SCO
John Spurlockb6e19e32015-03-10 21:33:44 -0400285 0, // STREAM_SYSTEM_ENFORCED
286 0, // STREAM_DTMF
287 0 // STREAM_TTS
288 };
289
Eric Laurent6d517662012-04-23 18:42:39 -0700290 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
Eric Laurenta553c252009-07-17 12:17:14 -0700291 * of another stream: This avoids multiplying the volume settings for hidden
292 * stream types that follow other stream behavior for volume settings
Eric Laurent6d517662012-04-23 18:42:39 -0700293 * NOTE: do not create loops in aliases!
294 * Some streams alias to different streams according to device category (phone or tablet) or
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700295 * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
Eric Laurent212532b2014-07-21 15:43:18 -0700296 * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
297 * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
298 * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
299 private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700300 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
301 AudioSystem.STREAM_RING, // STREAM_SYSTEM
302 AudioSystem.STREAM_RING, // STREAM_RING
303 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
304 AudioSystem.STREAM_ALARM, // STREAM_ALARM
305 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
306 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
307 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
308 AudioSystem.STREAM_RING, // STREAM_DTMF
309 AudioSystem.STREAM_MUSIC // STREAM_TTS
Eric Laurenta553c252009-07-17 12:17:14 -0700310 };
Eric Laurent212532b2014-07-21 15:43:18 -0700311 private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
312 AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL
313 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
314 AudioSystem.STREAM_MUSIC, // STREAM_RING
315 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
316 AudioSystem.STREAM_MUSIC, // STREAM_ALARM
317 AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
318 AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO
319 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
320 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
321 AudioSystem.STREAM_MUSIC // STREAM_TTS
322 };
323 private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700324 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
John Spurlock4f0f1202014-08-05 13:28:33 -0400325 AudioSystem.STREAM_RING, // STREAM_SYSTEM
Eric Laurent6d517662012-04-23 18:42:39 -0700326 AudioSystem.STREAM_RING, // STREAM_RING
327 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
328 AudioSystem.STREAM_ALARM, // STREAM_ALARM
329 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
330 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
John Spurlock4f0f1202014-08-05 13:28:33 -0400331 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
332 AudioSystem.STREAM_RING, // STREAM_DTMF
Eric Laurent6d517662012-04-23 18:42:39 -0700333 AudioSystem.STREAM_MUSIC // STREAM_TTS
334 };
335 private int[] mStreamVolumeAlias;
Eric Laurenta553c252009-07-17 12:17:14 -0700336
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700337 /**
338 * Map AudioSystem.STREAM_* constants to app ops. This should be used
339 * after mapping through mStreamVolumeAlias.
340 */
John Spurlock59dc9c12015-03-02 11:20:15 -0500341 private static final int[] STREAM_VOLUME_OPS = new int[] {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700342 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL
343 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM
344 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING
345 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC
346 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM
347 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION
348 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO
349 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED
350 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF
351 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS
352 };
353
Eric Laurent83a017b2013-03-19 18:15:31 -0700354 private final boolean mUseFixedVolume;
355
Glenn Kasten30c918c2011-11-10 17:56:41 -0800356 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 public void onError(int error) {
358 switch (error) {
359 case AudioSystem.AUDIO_STATUS_SERVER_DIED:
Andy Hunged0ea402015-10-30 14:11:46 -0700360 sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED,
Eric Laurentdfb881f2013-07-18 14:41:39 -0700361 SENDMSG_NOOP, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 break;
363 default:
364 break;
365 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700366 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 };
368
369 /**
370 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
371 * {@link AudioManager#RINGER_MODE_SILENT}, or
372 * {@link AudioManager#RINGER_MODE_VIBRATE}.
373 */
Glenn Kastenba195eb2011-12-13 09:30:40 -0800374 // protected by mSettingsLock
John Spurlock661f2cf2014-11-17 10:29:10 -0500375 private int mRingerMode; // internal ringer mode, affects muting of underlying streams
376 private int mRingerModeExternal = -1; // reported ringer mode to outside clients (AudioManager)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377
Eric Laurent9bcf4012009-06-12 06:09:28 -0700378 /** @see System#MODE_RINGER_STREAMS_AFFECTED */
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700379 private int mRingerModeAffectedStreams = 0;
Eric Laurent9bcf4012009-06-12 06:09:28 -0700380
Eric Laurent5b4e6542010-03-19 20:02:21 -0700381 // Streams currently muted by ringer mode
382 private int mRingerModeMutedStreams;
383
John Spurlock3ce37252015-02-17 13:20:45 -0500384 /** Streams that can be muted. Do not resolve to aliases when checking.
385 * @see System#MUTE_STREAMS_AFFECTED */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 private int mMuteAffectedStreams;
387
388 /**
Eric Laurentbffc3d12012-05-07 17:43:49 -0700389 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
390 * mVibrateSetting is just maintained during deprecation period but vibration policy is
391 * now only controlled by mHasVibrator and mRingerMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 */
393 private int mVibrateSetting;
394
Eric Laurentbffc3d12012-05-07 17:43:49 -0700395 // Is there a vibrator
396 private final boolean mHasVibrator;
397
Eric Laurenta553c252009-07-17 12:17:14 -0700398 // Broadcast receiver for device connections intent broadcasts
399 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
400
Makoto Onukid45a4a22015-11-02 17:17:38 -0800401 /** Interface for UserManagerService. */
402 private final UserManagerInternal mUserManagerInternal;
403
404 private final UserRestrictionsListener mUserRestrictionsListener =
405 new AudioServiceUserRestrictionsListener();
406
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700407 // Devices currently connected
Paul McLean394a8e12015-03-03 10:29:19 -0700408 // Use makeDeviceListKey() to make a unique key for this list.
409 private class DeviceListSpec {
410 int mDeviceType;
411 String mDeviceName;
412 String mDeviceAddress;
413
414 public DeviceListSpec(int deviceType, String deviceName, String deviceAddress) {
415 mDeviceType = deviceType;
416 mDeviceName = deviceName;
417 mDeviceAddress = deviceAddress;
418 }
419
420 public String toString() {
421 return "[type:0x" + Integer.toHexString(mDeviceType) + " name:" + mDeviceName
422 + " address:" + mDeviceAddress + "]";
423 }
424 }
425
426 // Generate a unique key for the mConnectedDevices List by composing the device "type"
427 // and the "address" associated with a specific instance of that device type
428 private String makeDeviceListKey(int device, String deviceAddress) {
429 return "0x" + Integer.toHexString(device) + ":" + deviceAddress;
430 }
431
John Spurlock8c3dc852015-04-23 21:32:37 -0400432 private final ArrayMap<String, DeviceListSpec> mConnectedDevices = new ArrayMap<>();
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700433
434 // Forced device usage for communications
435 private int mForcedUseForComm;
436
Eric Laurent9272b4b2010-01-23 17:12:59 -0800437 // List of binder death handlers for setMode() client processes.
438 // The last process to have called setMode() is at the top of the list.
Glenn Kasten30c918c2011-11-10 17:56:41 -0800439 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
Eric Laurenteb14a782009-12-17 03:12:59 -0800440
Eric Laurent3def1ee2010-03-17 23:26:26 -0700441 // List of clients having issued a SCO start request
Glenn Kasten30c918c2011-11-10 17:56:41 -0800442 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
Eric Laurent3def1ee2010-03-17 23:26:26 -0700443
444 // BluetoothHeadset API to control SCO connection
445 private BluetoothHeadset mBluetoothHeadset;
446
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700447 // Bluetooth headset device
448 private BluetoothDevice mBluetoothHeadsetDevice;
Eric Laurent3def1ee2010-03-17 23:26:26 -0700449
Eric Laurent62ef7672010-11-24 10:58:32 -0800450 // Indicate if SCO audio connection is currently active and if the initiator is
451 // audio service (internal) or bluetooth headset (external)
452 private int mScoAudioState;
453 // SCO audio state is not active
454 private static final int SCO_STATE_INACTIVE = 0;
Eric Laurentdc03c612011-04-01 10:59:41 -0700455 // SCO audio activation request waiting for headset service to connect
456 private static final int SCO_STATE_ACTIVATE_REQ = 1;
Eric Laurent25fc29b2013-04-05 12:13:54 -0700457 // SCO audio state is active or starting due to a request from AudioManager API
Eric Laurentdc03c612011-04-01 10:59:41 -0700458 private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
459 // SCO audio deactivation request waiting for headset service to connect
460 private static final int SCO_STATE_DEACTIVATE_REQ = 5;
461
Eric Laurent62ef7672010-11-24 10:58:32 -0800462 // SCO audio state is active due to an action in BT handsfree (either voice recognition or
463 // in call audio)
464 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
Eric Laurentdc03c612011-04-01 10:59:41 -0700465 // Deactivation request for all SCO connections (initiated by audio mode change)
466 // waiting for headset service to connect
467 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
468
Eric Laurentc18c9132013-04-12 17:24:56 -0700469 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
470 // originated from an app targeting an API version before JB MR2 and raw audio after that.
471 private int mScoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -0700472 // SCO audio mode is undefined
473 private static final int SCO_MODE_UNDEFINED = -1;
Eric Laurentc18c9132013-04-12 17:24:56 -0700474 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
475 private static final int SCO_MODE_VIRTUAL_CALL = 0;
476 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
477 private static final int SCO_MODE_RAW = 1;
Liejun Taof4e51d82014-07-16 11:18:29 -0700478 // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
479 private static final int SCO_MODE_VR = 2;
480
481 private static final int SCO_MODE_MAX = 2;
Eric Laurentc18c9132013-04-12 17:24:56 -0700482
Eric Laurentdc03c612011-04-01 10:59:41 -0700483 // Current connection state indicated by bluetooth headset
484 private int mScoConnectionState;
Eric Laurent62ef7672010-11-24 10:58:32 -0800485
Eric Laurenta60e2122010-12-28 16:49:07 -0800486 // true if boot sequence has been completed
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700487 private boolean mSystemReady;
Yasuhiro Matsuda4ced7192015-07-10 22:08:44 +0900488 // true if Intent.ACTION_USER_SWITCHED has ever been received
489 private boolean mUserSwitchedReceived;
Eric Laurenta60e2122010-12-28 16:49:07 -0800490 // listener for SoundPool sample load completion indication
491 private SoundPoolCallback mSoundPoolCallBack;
492 // thread for SoundPool listener
493 private SoundPoolListenerThread mSoundPoolListenerThread;
494 // message looper for SoundPool listener
495 private Looper mSoundPoolLooper = null;
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700496 // volume applied to sound played with playSoundEffect()
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700497 private static int sSoundEffectVolumeDb;
Eric Laurent25101b02011-02-02 09:33:30 -0800498 // previous volume adjustment direction received by checkForRingerModeChange()
499 private int mPrevVolDirection = AudioManager.ADJUST_SAME;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700500 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
501 // is controlled by Vol keys.
502 private int mVolumeControlStream = -1;
503 private final Object mForceControlStreamLock = new Object();
504 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
505 // server process so in theory it is not necessary to monitor the client death.
506 // However it is good to be ready for future evolutions.
507 private ForceControlStreamClient mForceControlStreamClient = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700508 // Used to play ringtones outside system_server
509 private volatile IRingtonePlayer mRingtonePlayer;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800510
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700511 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
512
Eric Laurent78472112012-05-21 08:57:21 -0700513 // Request to override default use of A2DP for media.
Sungsoo486f7d32016-09-28 16:20:52 +0900514 private boolean mBluetoothA2dpEnabled;
Eric Laurent78472112012-05-21 08:57:21 -0700515 private final Object mBluetoothA2dpEnabledLock = new Object();
516
Dianne Hackborn632ca412012-06-14 19:34:10 -0700517 // Monitoring of audio routes. Protected by mCurAudioRoutes.
518 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
519 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
520 = new RemoteCallbackList<IAudioRoutesObserver>();
521
Eric Laurent4bbcc652012-09-24 14:26:30 -0700522 // Devices for which the volume is fixed and VolumePanel slider should be disabled
Eric Laurent212532b2014-07-21 15:43:18 -0700523 int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700524 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Eric Laurent212532b2014-07-21 15:43:18 -0700525 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
526 AudioSystem.DEVICE_OUT_HDMI_ARC |
527 AudioSystem.DEVICE_OUT_SPDIF |
528 AudioSystem.DEVICE_OUT_AUX_LINE;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700529 int mFullVolumeDevices = 0;
Eric Laurent4bbcc652012-09-24 14:26:30 -0700530
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700531 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700532 private final boolean mMonitorOrientation;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700533 private final boolean mMonitorRotation;
Eric Laurentd640bd32012-09-28 18:01:48 -0700534
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700535 private boolean mDockAudioMediaEnabled = true;
536
Eric Laurent08ed1b92012-11-05 14:54:12 -0800537 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
538
Eric Laurentfde16d52012-12-03 14:42:39 -0800539 // Used when safe volume warning message display is requested by setStreamVolume(). In this
540 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
541 // and used later when/if disableSafeMediaVolume() is called.
542 private StreamVolumeCommand mPendingVolumeCommand;
543
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700544 private PowerManager.WakeLock mAudioEventWakeLock;
545
546 private final MediaFocusControl mMediaFocusControl;
547
John Du5a0cf7a2013-07-19 11:30:34 -0700548 // Reference to BluetoothA2dp to query for AbsoluteVolume.
549 private BluetoothA2dp mA2dp;
seunghwan.hong4fe77952014-10-29 17:43:20 +0900550 // lock always taken synchronized on mConnectedDevices
John Du5a0cf7a2013-07-19 11:30:34 -0700551 private final Object mA2dpAvrcpLock = new Object();
552 // If absolute volume is supported in AVRCP device
553 private boolean mAvrcpAbsVolSupported = false;
554
Eric Laurentadbe8bf2014-11-03 18:26:32 -0800555 private static Long mLastDeviceConnectMsgTime = new Long(0);
556
Julia Reynolds48034f82016-03-09 10:15:16 -0500557 private NotificationManager mNm;
John Spurlock661f2cf2014-11-17 10:29:10 -0500558 private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
John Spurlocka48d7792015-03-03 17:35:57 -0500559 private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
John Spurlock07e72432015-03-13 11:46:52 -0400560 private long mLoweredFromNormalToVibrateTime;
John Spurlock661f2cf2014-11-17 10:29:10 -0500561
Paul McLean10804eb2015-01-28 11:16:35 -0800562 // Intent "extra" data keys.
563 public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName";
564 public static final String CONNECT_INTENT_KEY_STATE = "state";
565 public static final String CONNECT_INTENT_KEY_ADDRESS = "address";
566 public static final String CONNECT_INTENT_KEY_HAS_PLAYBACK = "hasPlayback";
567 public static final String CONNECT_INTENT_KEY_HAS_CAPTURE = "hasCapture";
568 public static final String CONNECT_INTENT_KEY_HAS_MIDI = "hasMIDI";
569 public static final String CONNECT_INTENT_KEY_DEVICE_CLASS = "class";
570
571 // Defines the format for the connection "address" for ALSA devices
572 public static String makeAlsaAddressString(int card, int device) {
573 return "card=" + card + ";device=" + device + ";";
574 }
575
Makoto Onukie1aef852015-10-15 17:28:35 -0700576 public static final class Lifecycle extends SystemService {
577 private AudioService mService;
578
579 public Lifecycle(Context context) {
580 super(context);
581 mService = new AudioService(context);
582 }
583
584 @Override
585 public void onStart() {
586 publishBinderService(Context.AUDIO_SERVICE, mService);
587 }
588
589 @Override
590 public void onBootPhase(int phase) {
591 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
592 mService.systemReady();
593 }
594 }
595 }
596
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 ///////////////////////////////////////////////////////////////////////////
598 // Construction
599 ///////////////////////////////////////////////////////////////////////////
600
601 /** @hide */
602 public AudioService(Context context) {
603 mContext = context;
604 mContentResolver = context.getContentResolver();
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700605 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700606
John Spurlock61560172015-02-06 19:46:04 -0500607 mPlatformType = AudioSystem.getPlatformType(context);
Jared Suttles59820132009-08-13 21:50:52 -0500608
Makoto Onukid45a4a22015-11-02 17:17:38 -0800609 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
610
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700611 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700612 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700613
Eric Laurentbffc3d12012-05-07 17:43:49 -0700614 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
615 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
616
John Spurlockb6e19e32015-03-10 21:33:44 -0400617 // Initialize volume
Eric Laurent91377de2014-10-10 15:24:04 -0700618 int maxVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps",
619 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
620 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
621 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500622 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700623 }
624 maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
625 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
626 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
627 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500628 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700629 }
Jared Suttles59820132009-08-13 21:50:52 -0500630
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700631 sSoundEffectVolumeDb = context.getResources().getInteger(
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700632 com.android.internal.R.integer.config_soundEffectVolumeDb);
Eric Laurent25101b02011-02-02 09:33:30 -0800633
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700634 mForcedUseForComm = AudioSystem.FORCE_NONE;
Eric Laurentdd45d012012-10-08 09:04:34 -0700635
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 createAudioSystemThread();
Eric Laurentdd45d012012-10-08 09:04:34 -0700637
Eric Laurentdfb881f2013-07-18 14:41:39 -0700638 AudioSystem.setErrorCallback(mAudioSystemCallback);
639
John Spurlock5e783732015-02-19 10:28:59 -0500640 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -0700641 mCameraSoundForced = new Boolean(cameraSoundForced);
642 sendMsg(mAudioHandler,
643 MSG_SET_FORCE_USE,
644 SENDMSG_QUEUE,
645 AudioSystem.FOR_SYSTEM,
646 cameraSoundForced ?
647 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
648 null,
649 0);
650
Eric Laurent05274f32012-11-29 12:48:18 -0800651 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
652 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
653 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
654 // The default safe volume index read here will be replaced by the actual value when
655 // the mcc is read by onConfigureSafeVolume()
656 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
657 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
658
Eric Laurent83a017b2013-03-19 18:15:31 -0700659 mUseFixedVolume = mContext.getResources().getBoolean(
660 com.android.internal.R.bool.config_useFixedVolume);
661
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700662 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
663 // array initialized by updateStreamVolumeAlias()
John Spurlock90874332015-03-10 16:00:54 -0400664 updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 readPersistedSettings();
Eric Laurentc0232482016-03-15 18:19:23 -0700666 readUserRestrictions();
Eric Laurentc1d41662011-07-19 11:21:13 -0700667 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700668 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700669
Jean-Michel Trivid4de20d2015-11-04 14:45:54 -0800670 mMediaFocusControl = new MediaFocusControl(mContext);
John Spurlockb6e19e32015-03-10 21:33:44 -0400671
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700672 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700673
674 // Call setRingerModeInt() to apply correct mute
675 // state on streams affected by ringer mode.
676 mRingerModeMutedStreams = 0;
John Spurlock661f2cf2014-11-17 10:29:10 -0500677 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3891c4c2010-04-20 09:40:57 -0700678
Eric Laurenta553c252009-07-17 12:17:14 -0700679 // Register for device connection intent broadcasts.
680 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700681 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700682 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
683 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700684 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
685 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700686 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700687 intentFilter.addAction(Intent.ACTION_USER_BACKGROUND);
688 intentFilter.addAction(Intent.ACTION_USER_FOREGROUND);
Paul McLeanc837a452014-04-09 09:04:43 -0700689 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Eric Laurentb70b78a2016-01-13 19:16:04 -0800690 intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700691
Eric Laurentd640bd32012-09-28 18:01:48 -0700692 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700693 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700694 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
695 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700696 Log.v(TAG, "monitoring device orientation");
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700697 // initialize orientation in AudioSystem
698 setOrientationForAudioSystem();
699 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700700 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
701 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -0700702 RotationHelper.init(mContext, mAudioHandler);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700703 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700704
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700705 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null);
Jared Suttles59820132009-08-13 21:50:52 -0500706
RoboErik0dac35a2014-08-12 15:48:49 -0700707 LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
Makoto Onukid45a4a22015-11-02 17:17:38 -0800708
709 mUserManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -0800710
711 mRecordMonitor.initMonitor();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800712 }
713
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700714 public void systemReady() {
715 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
716 0, 0, null, 0);
717 }
718
719 public void onSystemReady() {
720 mSystemReady = true;
721 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
722 0, 0, null, 0);
723
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700724 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
725 resetBluetoothSco();
726 getBluetoothHeadset();
727 //FIXME: this is to maintain compatibility with deprecated intent
728 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
729 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
730 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
731 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
732 sendStickyBroadcastToAll(newIntent);
733
734 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
735 if (adapter != null) {
736 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
737 BluetoothProfile.A2DP);
738 }
739
Eric Laurent212532b2014-07-21 15:43:18 -0700740 mHdmiManager =
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900741 (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700742 if (mHdmiManager != null) {
743 synchronized (mHdmiManager) {
744 mHdmiTvClient = mHdmiManager.getTvClient();
Jungshik Jangc9ff9682014-09-15 17:41:06 +0900745 if (mHdmiTvClient != null) {
746 mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
747 }
Eric Laurent212532b2014-07-21 15:43:18 -0700748 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
749 mHdmiCecSink = false;
750 }
751 }
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900752
Julia Reynolds48034f82016-03-09 10:15:16 -0500753 mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
754
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700755 sendMsg(mAudioHandler,
756 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
757 SENDMSG_REPLACE,
758 0,
759 0,
John Spurlock90874332015-03-10 16:00:54 -0400760 TAG,
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700761 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700762
763 StreamOverride.init(mContext);
John Spurlockcdb57ae2015-02-11 19:04:11 -0500764 mControllerService.init();
Eric Laurent0867bed2015-05-20 14:49:08 -0700765 onIndicateSystemReady();
766 }
767
768 void onIndicateSystemReady() {
769 if (AudioSystem.systemReady() == AudioSystem.SUCCESS) {
770 return;
771 }
772 sendMsg(mAudioHandler,
773 MSG_INDICATE_SYSTEM_READY,
774 SENDMSG_REPLACE,
775 0,
776 0,
777 null,
778 INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
779 }
780
Andy Hunged0ea402015-10-30 14:11:46 -0700781 public void onAudioServerDied() {
Eric Laurent0867bed2015-05-20 14:49:08 -0700782 if (!mSystemReady ||
783 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Andy Hunged0ea402015-10-30 14:11:46 -0700784 Log.e(TAG, "Audioserver died.");
785 sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent0867bed2015-05-20 14:49:08 -0700786 null, 500);
787 return;
788 }
Andy Hunged0ea402015-10-30 14:11:46 -0700789 Log.e(TAG, "Audioserver started.");
Eric Laurent0867bed2015-05-20 14:49:08 -0700790
791 // indicate to audio HAL that we start the reconfiguration phase after a media
792 // server crash
793 // Note that we only execute this when the media server
794 // process restarts after a crash, not the first time it is started.
795 AudioSystem.setParameters("restarting=true");
796
797 readAndSetLowRamDevice();
798
799 // Restore device connection states
800 synchronized (mConnectedDevices) {
801 for (int i = 0; i < mConnectedDevices.size(); i++) {
802 DeviceListSpec spec = mConnectedDevices.valueAt(i);
803 AudioSystem.setDeviceConnectionState(
804 spec.mDeviceType,
805 AudioSystem.DEVICE_STATE_AVAILABLE,
806 spec.mDeviceAddress,
807 spec.mDeviceName);
808 }
809 }
810 // Restore call state
811 AudioSystem.setPhoneState(mMode);
812
813 // Restore forced usage for communcations and record
814 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
815 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
816 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
817 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
818
819 // Restore stream volumes
820 int numStreamTypes = AudioSystem.getNumStreamTypes();
821 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
822 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurente4381ec2015-10-29 17:52:48 -0700823 AudioSystem.initStreamVolume(
824 streamType, streamState.mIndexMin / 10, streamState.mIndexMax / 10);
Eric Laurent0867bed2015-05-20 14:49:08 -0700825
826 streamState.applyAllVolumes();
827 }
828
Andy Hungf04b84d2015-12-18 17:33:27 -0800829 // Restore mono mode
Andy Hung7b98e9a2016-02-25 18:34:50 -0800830 updateMasterMono(mContentResolver);
Andy Hungf04b84d2015-12-18 17:33:27 -0800831
Eric Laurent0867bed2015-05-20 14:49:08 -0700832 // Restore ringer mode
833 setRingerModeInt(getRingerModeInternal(), false);
834
835 // Reset device orientation (if monitored for this device)
836 if (mMonitorOrientation) {
837 setOrientationForAudioSystem();
838 }
839 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -0700840 RotationHelper.updateOrientation();
Eric Laurent0867bed2015-05-20 14:49:08 -0700841 }
842
Sungsoocf09fe62016-09-28 16:21:48 +0900843 synchronized (mBluetoothA2dpEnabledLock) {
844 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
845 mBluetoothA2dpEnabled ?
846 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
847 }
848
Eric Laurent0867bed2015-05-20 14:49:08 -0700849 synchronized (mSettingsLock) {
850 AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
851 mDockAudioMediaEnabled ?
852 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
Phil Burked43bf52016-03-01 17:01:35 -0800853 sendEncodedSurroundMode(mContentResolver);
Eric Laurent0867bed2015-05-20 14:49:08 -0700854 }
855 if (mHdmiManager != null) {
856 synchronized (mHdmiManager) {
857 if (mHdmiTvClient != null) {
858 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
859 }
860 }
861 }
862
863 synchronized (mAudioPolicies) {
864 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
865 policy.connectMixes();
866 }
867 }
868
869 onIndicateSystemReady();
870 // indicate the end of reconfiguration phase to audio HAL
871 AudioSystem.setParameters("restarting=false");
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700872 }
873
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874 private void createAudioSystemThread() {
875 mAudioSystemThread = new AudioSystemThread();
876 mAudioSystemThread.start();
877 waitForAudioHandlerCreation();
878 }
879
880 /** Waits for the volume handler to be created by the other thread. */
881 private void waitForAudioHandlerCreation() {
882 synchronized(this) {
883 while (mAudioHandler == null) {
884 try {
885 // Wait for mAudioHandler to be set by the other thread
886 wait();
887 } catch (InterruptedException e) {
888 Log.e(TAG, "Interrupted while waiting on volume handler.");
889 }
890 }
891 }
892 }
893
Eric Laurent24482012012-05-10 09:41:17 -0700894 private void checkAllAliasStreamVolumes() {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700895 synchronized (VolumeStreamState.class) {
896 int numStreamTypes = AudioSystem.getNumStreamTypes();
897 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
898 if (streamType != mStreamVolumeAlias[streamType]) {
899 mStreamStates[streamType].
John Spurlock90874332015-03-10 16:00:54 -0400900 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]],
901 TAG);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700902 }
903 // apply stream volume
RoboErik4197cb62015-01-21 15:45:32 -0800904 if (!mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700905 mStreamStates[streamType].applyAllVolumes();
906 }
Eric Laurent24482012012-05-10 09:41:17 -0700907 }
908 }
909 }
910
Eric Laurent212532b2014-07-21 15:43:18 -0700911 private void checkAllFixedVolumeDevices()
912 {
913 int numStreamTypes = AudioSystem.getNumStreamTypes();
914 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
915 mStreamStates[streamType].checkFixedVolumeDevices();
916 }
917 }
918
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700919 private void checkAllFixedVolumeDevices(int streamType) {
920 mStreamStates[streamType].checkFixedVolumeDevices();
921 }
922
John Spurlockb6e19e32015-03-10 21:33:44 -0400923 private void checkMuteAffectedStreams() {
924 // any stream with a min level > 0 is not muteable by definition
925 for (int i = 0; i < mStreamStates.length; i++) {
926 final VolumeStreamState vss = mStreamStates[i];
927 if (vss.mIndexMin > 0) {
928 mMuteAffectedStreams &= ~(1 << vss.mStreamType);
929 }
930 }
931 }
932
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800933 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800934 int numStreamTypes = AudioSystem.getNumStreamTypes();
935 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
936
937 for (int i = 0; i < numStreamTypes; i++) {
Eric Laurent6d517662012-04-23 18:42:39 -0700938 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -0700939 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940
Eric Laurent212532b2014-07-21 15:43:18 -0700941 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -0700942 checkAllAliasStreamVolumes();
John Spurlockb6e19e32015-03-10 21:33:44 -0400943 checkMuteAffectedStreams();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800944 }
945
Eric Laurentbffc3d12012-05-07 17:43:49 -0700946 private void dumpStreamStates(PrintWriter pw) {
947 pw.println("\nStream volumes (device: index)");
948 int numStreamTypes = AudioSystem.getNumStreamTypes();
949 for (int i = 0; i < numStreamTypes; i++) {
John Spurlock61560172015-02-06 19:46:04 -0500950 pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":");
Eric Laurentbffc3d12012-05-07 17:43:49 -0700951 mStreamStates[i].dump(pw);
952 pw.println("");
953 }
Eric Laurentdd45d012012-10-08 09:04:34 -0700954 pw.print("\n- mute affected streams = 0x");
955 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -0700956 }
957
John Spurlock90874332015-03-10 16:00:54 -0400958 private void updateStreamVolumeAlias(boolean updateVolumes, String caller) {
Eric Laurent6d517662012-04-23 18:42:39 -0700959 int dtmfStreamAlias;
Eric Laurent212532b2014-07-21 15:43:18 -0700960
961 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -0500962 case AudioSystem.PLATFORM_VOICE:
Eric Laurent212532b2014-07-21 15:43:18 -0700963 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
Eric Laurent6d517662012-04-23 18:42:39 -0700964 dtmfStreamAlias = AudioSystem.STREAM_RING;
Eric Laurent212532b2014-07-21 15:43:18 -0700965 break;
John Spurlock61560172015-02-06 19:46:04 -0500966 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -0700967 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
968 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
969 break;
970 default:
971 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
Eric Laurent6d517662012-04-23 18:42:39 -0700972 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
973 }
Eric Laurent212532b2014-07-21 15:43:18 -0700974
975 if (isPlatformTelevision()) {
976 mRingerModeAffectedStreams = 0;
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700977 } else {
Eric Laurent212532b2014-07-21 15:43:18 -0700978 if (isInCommunication()) {
979 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
980 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
981 } else {
982 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
983 }
Eric Laurent6d517662012-04-23 18:42:39 -0700984 }
Eric Laurent212532b2014-07-21 15:43:18 -0700985
Eric Laurent6d517662012-04-23 18:42:39 -0700986 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
987 if (updateVolumes) {
John Spurlock90874332015-03-10 16:00:54 -0400988 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
989 caller);
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700990 // apply stream mute states according to new value of mRingerModeAffectedStreams
John Spurlock661f2cf2014-11-17 10:29:10 -0500991 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent6d517662012-04-23 18:42:39 -0700992 sendMsg(mAudioHandler,
993 MSG_SET_ALL_VOLUMES,
994 SENDMSG_QUEUE,
995 0,
996 0,
997 mStreamStates[AudioSystem.STREAM_DTMF], 0);
998 }
999 }
1000
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001001 private void readDockAudioSettings(ContentResolver cr)
1002 {
1003 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -07001004 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001005
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001006 sendMsg(mAudioHandler,
1007 MSG_SET_FORCE_USE,
1008 SENDMSG_QUEUE,
1009 AudioSystem.FOR_DOCK,
1010 mDockAudioMediaEnabled ?
1011 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
1012 null,
1013 0);
1014 }
1015
Phil Burkac0f7042016-02-24 12:19:08 -08001016
Andy Hung7b98e9a2016-02-25 18:34:50 -08001017 private void updateMasterMono(ContentResolver cr)
1018 {
1019 final boolean masterMono = System.getIntForUser(
1020 cr, System.MASTER_MONO, 0 /* default */, UserHandle.USER_CURRENT) == 1;
1021 if (DEBUG_VOL) {
1022 Log.d(TAG, String.format("Master mono %b", masterMono));
1023 }
1024 AudioSystem.setMasterMono(masterMono);
1025 }
1026
Phil Burked43bf52016-03-01 17:01:35 -08001027 private void sendEncodedSurroundMode(ContentResolver cr)
Phil Burkac0f7042016-02-24 12:19:08 -08001028 {
1029 int encodedSurroundMode = Settings.Global.getInt(
1030 cr, Settings.Global.ENCODED_SURROUND_OUTPUT,
1031 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
1032 sendEncodedSurroundMode(encodedSurroundMode);
1033 }
1034
1035 private void sendEncodedSurroundMode(int encodedSurroundMode)
1036 {
1037 // initialize to guaranteed bad value
1038 int forceSetting = AudioSystem.NUM_FORCE_CONFIG;
1039 switch (encodedSurroundMode) {
1040 case Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO:
1041 forceSetting = AudioSystem.FORCE_NONE;
1042 break;
1043 case Settings.Global.ENCODED_SURROUND_OUTPUT_NEVER:
1044 forceSetting = AudioSystem.FORCE_ENCODED_SURROUND_NEVER;
1045 break;
1046 case Settings.Global.ENCODED_SURROUND_OUTPUT_ALWAYS:
1047 forceSetting = AudioSystem.FORCE_ENCODED_SURROUND_ALWAYS;
1048 break;
1049 default:
1050 Log.e(TAG, "updateSurroundSoundSettings: illegal value "
1051 + encodedSurroundMode);
1052 break;
1053 }
1054 if (forceSetting != AudioSystem.NUM_FORCE_CONFIG) {
1055 sendMsg(mAudioHandler,
1056 MSG_SET_FORCE_USE,
1057 SENDMSG_QUEUE,
1058 AudioSystem.FOR_ENCODED_SURROUND,
1059 forceSetting,
1060 null,
1061 0);
1062 }
1063 }
1064
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 private void readPersistedSettings() {
1066 final ContentResolver cr = mContentResolver;
1067
Eric Laurentbffc3d12012-05-07 17:43:49 -07001068 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07001069 Settings.Global.getInt(
1070 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -07001071 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -07001072 // sanity check in case the settings are restored from a device with incompatible
1073 // ringer modes
John Spurlock97559372014-10-24 16:27:36 -04001074 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001075 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -07001076 }
1077 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1078 ringerMode = AudioManager.RINGER_MODE_SILENT;
1079 }
1080 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07001081 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -08001082 }
Eric Laurent212532b2014-07-21 15:43:18 -07001083 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001084 ringerMode = AudioManager.RINGER_MODE_NORMAL;
1085 }
Glenn Kastenba195eb2011-12-13 09:30:40 -08001086 synchronized(mSettingsLock) {
1087 mRingerMode = ringerMode;
John Spurlock661f2cf2014-11-17 10:29:10 -05001088 if (mRingerModeExternal == -1) {
1089 mRingerModeExternal = mRingerMode;
1090 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091
Eric Laurentdd45d012012-10-08 09:04:34 -07001092 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
1093 // are still needed while setVibrateSetting() and getVibrateSetting() are being
1094 // deprecated.
John Spurlock61560172015-02-06 19:46:04 -05001095 mVibrateSetting = AudioSystem.getValueForVibrateSetting(0,
Eric Laurentdd45d012012-10-08 09:04:34 -07001096 AudioManager.VIBRATE_TYPE_NOTIFICATION,
1097 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
1098 : AudioManager.VIBRATE_SETTING_OFF);
John Spurlock61560172015-02-06 19:46:04 -05001099 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting,
Eric Laurentdd45d012012-10-08 09:04:34 -07001100 AudioManager.VIBRATE_TYPE_RINGER,
1101 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
1102 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103
Eric Laurent24e0d9b2013-10-03 18:15:07 -07001104 updateRingerModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001105 readDockAudioSettings(cr);
Phil Burked43bf52016-03-01 17:01:35 -08001106 sendEncodedSurroundMode(cr);
Eric Laurent402f7f22011-02-04 12:30:32 -08001107 }
Eric Laurentc1d41662011-07-19 11:21:13 -07001108
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001109 mMuteAffectedStreams = System.getIntForUser(cr,
John Spurlock61560172015-02-06 19:46:04 -05001110 System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
John Spurlock24c05182015-02-05 12:30:36 -05001111 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112
Andy Hung7b98e9a2016-02-25 18:34:50 -08001113 updateMasterMono(cr);
Andy Hungf04b84d2015-12-18 17:33:27 -08001114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 // Each stream will read its own persisted settings
1116
John Spurlockbcc10872014-11-28 15:29:21 -05001117 // Broadcast the sticky intents
1118 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
1119 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120
1121 // Broadcast vibrate settings
1122 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
1123 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07001124
John Spurlock33f4e042014-07-11 13:10:58 -04001125 // Load settings for the volume controller
1126 mVolumeController.loadSettings(cr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127 }
1128
Eric Laurentc0232482016-03-15 18:19:23 -07001129 private void readUserRestrictions() {
1130 final int currentUser = getCurrentUserId();
1131
1132 // Check the current user restriction.
Tony Makc1205112016-07-22 16:02:59 +01001133 boolean masterMute =
1134 mUserManagerInternal.getUserRestriction(currentUser,
1135 UserManager.DISALLLOW_UNMUTE_DEVICE)
1136 || mUserManagerInternal.getUserRestriction(currentUser,
1137 UserManager.DISALLOW_ADJUST_VOLUME);
Eric Laurentc0232482016-03-15 18:19:23 -07001138 if (mUseFixedVolume) {
1139 masterMute = false;
1140 AudioSystem.setMasterVolume(1.0f);
1141 }
1142 if (DEBUG_VOL) {
1143 Log.d(TAG, String.format("Master mute %s, user=%d", masterMute, currentUser));
1144 }
1145 setSystemAudioMute(masterMute);
1146 AudioSystem.setMasterMute(masterMute);
1147 broadcastMasterMuteStatus(masterMute);
1148
1149 boolean microphoneMute = mUserManagerInternal.getUserRestriction(
1150 currentUser, UserManager.DISALLOW_UNMUTE_MICROPHONE);
1151 if (DEBUG_VOL) {
1152 Log.d(TAG, String.format("Mic mute %s, user=%d", microphoneMute, currentUser));
1153 }
1154 AudioSystem.muteMicrophone(microphoneMute);
1155 }
1156
Eric Laurenta553c252009-07-17 12:17:14 -07001157 private int rescaleIndex(int index, int srcStream, int dstStream) {
1158 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
1159 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001160
1161 ///////////////////////////////////////////////////////////////////////////
1162 // IPC methods
1163 ///////////////////////////////////////////////////////////////////////////
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001164 /** @see AudioManager#adjustVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001165 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001166 String callingPackage, String caller) {
RoboErik272e1612014-09-05 11:39:29 -07001167 adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
John Spurlock90874332015-03-10 16:00:54 -04001168 caller, Binder.getCallingUid());
RoboErik272e1612014-09-05 11:39:29 -07001169 }
1170
1171 private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001172 String callingPackage, String caller, int uid) {
1173 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType
1174 + ", flags=" + flags + ", caller=" + caller);
Eric Laurent402f7f22011-02-04 12:30:32 -08001175 int streamType;
RoboErik4197cb62015-01-21 15:45:32 -08001176 boolean isMute = isMuteAdjust(direction);
Eric Laurent45c90ce2012-04-24 18:44:22 -07001177 if (mVolumeControlStream != -1) {
1178 streamType = mVolumeControlStream;
Eric Laurent402f7f22011-02-04 12:30:32 -08001179 } else {
1180 streamType = getActiveStreamType(suggestedStreamType);
1181 }
John Spurlock0a376af2015-03-26 16:24:12 -04001182 ensureValidStreamType(streamType);
John Spurlock33f4e042014-07-11 13:10:58 -04001183 final int resolvedStream = mStreamVolumeAlias[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184
RoboErik2811dd32014-08-12 09:48:13 -07001185 // Play sounds on STREAM_RING only.
1186 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
John Spurlock33f4e042014-07-11 13:10:58 -04001187 resolvedStream != AudioSystem.STREAM_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001188 flags &= ~AudioManager.FLAG_PLAY_SOUND;
1189 }
1190
John Spurlock33f4e042014-07-11 13:10:58 -04001191 // For notifications/ring, show the ui before making any adjustments
RoboErik4197cb62015-01-21 15:45:32 -08001192 // Don't suppress mute/unmute requests
1193 if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
John Spurlock33f4e042014-07-11 13:10:58 -04001194 direction = 0;
1195 flags &= ~AudioManager.FLAG_PLAY_SOUND;
1196 flags &= ~AudioManager.FLAG_VIBRATE;
1197 if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
1198 }
1199
John Spurlock90874332015-03-10 16:00:54 -04001200 adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001201 }
1202
1203 /** @see AudioManager#adjustStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001204 public void adjustStreamVolume(int streamType, int direction, int flags,
1205 String callingPackage) {
John Spurlock90874332015-03-10 16:00:54 -04001206 adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage,
1207 Binder.getCallingUid());
RoboErik0dac35a2014-08-12 15:48:49 -07001208 }
1209
1210 private void adjustStreamVolume(int streamType, int direction, int flags,
John Spurlock90874332015-03-10 16:00:54 -04001211 String callingPackage, String caller, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001212 if (mUseFixedVolume) {
1213 return;
1214 }
John Spurlock90874332015-03-10 16:00:54 -04001215 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream=" + streamType + ", dir=" + direction
1216 + ", flags=" + flags + ", caller=" + caller);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07001217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218 ensureValidDirection(direction);
1219 ensureValidStreamType(streamType);
1220
RoboErik4197cb62015-01-21 15:45:32 -08001221 boolean isMuteAdjust = isMuteAdjust(direction);
1222
John Spurlock3ce37252015-02-17 13:20:45 -05001223 if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
1224 return;
1225 }
1226
Eric Laurent96a33d12011-11-08 10:31:57 -08001227 // use stream type alias here so that streams with same alias have the same behavior,
1228 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
1229 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
Eric Laurent6d517662012-04-23 18:42:39 -07001230 int streamTypeAlias = mStreamVolumeAlias[streamType];
RoboErik4197cb62015-01-21 15:45:32 -08001231
Eric Laurentb024c302011-10-14 17:19:27 -07001232 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001233
1234 final int device = getDeviceForStream(streamTypeAlias);
Eric Laurent3ef75492012-11-28 12:12:23 -08001235
Eric Laurent42b041e2013-03-29 11:36:03 -07001236 int aliasIndex = streamState.getIndex(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001237 boolean adjustVolume = true;
Eric Laurent3ef75492012-11-28 12:12:23 -08001238 int step;
Eric Laurent24482012012-05-10 09:41:17 -07001239
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001240 // skip a2dp absolute volume control request when the device
1241 // is not an a2dp device
1242 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1243 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1244 return;
1245 }
1246
Kenny Guy70e0c582015-06-30 19:18:28 +01001247 // If we are being called by the system (e.g. hardware keys) check for current user
1248 // so we handle user restrictions correctly.
1249 if (uid == android.os.Process.SYSTEM_UID) {
1250 uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
1251 }
John Spurlock59dc9c12015-03-02 11:20:15 -05001252 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001253 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001254 return;
1255 }
1256
Eric Laurentfde16d52012-12-03 14:42:39 -08001257 // reset any pending volume command
1258 synchronized (mSafeMediaVolumeState) {
1259 mPendingVolumeCommand = null;
1260 }
1261
Eric Laurent3ef75492012-11-28 12:12:23 -08001262 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1263 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1264 ((device & mFixedVolumeDevices) != 0)) {
1265 flags |= AudioManager.FLAG_FIXED_VOLUME;
1266
1267 // Always toggle between max safe volume and 0 for fixed volume devices where safe
1268 // volume is enforced, and max and 0 for the others.
1269 // This is simulated by stepping by the full allowed volume range
1270 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1271 (device & mSafeMediaVolumeDevices) != 0) {
1272 step = mSafeMediaVolumeIndex;
1273 } else {
1274 step = streamState.getMaxIndex();
1275 }
1276 if (aliasIndex != 0) {
1277 aliasIndex = step;
1278 }
1279 } else {
1280 // convert one UI step (+/-1) into a number of internal units on the stream alias
1281 step = rescaleIndex(10, streamType, streamTypeAlias);
1282 }
1283
Eric Laurent42b041e2013-03-29 11:36:03 -07001284 // If either the client forces allowing ringer modes for this adjustment,
1285 // or the stream type is one that is affected by ringer modes
1286 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlockee5ad722015-03-03 16:17:21 -05001287 (streamTypeAlias == getUiSoundsStreamType())) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001288 int ringerMode = getRingerModeInternal();
Eric Laurent42b041e2013-03-29 11:36:03 -07001289 // do not vibrate if already in vibrate mode
1290 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
1291 flags &= ~AudioManager.FLAG_VIBRATE;
Eric Laurent3ef75492012-11-28 12:12:23 -08001292 }
RoboErik5452e252015-02-06 15:33:53 -08001293 // Check if the ringer mode handles this adjustment. If it does we don't
1294 // need to adjust the volume further.
John Spurlock50ced3f2015-05-11 16:00:09 -04001295 final int result = checkForRingerModeChange(aliasIndex, direction, step,
Julia Reynoldsed783792016-04-08 15:27:35 -04001296 streamState.mIsMuted, callingPackage, flags);
John Spurlocka11b4af2014-06-01 11:52:23 -04001297 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
1298 // If suppressing a volume adjustment in silent mode, display the UI hint
1299 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
1300 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
1301 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001302 // If suppressing a volume down adjustment in vibrate mode, display the UI hint
1303 if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
1304 flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
1305 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001306 }
John Spurlock50ced3f2015-05-11 16:00:09 -04001307 // If the ringermode is suppressing media, prevent changes
Julia Reynoldsed783792016-04-08 15:27:35 -04001308 if (!volumeAdjustmentAllowedByDnd(streamTypeAlias, flags)) {
John Spurlock50ced3f2015-05-11 16:00:09 -04001309 adjustVolume = false;
1310 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001311 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001312
Eric Laurent42b041e2013-03-29 11:36:03 -07001313 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
RoboErik5452e252015-02-06 15:33:53 -08001314 mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001315
John Du5a0cf7a2013-07-19 11:30:34 -07001316 // Check if volume update should be send to AVRCP
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001317 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1318 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1319 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1320 synchronized (mA2dpAvrcpLock) {
1321 if (mA2dp != null && mAvrcpAbsVolSupported) {
1322 mA2dp.adjustAvrcpAbsoluteVolume(direction);
1323 }
John Du5a0cf7a2013-07-19 11:30:34 -07001324 }
1325 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001326
RoboErik4197cb62015-01-21 15:45:32 -08001327 if (isMuteAdjust) {
1328 boolean state;
1329 if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
1330 state = !streamState.mIsMuted;
1331 } else {
1332 state = direction == AudioManager.ADJUST_MUTE;
1333 }
1334 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1335 setSystemAudioMute(state);
1336 }
1337 for (int stream = 0; stream < mStreamStates.length; stream++) {
1338 if (streamTypeAlias == mStreamVolumeAlias[stream]) {
Sungmin Choi841ed0a2015-07-26 23:09:49 -07001339 if (!(readCameraSoundForced()
1340 && (mStreamStates[stream].getStreamType()
1341 == AudioSystem.STREAM_SYSTEM_ENFORCED))) {
1342 mStreamStates[stream].mute(state);
1343 }
RoboErik4197cb62015-01-21 15:45:32 -08001344 }
1345 }
1346 } else if ((direction == AudioManager.ADJUST_RAISE) &&
Eric Laurent42b041e2013-03-29 11:36:03 -07001347 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
RoboErik4197cb62015-01-21 15:45:32 -08001348 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -04001349 mVolumeController.postDisplaySafeVolumeWarning(flags);
John Spurlock90874332015-03-10 16:00:54 -04001350 } else if (streamState.adjustIndex(direction * step, device, caller)
1351 || streamState.mIsMuted) {
RoboErik4197cb62015-01-21 15:45:32 -08001352 // Post message to set system volume (it in turn will post a
1353 // message to persist).
1354 if (streamState.mIsMuted) {
1355 // Unmute the stream if it was previously muted
RoboErik5452e252015-02-06 15:33:53 -08001356 if (direction == AudioManager.ADJUST_RAISE) {
1357 // unmute immediately for volume up
1358 streamState.mute(false);
1359 } else if (direction == AudioManager.ADJUST_LOWER) {
John Spurlocka48d7792015-03-03 17:35:57 -05001360 if (mPlatformType == AudioSystem.PLATFORM_TELEVISION) {
1361 sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
1362 streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
1363 }
RoboErik5452e252015-02-06 15:33:53 -08001364 }
RoboErik4197cb62015-01-21 15:45:32 -08001365 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001366 sendMsg(mAudioHandler,
1367 MSG_SET_DEVICE_VOLUME,
1368 SENDMSG_QUEUE,
1369 device,
1370 0,
1371 streamState,
1372 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001373 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001374
RoboErik4197cb62015-01-21 15:45:32 -08001375 // Check if volume update should be sent to Hdmi system audio.
Jungshik Jang41d97462014-06-30 22:26:29 +09001376 int newIndex = mStreamStates[streamType].getIndex(device);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001377 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1378 setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
1379 }
Eric Laurent212532b2014-07-21 15:43:18 -07001380 if (mHdmiManager != null) {
1381 synchronized (mHdmiManager) {
Eric Laurent212532b2014-07-21 15:43:18 -07001382 // mHdmiCecSink true => mHdmiPlaybackClient != null
1383 if (mHdmiCecSink &&
1384 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1385 oldIndex != newIndex) {
1386 synchronized (mHdmiPlaybackClient) {
1387 int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
RoboErik4197cb62015-01-21 15:45:32 -08001388 KeyEvent.KEYCODE_VOLUME_UP;
Donghyun Cho5f6d404e2016-03-17 20:39:25 +09001389 final long ident = Binder.clearCallingIdentity();
1390 try {
1391 mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1392 mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1393 } finally {
1394 Binder.restoreCallingIdentity(ident);
1395 }
Eric Laurent212532b2014-07-21 15:43:18 -07001396 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001397 }
1398 }
1399 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001400 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001401 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001402 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001403 }
1404
RoboErik5452e252015-02-06 15:33:53 -08001405 // Called after a delay when volume down is pressed while muted
1406 private void onUnmuteStream(int stream, int flags) {
1407 VolumeStreamState streamState = mStreamStates[stream];
1408 streamState.mute(false);
1409
1410 final int device = getDeviceForStream(stream);
1411 final int index = mStreamStates[stream].getIndex(device);
1412 sendVolumeUpdate(stream, index, index, flags);
1413 }
1414
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001415 private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
1416 if (mHdmiManager == null
1417 || mHdmiTvClient == null
1418 || oldVolume == newVolume
1419 || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
1420
1421 // Sets the audio volume of AVR when we are in system audio mode. The new volume info
1422 // is tranformed to HDMI-CEC commands and passed through CEC bus.
1423 synchronized (mHdmiManager) {
1424 if (!mHdmiSystemAudioSupported) return;
1425 synchronized (mHdmiTvClient) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001426 final long token = Binder.clearCallingIdentity();
1427 try {
Jinsuk Kim7a9ba422015-02-16 16:47:38 +09001428 mHdmiTvClient.setSystemAudioVolume(oldVolume, newVolume, maxVolume);
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001429 } finally {
1430 Binder.restoreCallingIdentity(token);
1431 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001432 }
1433 }
1434 }
1435
Eric Laurentfde16d52012-12-03 14:42:39 -08001436 // StreamVolumeCommand contains the information needed to defer the process of
1437 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1438 class StreamVolumeCommand {
1439 public final int mStreamType;
1440 public final int mIndex;
1441 public final int mFlags;
1442 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001443
Eric Laurentfde16d52012-12-03 14:42:39 -08001444 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1445 mStreamType = streamType;
1446 mIndex = index;
1447 mFlags = flags;
1448 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001449 }
John Spurlock35134602014-07-24 18:10:48 -04001450
1451 @Override
1452 public String toString() {
1453 return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1454 .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1455 .append(mDevice).append('}').toString();
1456 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001457 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001458
Julia Reynolds48034f82016-03-09 10:15:16 -05001459 private int getNewRingerMode(int stream, int index, int flags) {
John Spurlockee5ad722015-03-03 16:17:21 -05001460 // setting volume on ui sounds stream type also controls silent mode
Eric Laurent3ef75492012-11-28 12:12:23 -08001461 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlock75ae23c2015-06-02 16:26:43 -04001462 (stream == getUiSoundsStreamType())) {
Eric Laurent3ef75492012-11-28 12:12:23 -08001463 int newRingerMode;
1464 if (index == 0) {
1465 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlocka48d7792015-03-03 17:35:57 -05001466 : mVolumePolicy.volumeDownToEnterSilent ? AudioManager.RINGER_MODE_SILENT
Julia Reynolds48034f82016-03-09 10:15:16 -05001467 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001468 } else {
1469 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1470 }
Julia Reynolds48034f82016-03-09 10:15:16 -05001471 return newRingerMode;
1472 }
1473 return getRingerModeExternal();
1474 }
1475
1476 private boolean isAndroidNPlus(String caller) {
1477 try {
1478 final ApplicationInfo applicationInfo =
1479 mContext.getPackageManager().getApplicationInfoAsUser(
1480 caller, 0, UserHandle.getUserId(Binder.getCallingUid()));
1481 if (applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
1482 return true;
1483 }
1484 return false;
1485 } catch (PackageManager.NameNotFoundException e) {
1486 return true;
1487 }
1488 }
1489
1490 private boolean wouldToggleZenMode(int newMode) {
1491 if (getRingerModeExternal() == AudioManager.RINGER_MODE_SILENT
1492 && newMode != AudioManager.RINGER_MODE_SILENT) {
1493 return true;
1494 } else if (getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT
1495 && newMode == AudioManager.RINGER_MODE_SILENT) {
1496 return true;
1497 }
1498 return false;
1499 }
1500
1501 private void onSetStreamVolume(int streamType, int index, int flags, int device,
1502 String caller) {
1503 final int stream = mStreamVolumeAlias[streamType];
1504 setStreamVolumeInt(stream, index, device, false, caller);
1505 // setting volume on ui sounds stream type also controls silent mode
1506 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1507 (stream == getUiSoundsStreamType())) {
1508 setRingerMode(getNewRingerMode(stream, index, flags),
1509 TAG + ".onSetStreamVolume", false /*external*/);
Eric Laurent3ef75492012-11-28 12:12:23 -08001510 }
John Spurlock75ae23c2015-06-02 16:26:43 -04001511 // setting non-zero volume for a muted stream unmutes the stream and vice versa
1512 mStreamStates[stream].mute(index == 0);
Eric Laurentfde16d52012-12-03 14:42:39 -08001513 }
1514
1515 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001516 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
John Spurlock90874332015-03-10 16:00:54 -04001517 setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
1518 Binder.getCallingUid());
RoboErik0dac35a2014-08-12 15:48:49 -07001519 }
1520
1521 private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
John Spurlock90874332015-03-10 16:00:54 -04001522 String caller, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001523 if (mUseFixedVolume) {
1524 return;
1525 }
1526
Eric Laurentfde16d52012-12-03 14:42:39 -08001527 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001528 int streamTypeAlias = mStreamVolumeAlias[streamType];
1529 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001530
1531 final int device = getDeviceForStream(streamType);
1532 int oldIndex;
1533
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001534 // skip a2dp absolute volume control request when the device
1535 // is not an a2dp device
1536 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1537 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1538 return;
1539 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001540 // If we are being called by the system (e.g. hardware keys) check for current user
1541 // so we handle user restrictions correctly.
1542 if (uid == android.os.Process.SYSTEM_UID) {
1543 uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
1544 }
John Spurlock59dc9c12015-03-02 11:20:15 -05001545 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001546 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001547 return;
1548 }
1549
Julia Reynolds48034f82016-03-09 10:15:16 -05001550 if (isAndroidNPlus(callingPackage)
1551 && wouldToggleZenMode(getNewRingerMode(streamTypeAlias, index, flags))
1552 && !mNm.isNotificationPolicyAccessGrantedForPackage(callingPackage)) {
1553 throw new SecurityException("Not allowed to change Do Not Disturb state");
1554 }
1555
Julia Reynoldsed783792016-04-08 15:27:35 -04001556 if (!volumeAdjustmentAllowedByDnd(streamTypeAlias, flags)) {
1557 return;
1558 }
1559
Eric Laurentfde16d52012-12-03 14:42:39 -08001560 synchronized (mSafeMediaVolumeState) {
1561 // reset any pending volume command
1562 mPendingVolumeCommand = null;
1563
Eric Laurent42b041e2013-03-29 11:36:03 -07001564 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001565
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001566 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001567
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001568 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1569 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1570 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1571 synchronized (mA2dpAvrcpLock) {
1572 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001573 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001574 }
John Du5a0cf7a2013-07-19 11:30:34 -07001575 }
1576 }
1577
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001578 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1579 setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
Jungshik Jang41d97462014-06-30 22:26:29 +09001580 }
1581
Eric Laurentfde16d52012-12-03 14:42:39 -08001582 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001583 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001584 ((device & mFixedVolumeDevices) != 0)) {
1585 flags |= AudioManager.FLAG_FIXED_VOLUME;
1586
1587 // volume is either 0 or max allowed for fixed volume devices
1588 if (index != 0) {
1589 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1590 (device & mSafeMediaVolumeDevices) != 0) {
1591 index = mSafeMediaVolumeIndex;
1592 } else {
1593 index = streamState.getMaxIndex();
1594 }
1595 }
1596 }
1597
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001598 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001599 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001600 mPendingVolumeCommand = new StreamVolumeCommand(
1601 streamType, index, flags, device);
1602 } else {
John Spurlock90874332015-03-10 16:00:54 -04001603 onSetStreamVolume(streamType, index, flags, device, caller);
Eric Laurent42b041e2013-03-29 11:36:03 -07001604 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001605 }
1606 }
Eric Laurent25101b02011-02-02 09:33:30 -08001607 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001608 }
1609
Julia Reynoldsed783792016-04-08 15:27:35 -04001610 // No ringer affected streams can be changed in total silence mode except those that
1611 // will cause the device to exit total silence mode.
1612 private boolean volumeAdjustmentAllowedByDnd(int streamTypeAlias, int flags) {
1613 if (mNm.getZenMode() == Settings.Global.ZEN_MODE_NO_INTERRUPTIONS
1614 && isStreamMutedByRingerMode(streamTypeAlias)) {
1615 if (!(((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1616 (streamTypeAlias == getUiSoundsStreamType()))) {
1617 return false;
1618 }
1619 }
1620 return true;
1621 }
1622
Eric Laurent45c90ce2012-04-24 18:44:22 -07001623 /** @see AudioManager#forceVolumeControlStream(int) */
1624 public void forceVolumeControlStream(int streamType, IBinder cb) {
1625 synchronized(mForceControlStreamLock) {
1626 mVolumeControlStream = streamType;
1627 if (mVolumeControlStream == -1) {
1628 if (mForceControlStreamClient != null) {
1629 mForceControlStreamClient.release();
1630 mForceControlStreamClient = null;
1631 }
1632 } else {
1633 mForceControlStreamClient = new ForceControlStreamClient(cb);
1634 }
1635 }
1636 }
1637
1638 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1639 private IBinder mCb; // To be notified of client's death
1640
1641 ForceControlStreamClient(IBinder cb) {
1642 if (cb != null) {
1643 try {
1644 cb.linkToDeath(this, 0);
1645 } catch (RemoteException e) {
1646 // Client has died!
1647 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1648 cb = null;
1649 }
1650 }
1651 mCb = cb;
1652 }
1653
1654 public void binderDied() {
1655 synchronized(mForceControlStreamLock) {
1656 Log.w(TAG, "SCO client died");
1657 if (mForceControlStreamClient != this) {
1658 Log.w(TAG, "unregistered control stream client died");
1659 } else {
1660 mForceControlStreamClient = null;
1661 mVolumeControlStream = -1;
1662 }
1663 }
1664 }
1665
1666 public void release() {
1667 if (mCb != null) {
1668 mCb.unlinkToDeath(this, 0);
1669 mCb = null;
1670 }
1671 }
1672 }
1673
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001674 private void sendBroadcastToAll(Intent intent) {
Christopher Tate267603f2015-01-20 14:21:21 -08001675 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
John Spurlock86490862015-02-25 11:22:52 -05001676 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001677 final long ident = Binder.clearCallingIdentity();
1678 try {
1679 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1680 } finally {
1681 Binder.restoreCallingIdentity(ident);
1682 }
1683 }
1684
1685 private void sendStickyBroadcastToAll(Intent intent) {
John Spurlock86490862015-02-25 11:22:52 -05001686 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001687 final long ident = Binder.clearCallingIdentity();
1688 try {
1689 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1690 } finally {
1691 Binder.restoreCallingIdentity(ident);
1692 }
1693 }
1694
Kenny Guy70e0c582015-06-30 19:18:28 +01001695 private int getCurrentUserId() {
1696 final long ident = Binder.clearCallingIdentity();
1697 try {
1698 UserInfo currentUser = ActivityManagerNative.getDefault().getCurrentUser();
1699 return currentUser.id;
1700 } catch (RemoteException e) {
1701 // Activity manager not running, nothing we can do assume user 0.
1702 } finally {
1703 Binder.restoreCallingIdentity(ident);
1704 }
Xiaohui Chen7c696362015-09-16 09:56:14 -07001705 return UserHandle.USER_SYSTEM;
Kenny Guy70e0c582015-06-30 19:18:28 +01001706 }
1707
Eric Laurent25101b02011-02-02 09:33:30 -08001708 // UI update and Broadcast Intent
1709 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
John Spurlock72966d62015-06-18 15:45:07 -04001710 streamType = mStreamVolumeAlias[streamType];
Eric Laurent25101b02011-02-02 09:33:30 -08001711
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001712 if (streamType == AudioSystem.STREAM_MUSIC) {
1713 flags = updateFlagsForSystemAudio(flags);
Jungshik Jang1a6be6e2014-09-16 11:04:54 +09001714 }
John Spurlock3346a802014-05-20 16:25:37 -04001715 mVolumeController.postVolumeChanged(streamType, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001716 }
1717
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001718 // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
1719 // receives volume notification from Audio Receiver.
1720 private int updateFlagsForSystemAudio(int flags) {
1721 if (mHdmiTvClient != null) {
1722 synchronized (mHdmiTvClient) {
1723 if (mHdmiSystemAudioSupported &&
1724 ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
1725 flags &= ~AudioManager.FLAG_SHOW_UI;
1726 }
1727 }
1728 }
1729 return flags;
1730 }
1731
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001732 // UI update and Broadcast Intent
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001733 private void sendMasterMuteUpdate(boolean muted, int flags) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001734 mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
Justin Koh57978ed2012-04-03 17:37:58 -07001735 broadcastMasterMuteStatus(muted);
1736 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001737
Justin Koh57978ed2012-04-03 17:37:58 -07001738 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001739 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1740 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001741 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1742 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001743 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001744 }
1745
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001746 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001747 * Sets the stream state's index, and posts a message to set system volume.
1748 * This will not call out to the UI. Assumes a valid stream type.
1749 *
1750 * @param streamType Type of the stream
1751 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001752 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001753 * @param force If true, set the volume even if the desired volume is same
1754 * as the current volume.
1755 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001756 private void setStreamVolumeInt(int streamType,
1757 int index,
1758 int device,
John Spurlock90874332015-03-10 16:00:54 -04001759 boolean force,
1760 String caller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001761 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07001762
John Spurlock90874332015-03-10 16:00:54 -04001763 if (streamState.setIndex(index, device, caller) || force) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001764 // Post message to set system volume (it in turn will post a message
1765 // to persist).
1766 sendMsg(mAudioHandler,
1767 MSG_SET_DEVICE_VOLUME,
1768 SENDMSG_QUEUE,
1769 device,
1770 0,
1771 streamState,
1772 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001773 }
1774 }
1775
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001776 private void setSystemAudioMute(boolean state) {
1777 if (mHdmiManager == null || mHdmiTvClient == null) return;
1778 synchronized (mHdmiManager) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001779 if (!mHdmiSystemAudioSupported) return;
1780 synchronized (mHdmiTvClient) {
1781 final long token = Binder.clearCallingIdentity();
1782 try {
1783 mHdmiTvClient.setSystemAudioMute(state);
1784 } finally {
1785 Binder.restoreCallingIdentity(token);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001786 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001787 }
1788 }
1789 }
1790
Eric Laurent25101b02011-02-02 09:33:30 -08001791 /** get stream mute state. */
1792 public boolean isStreamMute(int streamType) {
RoboErik7c82ced2014-12-04 17:39:08 -08001793 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1794 streamType = getActiveStreamType(streamType);
1795 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001796 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08001797 return mStreamStates[streamType].mIsMuted;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001798 }
Eric Laurent25101b02011-02-02 09:33:30 -08001799 }
1800
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07001801 private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
1802 private IBinder mICallback; // To be notified of client's death
1803
1804 RmtSbmxFullVolDeathHandler(IBinder cb) {
1805 mICallback = cb;
1806 try {
1807 cb.linkToDeath(this, 0/*flags*/);
1808 } catch (RemoteException e) {
1809 Log.e(TAG, "can't link to death", e);
1810 }
1811 }
1812
1813 boolean isHandlerFor(IBinder cb) {
1814 return mICallback.equals(cb);
1815 }
1816
1817 void forget() {
1818 try {
1819 mICallback.unlinkToDeath(this, 0/*flags*/);
1820 } catch (NoSuchElementException e) {
1821 Log.e(TAG, "error unlinking to death", e);
1822 }
1823 }
1824
1825 public void binderDied() {
1826 Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
1827 forceRemoteSubmixFullVolume(false, mICallback);
1828 }
1829 }
1830
1831 /**
1832 * call must be synchronized on mRmtSbmxFullVolDeathHandlers
1833 * @return true if there is a registered death handler, false otherwise */
1834 private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1835 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1836 while (it.hasNext()) {
1837 final RmtSbmxFullVolDeathHandler handler = it.next();
1838 if (handler.isHandlerFor(cb)) {
1839 handler.forget();
1840 mRmtSbmxFullVolDeathHandlers.remove(handler);
1841 return true;
1842 }
1843 }
1844 return false;
1845 }
1846
1847 /** call synchronized on mRmtSbmxFullVolDeathHandlers */
1848 private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1849 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1850 while (it.hasNext()) {
1851 if (it.next().isHandlerFor(cb)) {
1852 return true;
1853 }
1854 }
1855 return false;
1856 }
1857
1858 private int mRmtSbmxFullVolRefCount = 0;
1859 private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
1860 new ArrayList<RmtSbmxFullVolDeathHandler>();
1861
1862 public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
1863 if (cb == null) {
1864 return;
1865 }
1866 if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
1867 android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
1868 Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
1869 return;
1870 }
1871 synchronized(mRmtSbmxFullVolDeathHandlers) {
1872 boolean applyRequired = false;
1873 if (startForcing) {
1874 if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
1875 mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
1876 if (mRmtSbmxFullVolRefCount == 0) {
1877 mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1878 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1879 applyRequired = true;
1880 }
1881 mRmtSbmxFullVolRefCount++;
1882 }
1883 } else {
1884 if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
1885 mRmtSbmxFullVolRefCount--;
1886 if (mRmtSbmxFullVolRefCount == 0) {
1887 mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1888 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1889 applyRequired = true;
1890 }
1891 }
1892 }
1893 if (applyRequired) {
1894 // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
1895 checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
1896 mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
1897 }
1898 }
1899 }
1900
Kenny Guy70e0c582015-06-30 19:18:28 +01001901 private void setMasterMuteInternal(boolean mute, int flags, String callingPackage, int uid,
1902 int userId) {
1903 // If we are being called by the system check for user we are going to change
1904 // so we handle user restrictions correctly.
1905 if (uid == android.os.Process.SYSTEM_UID) {
1906 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
1907 }
Makoto Onuki4f160732015-10-27 17:15:38 -07001908 // If OP_AUDIO_MASTER_VOLUME is set, disallow unmuting.
1909 if (!mute && mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
RoboErik7c82ced2014-12-04 17:39:08 -08001910 != AppOpsManager.MODE_ALLOWED) {
Julia Reynolds4a21b252014-06-04 11:11:43 -04001911 return;
1912 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001913 if (userId != UserHandle.getCallingUserId() &&
1914 mContext.checkCallingOrSelfPermission(
1915 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1916 != PackageManager.PERMISSION_GRANTED) {
1917 return;
1918 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08001919 setMasterMuteInternalNoCallerCheck(mute, flags, userId);
1920 }
1921
1922 private void setMasterMuteInternalNoCallerCheck(boolean mute, int flags, int userId) {
1923 if (DEBUG_VOL) {
1924 Log.d(TAG, String.format("Master mute %s, %d, user=%d", mute, flags, userId));
1925 }
1926 if (mUseFixedVolume) {
1927 return; // If using fixed volume, we don't mute.
1928 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001929 if (getCurrentUserId() == userId) {
1930 if (mute != AudioSystem.getMasterMute()) {
1931 setSystemAudioMute(mute);
1932 AudioSystem.setMasterMute(mute);
Kenny Guy70e0c582015-06-30 19:18:28 +01001933 sendMasterMuteUpdate(mute, flags);
RoboErik7c82ced2014-12-04 17:39:08 -08001934
Kenny Guy70e0c582015-06-30 19:18:28 +01001935 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1936 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute);
1937 sendBroadcastToAll(intent);
1938 }
Jason Simmons1ce5b262012-02-02 13:00:17 -08001939 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08001940 }
1941
1942 /** get master mute state. */
1943 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08001944 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001945 }
1946
Kenny Guy70e0c582015-06-30 19:18:28 +01001947 public void setMasterMute(boolean mute, int flags, String callingPackage, int userId) {
1948 setMasterMuteInternal(mute, flags, callingPackage, Binder.getCallingUid(),
1949 userId);
John Spurlockee5ad722015-03-03 16:17:21 -05001950 }
1951
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001952 /** @see AudioManager#getStreamVolume(int) */
1953 public int getStreamVolume(int streamType) {
1954 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001955 int device = getDeviceForStream(streamType);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001956 synchronized (VolumeStreamState.class) {
1957 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001958
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001959 // by convention getStreamVolume() returns 0 when a stream is muted.
RoboErik4197cb62015-01-21 15:45:32 -08001960 if (mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001961 index = 0;
1962 }
1963 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
1964 (device & mFixedVolumeDevices) != 0) {
1965 index = mStreamStates[streamType].getMaxIndex();
1966 }
1967 return (index + 5) / 10;
Eric Laurent42b041e2013-03-29 11:36:03 -07001968 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001969 }
1970
1971 /** @see AudioManager#getStreamMaxVolume(int) */
1972 public int getStreamMaxVolume(int streamType) {
1973 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07001974 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001975 }
1976
John Spurlockb6e19e32015-03-10 21:33:44 -04001977 /** @see AudioManager#getStreamMinVolume(int) */
1978 public int getStreamMinVolume(int streamType) {
1979 ensureValidStreamType(streamType);
1980 return (mStreamStates[streamType].getMinIndex() + 5) / 10;
1981 }
1982
Eric Laurent25101b02011-02-02 09:33:30 -08001983 /** Get last audible volume before stream was muted. */
1984 public int getLastAudibleStreamVolume(int streamType) {
1985 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001986 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001987 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08001988 }
1989
John Spurlockee5ad722015-03-03 16:17:21 -05001990 /** @see AudioManager#getUiSoundsStreamType() */
1991 public int getUiSoundsStreamType() {
John Spurlock4f0f1202014-08-05 13:28:33 -04001992 return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
Eric Laurent6d517662012-04-23 18:42:39 -07001993 }
1994
Makoto Onukid45a4a22015-11-02 17:17:38 -08001995 /** @see AudioManager#setMicrophoneMute(boolean) */
1996 @Override
Kenny Guy70e0c582015-06-30 19:18:28 +01001997 public void setMicrophoneMute(boolean on, String callingPackage, int userId) {
1998 // If we are being called by the system check for user we are going to change
1999 // so we handle user restrictions correctly.
2000 int uid = Binder.getCallingUid();
2001 if (uid == android.os.Process.SYSTEM_UID) {
2002 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
2003 }
Makoto Onuki4f160732015-10-27 17:15:38 -07002004 // If OP_MUTE_MICROPHONE is set, disallow unmuting.
2005 if (!on && mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, uid, callingPackage)
Kenny Guy70e0c582015-06-30 19:18:28 +01002006 != AppOpsManager.MODE_ALLOWED) {
Emily Bernier22c921a2014-05-28 11:01:32 -04002007 return;
2008 }
Jean-Michel Trivi4a4fea02014-08-29 18:14:09 -07002009 if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
2010 return;
2011 }
Kenny Guy70e0c582015-06-30 19:18:28 +01002012 if (userId != UserHandle.getCallingUserId() &&
2013 mContext.checkCallingOrSelfPermission(
2014 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
2015 != PackageManager.PERMISSION_GRANTED) {
2016 return;
2017 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08002018 setMicrophoneMuteNoCallerCheck(on, userId);
2019 }
Emily Bernier22c921a2014-05-28 11:01:32 -04002020
Makoto Onukid45a4a22015-11-02 17:17:38 -08002021 private void setMicrophoneMuteNoCallerCheck(boolean on, int userId) {
2022 if (DEBUG_VOL) {
2023 Log.d(TAG, String.format("Mic mute %s, user=%d", on, userId));
2024 }
Kenny Guy70e0c582015-06-30 19:18:28 +01002025 // If mute is for current user actually mute, else just persist the setting
2026 // which will be loaded on user switch.
2027 if (getCurrentUserId() == userId) {
2028 AudioSystem.muteMicrophone(on);
2029 }
Julia Reynoldsb53453f2014-08-22 11:42:43 -04002030 // Post a persist microphone msg.
Emily Bernier22c921a2014-05-28 11:01:32 -04002031 }
2032
John Spurlock661f2cf2014-11-17 10:29:10 -05002033 @Override
2034 public int getRingerModeExternal() {
2035 synchronized(mSettingsLock) {
2036 return mRingerModeExternal;
2037 }
2038 }
2039
2040 @Override
2041 public int getRingerModeInternal() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08002042 synchronized(mSettingsLock) {
2043 return mRingerMode;
2044 }
2045 }
2046
2047 private void ensureValidRingerMode(int ringerMode) {
John Spurlock97559372014-10-24 16:27:36 -04002048 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08002049 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
2050 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002051 }
2052
John Spurlock97559372014-10-24 16:27:36 -04002053 /** @see AudioManager#isValidRingerMode(int) */
2054 public boolean isValidRingerMode(int ringerMode) {
2055 return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
2056 }
2057
John Spurlock661f2cf2014-11-17 10:29:10 -05002058 public void setRingerModeExternal(int ringerMode, String caller) {
Julia Reynolds48034f82016-03-09 10:15:16 -05002059 if (isAndroidNPlus(caller) && wouldToggleZenMode(ringerMode)
2060 && !mNm.isNotificationPolicyAccessGrantedForPackage(caller)) {
2061 throw new SecurityException("Not allowed to change Do Not Disturb state");
2062 }
2063
John Spurlockaf88a192014-12-23 16:14:44 -05002064 setRingerMode(ringerMode, caller, true /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05002065 }
2066
2067 public void setRingerModeInternal(int ringerMode, String caller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05002068 enforceVolumeController("setRingerModeInternal");
John Spurlockaf88a192014-12-23 16:14:44 -05002069 setRingerMode(ringerMode, caller, false /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05002070 }
2071
2072 private void setRingerMode(int ringerMode, String caller, boolean external) {
Eric Laurent212532b2014-07-21 15:43:18 -07002073 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07002074 return;
2075 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002076 if (caller == null || caller.length() == 0) {
2077 throw new IllegalArgumentException("Bad caller: " + caller);
2078 }
John Spurlock97559372014-10-24 16:27:36 -04002079 ensureValidRingerMode(ringerMode);
Eric Laurent24482012012-05-10 09:41:17 -07002080 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
2081 ringerMode = AudioManager.RINGER_MODE_SILENT;
2082 }
John Spurlockaf88a192014-12-23 16:14:44 -05002083 final long identity = Binder.clearCallingIdentity();
2084 try {
2085 synchronized (mSettingsLock) {
2086 final int ringerModeInternal = getRingerModeInternal();
2087 final int ringerModeExternal = getRingerModeExternal();
2088 if (external) {
2089 setRingerModeExt(ringerMode);
2090 if (mRingerModeDelegate != null) {
2091 ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
John Spurlocka48d7792015-03-03 17:35:57 -05002092 ringerMode, caller, ringerModeInternal, mVolumePolicy);
John Spurlockaf88a192014-12-23 16:14:44 -05002093 }
2094 if (ringerMode != ringerModeInternal) {
2095 setRingerModeInt(ringerMode, true /*persist*/);
2096 }
2097 } else /*internal*/ {
2098 if (ringerMode != ringerModeInternal) {
2099 setRingerModeInt(ringerMode, true /*persist*/);
2100 }
2101 if (mRingerModeDelegate != null) {
2102 ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
John Spurlocka48d7792015-03-03 17:35:57 -05002103 ringerMode, caller, ringerModeExternal, mVolumePolicy);
John Spurlockaf88a192014-12-23 16:14:44 -05002104 }
2105 setRingerModeExt(ringerMode);
John Spurlock57627792014-12-11 11:29:54 -05002106 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002107 }
John Spurlockaf88a192014-12-23 16:14:44 -05002108 } finally {
2109 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002110 }
2111 }
2112
John Spurlock661f2cf2014-11-17 10:29:10 -05002113 private void setRingerModeExt(int ringerMode) {
2114 synchronized(mSettingsLock) {
2115 if (ringerMode == mRingerModeExternal) return;
2116 mRingerModeExternal = ringerMode;
John Spurlocke5b42d92014-10-15 12:03:48 -04002117 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002118 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05002119 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
John Spurlocke5b42d92014-10-15 12:03:48 -04002120 }
2121
John Spurlock50ced3f2015-05-11 16:00:09 -04002122 private void muteRingerModeStreams() {
Eric Laurent5b4e6542010-03-19 20:02:21 -07002123 // Mute stream if not previously muted by ringer mode and ringer mode
2124 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
2125 // Unmute stream if previously muted by ringer mode and ringer mode
2126 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07002127 int numStreamTypes = AudioSystem.getNumStreamTypes();
John Spurlock50ced3f2015-05-11 16:00:09 -04002128 final boolean ringerModeMute = mRingerMode == AudioManager.RINGER_MODE_VIBRATE
2129 || mRingerMode == AudioManager.RINGER_MODE_SILENT;
Eric Laurent5b4e6542010-03-19 20:02:21 -07002130 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002131 final boolean isMuted = isStreamMutedByRingerMode(streamType);
2132 final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
2133 if (isMuted == shouldMute) continue;
2134 if (!shouldMute) {
2135 // unmute
2136 // ring and notifications volume should never be 0 when not silenced
John Spurlockd9c75db2015-04-28 11:19:13 -04002137 if (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002138 synchronized (VolumeStreamState.class) {
John Spurlocka48d7792015-03-03 17:35:57 -05002139 final VolumeStreamState vss = mStreamStates[streamType];
2140 for (int i = 0; i < vss.mIndexMap.size(); i++) {
2141 int device = vss.mIndexMap.keyAt(i);
2142 int value = vss.mIndexMap.valueAt(i);
John Spurlock2bb02ec2015-03-02 13:13:06 -05002143 if (value == 0) {
John Spurlocka48d7792015-03-03 17:35:57 -05002144 vss.setIndex(10, device, TAG);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002145 }
2146 }
Eric Laurent9e0d25f2015-02-12 17:28:53 -08002147 // Persist volume for stream ring when it is changed here
2148 final int device = getDeviceForStream(streamType);
2149 sendMsg(mAudioHandler,
2150 MSG_PERSIST_VOLUME,
2151 SENDMSG_QUEUE,
2152 device,
2153 0,
2154 mStreamStates[streamType],
2155 PERSIST_DELAY);
Eric Laurentb024c302011-10-14 17:19:27 -07002156 }
Eric Laurent9bcf4012009-06-12 06:09:28 -07002157 }
RoboErik4197cb62015-01-21 15:45:32 -08002158 mStreamStates[streamType].mute(false);
John Spurlock661f2cf2014-11-17 10:29:10 -05002159 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent5b4e6542010-03-19 20:02:21 -07002160 } else {
John Spurlock661f2cf2014-11-17 10:29:10 -05002161 // mute
RoboErik4197cb62015-01-21 15:45:32 -08002162 mStreamStates[streamType].mute(true);
John Spurlock661f2cf2014-11-17 10:29:10 -05002163 mRingerModeMutedStreams |= (1 << streamType);
Jason Parekhb1096152009-03-24 17:48:25 -07002164 }
2165 }
John Spurlock50ced3f2015-05-11 16:00:09 -04002166 }
2167
2168 private void setRingerModeInt(int ringerMode, boolean persist) {
2169 final boolean change;
2170 synchronized(mSettingsLock) {
2171 change = mRingerMode != ringerMode;
2172 mRingerMode = ringerMode;
2173 }
2174
2175 muteRingerModeStreams();
Eric Laurenta553c252009-07-17 12:17:14 -07002176
Jason Parekhb1096152009-03-24 17:48:25 -07002177 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07002178 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002179 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07002180 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
2181 }
John Spurlockbcc10872014-11-28 15:29:21 -05002182 if (change) {
2183 // Send sticky broadcast
2184 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
2185 }
Jason Parekhb1096152009-03-24 17:48:25 -07002186 }
2187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002188 /** @see AudioManager#shouldVibrate(int) */
2189 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002190 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002191
2192 switch (getVibrateSetting(vibrateType)) {
2193
2194 case AudioManager.VIBRATE_SETTING_ON:
John Spurlock57627792014-12-11 11:29:54 -05002195 return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002196
2197 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
John Spurlock57627792014-12-11 11:29:54 -05002198 return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002199
2200 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04002201 // return false, even for incoming calls
2202 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002203
2204 default:
2205 return false;
2206 }
2207 }
2208
2209 /** @see AudioManager#getVibrateSetting(int) */
2210 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002211 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002212 return (mVibrateSetting >> (vibrateType * 2)) & 3;
2213 }
2214
2215 /** @see AudioManager#setVibrateSetting(int, int) */
2216 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
2217
Eric Laurentbffc3d12012-05-07 17:43:49 -07002218 if (!mHasVibrator) return;
2219
John Spurlock61560172015-02-06 19:46:04 -05002220 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
2221 vibrateSetting);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002222
2223 // Broadcast change
2224 broadcastVibrateSetting(vibrateType);
2225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002226 }
2227
Eric Laurent9272b4b2010-01-23 17:12:59 -08002228 private class SetModeDeathHandler implements IBinder.DeathRecipient {
2229 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002230 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002231 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
2232
Eric Laurent9f103de2011-09-08 15:04:23 -07002233 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08002234 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07002235 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002236 }
2237
2238 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07002239 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002240 synchronized(mSetModeDeathHandlers) {
2241 Log.w(TAG, "setMode() client died");
2242 int index = mSetModeDeathHandlers.indexOf(this);
2243 if (index < 0) {
2244 Log.w(TAG, "unregistered setMode() client died");
2245 } else {
John Spurlock90874332015-03-10 16:00:54 -04002246 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid, TAG);
Eric Laurent9272b4b2010-01-23 17:12:59 -08002247 }
2248 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002249 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2250 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002251 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07002252 final long ident = Binder.clearCallingIdentity();
2253 disconnectBluetoothSco(newModeOwnerPid);
2254 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07002255 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08002256 }
2257
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002258 public int getPid() {
2259 return mPid;
2260 }
2261
Eric Laurent9272b4b2010-01-23 17:12:59 -08002262 public void setMode(int mode) {
2263 mMode = mode;
2264 }
2265
2266 public int getMode() {
2267 return mMode;
2268 }
2269
2270 public IBinder getBinder() {
2271 return mCb;
2272 }
2273 }
2274
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002275 /** @see AudioManager#setMode(int) */
John Spurlock90874332015-03-10 16:00:54 -04002276 public void setMode(int mode, IBinder cb, String callingPackage) {
2277 if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ", callingPackage=" + callingPackage + ")"); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002278 if (!checkAudioSettingsPermission("setMode()")) {
2279 return;
2280 }
Eric Laurenta553c252009-07-17 12:17:14 -07002281
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07002282 if ( (mode == AudioSystem.MODE_IN_CALL) &&
2283 (mContext.checkCallingOrSelfPermission(
2284 android.Manifest.permission.MODIFY_PHONE_STATE)
2285 != PackageManager.PERMISSION_GRANTED)) {
2286 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
2287 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
2288 return;
2289 }
2290
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08002291 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07002292 return;
2293 }
2294
Eric Laurentd7454be2011-09-14 08:45:58 -07002295 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002296 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07002297 if (mode == AudioSystem.MODE_CURRENT) {
2298 mode = mMode;
2299 }
John Spurlock90874332015-03-10 16:00:54 -04002300 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid(), callingPackage);
Eric Laurent9f103de2011-09-08 15:04:23 -07002301 }
2302 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2303 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002304 if (newModeOwnerPid != 0) {
2305 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07002306 }
2307 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002308
Eric Laurent9f103de2011-09-08 15:04:23 -07002309 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07002310 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07002311 // any mode other than NORMAL.
John Spurlock90874332015-03-10 16:00:54 -04002312 private int setModeInt(int mode, IBinder cb, int pid, String caller) {
2313 if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ", caller="
2314 + caller + ")"); }
Eric Laurentd7454be2011-09-14 08:45:58 -07002315 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002316 if (cb == null) {
2317 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07002318 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07002319 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002320
Eric Laurent9f103de2011-09-08 15:04:23 -07002321 SetModeDeathHandler hdlr = null;
2322 Iterator iter = mSetModeDeathHandlers.iterator();
2323 while (iter.hasNext()) {
2324 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
2325 if (h.getPid() == pid) {
2326 hdlr = h;
2327 // Remove from client list so that it is re-inserted at top of list
2328 iter.remove();
2329 hdlr.getBinder().unlinkToDeath(hdlr, 0);
2330 break;
2331 }
2332 }
2333 int status = AudioSystem.AUDIO_STATUS_OK;
2334 do {
2335 if (mode == AudioSystem.MODE_NORMAL) {
2336 // get new mode from client at top the list if any
2337 if (!mSetModeDeathHandlers.isEmpty()) {
2338 hdlr = mSetModeDeathHandlers.get(0);
2339 cb = hdlr.getBinder();
2340 mode = hdlr.getMode();
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002341 if (DEBUG_MODE) {
2342 Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
2343 + hdlr.mPid);
2344 }
Eric Laurentb9c9d262009-05-06 08:13:20 -07002345 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002346 } else {
2347 if (hdlr == null) {
2348 hdlr = new SetModeDeathHandler(cb, pid);
2349 }
2350 // Register for client death notification
2351 try {
2352 cb.linkToDeath(hdlr, 0);
2353 } catch (RemoteException e) {
2354 // Client has died!
2355 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
2356 }
2357
2358 // Last client to call setMode() is always at top of client list
2359 // as required by SetModeDeathHandler.binderDied()
2360 mSetModeDeathHandlers.add(0, hdlr);
2361 hdlr.setMode(mode);
2362 }
2363
2364 if (mode != mMode) {
2365 status = AudioSystem.setPhoneState(mode);
2366 if (status == AudioSystem.AUDIO_STATUS_OK) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002367 if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002368 mMode = mode;
2369 } else {
2370 if (hdlr != null) {
2371 mSetModeDeathHandlers.remove(hdlr);
2372 cb.unlinkToDeath(hdlr, 0);
2373 }
2374 // force reading new top of mSetModeDeathHandlers stack
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002375 if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002376 mode = AudioSystem.MODE_NORMAL;
2377 }
2378 } else {
2379 status = AudioSystem.AUDIO_STATUS_OK;
2380 }
2381 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
2382
2383 if (status == AudioSystem.AUDIO_STATUS_OK) {
2384 if (mode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002385 if (mSetModeDeathHandlers.isEmpty()) {
2386 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
2387 } else {
2388 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2389 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002390 }
2391 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002392 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07002393 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
John Spurlock90874332015-03-10 16:00:54 -04002394 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, caller);
Eric Laurent6d517662012-04-23 18:42:39 -07002395
John Spurlock90874332015-03-10 16:00:54 -04002396 updateStreamVolumeAlias(true /*updateVolumes*/, caller);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002397 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002398 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002399 }
2400
2401 /** @see AudioManager#getMode() */
2402 public int getMode() {
2403 return mMode;
2404 }
2405
Eric Laurente78fced2013-03-15 16:03:47 -07002406 //==========================================================================================
2407 // Sound Effects
2408 //==========================================================================================
2409
2410 private static final String TAG_AUDIO_ASSETS = "audio_assets";
2411 private static final String ATTR_VERSION = "version";
2412 private static final String TAG_GROUP = "group";
2413 private static final String ATTR_GROUP_NAME = "name";
2414 private static final String TAG_ASSET = "asset";
2415 private static final String ATTR_ASSET_ID = "id";
2416 private static final String ATTR_ASSET_FILE = "file";
2417
2418 private static final String ASSET_FILE_VERSION = "1.0";
2419 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
2420
Glenn Kasten167d1a22013-07-23 16:24:41 -07002421 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002422
2423 class LoadSoundEffectReply {
2424 public int mStatus = 1;
2425 };
2426
Eric Laurente78fced2013-03-15 16:03:47 -07002427 private void loadTouchSoundAssetDefaults() {
2428 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
2429 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
2430 SOUND_EFFECT_FILES_MAP[i][0] = 0;
2431 SOUND_EFFECT_FILES_MAP[i][1] = -1;
2432 }
2433 }
2434
2435 private void loadTouchSoundAssets() {
2436 XmlResourceParser parser = null;
2437
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002438 // only load assets once.
2439 if (!SOUND_EFFECT_FILES.isEmpty()) {
2440 return;
2441 }
2442
Eric Laurente78fced2013-03-15 16:03:47 -07002443 loadTouchSoundAssetDefaults();
2444
2445 try {
2446 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
2447
2448 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
2449 String version = parser.getAttributeValue(null, ATTR_VERSION);
2450 boolean inTouchSoundsGroup = false;
2451
2452 if (ASSET_FILE_VERSION.equals(version)) {
2453 while (true) {
2454 XmlUtils.nextElement(parser);
2455 String element = parser.getName();
2456 if (element == null) {
2457 break;
2458 }
2459 if (element.equals(TAG_GROUP)) {
2460 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
2461 if (GROUP_TOUCH_SOUNDS.equals(name)) {
2462 inTouchSoundsGroup = true;
2463 break;
2464 }
2465 }
2466 }
2467 while (inTouchSoundsGroup) {
2468 XmlUtils.nextElement(parser);
2469 String element = parser.getName();
2470 if (element == null) {
2471 break;
2472 }
2473 if (element.equals(TAG_ASSET)) {
2474 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
2475 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
2476 int fx;
2477
2478 try {
2479 Field field = AudioManager.class.getField(id);
2480 fx = field.getInt(null);
2481 } catch (Exception e) {
2482 Log.w(TAG, "Invalid touch sound ID: "+id);
2483 continue;
2484 }
2485
2486 int i = SOUND_EFFECT_FILES.indexOf(file);
2487 if (i == -1) {
2488 i = SOUND_EFFECT_FILES.size();
2489 SOUND_EFFECT_FILES.add(file);
2490 }
2491 SOUND_EFFECT_FILES_MAP[fx][0] = i;
2492 } else {
2493 break;
2494 }
2495 }
2496 }
2497 } catch (Resources.NotFoundException e) {
2498 Log.w(TAG, "audio assets file not found", e);
2499 } catch (XmlPullParserException e) {
2500 Log.w(TAG, "XML parser exception reading touch sound assets", e);
2501 } catch (IOException e) {
2502 Log.w(TAG, "I/O exception reading touch sound assets", e);
2503 } finally {
2504 if (parser != null) {
2505 parser.close();
2506 }
2507 }
2508 }
2509
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002510 /** @see AudioManager#playSoundEffect(int) */
2511 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002512 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002513 }
2514
2515 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002516 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07002517 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
2518 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
2519 return;
2520 }
2521
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002522 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002523 effectType, (int) (volume * 1000), null, 0);
2524 }
2525
2526 /**
2527 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08002528 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002529 */
2530 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002531 int attempts = 3;
2532 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08002533
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002534 synchronized (reply) {
2535 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
2536 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08002537 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07002538 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002539 } catch (InterruptedException e) {
2540 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08002541 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002542 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002543 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002544 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002545 }
2546
2547 /**
2548 * Unloads samples from the sound pool.
2549 * This method can be called to free some memory when
2550 * sound effects are disabled.
2551 */
2552 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002553 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002554 }
2555
Eric Laurenta60e2122010-12-28 16:49:07 -08002556 class SoundPoolListenerThread extends Thread {
2557 public SoundPoolListenerThread() {
2558 super("SoundPoolListenerThread");
2559 }
2560
2561 @Override
2562 public void run() {
2563
2564 Looper.prepare();
2565 mSoundPoolLooper = Looper.myLooper();
2566
2567 synchronized (mSoundEffectsLock) {
2568 if (mSoundPool != null) {
2569 mSoundPoolCallBack = new SoundPoolCallback();
2570 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2571 }
2572 mSoundEffectsLock.notify();
2573 }
2574 Looper.loop();
2575 }
2576 }
2577
2578 private final class SoundPoolCallback implements
2579 android.media.SoundPool.OnLoadCompleteListener {
2580
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002581 int mStatus = 1; // 1 means neither error nor last sample loaded yet
2582 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08002583
2584 public int status() {
2585 return mStatus;
2586 }
2587
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002588 public void setSamples(int[] samples) {
2589 for (int i = 0; i < samples.length; i++) {
2590 // do not wait ack for samples rejected upfront by SoundPool
2591 if (samples[i] > 0) {
2592 mSamples.add(samples[i]);
2593 }
2594 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002595 }
2596
2597 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2598 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002599 int i = mSamples.indexOf(sampleId);
2600 if (i >= 0) {
2601 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08002602 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002603 if ((status != 0) || mSamples. isEmpty()) {
2604 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08002605 mSoundEffectsLock.notify();
2606 }
2607 }
2608 }
2609 }
2610
Eric Laurent4050c932009-07-08 02:52:14 -07002611 /** @see AudioManager#reloadAudioSettings() */
2612 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002613 readAudioSettings(false /*userSwitch*/);
2614 }
2615
2616 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07002617 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2618 readPersistedSettings();
Eric Laurentc0232482016-03-15 18:19:23 -07002619 readUserRestrictions();
Eric Laurent4050c932009-07-08 02:52:14 -07002620
2621 // restore volume settings
2622 int numStreamTypes = AudioSystem.getNumStreamTypes();
2623 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2624 VolumeStreamState streamState = mStreamStates[streamType];
2625
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002626 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2627 continue;
2628 }
2629
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002630 streamState.readSettings();
2631 synchronized (VolumeStreamState.class) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002632 // unmute stream that was muted but is not affect by mute anymore
RoboErik4197cb62015-01-21 15:45:32 -08002633 if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07002634 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
RoboErik4197cb62015-01-21 15:45:32 -08002635 streamState.mIsMuted = false;
Eric Laurent4050c932009-07-08 02:52:14 -07002636 }
Eric Laurent4050c932009-07-08 02:52:14 -07002637 }
2638 }
2639
Eric Laurent33902db2012-10-07 16:15:07 -07002640 // apply new ringer mode before checking volume for alias streams so that streams
2641 // muted by ringer mode have the correct volume
John Spurlock661f2cf2014-11-17 10:29:10 -05002642 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent33902db2012-10-07 16:15:07 -07002643
Eric Laurent212532b2014-07-21 15:43:18 -07002644 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07002645 checkAllAliasStreamVolumes();
John Spurlockb6e19e32015-03-10 21:33:44 -04002646 checkMuteAffectedStreams();
Eric Laurent24482012012-05-10 09:41:17 -07002647
Eric Laurentd640bd32012-09-28 18:01:48 -07002648 synchronized (mSafeMediaVolumeState) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002649 mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2650 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2651 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
Eric Laurentd640bd32012-09-28 18:01:48 -07002652 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
John Spurlock90874332015-03-10 16:00:54 -04002653 enforceSafeMediaVolume(TAG);
Eric Laurentf1a457d2012-09-20 16:27:23 -07002654 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07002655 }
Eric Laurent4050c932009-07-08 02:52:14 -07002656 }
2657
Dianne Hackborn961cae92013-03-20 14:59:43 -07002658 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002659 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002660 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2661 return;
2662 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002663
2664 if (on) {
2665 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2666 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2667 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
2668 }
2669 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2670 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2671 mForcedUseForComm = AudioSystem.FORCE_NONE;
2672 }
Eric Laurentfa640152011-03-12 15:59:51 -08002673
Eric Laurentafbb0472011-12-15 09:04:23 -08002674 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002675 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002676 }
2677
2678 /** @see AudioManager#isSpeakerphoneOn() */
2679 public boolean isSpeakerphoneOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002680 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002681 }
2682
Dianne Hackborn961cae92013-03-20 14:59:43 -07002683 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurent48221252015-09-24 18:41:48 -07002684 public void setBluetoothScoOn(boolean on) {
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002685 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2686 return;
2687 }
Eric Laurent48221252015-09-24 18:41:48 -07002688 setBluetoothScoOnInt(on);
2689 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002690
Eric Laurent48221252015-09-24 18:41:48 -07002691 public void setBluetoothScoOnInt(boolean on) {
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002692 if (on) {
2693 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2694 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2695 mForcedUseForComm = AudioSystem.FORCE_NONE;
2696 }
Eric Laurentfa640152011-03-12 15:59:51 -08002697
Eric Laurentafbb0472011-12-15 09:04:23 -08002698 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002699 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08002700 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002701 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002702 }
2703
2704 /** @see AudioManager#isBluetoothScoOn() */
2705 public boolean isBluetoothScoOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002706 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002707 }
2708
Sungsoocf09fe62016-09-28 16:21:48 +09002709 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07002710 public void setBluetoothA2dpOn(boolean on) {
Sungsoocf09fe62016-09-28 16:21:48 +09002711 synchronized (mBluetoothA2dpEnabledLock) {
2712 mBluetoothA2dpEnabled = on;
2713 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2714 AudioSystem.FOR_MEDIA,
2715 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2716 null, 0);
2717 }
Eric Laurent78472112012-05-21 08:57:21 -07002718 }
2719
Sungsoocf09fe62016-09-28 16:21:48 +09002720 /** @see AudioManager#isBluetoothA2dpOn() */
Eric Laurent78472112012-05-21 08:57:21 -07002721 public boolean isBluetoothA2dpOn() {
Sungsoocf09fe62016-09-28 16:21:48 +09002722 synchronized (mBluetoothA2dpEnabledLock) {
2723 return mBluetoothA2dpEnabled;
2724 }
Eric Laurent78472112012-05-21 08:57:21 -07002725 }
2726
Eric Laurent3def1ee2010-03-17 23:26:26 -07002727 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07002728 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
2729 int scoAudioMode =
2730 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
Liejun Taof4e51d82014-07-16 11:18:29 -07002731 SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
Eric Laurent83900752014-05-15 15:14:22 -07002732 startBluetoothScoInt(cb, scoAudioMode);
2733 }
2734
2735 /** @see AudioManager#startBluetoothScoVirtualCall() */
2736 public void startBluetoothScoVirtualCall(IBinder cb) {
2737 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
2738 }
2739
2740 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07002741 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002742 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002743 return;
2744 }
Eric Laurent854938a2011-02-22 12:05:20 -08002745 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002746 // The calling identity must be cleared before calling ScoClient.incCount().
2747 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2748 // and this must be done on behalf of system server to make sure permissions are granted.
2749 // The caller identity must be cleared after getScoClient() because it is needed if a new
2750 // client is created.
2751 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07002752 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08002753 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002754 }
2755
2756 /** @see AudioManager#stopBluetoothSco() */
2757 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07002758 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002759 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002760 return;
2761 }
Eric Laurent854938a2011-02-22 12:05:20 -08002762 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002763 // The calling identity must be cleared before calling ScoClient.decCount().
2764 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2765 // and this must be done on behalf of system server to make sure permissions are granted.
2766 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08002767 if (client != null) {
2768 client.decCount();
2769 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08002770 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002771 }
2772
Eric Laurent78472112012-05-21 08:57:21 -07002773
Eric Laurent3def1ee2010-03-17 23:26:26 -07002774 private class ScoClient implements IBinder.DeathRecipient {
2775 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002776 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002777 private int mStartcount; // number of SCO connections started by this client
2778
2779 ScoClient(IBinder cb) {
2780 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002781 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002782 mStartcount = 0;
2783 }
2784
2785 public void binderDied() {
2786 synchronized(mScoClients) {
2787 Log.w(TAG, "SCO client died");
2788 int index = mScoClients.indexOf(this);
2789 if (index < 0) {
2790 Log.w(TAG, "unregistered SCO client died");
2791 } else {
2792 clearCount(true);
2793 mScoClients.remove(this);
2794 }
2795 }
2796 }
2797
Eric Laurent83900752014-05-15 15:14:22 -07002798 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002799 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07002800 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002801 if (mStartcount == 0) {
2802 try {
2803 mCb.linkToDeath(this, 0);
2804 } catch (RemoteException e) {
2805 // client has already died!
2806 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
2807 }
2808 }
2809 mStartcount++;
2810 }
2811 }
2812
2813 public void decCount() {
2814 synchronized(mScoClients) {
2815 if (mStartcount == 0) {
2816 Log.w(TAG, "ScoClient.decCount() already 0");
2817 } else {
2818 mStartcount--;
2819 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002820 try {
2821 mCb.unlinkToDeath(this, 0);
2822 } catch (NoSuchElementException e) {
2823 Log.w(TAG, "decCount() going to 0 but not registered to binder");
2824 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002825 }
Eric Laurentc18c9132013-04-12 17:24:56 -07002826 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002827 }
2828 }
2829 }
2830
2831 public void clearCount(boolean stopSco) {
2832 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002833 if (mStartcount != 0) {
2834 try {
2835 mCb.unlinkToDeath(this, 0);
2836 } catch (NoSuchElementException e) {
2837 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2838 }
2839 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002840 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002841 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002842 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002843 }
2844 }
2845 }
2846
2847 public int getCount() {
2848 return mStartcount;
2849 }
2850
2851 public IBinder getBinder() {
2852 return mCb;
2853 }
2854
Eric Laurentd7454be2011-09-14 08:45:58 -07002855 public int getPid() {
2856 return mCreatorPid;
2857 }
2858
Eric Laurent3def1ee2010-03-17 23:26:26 -07002859 public int totalCount() {
2860 synchronized(mScoClients) {
2861 int count = 0;
2862 int size = mScoClients.size();
2863 for (int i = 0; i < size; i++) {
2864 count += mScoClients.get(i).getCount();
2865 }
2866 return count;
2867 }
2868 }
2869
Eric Laurent83900752014-05-15 15:14:22 -07002870 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08002871 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07002872 if (totalCount() == 0) {
2873 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2874 // Make sure that the state transitions to CONNECTING even if we cannot initiate
2875 // the connection.
2876 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2877 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002878 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07002879 synchronized(mSetModeDeathHandlers) {
2880 if ((mSetModeDeathHandlers.isEmpty() ||
2881 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2882 (mScoAudioState == SCO_STATE_INACTIVE ||
2883 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2884 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07002885 mScoAudioMode = scoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -07002886 if (scoAudioMode == SCO_MODE_UNDEFINED) {
Andre Eisenbach570cc532014-10-28 17:03:18 -07002887 if (mBluetoothHeadsetDevice != null) {
2888 mScoAudioMode = new Integer(Settings.Global.getInt(
2889 mContentResolver,
2890 "bluetooth_sco_channel_"+
2891 mBluetoothHeadsetDevice.getAddress(),
2892 SCO_MODE_VIRTUAL_CALL));
2893 if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2894 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2895 }
2896 } else {
2897 mScoAudioMode = SCO_MODE_RAW;
Liejun Taof4e51d82014-07-16 11:18:29 -07002898 }
2899 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002900 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002901 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002902 if (mScoAudioMode == SCO_MODE_RAW) {
2903 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002904 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002905 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2906 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002907 } else if (mScoAudioMode == SCO_MODE_VR) {
2908 status = mBluetoothHeadset.startVoiceRecognition(
2909 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002910 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002911
Eric Laurentc18c9132013-04-12 17:24:56 -07002912 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07002913 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2914 } else {
2915 broadcastScoConnectionState(
2916 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2917 }
2918 } else if (getBluetoothHeadset()) {
2919 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07002920 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002921 } else {
2922 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2923 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002924 }
2925 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07002926 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002927 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002928 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002929 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002930 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2931 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2932 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07002933 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002934 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002935 if (mScoAudioMode == SCO_MODE_RAW) {
2936 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002937 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002938 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2939 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002940 } else if (mScoAudioMode == SCO_MODE_VR) {
2941 status = mBluetoothHeadset.stopVoiceRecognition(
2942 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002943 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002944
Eric Laurentc18c9132013-04-12 17:24:56 -07002945 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002946 mScoAudioState = SCO_STATE_INACTIVE;
2947 broadcastScoConnectionState(
2948 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2949 }
2950 } else if (getBluetoothHeadset()) {
2951 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2952 }
2953 } else {
2954 mScoAudioState = SCO_STATE_INACTIVE;
2955 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2956 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002957 }
2958 }
2959 }
2960 }
2961
Eric Laurent62ef7672010-11-24 10:58:32 -08002962 private void checkScoAudioState() {
2963 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002964 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08002965 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2966 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2967 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2968 }
2969 }
2970
Eric Laurent854938a2011-02-22 12:05:20 -08002971 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002972 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002973 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002974 int size = mScoClients.size();
2975 for (int i = 0; i < size; i++) {
2976 client = mScoClients.get(i);
2977 if (client.getBinder() == cb)
2978 return client;
2979 }
Eric Laurent854938a2011-02-22 12:05:20 -08002980 if (create) {
2981 client = new ScoClient(cb);
2982 mScoClients.add(client);
2983 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002984 return client;
2985 }
2986 }
2987
Eric Laurentd7454be2011-09-14 08:45:58 -07002988 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002989 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002990 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002991 int size = mScoClients.size();
2992 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08002993 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07002994 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08002995 cl.clearCount(stopSco);
2996 } else {
2997 savedClient = cl;
2998 }
2999 }
3000 mScoClients.clear();
3001 if (savedClient != null) {
3002 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07003003 }
3004 }
3005 }
3006
Eric Laurentdc03c612011-04-01 10:59:41 -07003007 private boolean getBluetoothHeadset() {
3008 boolean result = false;
3009 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
3010 if (adapter != null) {
3011 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
3012 BluetoothProfile.HEADSET);
3013 }
3014 // If we could not get a bluetooth headset proxy, send a failure message
3015 // without delay to reset the SCO audio state and clear SCO clients.
3016 // If we could get a proxy, send a delayed failure message that will reset our state
3017 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08003018 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07003019 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
3020 return result;
3021 }
3022
Eric Laurentd7454be2011-09-14 08:45:58 -07003023 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07003024 synchronized(mScoClients) {
3025 checkScoAudioState();
3026 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
3027 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
3028 if (mBluetoothHeadsetDevice != null) {
3029 if (mBluetoothHeadset != null) {
3030 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07003031 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08003032 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07003033 SENDMSG_REPLACE, 0, 0, null, 0);
3034 }
3035 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
3036 getBluetoothHeadset()) {
3037 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
3038 }
3039 }
3040 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07003041 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07003042 }
3043 }
3044 }
3045
3046 private void resetBluetoothSco() {
3047 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07003048 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07003049 mScoAudioState = SCO_STATE_INACTIVE;
3050 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
3051 }
Eric Laurent48221252015-09-24 18:41:48 -07003052 AudioSystem.setParameters("A2dpSuspended=false");
3053 setBluetoothScoOnInt(false);
Eric Laurentdc03c612011-04-01 10:59:41 -07003054 }
3055
3056 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08003057 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
3058 SENDMSG_QUEUE, state, 0, null, 0);
3059 }
3060
3061 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07003062 if (state != mScoConnectionState) {
3063 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
3064 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
3065 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
3066 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003067 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07003068 mScoConnectionState = state;
3069 }
3070 }
3071
Eric Laurent98859b22015-06-12 14:35:59 -07003072 void setBtScoDeviceConnectionState(BluetoothDevice btDevice, int state) {
3073 if (btDevice == null) {
3074 return;
3075 }
3076
3077 String address = btDevice.getAddress();
3078 BluetoothClass btClass = btDevice.getBluetoothClass();
3079 int outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
3080 int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
3081 if (btClass != null) {
3082 switch (btClass.getDeviceClass()) {
3083 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
3084 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
3085 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
3086 break;
3087 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
3088 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
3089 break;
3090 }
3091 }
3092
3093 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
3094 address = "";
3095 }
3096
3097 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
3098
3099 String btDeviceName = btDevice.getName();
3100 boolean success =
3101 handleDeviceConnection(connected, outDevice, address, btDeviceName) &&
3102 handleDeviceConnection(connected, inDevice, address, btDeviceName);
3103 if (success) {
3104 synchronized (mScoClients) {
3105 if (connected) {
3106 mBluetoothHeadsetDevice = btDevice;
3107 } else {
3108 mBluetoothHeadsetDevice = null;
3109 resetBluetoothSco();
3110 }
3111 }
3112 }
3113 }
3114
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07003115 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
3116 new BluetoothProfile.ServiceListener() {
3117 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003118 BluetoothDevice btDevice;
3119 List<BluetoothDevice> deviceList;
3120 switch(profile) {
3121 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09003122 synchronized (mConnectedDevices) {
3123 synchronized (mA2dpAvrcpLock) {
3124 mA2dp = (BluetoothA2dp) proxy;
3125 deviceList = mA2dp.getConnectedDevices();
3126 if (deviceList.size() > 0) {
3127 btDevice = deviceList.get(0);
John Du5a0cf7a2013-07-19 11:30:34 -07003128 int state = mA2dp.getConnectionState(btDevice);
3129 int delay = checkSendBecomingNoisyIntent(
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003130 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3131 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
John Du5a0cf7a2013-07-19 11:30:34 -07003132 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003133 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07003134 state,
3135 0,
3136 btDevice,
3137 delay);
3138 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003139 }
Eric Laurent62ef7672010-11-24 10:58:32 -08003140 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003141 break;
3142
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003143 case BluetoothProfile.A2DP_SINK:
3144 deviceList = proxy.getConnectedDevices();
3145 if (deviceList.size() > 0) {
3146 btDevice = deviceList.get(0);
3147 synchronized (mConnectedDevices) {
3148 int state = proxy.getConnectionState(btDevice);
3149 queueMsgUnderWakeLock(mAudioHandler,
3150 MSG_SET_A2DP_SRC_CONNECTION_STATE,
3151 state,
3152 0,
3153 btDevice,
3154 0 /* delay */);
3155 }
3156 }
3157 break;
3158
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003159 case BluetoothProfile.HEADSET:
3160 synchronized (mScoClients) {
3161 // Discard timeout message
3162 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
3163 mBluetoothHeadset = (BluetoothHeadset) proxy;
3164 deviceList = mBluetoothHeadset.getConnectedDevices();
3165 if (deviceList.size() > 0) {
3166 mBluetoothHeadsetDevice = deviceList.get(0);
3167 } else {
3168 mBluetoothHeadsetDevice = null;
3169 }
3170 // Refresh SCO audio state
3171 checkScoAudioState();
3172 // Continue pending action if any
3173 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
3174 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
3175 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
3176 boolean status = false;
3177 if (mBluetoothHeadsetDevice != null) {
3178 switch (mScoAudioState) {
3179 case SCO_STATE_ACTIVATE_REQ:
3180 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07003181 if (mScoAudioMode == SCO_MODE_RAW) {
3182 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003183 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003184 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
3185 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003186 } else if (mScoAudioMode == SCO_MODE_VR) {
3187 status = mBluetoothHeadset.startVoiceRecognition(
3188 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003189 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003190 break;
3191 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07003192 if (mScoAudioMode == SCO_MODE_RAW) {
3193 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003194 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003195 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
3196 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003197 } else if (mScoAudioMode == SCO_MODE_VR) {
3198 status = mBluetoothHeadset.stopVoiceRecognition(
3199 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003200 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003201 break;
3202 case SCO_STATE_DEACTIVATE_EXT_REQ:
3203 status = mBluetoothHeadset.stopVoiceRecognition(
3204 mBluetoothHeadsetDevice);
3205 }
3206 }
3207 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08003208 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003209 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07003210 }
3211 }
Eric Laurentdc03c612011-04-01 10:59:41 -07003212 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003213 break;
3214
3215 default:
3216 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003217 }
3218 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07003219 public void onServiceDisconnected(int profile) {
Eric Laurentb70b78a2016-01-13 19:16:04 -08003220
Paul McLean394a8e12015-03-03 10:29:19 -07003221 switch (profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003222 case BluetoothProfile.A2DP:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003223 disconnectA2dp();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003224 break;
3225
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003226 case BluetoothProfile.A2DP_SINK:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003227 disconnectA2dpSink();
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003228 break;
3229
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003230 case BluetoothProfile.HEADSET:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003231 disconnectHeadset();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003232 break;
3233
3234 default:
3235 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003236 }
3237 }
3238 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003239
Eric Laurentb70b78a2016-01-13 19:16:04 -08003240 void disconnectAllBluetoothProfiles() {
3241 disconnectA2dp();
3242 disconnectA2dpSink();
3243 disconnectHeadset();
3244 }
3245
3246 void disconnectA2dp() {
3247 synchronized (mConnectedDevices) {
3248 synchronized (mA2dpAvrcpLock) {
3249 ArraySet<String> toRemove = null;
3250 // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
3251 for (int i = 0; i < mConnectedDevices.size(); i++) {
3252 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
3253 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
3254 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
3255 toRemove.add(deviceSpec.mDeviceAddress);
3256 }
3257 }
3258 if (toRemove != null) {
3259 int delay = checkSendBecomingNoisyIntent(
3260 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3261 0);
3262 for (int i = 0; i < toRemove.size(); i++) {
3263 makeA2dpDeviceUnavailableLater(toRemove.valueAt(i), delay);
3264 }
3265 }
3266 }
3267 }
3268 }
3269
3270 void disconnectA2dpSink() {
3271 synchronized (mConnectedDevices) {
3272 ArraySet<String> toRemove = null;
3273 // Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
3274 for(int i = 0; i < mConnectedDevices.size(); i++) {
3275 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
3276 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) {
3277 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
3278 toRemove.add(deviceSpec.mDeviceAddress);
3279 }
3280 }
3281 if (toRemove != null) {
3282 for (int i = 0; i < toRemove.size(); i++) {
3283 makeA2dpSrcUnavailable(toRemove.valueAt(i));
3284 }
3285 }
3286 }
3287 }
3288
3289 void disconnectHeadset() {
3290 synchronized (mScoClients) {
3291 if (mBluetoothHeadsetDevice != null) {
3292 setBtScoDeviceConnectionState(mBluetoothHeadsetDevice,
3293 BluetoothProfile.STATE_DISCONNECTED);
3294 }
3295 mBluetoothHeadset = null;
3296 }
3297 }
3298
John Spurlock90874332015-03-10 16:00:54 -04003299 private void onCheckMusicActive(String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07003300 synchronized (mSafeMediaVolumeState) {
3301 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07003302 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
3303
3304 if ((device & mSafeMediaVolumeDevices) != 0) {
3305 sendMsg(mAudioHandler,
3306 MSG_CHECK_MUSIC_ACTIVE,
3307 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07003308 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07003309 0,
John Spurlock90874332015-03-10 16:00:54 -04003310 caller,
Eric Laurentc34dcc12012-09-10 13:51:52 -07003311 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07003312 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07003313 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
3314 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07003315 // Approximate cumulative active music time
3316 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
3317 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
John Spurlock90874332015-03-10 16:00:54 -04003318 setSafeMediaVolumeEnabled(true, caller);
Eric Laurentc34dcc12012-09-10 13:51:52 -07003319 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07003320 }
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003321 saveMusicActiveMs();
Eric Laurentc34dcc12012-09-10 13:51:52 -07003322 }
3323 }
3324 }
3325 }
3326 }
3327
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003328 private void saveMusicActiveMs() {
3329 mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
3330 }
3331
John Spurlock90874332015-03-10 16:00:54 -04003332 private void onConfigureSafeVolume(boolean force, String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07003333 synchronized (mSafeMediaVolumeState) {
3334 int mcc = mContext.getResources().getConfiguration().mcc;
3335 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
3336 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
3337 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
John Spurlock35134602014-07-24 18:10:48 -04003338 boolean safeMediaVolumeEnabled =
3339 SystemProperties.getBoolean("audio.safemedia.force", false)
3340 || mContext.getResources().getBoolean(
3341 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08003342
Ricardo Garcia3a30a762015-06-23 15:54:45 -07003343 boolean safeMediaVolumeBypass =
3344 SystemProperties.getBoolean("audio.safemedia.bypass", false);
3345
Eric Laurent05274f32012-11-29 12:48:18 -08003346 // The persisted state is either "disabled" or "active": this is the state applied
3347 // next time we boot and cannot be "inactive"
3348 int persistedState;
Ricardo Garcia3a30a762015-06-23 15:54:45 -07003349 if (safeMediaVolumeEnabled && !safeMediaVolumeBypass) {
Eric Laurent05274f32012-11-29 12:48:18 -08003350 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
3351 // The state can already be "inactive" here if the user has forced it before
3352 // the 30 seconds timeout for forced configuration. In this case we don't reset
3353 // it to "active".
3354 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003355 if (mMusicActiveMs == 0) {
3356 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
John Spurlock90874332015-03-10 16:00:54 -04003357 enforceSafeMediaVolume(caller);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003358 } else {
3359 // We have existing playback time recorded, already confirmed.
3360 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
3361 }
Eric Laurent05274f32012-11-29 12:48:18 -08003362 }
Eric Laurentd640bd32012-09-28 18:01:48 -07003363 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08003364 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07003365 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
3366 }
3367 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08003368 sendMsg(mAudioHandler,
3369 MSG_PERSIST_SAFE_VOLUME_STATE,
3370 SENDMSG_QUEUE,
3371 persistedState,
3372 0,
3373 null,
3374 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07003375 }
3376 }
3377 }
3378
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003379 ///////////////////////////////////////////////////////////////////////////
3380 // Internal methods
3381 ///////////////////////////////////////////////////////////////////////////
3382
3383 /**
3384 * Checks if the adjustment should change ringer mode instead of just
3385 * adjusting volume. If so, this will set the proper ringer mode and volume
3386 * indices on the stream states.
3387 */
Julia Reynoldsed783792016-04-08 15:27:35 -04003388 private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted,
3389 String caller, int flags) {
John Spurlocka48d7792015-03-03 17:35:57 -05003390 final boolean isTv = mPlatformType == AudioSystem.PLATFORM_TELEVISION;
John Spurlocka11b4af2014-06-01 11:52:23 -04003391 int result = FLAG_ADJUST_VOLUME;
John Spurlock661f2cf2014-11-17 10:29:10 -05003392 int ringerMode = getRingerModeInternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003393
Eric Laurentbffc3d12012-05-07 17:43:49 -07003394 switch (ringerMode) {
3395 case RINGER_MODE_NORMAL:
3396 if (direction == AudioManager.ADJUST_LOWER) {
3397 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07003398 // "step" is the delta in internal index units corresponding to a
3399 // change of 1 in UI index units.
3400 // Because of rounding when rescaling from one stream index range to its alias
3401 // index range, we cannot simply test oldIndex == step:
3402 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
3403 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003404 ringerMode = RINGER_MODE_VIBRATE;
John Spurlock07e72432015-03-13 11:46:52 -04003405 mLoweredFromNormalToVibrateTime = SystemClock.uptimeMillis();
Eric Laurentbffc3d12012-05-07 17:43:49 -07003406 }
3407 } else {
John Spurlockd9c75db2015-04-28 11:19:13 -04003408 if (oldIndex == step && mVolumePolicy.volumeDownToEnterSilent) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003409 ringerMode = RINGER_MODE_SILENT;
3410 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07003411 }
John Spurlocka48d7792015-03-03 17:35:57 -05003412 } else if (isTv && (direction == AudioManager.ADJUST_TOGGLE_MUTE
3413 || direction == AudioManager.ADJUST_MUTE)) {
RoboErik5452e252015-02-06 15:33:53 -08003414 if (mHasVibrator) {
3415 ringerMode = RINGER_MODE_VIBRATE;
3416 } else {
3417 ringerMode = RINGER_MODE_SILENT;
3418 }
3419 // Setting the ringer mode will toggle mute
3420 result &= ~FLAG_ADJUST_VOLUME;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003421 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003422 break;
3423 case RINGER_MODE_VIBRATE:
3424 if (!mHasVibrator) {
3425 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
3426 "but no vibrator is present");
3427 break;
3428 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003429 if ((direction == AudioManager.ADJUST_LOWER)) {
RoboErik5452e252015-02-06 15:33:53 -08003430 // This is the case we were muted with the volume turned up
John Spurlocka48d7792015-03-03 17:35:57 -05003431 if (isTv && oldIndex >= 2 * step && isMuted) {
RoboErik5452e252015-02-06 15:33:53 -08003432 ringerMode = RINGER_MODE_NORMAL;
3433 } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
John Spurlocka48d7792015-03-03 17:35:57 -05003434 if (mVolumePolicy.volumeDownToEnterSilent) {
John Spurlock07e72432015-03-13 11:46:52 -04003435 final long diff = SystemClock.uptimeMillis()
3436 - mLoweredFromNormalToVibrateTime;
John Spurlockd9c75db2015-04-28 11:19:13 -04003437 if (diff > mVolumePolicy.vibrateToSilentDebounce
3438 && mRingerModeDelegate.canVolumeDownEnterSilent()) {
John Spurlock07e72432015-03-13 11:46:52 -04003439 ringerMode = RINGER_MODE_SILENT;
3440 }
John Spurlock795a5142014-12-08 14:09:35 -05003441 } else {
3442 result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
3443 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003444 }
RoboErik5452e252015-02-06 15:33:53 -08003445 } else if (direction == AudioManager.ADJUST_RAISE
3446 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3447 || direction == AudioManager.ADJUST_UNMUTE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003448 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07003449 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003450 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003451 break;
3452 case RINGER_MODE_SILENT:
John Spurlocka48d7792015-03-03 17:35:57 -05003453 if (isTv && direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
RoboErik5452e252015-02-06 15:33:53 -08003454 // This is the case we were muted with the volume turned up
3455 ringerMode = RINGER_MODE_NORMAL;
3456 } else if (direction == AudioManager.ADJUST_RAISE
3457 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3458 || direction == AudioManager.ADJUST_UNMUTE) {
John Spurlocka48d7792015-03-03 17:35:57 -05003459 if (!mVolumePolicy.volumeUpToExitSilent) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003460 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003461 } else {
RoboErik5452e252015-02-06 15:33:53 -08003462 if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003463 ringerMode = RINGER_MODE_VIBRATE;
3464 } else {
RoboErik5452e252015-02-06 15:33:53 -08003465 // If we don't have a vibrator or they were toggling mute
3466 // go straight back to normal.
John Spurlocka11b4af2014-06-01 11:52:23 -04003467 ringerMode = RINGER_MODE_NORMAL;
3468 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003469 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05003470 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003471 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003472 break;
3473 default:
3474 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
3475 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003476 }
3477
Julia Reynoldsed783792016-04-08 15:27:35 -04003478 if (isAndroidNPlus(caller) && wouldToggleZenMode(ringerMode)
3479 && !mNm.isNotificationPolicyAccessGrantedForPackage(caller)
3480 && (flags & AudioManager.FLAG_FROM_KEY) == 0) {
3481 throw new SecurityException("Not allowed to change Do Not Disturb state");
3482 }
3483
John Spurlock661f2cf2014-11-17 10:29:10 -05003484 setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003485
Eric Laurent25101b02011-02-02 09:33:30 -08003486 mPrevVolDirection = direction;
3487
John Spurlocka11b4af2014-06-01 11:52:23 -04003488 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003489 }
3490
John Spurlock3346a802014-05-20 16:25:37 -04003491 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003492 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07003493 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003494 }
3495
Eric Laurent5b4e6542010-03-19 20:02:21 -07003496 private boolean isStreamMutedByRingerMode(int streamType) {
3497 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
3498 }
3499
John Spurlock50ced3f2015-05-11 16:00:09 -04003500 private boolean updateRingerModeAffectedStreams() {
3501 int ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003502 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3503 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
3504 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
3505 UserHandle.USER_CURRENT);
3506
John Spurlock50ced3f2015-05-11 16:00:09 -04003507 if (mPlatformType == AudioSystem.PLATFORM_TELEVISION) {
3508 ringerModeAffectedStreams = 0;
3509 } else if (mRingerModeDelegate != null) {
3510 ringerModeAffectedStreams = mRingerModeDelegate
3511 .getRingerModeAffectedStreams(ringerModeAffectedStreams);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003512 }
3513 synchronized (mCameraSoundForced) {
3514 if (mCameraSoundForced) {
3515 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3516 } else {
3517 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3518 }
3519 }
3520 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
3521 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
3522 } else {
3523 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
3524 }
3525
3526 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3527 Settings.System.putIntForUser(mContentResolver,
3528 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3529 ringerModeAffectedStreams,
3530 UserHandle.USER_CURRENT);
3531 mRingerModeAffectedStreams = ringerModeAffectedStreams;
3532 return true;
3533 }
3534 return false;
3535 }
3536
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05003537 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003538 public boolean isStreamAffectedByMute(int streamType) {
3539 return (mMuteAffectedStreams & (1 << streamType)) != 0;
3540 }
3541
3542 private void ensureValidDirection(int direction) {
RoboErik4197cb62015-01-21 15:45:32 -08003543 switch (direction) {
3544 case AudioManager.ADJUST_LOWER:
3545 case AudioManager.ADJUST_RAISE:
3546 case AudioManager.ADJUST_SAME:
3547 case AudioManager.ADJUST_MUTE:
3548 case AudioManager.ADJUST_UNMUTE:
3549 case AudioManager.ADJUST_TOGGLE_MUTE:
3550 break;
3551 default:
3552 throw new IllegalArgumentException("Bad direction " + direction);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003553 }
3554 }
3555
3556 private void ensureValidStreamType(int streamType) {
3557 if (streamType < 0 || streamType >= mStreamStates.length) {
3558 throw new IllegalArgumentException("Bad stream type " + streamType);
3559 }
3560 }
3561
RoboErik4197cb62015-01-21 15:45:32 -08003562 private boolean isMuteAdjust(int adjust) {
3563 return adjust == AudioManager.ADJUST_MUTE || adjust == AudioManager.ADJUST_UNMUTE
3564 || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
3565 }
3566
Eric Laurent6d517662012-04-23 18:42:39 -07003567 private boolean isInCommunication() {
Nancy Chen0eb1e402014-08-21 22:52:29 -07003568 boolean IsInCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003569
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003570 TelecomManager telecomManager =
3571 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
Eric Laurent38edfda2014-12-18 17:38:04 -08003572
3573 final long ident = Binder.clearCallingIdentity();
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003574 IsInCall = telecomManager.isInCall();
Eric Laurent38edfda2014-12-18 17:38:04 -08003575 Binder.restoreCallingIdentity(ident);
Santos Cordon9eb45932014-06-27 12:28:43 -07003576
Nancy Chen0eb1e402014-08-21 22:52:29 -07003577 return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
Eric Laurent6d517662012-04-23 18:42:39 -07003578 }
Eric Laurent25101b02011-02-02 09:33:30 -08003579
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003580 /**
3581 * For code clarity for getActiveStreamType(int)
3582 * @param delay_ms max time since last STREAM_MUSIC activity to consider
3583 * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
3584 * in the last "delay_ms" ms.
3585 */
3586 private boolean isAfMusicActiveRecently(int delay_ms) {
3587 return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
3588 || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
3589 }
3590
Eric Laurent6d517662012-04-23 18:42:39 -07003591 private int getActiveStreamType(int suggestedStreamType) {
Eric Laurent212532b2014-07-21 15:43:18 -07003592 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003593 case AudioSystem.PLATFORM_VOICE:
Eric Laurent6d517662012-04-23 18:42:39 -07003594 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003595 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3596 == AudioSystem.FORCE_BT_SCO) {
3597 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
3598 return AudioSystem.STREAM_BLUETOOTH_SCO;
3599 } else {
3600 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
3601 return AudioSystem.STREAM_VOICE_CALL;
3602 }
Eric Laurent25101b02011-02-02 09:33:30 -08003603 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003604 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003605 if (DEBUG_VOL)
3606 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3607 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003608 } else {
3609 if (DEBUG_VOL)
3610 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
3611 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003612 }
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003613 } else if (isAfMusicActiveRecently(0)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003614 if (DEBUG_VOL)
3615 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3616 return AudioSystem.STREAM_MUSIC;
Eric Laurent25101b02011-02-02 09:33:30 -08003617 }
Eric Laurent212532b2014-07-21 15:43:18 -07003618 break;
John Spurlock61560172015-02-06 19:46:04 -05003619 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -07003620 if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
RoboErik2811dd32014-08-12 09:48:13 -07003621 // TV always defaults to STREAM_MUSIC
Eric Laurent212532b2014-07-21 15:43:18 -07003622 return AudioSystem.STREAM_MUSIC;
Eric Laurent212532b2014-07-21 15:43:18 -07003623 }
3624 break;
3625 default:
Eric Laurent6d517662012-04-23 18:42:39 -07003626 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003627 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3628 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003629 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08003630 return AudioSystem.STREAM_BLUETOOTH_SCO;
3631 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003632 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08003633 return AudioSystem.STREAM_VOICE_CALL;
3634 }
3635 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003636 StreamOverride.sDelayMs) ||
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003637 AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003638 StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003639 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08003640 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003641 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003642 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003643 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
3644 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003645 } else {
John Spurlockeb1d88d2014-07-19 14:49:19 -04003646 if (DEBUG_VOL) Log.v(TAG,
3647 "getActiveStreamType: using STREAM_NOTIFICATION as default");
3648 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003649 }
Joe Onoratoc7fcba42011-01-05 16:53:11 -08003650 }
Eric Laurent212532b2014-07-21 15:43:18 -07003651 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003652 }
Eric Laurent212532b2014-07-21 15:43:18 -07003653 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
3654 + suggestedStreamType);
3655 return suggestedStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003656 }
3657
John Spurlockbcc10872014-11-28 15:29:21 -05003658 private void broadcastRingerMode(String action, int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003659 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05003660 Intent broadcast = new Intent(action);
Glenn Kastenba195eb2011-12-13 09:30:40 -08003661 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003662 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
3663 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003664 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003665 }
3666
3667 private void broadcastVibrateSetting(int vibrateType) {
3668 // Send broadcast
3669 if (ActivityManagerNative.isSystemReady()) {
3670 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
3671 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
3672 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003673 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003674 }
3675 }
3676
3677 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003678 /**
3679 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
3680 * Note that the wake lock needs to be released after the message has been handled.
3681 */
3682 private void queueMsgUnderWakeLock(Handler handler, int msg,
3683 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003684 final long ident = Binder.clearCallingIdentity();
3685 // Always acquire the wake lock as AudioService because it is released by the
3686 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003687 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003688 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003689 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
3690 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003691
Eric Laurentafbb0472011-12-15 09:04:23 -08003692 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003693 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003694
3695 if (existingMsgPolicy == SENDMSG_REPLACE) {
3696 handler.removeMessages(msg);
3697 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
3698 return;
3699 }
Eric Laurentadbe8bf2014-11-03 18:26:32 -08003700 synchronized (mLastDeviceConnectMsgTime) {
3701 long time = SystemClock.uptimeMillis() + delay;
3702 handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
3703 if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
3704 msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
3705 msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
3706 mLastDeviceConnectMsgTime = time;
3707 }
3708 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003709 }
3710
3711 boolean checkAudioSettingsPermission(String method) {
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07003712 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003713 == PackageManager.PERMISSION_GRANTED) {
3714 return true;
3715 }
3716 String msg = "Audio Settings Permission Denial: " + method + " from pid="
3717 + Binder.getCallingPid()
3718 + ", uid=" + Binder.getCallingUid();
3719 Log.w(TAG, msg);
3720 return false;
3721 }
3722
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003723 private int getDeviceForStream(int stream) {
John Spurlock8a52c442015-03-26 14:23:58 -04003724 int device = getDevicesForStream(stream);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003725 if ((device & (device - 1)) != 0) {
3726 // Multiple device selection is either:
3727 // - speaker + one other device: give priority to speaker in this case.
3728 // - one A2DP device + another device: happens with duplicated output. In this case
3729 // retain the device on the A2DP output as the other must not correspond to an active
3730 // selection if not the speaker.
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003731 // - HDMI-CEC system audio mode only output: give priority to available item in order.
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003732 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
3733 device = AudioSystem.DEVICE_OUT_SPEAKER;
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003734 } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
3735 device = AudioSystem.DEVICE_OUT_HDMI_ARC;
3736 } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
3737 device = AudioSystem.DEVICE_OUT_SPDIF;
3738 } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
3739 device = AudioSystem.DEVICE_OUT_AUX_LINE;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003740 } else {
3741 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
3742 }
3743 }
3744 return device;
3745 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003746
John Spurlock8a52c442015-03-26 14:23:58 -04003747 private int getDevicesForStream(int stream) {
3748 return getDevicesForStream(stream, true /*checkOthers*/);
3749 }
3750
3751 private int getDevicesForStream(int stream, boolean checkOthers) {
3752 ensureValidStreamType(stream);
3753 synchronized (VolumeStreamState.class) {
3754 return mStreamStates[stream].observeDevicesForStream_syncVSS(checkOthers);
3755 }
3756 }
3757
3758 private void observeDevicesForStreams(int skipStream) {
3759 synchronized (VolumeStreamState.class) {
3760 for (int stream = 0; stream < mStreamStates.length; stream++) {
3761 if (stream != skipStream) {
3762 mStreamStates[stream].observeDevicesForStream_syncVSS(false /*checkOthers*/);
3763 }
3764 }
3765 }
3766 }
3767
Paul McLean10804eb2015-01-28 11:16:35 -08003768 /*
3769 * A class just for packaging up a set of connection parameters.
3770 */
3771 private class WiredDeviceConnectionState {
John Spurlock90874332015-03-10 16:00:54 -04003772 public final int mType;
3773 public final int mState;
3774 public final String mAddress;
3775 public final String mName;
3776 public final String mCaller;
Paul McLean10804eb2015-01-28 11:16:35 -08003777
John Spurlock90874332015-03-10 16:00:54 -04003778 public WiredDeviceConnectionState(int type, int state, String address, String name,
3779 String caller) {
Paul McLean10804eb2015-01-28 11:16:35 -08003780 mType = type;
3781 mState = state;
3782 mAddress = address;
3783 mName = name;
John Spurlock90874332015-03-10 16:00:54 -04003784 mCaller = caller;
Paul McLean10804eb2015-01-28 11:16:35 -08003785 }
3786 }
3787
John Spurlock90874332015-03-10 16:00:54 -04003788 public void setWiredDeviceConnectionState(int type, int state, String address, String name,
3789 String caller) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003790 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07003791 if (DEBUG_DEVICES) {
3792 Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
3793 + address + ")");
3794 }
Paul McLean10804eb2015-01-28 11:16:35 -08003795 int delay = checkSendBecomingNoisyIntent(type, state);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003796 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003797 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Paul McLean10804eb2015-01-28 11:16:35 -08003798 0,
3799 0,
John Spurlock90874332015-03-10 16:00:54 -04003800 new WiredDeviceConnectionState(type, state, address, name, caller),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003801 delay);
3802 }
3803 }
3804
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003805 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003806 {
3807 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003808 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
3809 throw new IllegalArgumentException("invalid profile " + profile);
3810 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003811 synchronized (mConnectedDevices) {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003812 if (profile == BluetoothProfile.A2DP) {
3813 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3814 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
3815 } else {
3816 delay = 0;
3817 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003818 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003819 (profile == BluetoothProfile.A2DP ?
3820 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003821 state,
3822 0,
3823 device,
3824 delay);
3825 }
3826 return delay;
3827 }
3828
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003829 ///////////////////////////////////////////////////////////////////////////
3830 // Inner classes
3831 ///////////////////////////////////////////////////////////////////////////
3832
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003833 // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
3834 // 1 mScoclient OR mSafeMediaVolumeState
3835 // 2 mSetModeDeathHandlers
3836 // 3 mSettingsLock
3837 // 4 VolumeStreamState.class
3838 // 5 mCameraSoundForced
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003839 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003840 private final int mStreamType;
John Spurlockb6e19e32015-03-10 21:33:44 -04003841 private final int mIndexMin;
3842 private final int mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003843
RoboErik4197cb62015-01-21 15:45:32 -08003844 private boolean mIsMuted;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003845 private String mVolumeIndexSettingName;
John Spurlock8a52c442015-03-26 14:23:58 -04003846 private int mObservedDevices;
John Spurlockb6e19e32015-03-10 21:33:44 -04003847
John Spurlock2bb02ec2015-03-02 13:13:06 -05003848 private final SparseIntArray mIndexMap = new SparseIntArray(8);
John Spurlockf63860c2015-02-19 09:46:27 -05003849 private final Intent mVolumeChanged;
John Spurlock8a52c442015-03-26 14:23:58 -04003850 private final Intent mStreamDevicesChanged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003851
Eric Laurenta553c252009-07-17 12:17:14 -07003852 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003853
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003854 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003855
3856 mStreamType = streamType;
John Spurlockb6e19e32015-03-10 21:33:44 -04003857 mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;
3858 mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;
3859 AudioSystem.initStreamVolume(streamType, mIndexMin / 10, mIndexMax / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003860
Eric Laurent33902db2012-10-07 16:15:07 -07003861 readSettings();
John Spurlockf63860c2015-02-19 09:46:27 -05003862 mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
3863 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
John Spurlock8a52c442015-03-26 14:23:58 -04003864 mStreamDevicesChanged = new Intent(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
3865 mStreamDevicesChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
3866 }
3867
3868 public int observeDevicesForStream_syncVSS(boolean checkOthers) {
3869 final int devices = AudioSystem.getDevicesForStream(mStreamType);
3870 if (devices == mObservedDevices) {
3871 return devices;
3872 }
3873 final int prevDevices = mObservedDevices;
3874 mObservedDevices = devices;
3875 if (checkOthers) {
3876 // one stream's devices have changed, check the others
3877 observeDevicesForStreams(mStreamType);
3878 }
3879 // log base stream changes to the event log
3880 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
3881 EventLogTags.writeStreamDevicesChanged(mStreamType, prevDevices, devices);
3882 }
3883 sendBroadcastToAll(mStreamDevicesChanged
3884 .putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, prevDevices)
3885 .putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, devices));
3886 return devices;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003887 }
3888
Eric Laurent42b041e2013-03-29 11:36:03 -07003889 public String getSettingNameForDevice(int device) {
3890 String name = mVolumeIndexSettingName;
Eric Laurent948d3272014-05-16 15:18:45 -07003891 String suffix = AudioSystem.getOutputDeviceName(device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003892 if (suffix.isEmpty()) {
3893 return name;
3894 }
3895 return name + "_" + suffix;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003896 }
3897
Eric Laurentfdbee862014-05-12 15:26:12 -07003898 public void readSettings() {
3899 synchronized (VolumeStreamState.class) {
John Spurlockee5ad722015-03-03 16:17:21 -05003900 // force maximum volume on all streams if fixed volume property is set
3901 if (mUseFixedVolume) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003902 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07003903 return;
3904 }
3905 // do not read system stream volume from settings: this stream is always aliased
3906 // to another stream type and its volume is never persisted. Values in settings can
3907 // only be stale values
3908 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3909 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
John Spurlock61560172015-02-06 19:46:04 -05003910 int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
Eric Laurentfdbee862014-05-12 15:26:12 -07003911 synchronized (mCameraSoundForced) {
3912 if (mCameraSoundForced) {
3913 index = mIndexMax;
3914 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003915 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003916 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003917 return;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003918 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003919
Eric Laurentfdbee862014-05-12 15:26:12 -07003920 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
3921
3922 for (int i = 0; remainingDevices != 0; i++) {
3923 int device = (1 << i);
3924 if ((device & remainingDevices) == 0) {
3925 continue;
3926 }
3927 remainingDevices &= ~device;
3928
3929 // retrieve current volume for device
3930 String name = getSettingNameForDevice(device);
3931 // if no volume stored for current stream and device, use default volume if default
3932 // device, continue otherwise
3933 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
John Spurlock61560172015-02-06 19:46:04 -05003934 AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
Eric Laurentfdbee862014-05-12 15:26:12 -07003935 int index = Settings.System.getIntForUser(
3936 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3937 if (index == -1) {
3938 continue;
3939 }
3940
John Spurlock2bb02ec2015-03-02 13:13:06 -05003941 mIndexMap.put(device, getValidIndex(10 * index));
Eric Laurentdd45d012012-10-08 09:04:34 -07003942 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003943 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003944 }
3945
Liejun Tao39fb5672016-03-09 15:52:13 -06003946 private int getAbsoluteVolumeIndex(int index) {
3947 /* Special handling for Bluetooth Absolute Volume scenario
3948 * If we send full audio gain, some accessories are too loud even at its lowest
3949 * volume. We are not able to enumerate all such accessories, so here is the
3950 * workaround from phone side.
3951 * Pre-scale volume at lowest volume steps 1 2 and 3.
3952 * For volume step 0, set audio gain to 0 as some accessories won't mute on their end.
3953 */
3954 if (index == 0) {
3955 // 0% for volume 0
3956 index = 0;
3957 } else if (index == 1) {
3958 // 50% for volume 1
3959 index = (int)(mIndexMax * 0.5) /10;
3960 } else if (index == 2) {
3961 // 70% for volume 2
3962 index = (int)(mIndexMax * 0.70) /10;
3963 } else if (index == 3) {
3964 // 85% for volume 3
3965 index = (int)(mIndexMax * 0.85) /10;
3966 } else {
3967 // otherwise, full gain
3968 index = (mIndexMax + 5)/10;
3969 }
3970 return index;
3971 }
3972
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003973 // must be called while synchronized VolumeStreamState.class
3974 public void applyDeviceVolume_syncVSS(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003975 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003976 if (mIsMuted) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003977 index = 0;
Liejun Tao4565a472016-01-20 17:52:20 -06003978 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) {
Liejun Tao39fb5672016-03-09 15:52:13 -06003979 index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
Liejun Tao4565a472016-01-20 17:52:20 -06003980 } else if ((device & mFullVolumeDevices) != 0) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003981 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07003982 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07003983 index = (getIndex(device) + 5)/10;
3984 }
3985 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003986 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003987
Eric Laurentfdbee862014-05-12 15:26:12 -07003988 public void applyAllVolumes() {
3989 synchronized (VolumeStreamState.class) {
Eric Laurentd9ac2be2016-04-07 14:04:23 -07003990 // apply device specific volumes first
Eric Laurentfdbee862014-05-12 15:26:12 -07003991 int index;
John Spurlock2bb02ec2015-03-02 13:13:06 -05003992 for (int i = 0; i < mIndexMap.size(); i++) {
Eric Laurentd9ac2be2016-04-07 14:04:23 -07003993 final int device = mIndexMap.keyAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07003994 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
RoboErik4197cb62015-01-21 15:45:32 -08003995 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003996 index = 0;
Liejun Tao39fb5672016-03-09 15:52:13 -06003997 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3998 mAvrcpAbsVolSupported) {
3999 index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
4000 } else if ((device & mFullVolumeDevices) != 0) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004001 index = (mIndexMax + 5)/10;
4002 } else {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004003 index = (mIndexMap.valueAt(i) + 5)/10;
Eric Laurentfdbee862014-05-12 15:26:12 -07004004 }
4005 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07004006 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004007 }
Eric Laurentd9ac2be2016-04-07 14:04:23 -07004008 // apply default volume last: by convention , default device volume will be used
4009 // by audio policy manager if no explicit volume is present for a given device type
4010 if (mIsMuted) {
4011 index = 0;
4012 } else {
4013 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
4014 }
4015 AudioSystem.setStreamVolumeIndex(
4016 mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004017 }
4018 }
4019
John Spurlock90874332015-03-10 16:00:54 -04004020 public boolean adjustIndex(int deltaIndex, int device, String caller) {
4021 return setIndex(getIndex(device) + deltaIndex, device, caller);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004022 }
4023
John Spurlock90874332015-03-10 16:00:54 -04004024 public boolean setIndex(int index, int device, String caller) {
John Spurlockf63860c2015-02-19 09:46:27 -05004025 boolean changed = false;
4026 int oldIndex;
Eric Laurentfdbee862014-05-12 15:26:12 -07004027 synchronized (VolumeStreamState.class) {
John Spurlockf63860c2015-02-19 09:46:27 -05004028 oldIndex = getIndex(device);
Eric Laurentfdbee862014-05-12 15:26:12 -07004029 index = getValidIndex(index);
4030 synchronized (mCameraSoundForced) {
4031 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
4032 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07004033 }
4034 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05004035 mIndexMap.put(device, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07004036
John Spurlockf63860c2015-02-19 09:46:27 -05004037 changed = oldIndex != index;
Eric Laurent825a5ea2016-11-03 16:27:40 -07004038 // Apply change to all streams using this one as alias if:
4039 // - the index actually changed OR
4040 // - there is no volume index stored for this device on alias stream.
4041 // If changing volume of current device, also change volume of current
4042 // device on aliased stream
4043 final boolean currentDevice = (device == getDeviceForStream(mStreamType));
4044 final int numStreamTypes = AudioSystem.getNumStreamTypes();
4045 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4046 final VolumeStreamState aliasStreamState = mStreamStates[streamType];
4047 if (streamType != mStreamType &&
4048 mStreamVolumeAlias[streamType] == mStreamType &&
4049 (changed || !aliasStreamState.hasIndexForDevice(device))) {
4050 final int scaledIndex = rescaleIndex(index, mStreamType, streamType);
4051 aliasStreamState.setIndex(scaledIndex, device, caller);
4052 if (currentDevice) {
4053 aliasStreamState.setIndex(scaledIndex,
4054 getDeviceForStream(streamType), caller);
Eric Laurentfdbee862014-05-12 15:26:12 -07004055 }
4056 }
Eric Laurentfdbee862014-05-12 15:26:12 -07004057 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004058 }
John Spurlockf63860c2015-02-19 09:46:27 -05004059 if (changed) {
4060 oldIndex = (oldIndex + 5) / 10;
4061 index = (index + 5) / 10;
John Spurlock90874332015-03-10 16:00:54 -04004062 // log base stream changes to the event log
4063 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
4064 if (caller == null) {
4065 Log.w(TAG, "No caller for volume_changed event", new Throwable());
4066 }
4067 EventLogTags.writeVolumeChanged(mStreamType, oldIndex, index, mIndexMax / 10,
4068 caller);
4069 }
4070 // fire changed intents for all streams
John Spurlockf63860c2015-02-19 09:46:27 -05004071 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
4072 mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
Jean-Michel Trivi560877d2015-06-25 17:38:35 -07004073 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
4074 mStreamVolumeAlias[mStreamType]);
John Spurlockf63860c2015-02-19 09:46:27 -05004075 sendBroadcastToAll(mVolumeChanged);
4076 }
4077 return changed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004078 }
4079
Eric Laurentfdbee862014-05-12 15:26:12 -07004080 public int getIndex(int device) {
4081 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004082 int index = mIndexMap.get(device, -1);
4083 if (index == -1) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004084 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
John Spurlock2bb02ec2015-03-02 13:13:06 -05004085 index = mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurentfdbee862014-05-12 15:26:12 -07004086 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05004087 return index;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004088 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07004089 }
4090
Eric Laurent825a5ea2016-11-03 16:27:40 -07004091 public boolean hasIndexForDevice(int device) {
4092 synchronized (VolumeStreamState.class) {
4093 return (mIndexMap.get(device, -1) != -1);
4094 }
4095 }
4096
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004097 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07004098 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004099 }
4100
John Spurlockb6e19e32015-03-10 21:33:44 -04004101 public int getMinIndex() {
4102 return mIndexMin;
4103 }
4104
John Spurlock90874332015-03-10 16:00:54 -04004105 public void setAllIndexes(VolumeStreamState srcStream, String caller) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004106 synchronized (VolumeStreamState.class) {
4107 int srcStreamType = srcStream.getStreamType();
4108 // apply default device volume from source stream to all devices first in case
4109 // some devices are present in this stream state but not in source stream state
4110 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004111 index = rescaleIndex(index, srcStreamType, mStreamType);
John Spurlock2bb02ec2015-03-02 13:13:06 -05004112 for (int i = 0; i < mIndexMap.size(); i++) {
4113 mIndexMap.put(mIndexMap.keyAt(i), index);
Eric Laurentfdbee862014-05-12 15:26:12 -07004114 }
4115 // Now apply actual volume for devices in source stream state
John Spurlock2bb02ec2015-03-02 13:13:06 -05004116 SparseIntArray srcMap = srcStream.mIndexMap;
4117 for (int i = 0; i < srcMap.size(); i++) {
4118 int device = srcMap.keyAt(i);
4119 index = srcMap.valueAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07004120 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07004121
John Spurlock90874332015-03-10 16:00:54 -04004122 setIndex(index, device, caller);
Eric Laurentfdbee862014-05-12 15:26:12 -07004123 }
Eric Laurent6d517662012-04-23 18:42:39 -07004124 }
4125 }
4126
Eric Laurentfdbee862014-05-12 15:26:12 -07004127 public void setAllIndexesToMax() {
4128 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004129 for (int i = 0; i < mIndexMap.size(); i++) {
4130 mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07004131 }
Eric Laurentdd45d012012-10-08 09:04:34 -07004132 }
Eric Laurentdd45d012012-10-08 09:04:34 -07004133 }
4134
RoboErik4197cb62015-01-21 15:45:32 -08004135 public void mute(boolean state) {
John Spurlock22b9ee12015-02-18 22:51:44 -05004136 boolean changed = false;
Eric Laurentfdbee862014-05-12 15:26:12 -07004137 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08004138 if (state != mIsMuted) {
John Spurlock22b9ee12015-02-18 22:51:44 -05004139 changed = true;
RoboErik4197cb62015-01-21 15:45:32 -08004140 mIsMuted = state;
John Spurlock22b9ee12015-02-18 22:51:44 -05004141
RoboErik4197cb62015-01-21 15:45:32 -08004142 // Set the new mute volume. This propagates the values to
4143 // the audio system, otherwise the volume won't be changed
4144 // at the lower level.
4145 sendMsg(mAudioHandler,
4146 MSG_SET_ALL_VOLUMES,
4147 SENDMSG_QUEUE,
4148 0,
4149 0,
4150 this, 0);
Eric Laurentfdbee862014-05-12 15:26:12 -07004151 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004152 }
John Spurlock22b9ee12015-02-18 22:51:44 -05004153 if (changed) {
4154 // Stream mute changed, fire the intent.
4155 Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
4156 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
4157 intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
4158 sendBroadcastToAll(intent);
4159 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004160 }
4161
Eric Laurent6d517662012-04-23 18:42:39 -07004162 public int getStreamType() {
4163 return mStreamType;
4164 }
4165
Eric Laurent212532b2014-07-21 15:43:18 -07004166 public void checkFixedVolumeDevices() {
4167 synchronized (VolumeStreamState.class) {
4168 // ignore settings for fixed volume devices: volume should always be at max or 0
4169 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004170 for (int i = 0; i < mIndexMap.size(); i++) {
4171 int device = mIndexMap.keyAt(i);
4172 int index = mIndexMap.valueAt(i);
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07004173 if (((device & mFullVolumeDevices) != 0)
4174 || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004175 mIndexMap.put(device, mIndexMax);
Eric Laurent212532b2014-07-21 15:43:18 -07004176 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004177 applyDeviceVolume_syncVSS(device);
Eric Laurent212532b2014-07-21 15:43:18 -07004178 }
4179 }
4180 }
4181 }
4182
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004183 private int getValidIndex(int index) {
John Spurlockb6e19e32015-03-10 21:33:44 -04004184 if (index < mIndexMin) {
4185 return mIndexMin;
John Spurlockee5ad722015-03-03 16:17:21 -05004186 } else if (mUseFixedVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07004187 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004188 }
4189
4190 return index;
4191 }
4192
Eric Laurentbffc3d12012-05-07 17:43:49 -07004193 private void dump(PrintWriter pw) {
RoboErik4197cb62015-01-21 15:45:32 -08004194 pw.print(" Muted: ");
4195 pw.println(mIsMuted);
John Spurlockb6e19e32015-03-10 21:33:44 -04004196 pw.print(" Min: ");
4197 pw.println((mIndexMin + 5) / 10);
John Spurlock2b29bc42014-08-26 16:40:35 -04004198 pw.print(" Max: ");
4199 pw.println((mIndexMax + 5) / 10);
Eric Laurentbffc3d12012-05-07 17:43:49 -07004200 pw.print(" Current: ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05004201 for (int i = 0; i < mIndexMap.size(); i++) {
4202 if (i > 0) {
4203 pw.print(", ");
4204 }
4205 final int device = mIndexMap.keyAt(i);
John Spurlock2b29bc42014-08-26 16:40:35 -04004206 pw.print(Integer.toHexString(device));
4207 final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
4208 : AudioSystem.getOutputDeviceName(device);
4209 if (!deviceName.isEmpty()) {
4210 pw.print(" (");
4211 pw.print(deviceName);
4212 pw.print(")");
4213 }
4214 pw.print(": ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05004215 final int index = (mIndexMap.valueAt(i) + 5) / 10;
John Spurlock2b29bc42014-08-26 16:40:35 -04004216 pw.print(index);
Eric Laurentbffc3d12012-05-07 17:43:49 -07004217 }
John Spurlockb32fc972015-03-05 13:58:00 -05004218 pw.println();
4219 pw.print(" Devices: ");
John Spurlock8a52c442015-03-26 14:23:58 -04004220 final int devices = getDevicesForStream(mStreamType);
John Spurlockb32fc972015-03-05 13:58:00 -05004221 int device, i = 0, n = 0;
John Spurlock1ff1e6e2015-03-09 14:21:20 -04004222 // iterate all devices from 1 to DEVICE_OUT_DEFAULT exclusive
4223 // (the default device is not returned by getDevicesForStream)
4224 while ((device = 1 << i) != AudioSystem.DEVICE_OUT_DEFAULT) {
John Spurlockb32fc972015-03-05 13:58:00 -05004225 if ((devices & device) != 0) {
4226 if (n++ > 0) {
4227 pw.print(", ");
4228 }
4229 pw.print(AudioSystem.getOutputDeviceName(device));
4230 }
4231 i++;
4232 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07004233 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004234 }
4235
4236 /** Thread that handles native AudioSystem control. */
4237 private class AudioSystemThread extends Thread {
4238 AudioSystemThread() {
4239 super("AudioService");
4240 }
4241
4242 @Override
4243 public void run() {
4244 // Set this thread up so the handler will work on it
4245 Looper.prepare();
4246
4247 synchronized(AudioService.this) {
4248 mAudioHandler = new AudioHandler();
4249
4250 // Notify that the handler has been created
4251 AudioService.this.notify();
4252 }
4253
4254 // Listen for volume change requests that are set by VolumePanel
4255 Looper.loop();
4256 }
4257 }
4258
4259 /** Handles internal volume messages in separate volume thread. */
4260 private class AudioHandler extends Handler {
4261
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004262 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004263
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004264 synchronized (VolumeStreamState.class) {
4265 // Apply volume
4266 streamState.applyDeviceVolume_syncVSS(device);
Eric Laurenta553c252009-07-17 12:17:14 -07004267
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004268 // Apply change to all streams using this one as alias
4269 int numStreamTypes = AudioSystem.getNumStreamTypes();
4270 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4271 if (streamType != streamState.mStreamType &&
4272 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
4273 // Make sure volume is also maxed out on A2DP device for aliased stream
4274 // that may have a different device selected
4275 int streamDevice = getDeviceForStream(streamType);
4276 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
4277 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
4278 mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
4279 }
4280 mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
Eric Laurentcd772d02013-10-30 18:31:07 -07004281 }
Eric Laurenta553c252009-07-17 12:17:14 -07004282 }
4283 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004284 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08004285 sendMsg(mAudioHandler,
4286 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08004287 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004288 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07004289 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08004290 streamState,
4291 PERSIST_DELAY);
4292
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004293 }
4294
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004295 private void setAllVolumes(VolumeStreamState streamState) {
4296
4297 // Apply volume
4298 streamState.applyAllVolumes();
4299
4300 // Apply change to all streams using this one as alias
4301 int numStreamTypes = AudioSystem.getNumStreamTypes();
4302 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4303 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07004304 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004305 mStreamStates[streamType].applyAllVolumes();
4306 }
4307 }
4308 }
4309
Eric Laurent42b041e2013-03-29 11:36:03 -07004310 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07004311 if (mUseFixedVolume) {
4312 return;
4313 }
Eric Laurent212532b2014-07-21 15:43:18 -07004314 if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
4315 return;
4316 }
Eric Laurent42b041e2013-03-29 11:36:03 -07004317 System.putIntForUser(mContentResolver,
4318 streamState.getSettingNameForDevice(device),
4319 (streamState.getIndex(device) + 5)/ 10,
4320 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004321 }
4322
Glenn Kastenba195eb2011-12-13 09:30:40 -08004323 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07004324 if (mUseFixedVolume) {
4325 return;
4326 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07004327 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004328 }
4329
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004330 private boolean onLoadSoundEffects() {
4331 int status;
4332
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004333 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004334 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004335 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
4336 return false;
4337 }
4338
4339 if (mSoundPool != null) {
4340 return true;
4341 }
4342
4343 loadTouchSoundAssets();
4344
Jean-Michel Trivi55a30c42014-07-20 17:56:11 -07004345 mSoundPool = new SoundPool.Builder()
4346 .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
4347 .setAudioAttributes(new AudioAttributes.Builder()
4348 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
4349 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
4350 .build())
4351 .build();
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004352 mSoundPoolCallBack = null;
4353 mSoundPoolListenerThread = new SoundPoolListenerThread();
4354 mSoundPoolListenerThread.start();
4355 int attempts = 3;
4356 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
4357 try {
4358 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07004359 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004360 } catch (InterruptedException e) {
4361 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
4362 }
4363 }
4364
4365 if (mSoundPoolCallBack == null) {
4366 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
4367 if (mSoundPoolLooper != null) {
4368 mSoundPoolLooper.quit();
4369 mSoundPoolLooper = null;
4370 }
4371 mSoundPoolListenerThread = null;
4372 mSoundPool.release();
4373 mSoundPool = null;
4374 return false;
4375 }
4376 /*
4377 * poolId table: The value -1 in this table indicates that corresponding
4378 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
4379 * Once loaded, the value in poolId is the sample ID and the same
4380 * sample can be reused for another effect using the same file.
4381 */
4382 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4383 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4384 poolId[fileIdx] = -1;
4385 }
4386 /*
4387 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
4388 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
4389 * this indicates we have a valid sample loaded for this effect.
4390 */
4391
4392 int numSamples = 0;
4393 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4394 // Do not load sample if this effect uses the MediaPlayer
4395 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
4396 continue;
4397 }
4398 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
4399 String filePath = Environment.getRootDirectory()
4400 + SOUND_EFFECTS_PATH
4401 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
4402 int sampleId = mSoundPool.load(filePath, 0);
4403 if (sampleId <= 0) {
4404 Log.w(TAG, "Soundpool could not load file: "+filePath);
4405 } else {
4406 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
4407 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
4408 numSamples++;
4409 }
4410 } else {
4411 SOUND_EFFECT_FILES_MAP[effect][1] =
4412 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
4413 }
4414 }
4415 // wait for all samples to be loaded
4416 if (numSamples > 0) {
4417 mSoundPoolCallBack.setSamples(poolId);
4418
4419 attempts = 3;
4420 status = 1;
4421 while ((status == 1) && (attempts-- > 0)) {
4422 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07004423 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004424 status = mSoundPoolCallBack.status();
4425 } catch (InterruptedException e) {
4426 Log.w(TAG, "Interrupted while waiting sound pool callback.");
4427 }
4428 }
4429 } else {
4430 status = -1;
4431 }
4432
4433 if (mSoundPoolLooper != null) {
4434 mSoundPoolLooper.quit();
4435 mSoundPoolLooper = null;
4436 }
4437 mSoundPoolListenerThread = null;
4438 if (status != 0) {
4439 Log.w(TAG,
4440 "onLoadSoundEffects(), Error "+status+ " while loading samples");
4441 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4442 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
4443 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4444 }
4445 }
4446
4447 mSoundPool.release();
4448 mSoundPool = null;
4449 }
4450 }
4451 return (status == 0);
4452 }
4453
4454 /**
4455 * Unloads samples from the sound pool.
4456 * This method can be called to free some memory when
4457 * sound effects are disabled.
4458 */
4459 private void onUnloadSoundEffects() {
4460 synchronized (mSoundEffectsLock) {
4461 if (mSoundPool == null) {
4462 return;
4463 }
4464
4465 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4466 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4467 poolId[fileIdx] = 0;
4468 }
4469
4470 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4471 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
4472 continue;
4473 }
4474 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
4475 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
4476 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4477 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
4478 }
4479 }
4480 mSoundPool.release();
4481 mSoundPool = null;
4482 }
4483 }
4484
4485 private void onPlaySoundEffect(int effectType, int volume) {
4486 synchronized (mSoundEffectsLock) {
4487
4488 onLoadSoundEffects();
4489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004490 if (mSoundPool == null) {
4491 return;
4492 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004493 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08004494 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004495 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07004496 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004497 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07004498 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004499 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004500
4501 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004502 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
4503 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004504 } else {
4505 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004506 try {
Eric Laurente78fced2013-03-15 16:03:47 -07004507 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
4508 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004509 mediaPlayer.setDataSource(filePath);
4510 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
4511 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08004512 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004513 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
4514 public void onCompletion(MediaPlayer mp) {
4515 cleanupPlayer(mp);
4516 }
4517 });
4518 mediaPlayer.setOnErrorListener(new OnErrorListener() {
4519 public boolean onError(MediaPlayer mp, int what, int extra) {
4520 cleanupPlayer(mp);
4521 return true;
4522 }
4523 });
4524 mediaPlayer.start();
4525 } catch (IOException ex) {
4526 Log.w(TAG, "MediaPlayer IOException: "+ex);
4527 } catch (IllegalArgumentException ex) {
4528 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
4529 } catch (IllegalStateException ex) {
4530 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004531 }
4532 }
4533 }
4534 }
4535
4536 private void cleanupPlayer(MediaPlayer mp) {
4537 if (mp != null) {
4538 try {
4539 mp.stop();
4540 mp.release();
4541 } catch (IllegalStateException ex) {
4542 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
4543 }
4544 }
4545 }
4546
Eric Laurentfa640152011-03-12 15:59:51 -08004547 private void setForceUse(int usage, int config) {
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004548 synchronized (mConnectedDevices) {
4549 setForceUseInt_SyncDevices(usage, config);
4550 }
Eric Laurentfa640152011-03-12 15:59:51 -08004551 }
4552
Eric Laurent05274f32012-11-29 12:48:18 -08004553 private void onPersistSafeVolumeState(int state) {
4554 Settings.Global.putInt(mContentResolver,
4555 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
4556 state);
4557 }
4558
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004559 @Override
4560 public void handleMessage(Message msg) {
Eric Laurentafbb0472011-12-15 09:04:23 -08004561 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004562
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004563 case MSG_SET_DEVICE_VOLUME:
4564 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
4565 break;
4566
4567 case MSG_SET_ALL_VOLUMES:
4568 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004569 break;
4570
4571 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07004572 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004573 break;
4574
4575 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08004576 // note that the value persisted is the current ringer mode, not the
4577 // value of ringer mode as of the time the request was made to persist
John Spurlock661f2cf2014-11-17 10:29:10 -05004578 persistRingerMode(getRingerModeInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004579 break;
4580
Andy Hunged0ea402015-10-30 14:11:46 -07004581 case MSG_AUDIO_SERVER_DIED:
4582 onAudioServerDied();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004583 break;
4584
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004585 case MSG_UNLOAD_SOUND_EFFECTS:
4586 onUnloadSoundEffects();
4587 break;
4588
Eric Laurent117b7bb2011-01-16 17:07:27 -08004589 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004590 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
4591 // can take several dozens of milliseconds to complete
4592 boolean loaded = onLoadSoundEffects();
4593 if (msg.obj != null) {
4594 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
4595 synchronized (reply) {
4596 reply.mStatus = loaded ? 0 : -1;
4597 reply.notify();
4598 }
4599 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08004600 break;
4601
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004602 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004603 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004604 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004605
4606 case MSG_BTA2DP_DOCK_TIMEOUT:
4607 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004608 synchronized (mConnectedDevices) {
4609 makeA2dpDeviceUnavailableNow( (String) msg.obj );
4610 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004611 break;
Eric Laurentfa640152011-03-12 15:59:51 -08004612
4613 case MSG_SET_FORCE_USE:
Sungsoocf09fe62016-09-28 16:21:48 +09004614 case MSG_SET_FORCE_BT_A2DP_USE:
Eric Laurentfa640152011-03-12 15:59:51 -08004615 setForceUse(msg.arg1, msg.arg2);
4616 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07004617
Eric Laurentdc03c612011-04-01 10:59:41 -07004618 case MSG_BT_HEADSET_CNCT_FAILED:
4619 resetBluetoothSco();
4620 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004621
4622 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
Paul McLean10804eb2015-01-28 11:16:35 -08004623 { WiredDeviceConnectionState connectState =
4624 (WiredDeviceConnectionState)msg.obj;
4625 onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
John Spurlock90874332015-03-10 16:00:54 -04004626 connectState.mAddress, connectState.mName, connectState.mCaller);
Paul McLean10804eb2015-01-28 11:16:35 -08004627 mAudioEventWakeLock.release();
4628 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004629 break;
4630
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004631 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
4632 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
4633 mAudioEventWakeLock.release();
4634 break;
4635
4636 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
4637 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004638 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004639 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004640
4641 case MSG_REPORT_NEW_ROUTES: {
4642 int N = mRoutesObservers.beginBroadcast();
4643 if (N > 0) {
4644 AudioRoutesInfo routes;
4645 synchronized (mCurAudioRoutes) {
4646 routes = new AudioRoutesInfo(mCurAudioRoutes);
4647 }
4648 while (N > 0) {
4649 N--;
4650 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
4651 try {
4652 obs.dispatchAudioRoutesChanged(routes);
4653 } catch (RemoteException e) {
4654 }
4655 }
4656 }
4657 mRoutesObservers.finishBroadcast();
John Spurlock8a52c442015-03-26 14:23:58 -04004658 observeDevicesForStreams(-1);
Dianne Hackborn632ca412012-06-14 19:34:10 -07004659 break;
4660 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004661
Eric Laurentc34dcc12012-09-10 13:51:52 -07004662 case MSG_CHECK_MUSIC_ACTIVE:
John Spurlock90874332015-03-10 16:00:54 -04004663 onCheckMusicActive((String) msg.obj);
Eric Laurentc34dcc12012-09-10 13:51:52 -07004664 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004665
4666 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
4667 onSendBecomingNoisyIntent();
4668 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07004669
4670 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
4671 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
John Spurlock90874332015-03-10 16:00:54 -04004672 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED),
4673 (String) msg.obj);
Eric Laurentd640bd32012-09-28 18:01:48 -07004674 break;
Eric Laurent05274f32012-11-29 12:48:18 -08004675 case MSG_PERSIST_SAFE_VOLUME_STATE:
4676 onPersistSafeVolumeState(msg.arg1);
4677 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08004678
Eric Laurent2a57ca92013-03-07 17:29:27 -08004679 case MSG_BROADCAST_BT_CONNECTION_STATE:
4680 onBroadcastScoConnectionState(msg.arg1);
4681 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004682
4683 case MSG_SYSTEM_READY:
4684 onSystemReady();
4685 break;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004686
Eric Laurent0867bed2015-05-20 14:49:08 -07004687 case MSG_INDICATE_SYSTEM_READY:
4688 onIndicateSystemReady();
4689 break;
4690
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004691 case MSG_PERSIST_MUSIC_ACTIVE_MS:
4692 final int musicActiveMs = msg.arg1;
4693 Settings.Secure.putIntForUser(mContentResolver,
4694 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
4695 UserHandle.USER_CURRENT);
4696 break;
Eric Laurentc0232482016-03-15 18:19:23 -07004697
RoboErik5452e252015-02-06 15:33:53 -08004698 case MSG_UNMUTE_STREAM:
4699 onUnmuteStream(msg.arg1, msg.arg2);
4700 break;
Eric Laurentc0232482016-03-15 18:19:23 -07004701
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07004702 case MSG_DYN_POLICY_MIX_STATE_UPDATE:
4703 onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1);
4704 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004705 }
4706 }
4707 }
4708
Jason Parekhb1096152009-03-24 17:48:25 -07004709 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07004710
Phil Burked43bf52016-03-01 17:01:35 -08004711 private int mEncodedSurroundMode;
4712
Jason Parekhb1096152009-03-24 17:48:25 -07004713 SettingsObserver() {
4714 super(new Handler());
4715 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4716 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004717 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4718 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Andy Hung7b98e9a2016-02-25 18:34:50 -08004719 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4720 Settings.System.MASTER_MONO), false, this);
Phil Burked43bf52016-03-01 17:01:35 -08004721
4722 mEncodedSurroundMode = Settings.Global.getInt(
4723 mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT,
4724 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
4725 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4726 Settings.Global.ENCODED_SURROUND_OUTPUT), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07004727 }
4728
4729 @Override
4730 public void onChange(boolean selfChange) {
4731 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08004732 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
4733 // However there appear to be some missing locks around mRingerModeMutedStreams
4734 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
4735 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07004736 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004737 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07004738 /*
4739 * Ensure all stream types that should be affected by ringer mode
4740 * are in the proper state.
4741 */
John Spurlock661f2cf2014-11-17 10:29:10 -05004742 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurenta553c252009-07-17 12:17:14 -07004743 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004744 readDockAudioSettings(mContentResolver);
Andy Hung7b98e9a2016-02-25 18:34:50 -08004745 updateMasterMono(mContentResolver);
Phil Burked43bf52016-03-01 17:01:35 -08004746 updateEncodedSurroundOutput();
4747 }
4748 }
4749
4750 private void updateEncodedSurroundOutput() {
4751 int newSurroundMode = Settings.Global.getInt(
4752 mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT,
4753 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
4754 // Did it change?
4755 if (mEncodedSurroundMode != newSurroundMode) {
4756 // Send to AudioPolicyManager
4757 sendEncodedSurroundMode(newSurroundMode);
4758 synchronized(mConnectedDevices) {
4759 // Is HDMI connected?
4760 String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_HDMI, "");
4761 DeviceListSpec deviceSpec = mConnectedDevices.get(key);
4762 if (deviceSpec != null) {
4763 // Toggle HDMI to retrigger broadcast with proper formats.
4764 setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
4765 AudioSystem.DEVICE_STATE_UNAVAILABLE, "", "",
4766 "android"); // disconnect
4767 setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
4768 AudioSystem.DEVICE_STATE_AVAILABLE, "", "",
4769 "android"); // reconnect
4770 }
4771 }
4772 mEncodedSurroundMode = newSurroundMode;
Eric Laurenta553c252009-07-17 12:17:14 -07004773 }
Jason Parekhb1096152009-03-24 17:48:25 -07004774 }
Jason Parekhb1096152009-03-24 17:48:25 -07004775 }
Eric Laurenta553c252009-07-17 12:17:14 -07004776
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004777 // must be called synchronized on mConnectedDevices
Paul McLean20eec5b2015-05-09 13:02:18 -07004778 private void makeA2dpDeviceAvailable(String address, String name) {
Eric Laurent78472112012-05-21 08:57:21 -07004779 // enable A2DP before notifying A2DP connection to avoid unecessary processing in
4780 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004781 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4782 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4783 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Sungsoocf09fe62016-09-28 16:21:48 +09004784 setBluetoothA2dpOnInt(true);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004785 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004786 AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004787 // Reset A2DP suspend state each time a new sink is connected
4788 AudioSystem.setParameters("A2dpSuspended=false");
Paul McLean394a8e12015-03-03 10:29:19 -07004789 mConnectedDevices.put(
4790 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
Paul McLean20eec5b2015-05-09 13:02:18 -07004791 new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
Paul McLean394a8e12015-03-03 10:29:19 -07004792 address));
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004793 }
4794
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004795 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004796 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07004797 }
4798
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004799 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004800 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004801 synchronized (mA2dpAvrcpLock) {
4802 mAvrcpAbsVolSupported = false;
4803 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004804 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004805 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004806 mConnectedDevices.remove(
4807 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
RoboErik5535ea82014-09-25 14:53:16 -07004808 synchronized (mCurAudioRoutes) {
4809 // Remove A2DP routes as well
John Spurlock61560172015-02-06 19:46:04 -05004810 if (mCurAudioRoutes.bluetoothName != null) {
4811 mCurAudioRoutes.bluetoothName = null;
RoboErik5535ea82014-09-25 14:53:16 -07004812 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4813 SENDMSG_NOOP, 0, 0, null, 0);
4814 }
4815 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004816 }
4817
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004818 // must be called synchronized on mConnectedDevices
Eric Laurentd138e4e2015-05-15 16:41:15 -07004819 private void makeA2dpDeviceUnavailableLater(String address, int delayMs) {
Eric Laurent3b591262010-04-20 07:01:00 -07004820 // prevent any activity on the A2DP audio output to avoid unwanted
4821 // reconnection of the sink.
4822 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004823 // the device will be made unavailable later, so consider it disconnected right away
Paul McLean394a8e12015-03-03 10:29:19 -07004824 mConnectedDevices.remove(
4825 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004826 // send the delayed message to make the device unavailable later
4827 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
Eric Laurentd138e4e2015-05-15 16:41:15 -07004828 mAudioHandler.sendMessageDelayed(msg, delayMs);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004829
4830 }
4831
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004832 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004833 private void makeA2dpSrcAvailable(String address) {
4834 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004835 AudioSystem.DEVICE_STATE_AVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004836 mConnectedDevices.put(
4837 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
Paul McLean20eec5b2015-05-09 13:02:18 -07004838 new DeviceListSpec(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "",
Paul McLean394a8e12015-03-03 10:29:19 -07004839 address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004840 }
4841
4842 // must be called synchronized on mConnectedDevices
4843 private void makeA2dpSrcUnavailable(String address) {
4844 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004845 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004846 mConnectedDevices.remove(
4847 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004848 }
4849
4850 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004851 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004852 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4853 }
4854
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004855 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004856 private boolean hasScheduledA2dpDockTimeout() {
4857 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4858 }
4859
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004860 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004861 {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004862 if (DEBUG_VOL) {
4863 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
4864 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004865 if (btDevice == null) {
4866 return;
4867 }
4868 String address = btDevice.getAddress();
4869 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4870 address = "";
4871 }
John Du5a0cf7a2013-07-19 11:30:34 -07004872
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004873 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004874 String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4875 btDevice.getAddress());
4876 DeviceListSpec deviceSpec = mConnectedDevices.get(key);
4877 boolean isConnected = deviceSpec != null;
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004878
4879 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4880 if (btDevice.isBluetoothDock()) {
4881 if (state == BluetoothProfile.STATE_DISCONNECTED) {
4882 // introduction of a delay for transient disconnections of docks when
4883 // power is rapidly turned off/on, this message will be canceled if
4884 // we reconnect the dock under a preset delay
Eric Laurentd138e4e2015-05-15 16:41:15 -07004885 makeA2dpDeviceUnavailableLater(address, BTA2DP_DOCK_TIMEOUT_MILLIS);
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004886 // the next time isConnected is evaluated, it will be false for the dock
4887 }
4888 } else {
4889 makeA2dpDeviceUnavailableNow(address);
4890 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07004891 synchronized (mCurAudioRoutes) {
John Spurlock61560172015-02-06 19:46:04 -05004892 if (mCurAudioRoutes.bluetoothName != null) {
4893 mCurAudioRoutes.bluetoothName = null;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004894 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4895 SENDMSG_NOOP, 0, 0, null, 0);
4896 }
4897 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004898 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4899 if (btDevice.isBluetoothDock()) {
4900 // this could be a reconnection after a transient disconnection
4901 cancelA2dpDeviceTimeout();
4902 mDockAddress = address;
4903 } else {
4904 // this could be a connection of another A2DP device before the timeout of
4905 // a dock: cancel the dock timeout, and make the dock unavailable now
4906 if(hasScheduledA2dpDockTimeout()) {
4907 cancelA2dpDeviceTimeout();
4908 makeA2dpDeviceUnavailableNow(mDockAddress);
4909 }
4910 }
Paul McLean20eec5b2015-05-09 13:02:18 -07004911 makeA2dpDeviceAvailable(address, btDevice.getName());
Dianne Hackborn632ca412012-06-14 19:34:10 -07004912 synchronized (mCurAudioRoutes) {
4913 String name = btDevice.getAliasName();
John Spurlock61560172015-02-06 19:46:04 -05004914 if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
4915 mCurAudioRoutes.bluetoothName = name;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004916 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4917 SENDMSG_NOOP, 0, 0, null, 0);
4918 }
4919 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004920 }
4921 }
4922 }
4923
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004924 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
4925 {
4926 if (DEBUG_VOL) {
4927 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
4928 }
4929 if (btDevice == null) {
4930 return;
4931 }
4932 String address = btDevice.getAddress();
4933 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4934 address = "";
4935 }
4936
4937 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004938 String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
4939 DeviceListSpec deviceSpec = mConnectedDevices.get(key);
4940 boolean isConnected = deviceSpec != null;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004941
4942 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4943 makeA2dpSrcUnavailable(address);
4944 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4945 makeA2dpSrcAvailable(address);
4946 }
4947 }
4948 }
4949
John Du5a0cf7a2013-07-19 11:30:34 -07004950 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
4951 // address is not used for now, but may be used when multiple a2dp devices are supported
4952 synchronized (mA2dpAvrcpLock) {
4953 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004954 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07004955 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4956 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4957 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4958 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4959 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07004960 }
4961 }
4962
Paul McLean394a8e12015-03-03 10:29:19 -07004963 private boolean handleDeviceConnection(boolean connect, int device, String address,
4964 String deviceName) {
4965 if (DEBUG_DEVICES) {
4966 Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device)
4967 + " address:" + address + " name:" + deviceName + ")");
4968 }
Eric Laurent59f48272012-04-05 19:42:21 -07004969 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004970 String deviceKey = makeDeviceListKey(device, address);
4971 if (DEBUG_DEVICES) {
4972 Slog.i(TAG, "deviceKey:" + deviceKey);
4973 }
4974 DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
4975 boolean isConnected = deviceSpec != null;
4976 if (DEBUG_DEVICES) {
4977 Slog.i(TAG, "deviceSpec:" + deviceSpec + " is(already)Connected:" + isConnected);
4978 }
4979 if (connect && !isConnected) {
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07004980 final int res = AudioSystem.setDeviceConnectionState(device,
4981 AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);
4982 if (res != AudioSystem.AUDIO_STATUS_OK) {
4983 Slog.e(TAG, "not connecting device 0x" + Integer.toHexString(device) +
4984 " due to command error " + res );
4985 return false;
4986 }
Paul McLean394a8e12015-03-03 10:29:19 -07004987 mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
4988 return true;
4989 } else if (!connect && isConnected) {
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07004990 AudioSystem.setDeviceConnectionState(device,
4991 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName);
4992 // always remove even if disconnection failed
Paul McLean394a8e12015-03-03 10:29:19 -07004993 mConnectedDevices.remove(deviceKey);
4994 return true;
Eric Laurent59f48272012-04-05 19:42:21 -07004995 }
4996 }
4997 return false;
4998 }
4999
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005000 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
5001 // sent if none of these devices is connected.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005002 // Access synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005003 int mBecomingNoisyIntentDevices =
5004 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07005005 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07005006 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Jon Eklund43cc8bb2014-07-28 16:07:24 -05005007 AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005008
5009 // must be called before removing the device from mConnectedDevices
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005010 // Called synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005011 private int checkSendBecomingNoisyIntent(int device, int state) {
5012 int delay = 0;
5013 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
5014 int devices = 0;
John Spurlock8c3dc852015-04-23 21:32:37 -04005015 for (int i = 0; i < mConnectedDevices.size(); i++) {
5016 int dev = mConnectedDevices.valueAt(i).mDeviceType;
Paul McLean394a8e12015-03-03 10:29:19 -07005017 if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
5018 && ((dev & mBecomingNoisyIntentDevices) != 0)) {
5019 devices |= dev;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005020 }
5021 }
5022 if (devices == device) {
Eric Laurent5bfaeae2012-09-21 18:44:48 -07005023 sendMsg(mAudioHandler,
5024 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
5025 SENDMSG_REPLACE,
5026 0,
5027 0,
5028 null,
5029 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005030 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005031 }
5032 }
5033
Mike Lockwood0a40ec22014-05-21 10:08:50 -07005034 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
5035 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005036 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
Eric Laurentadbe8bf2014-11-03 18:26:32 -08005037 synchronized (mLastDeviceConnectMsgTime) {
5038 long time = SystemClock.uptimeMillis();
5039 if (mLastDeviceConnectMsgTime > time) {
Matthew Xiec525cf72015-01-22 20:13:17 -08005040 delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
Eric Laurentadbe8bf2014-11-03 18:26:32 -08005041 }
5042 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005043 }
5044 return delay;
5045 }
5046
Paul McLean394a8e12015-03-03 10:29:19 -07005047 private void sendDeviceConnectionIntent(int device, int state, String address,
5048 String deviceName) {
5049 if (DEBUG_DEVICES) {
5050 Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
5051 " state:0x" + Integer.toHexString(state) + " address:" + address +
5052 " name:" + deviceName + ");");
5053 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005054 Intent intent = new Intent();
5055
Paul McLean10804eb2015-01-28 11:16:35 -08005056 intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
5057 intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
5058 intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
5059
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005060 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
5061
Dianne Hackborn632ca412012-06-14 19:34:10 -07005062 int connType = 0;
5063
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005064 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07005065 connType = AudioRoutesInfo.MAIN_HEADSET;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005066 intent.setAction(Intent.ACTION_HEADSET_PLUG);
5067 intent.putExtra("microphone", 1);
Jon Eklund43cc8bb2014-07-28 16:07:24 -05005068 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
5069 device == AudioSystem.DEVICE_OUT_LINE) {
5070 /*do apps care about line-out vs headphones?*/
Dianne Hackborn632ca412012-06-14 19:34:10 -07005071 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005072 intent.setAction(Intent.ACTION_HEADSET_PLUG);
5073 intent.putExtra("microphone", 0);
Eric Laurent6fa42452015-01-09 15:09:40 -08005074 } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
5075 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07005076 connType = AudioRoutesInfo.MAIN_HDMI;
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005077 configureHdmiPlugIntent(intent, state);
Paul McLean10804eb2015-01-28 11:16:35 -08005078 } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE) {
5079 connType = AudioRoutesInfo.MAIN_USB;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005080 }
5081
Dianne Hackborn632ca412012-06-14 19:34:10 -07005082 synchronized (mCurAudioRoutes) {
5083 if (connType != 0) {
John Spurlock61560172015-02-06 19:46:04 -05005084 int newConn = mCurAudioRoutes.mainType;
Dianne Hackborn632ca412012-06-14 19:34:10 -07005085 if (state != 0) {
5086 newConn |= connType;
5087 } else {
5088 newConn &= ~connType;
5089 }
John Spurlock61560172015-02-06 19:46:04 -05005090 if (newConn != mCurAudioRoutes.mainType) {
5091 mCurAudioRoutes.mainType = newConn;
Dianne Hackborn632ca412012-06-14 19:34:10 -07005092 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
5093 SENDMSG_NOOP, 0, 0, null, 0);
5094 }
5095 }
5096 }
5097
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005098 final long ident = Binder.clearCallingIdentity();
5099 try {
5100 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
5101 } finally {
5102 Binder.restoreCallingIdentity(ident);
5103 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005104 }
5105
Paul McLean10804eb2015-01-28 11:16:35 -08005106 private void onSetWiredDeviceConnectionState(int device, int state, String address,
John Spurlock90874332015-03-10 16:00:54 -04005107 String deviceName, String caller) {
Paul McLean394a8e12015-03-03 10:29:19 -07005108 if (DEBUG_DEVICES) {
John Spurlock90874332015-03-10 16:00:54 -04005109 Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
5110 + " state:" + Integer.toHexString(state)
5111 + " address:" + address
5112 + " deviceName:" + deviceName
5113 + " caller: " + caller + ");");
Paul McLean394a8e12015-03-03 10:29:19 -07005114 }
Paul McLean10804eb2015-01-28 11:16:35 -08005115
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005116 synchronized (mConnectedDevices) {
Sungsoocf09fe62016-09-28 16:21:48 +09005117 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
5118 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
5119 (device == AudioSystem.DEVICE_OUT_LINE))) {
5120 setBluetoothA2dpOnInt(true);
5121 }
Eric Laurentae4506e2014-05-29 16:04:32 -07005122 boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
5123 (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
5124 ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07005125 if (!handleDeviceConnection(state == 1, device, address, deviceName)) {
5126 // change of connection state failed, bailout
5127 return;
5128 }
Eric Laurentf1a457d2012-09-20 16:27:23 -07005129 if (state != 0) {
Sungsoocf09fe62016-09-28 16:21:48 +09005130 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
5131 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
5132 (device == AudioSystem.DEVICE_OUT_LINE)) {
5133 setBluetoothA2dpOnInt(false);
5134 }
Eric Laurentf1a457d2012-09-20 16:27:23 -07005135 if ((device & mSafeMediaVolumeDevices) != 0) {
5136 sendMsg(mAudioHandler,
5137 MSG_CHECK_MUSIC_ACTIVE,
5138 SENDMSG_REPLACE,
5139 0,
5140 0,
John Spurlock90874332015-03-10 16:00:54 -04005141 caller,
Eric Laurentf1a457d2012-09-20 16:27:23 -07005142 MUSIC_ACTIVE_POLL_PERIOD_MS);
5143 }
Eric Laurent212532b2014-07-21 15:43:18 -07005144 // Television devices without CEC service apply software volume on HDMI output
5145 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
5146 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
5147 checkAllFixedVolumeDevices();
5148 if (mHdmiManager != null) {
5149 synchronized (mHdmiManager) {
5150 if (mHdmiPlaybackClient != null) {
5151 mHdmiCecSink = false;
5152 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
5153 }
5154 }
5155 }
5156 }
5157 } else {
5158 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
5159 if (mHdmiManager != null) {
5160 synchronized (mHdmiManager) {
5161 mHdmiCecSink = false;
5162 }
5163 }
5164 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005165 }
Paul McLean10804eb2015-01-28 11:16:35 -08005166 if (!isUsb && device != AudioSystem.DEVICE_IN_WIRED_HEADSET) {
5167 sendDeviceConnectionIntent(device, state, address, deviceName);
Mike Lockwooddb454842012-09-18 11:16:57 -07005168 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005169 }
5170 }
5171
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005172 private void configureHdmiPlugIntent(Intent intent, int state) {
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005173 intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
5174 intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005175 if (state == 1) {
5176 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
5177 int[] portGeneration = new int[1];
5178 int status = AudioSystem.listAudioPorts(ports, portGeneration);
5179 if (status == AudioManager.SUCCESS) {
5180 for (AudioPort port : ports) {
5181 if (port instanceof AudioDevicePort) {
5182 final AudioDevicePort devicePort = (AudioDevicePort) port;
Eric Laurent6fa42452015-01-09 15:09:40 -08005183 if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
5184 devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005185 // format the list of supported encodings
Eric Laurentcae34662015-05-19 16:46:52 -07005186 int[] formats = AudioFormat.filterPublicFormats(devicePort.formats());
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005187 if (formats.length > 0) {
5188 ArrayList<Integer> encodingList = new ArrayList(1);
5189 for (int format : formats) {
5190 // a format in the list can be 0, skip it
5191 if (format != AudioFormat.ENCODING_INVALID) {
5192 encodingList.add(format);
5193 }
5194 }
5195 int[] encodingArray = new int[encodingList.size()];
5196 for (int i = 0 ; i < encodingArray.length ; i++) {
5197 encodingArray[i] = encodingList.get(i);
5198 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005199 intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005200 }
5201 // find the maximum supported number of channels
5202 int maxChannels = 0;
5203 for (int mask : devicePort.channelMasks()) {
5204 int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
5205 if (channelCount > maxChannels) {
5206 maxChannels = channelCount;
5207 }
5208 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005209 intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005210 }
5211 }
5212 }
5213 }
5214 }
5215 }
5216
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07005217 /* cache of the address of the last dock the device was connected to */
5218 private String mDockAddress;
5219
Eric Laurenta553c252009-07-17 12:17:14 -07005220 /**
5221 * Receiver for misc intent broadcasts the Phone app cares about.
5222 */
5223 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
5224 @Override
5225 public void onReceive(Context context, Intent intent) {
5226 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07005227 int outDevice;
5228 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07005229 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07005230
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08005231 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
5232 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
5233 Intent.EXTRA_DOCK_STATE_UNDOCKED);
5234 int config;
5235 switch (dockState) {
5236 case Intent.EXTRA_DOCK_STATE_DESK:
5237 config = AudioSystem.FORCE_BT_DESK_DOCK;
5238 break;
5239 case Intent.EXTRA_DOCK_STATE_CAR:
5240 config = AudioSystem.FORCE_BT_CAR_DOCK;
5241 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05005242 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08005243 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05005244 break;
5245 case Intent.EXTRA_DOCK_STATE_HE_DESK:
5246 config = AudioSystem.FORCE_DIGITAL_DOCK;
5247 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08005248 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
5249 default:
5250 config = AudioSystem.FORCE_NONE;
5251 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08005252 // Low end docks have a menu to enable or disable audio
5253 // (see mDockAudioMediaEnabled)
5254 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
5255 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
5256 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
5257 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
5258 }
5259 mDockState = dockState;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07005260 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
Eric Laurent59f48272012-04-05 19:42:21 -07005261 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07005262 BluetoothProfile.STATE_DISCONNECTED);
Eric Laurentdca56b92011-09-02 14:20:56 -07005263 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Eric Laurent0867bed2015-05-20 14:49:08 -07005264
Eric Laurent98859b22015-06-12 14:35:59 -07005265 setBtScoDeviceConnectionState(btDevice, state);
Paul McLeandf361462014-04-10 16:02:55 -07005266 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005267 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07005268 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005269 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005270 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07005271 // broadcast intent if the connection was initated by AudioService
5272 if (!mScoClients.isEmpty() &&
5273 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
5274 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
5275 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005276 broadcast = true;
5277 }
5278 switch (btState) {
5279 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07005280 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07005281 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5282 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5283 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005284 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005285 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005286 break;
5287 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07005288 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08005289 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07005290 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08005291 break;
5292 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07005293 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5294 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5295 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005296 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005297 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005298 default:
5299 // do not broadcast CONNECTING or invalid state
5300 broadcast = false;
5301 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005302 }
5303 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005304 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07005305 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07005306 //FIXME: this is to maintain compatibility with deprecated intent
5307 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08005308 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07005309 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005310 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08005311 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005312 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06005313 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005314 RotationHelper.enable();
Jon Eklund318f0fe2014-01-23 17:53:48 -06005315 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005316 AudioSystem.setParameters("screen_state=on");
5317 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06005318 if (mMonitorRotation) {
5319 //reduce wakeups (save current) by only listening when display is on
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005320 RotationHelper.disable();
Jon Eklund318f0fe2014-01-23 17:53:48 -06005321 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005322 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07005323 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005324 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07005325 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Yasuhiro Matsuda4ced7192015-07-10 22:08:44 +09005326 if (mUserSwitchedReceived) {
5327 // attempt to stop music playback for background user except on first user
5328 // switch (i.e. first boot)
5329 sendMsg(mAudioHandler,
5330 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
5331 SENDMSG_REPLACE,
5332 0,
5333 0,
5334 null,
5335 0);
5336 }
5337 mUserSwitchedReceived = true;
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07005338 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005339 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07005340
Eric Laurent5bfaeae2012-09-21 18:44:48 -07005341 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07005342 readAudioSettings(true /*userSwitch*/);
5343 // preserve STREAM_MUSIC volume from one user to the next.
5344 sendMsg(mAudioHandler,
5345 MSG_SET_ALL_VOLUMES,
5346 SENDMSG_QUEUE,
5347 0,
5348 0,
5349 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005350 } else if (action.equals(Intent.ACTION_USER_BACKGROUND)) {
5351 // Disable audio recording for the background user/profile
5352 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
5353 if (userId >= 0) {
5354 // TODO Kill recording streams instead of killing processes holding permission
5355 UserInfo userInfo = UserManagerService.getInstance().getUserInfo(userId);
5356 killBackgroundUserProcessesWithRecordAudioPermission(userInfo);
5357 }
Makoto Onukiac65e1e2015-11-20 15:33:17 -08005358 UserManagerService.getInstance().setUserRestriction(
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005359 UserManager.DISALLOW_RECORD_AUDIO, true, userId);
5360 } else if (action.equals(Intent.ACTION_USER_FOREGROUND)) {
5361 // Enable audio recording for foreground user/profile
5362 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Makoto Onukiac65e1e2015-11-20 15:33:17 -08005363 UserManagerService.getInstance().setUserRestriction(
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005364 UserManager.DISALLOW_RECORD_AUDIO, false, userId);
Eric Laurentb70b78a2016-01-13 19:16:04 -08005365 } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
5366 state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
5367 if (state == BluetoothAdapter.STATE_OFF ||
5368 state == BluetoothAdapter.STATE_TURNING_OFF) {
5369 disconnectAllBluetoothProfiles();
5370 }
Eric Laurenta553c252009-07-17 12:17:14 -07005371 }
5372 }
Paul McLeanc837a452014-04-09 09:04:43 -07005373 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005374
Makoto Onukid45a4a22015-11-02 17:17:38 -08005375 private class AudioServiceUserRestrictionsListener implements UserRestrictionsListener {
5376
5377 @Override
5378 public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
5379 Bundle prevRestrictions) {
5380 // Update mic mute state.
5381 {
5382 final boolean wasRestricted =
5383 prevRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
5384 final boolean isRestricted =
5385 newRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
5386 if (wasRestricted != isRestricted) {
5387 setMicrophoneMuteNoCallerCheck(isRestricted, userId);
5388 }
5389 }
5390
5391 // Update speaker mute state.
5392 {
5393 final boolean wasRestricted =
Tony Makc1205112016-07-22 16:02:59 +01005394 prevRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)
5395 || prevRestrictions.getBoolean(UserManager.DISALLLOW_UNMUTE_DEVICE);
Makoto Onukid45a4a22015-11-02 17:17:38 -08005396 final boolean isRestricted =
Tony Makc1205112016-07-22 16:02:59 +01005397 newRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)
5398 || newRestrictions.getBoolean(UserManager.DISALLLOW_UNMUTE_DEVICE);
Makoto Onukid45a4a22015-11-02 17:17:38 -08005399 if (wasRestricted != isRestricted) {
5400 setMasterMuteInternalNoCallerCheck(isRestricted, /* flags =*/ 0, userId);
5401 }
5402 }
5403 }
5404 } // end class AudioServiceUserRestrictionsListener
5405
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005406 private void killBackgroundUserProcessesWithRecordAudioPermission(UserInfo oldUser) {
5407 PackageManager pm = mContext.getPackageManager();
5408 // Find the home activity of the user. It should not be killed to avoid expensive restart,
5409 // when the user switches back. For managed profiles, we should kill all recording apps
5410 ComponentName homeActivityName = null;
5411 if (!oldUser.isManagedProfile()) {
5412 homeActivityName = LocalServices.getService(ActivityManagerInternal.class)
5413 .getHomeActivityForUser(oldUser.id);
5414 }
5415 final String[] permissions = { Manifest.permission.RECORD_AUDIO };
5416 List<PackageInfo> packages;
5417 try {
5418 packages = AppGlobals.getPackageManager()
5419 .getPackagesHoldingPermissions(permissions, 0, oldUser.id).getList();
5420 } catch (RemoteException e) {
5421 throw new AndroidRuntimeException(e);
5422 }
5423 for (int j = packages.size() - 1; j >= 0; j--) {
5424 PackageInfo pkg = packages.get(j);
Fyodor Kupolovbcb6c1e2015-05-11 12:05:15 -07005425 // Skip system processes
5426 if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
5427 continue;
5428 }
Amith Yamasanic1cbaab2015-07-21 11:46:14 -07005429 // Skip packages that have permission to interact across users
5430 if (pm.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS, pkg.packageName)
5431 == PackageManager.PERMISSION_GRANTED) {
5432 continue;
5433 }
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005434 if (homeActivityName != null
5435 && pkg.packageName.equals(homeActivityName.getPackageName())
5436 && pkg.applicationInfo.isSystemApp()) {
5437 continue;
5438 }
5439 try {
Svetoslavaa41add2015-08-06 15:03:55 -07005440 final int uid = pkg.applicationInfo.uid;
5441 ActivityManagerNative.getDefault().killUid(UserHandle.getAppId(uid),
5442 UserHandle.getUserId(uid),
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005443 "killBackgroundUserProcessesWithAudioRecordPermission");
5444 } catch (RemoteException e) {
5445 Log.w(TAG, "Error calling killUid", e);
5446 }
5447 }
5448 }
5449
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005450
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005451 //==========================================================================================
5452 // Audio Focus
5453 //==========================================================================================
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005454 public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005455 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005456 IAudioPolicyCallback pcb) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005457 // permission checks
5458 if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
John Spurlock61560172015-02-06 19:46:04 -05005459 if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005460 if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
5461 android.Manifest.permission.MODIFY_PHONE_STATE)) {
5462 Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
5463 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5464 }
5465 } else {
5466 // only a registered audio policy can be used to lock focus
5467 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005468 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
5469 Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005470 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5471 }
5472 }
5473 }
5474 }
5475
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005476 return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
5477 clientId, callingPackageName, flags);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005478 }
5479
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005480 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
5481 return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005482 }
5483
5484 public void unregisterAudioFocusClient(String clientId) {
5485 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005486 }
5487
Jean-Michel Trivi23805662013-07-31 14:19:18 -07005488 public int getCurrentAudioFocus() {
5489 return mMediaFocusControl.getCurrentAudioFocus();
5490 }
5491
John Spurlock5e783732015-02-19 10:28:59 -05005492 private boolean readCameraSoundForced() {
5493 return SystemProperties.getBoolean("audio.camerasound.force", false) ||
5494 mContext.getResources().getBoolean(
5495 com.android.internal.R.bool.config_camera_sound_forced);
5496 }
5497
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005498 //==========================================================================================
5499 // Device orientation
5500 //==========================================================================================
5501 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005502 * Handles device configuration changes that may map to a change in the orientation
5503 * or orientation.
5504 * Monitoring orientation and rotation is optional, and is defined by the definition and value
5505 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005506 */
5507 private void handleConfigurationChanged(Context context) {
5508 try {
5509 // reading new orientation "safely" (i.e. under try catch) in case anything
5510 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07005511 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005512 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07005513 if (mMonitorOrientation) {
5514 int newOrientation = config.orientation;
5515 if (newOrientation != mDeviceOrientation) {
5516 mDeviceOrientation = newOrientation;
5517 setOrientationForAudioSystem();
5518 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005519 }
Eric Laurentd640bd32012-09-28 18:01:48 -07005520 sendMsg(mAudioHandler,
5521 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
5522 SENDMSG_REPLACE,
5523 0,
5524 0,
John Spurlock90874332015-03-10 16:00:54 -04005525 TAG,
Eric Laurentd640bd32012-09-28 18:01:48 -07005526 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07005527
John Spurlock5e783732015-02-19 10:28:59 -05005528 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -07005529 synchronized (mSettingsLock) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005530 boolean cameraSoundForcedChanged = false;
Eric Laurentdd45d012012-10-08 09:04:34 -07005531 synchronized (mCameraSoundForced) {
5532 if (cameraSoundForced != mCameraSoundForced) {
5533 mCameraSoundForced = cameraSoundForced;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005534 cameraSoundForcedChanged = true;
Eric Laurentdd45d012012-10-08 09:04:34 -07005535 }
5536 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005537 if (cameraSoundForcedChanged) {
5538 if (!isPlatformTelevision()) {
5539 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
5540 if (cameraSoundForced) {
5541 s.setAllIndexesToMax();
5542 mRingerModeAffectedStreams &=
5543 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5544 } else {
John Spurlock90874332015-03-10 16:00:54 -04005545 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005546 mRingerModeAffectedStreams |=
5547 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5548 }
5549 // take new state into account for streams muted by ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05005550 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005551 }
5552
5553 sendMsg(mAudioHandler,
5554 MSG_SET_FORCE_USE,
5555 SENDMSG_QUEUE,
5556 AudioSystem.FOR_SYSTEM,
5557 cameraSoundForced ?
5558 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
5559 null,
5560 0);
5561
5562 sendMsg(mAudioHandler,
5563 MSG_SET_ALL_VOLUMES,
5564 SENDMSG_QUEUE,
5565 0,
5566 0,
5567 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
5568 }
Eric Laurentdd45d012012-10-08 09:04:34 -07005569 }
John Spurlock3346a802014-05-20 16:25:37 -04005570 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005571 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005572 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005573 }
5574 }
5575
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005576 //TODO move to an external "orientation helper" class
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005577 private void setOrientationForAudioSystem() {
5578 switch (mDeviceOrientation) {
5579 case Configuration.ORIENTATION_LANDSCAPE:
5580 //Log.i(TAG, "orientation is landscape");
5581 AudioSystem.setParameters("orientation=landscape");
5582 break;
5583 case Configuration.ORIENTATION_PORTRAIT:
5584 //Log.i(TAG, "orientation is portrait");
5585 AudioSystem.setParameters("orientation=portrait");
5586 break;
5587 case Configuration.ORIENTATION_SQUARE:
5588 //Log.i(TAG, "orientation is square");
5589 AudioSystem.setParameters("orientation=square");
5590 break;
5591 case Configuration.ORIENTATION_UNDEFINED:
5592 //Log.i(TAG, "orientation is undefined");
5593 AudioSystem.setParameters("orientation=undefined");
5594 break;
5595 default:
5596 Log.e(TAG, "Unknown orientation");
5597 }
5598 }
5599
Sungsoocf09fe62016-09-28 16:21:48 +09005600 // Handles request to override default use of A2DP for media.
5601 // Must be called synchronized on mConnectedDevices
5602 public void setBluetoothA2dpOnInt(boolean on) {
5603 synchronized (mBluetoothA2dpEnabledLock) {
5604 mBluetoothA2dpEnabled = on;
5605 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
5606 setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
5607 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
5608 }
5609 }
5610
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005611 // Must be called synchronized on mConnectedDevices
5612 private void setForceUseInt_SyncDevices(int usage, int config) {
5613 switch (usage) {
Sungsoocf09fe62016-09-28 16:21:48 +09005614 case AudioSystem.FOR_MEDIA:
5615 if (config == AudioSystem.FORCE_NO_BT_A2DP) {
5616 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ALL_A2DP;
5617 } else { // config == AudioSystem.FORCE_NONE
5618 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
5619 }
Sungsoo71f35632016-09-28 16:26:49 +09005620 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
5621 SENDMSG_NOOP, 0, 0, null, 0);
Sungsoocf09fe62016-09-28 16:21:48 +09005622 break;
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005623 case AudioSystem.FOR_DOCK:
5624 if (config == AudioSystem.FORCE_ANALOG_DOCK) {
5625 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5626 } else { // config == AudioSystem.FORCE_NONE
5627 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5628 }
5629 break;
5630 default:
5631 // usage doesn't affect the broadcast of ACTION_AUDIO_BECOMING_NOISY
5632 }
5633 AudioSystem.setForceUse(usage, config);
5634 }
5635
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005636 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07005637 public void setRingtonePlayer(IRingtonePlayer player) {
5638 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5639 mRingtonePlayer = player;
5640 }
5641
5642 @Override
5643 public IRingtonePlayer getRingtonePlayer() {
5644 return mRingtonePlayer;
5645 }
5646
5647 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07005648 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5649 synchronized (mCurAudioRoutes) {
5650 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5651 mRoutesObservers.register(observer);
5652 return routes;
5653 }
5654 }
5655
Eric Laurentc34dcc12012-09-10 13:51:52 -07005656
5657 //==========================================================================================
5658 // Safe media volume management.
5659 // MUSIC stream volume level is limited when headphones are connected according to safety
5660 // regulation. When the user attempts to raise the volume above the limit, a warning is
5661 // displayed and the user has to acknowlegde before the volume is actually changed.
5662 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
5663 // property. Platforms with a different limit must set this property accordingly in their
5664 // overlay.
5665 //==========================================================================================
5666
Eric Laurentd640bd32012-09-28 18:01:48 -07005667 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
5668 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
5669 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
5670 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
5671 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
5672 // (when user opts out).
John Spurlock35134602014-07-24 18:10:48 -04005673 private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
5674 private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
5675 private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed
5676 private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
Eric Laurentd640bd32012-09-28 18:01:48 -07005677 private Integer mSafeMediaVolumeState;
5678
5679 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005680 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07005681 private int mSafeMediaVolumeIndex;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005682 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
5683 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
5684 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
5685 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
5686 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
5687 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
5688 private int mMusicActiveMs;
5689 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
5690 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07005691 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07005692
John Spurlock90874332015-03-10 16:00:54 -04005693 private void setSafeMediaVolumeEnabled(boolean on, String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005694 synchronized (mSafeMediaVolumeState) {
5695 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
5696 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
5697 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
5698 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
John Spurlock90874332015-03-10 16:00:54 -04005699 enforceSafeMediaVolume(caller);
Eric Laurentd640bd32012-09-28 18:01:48 -07005700 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
5701 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005702 mMusicActiveMs = 1; // nonzero = confirmed
5703 saveMusicActiveMs();
Eric Laurentd640bd32012-09-28 18:01:48 -07005704 sendMsg(mAudioHandler,
5705 MSG_CHECK_MUSIC_ACTIVE,
5706 SENDMSG_REPLACE,
5707 0,
5708 0,
John Spurlock90874332015-03-10 16:00:54 -04005709 caller,
Eric Laurentd640bd32012-09-28 18:01:48 -07005710 MUSIC_ACTIVE_POLL_PERIOD_MS);
5711 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005712 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005713 }
5714 }
5715
John Spurlock90874332015-03-10 16:00:54 -04005716 private void enforceSafeMediaVolume(String caller) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005717 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07005718 int devices = mSafeMediaVolumeDevices;
5719 int i = 0;
5720
5721 while (devices != 0) {
5722 int device = 1 << i++;
5723 if ((device & devices) == 0) {
5724 continue;
5725 }
Eric Laurent42b041e2013-03-29 11:36:03 -07005726 int index = streamState.getIndex(device);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005727 if (index > mSafeMediaVolumeIndex) {
John Spurlock90874332015-03-10 16:00:54 -04005728 streamState.setIndex(mSafeMediaVolumeIndex, device, caller);
Eric Laurent42b041e2013-03-29 11:36:03 -07005729 sendMsg(mAudioHandler,
5730 MSG_SET_DEVICE_VOLUME,
5731 SENDMSG_QUEUE,
5732 device,
5733 0,
5734 streamState,
5735 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005736 }
5737 devices &= ~device;
5738 }
5739 }
5740
5741 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005742 synchronized (mSafeMediaVolumeState) {
5743 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07005744 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
5745 ((device & mSafeMediaVolumeDevices) != 0) &&
5746 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005747 return false;
5748 }
5749 return true;
5750 }
5751 }
5752
John Spurlock3346a802014-05-20 16:25:37 -04005753 @Override
John Spurlock90874332015-03-10 16:00:54 -04005754 public void disableSafeMediaVolume(String callingPackage) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005755 enforceVolumeController("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07005756 synchronized (mSafeMediaVolumeState) {
John Spurlock90874332015-03-10 16:00:54 -04005757 setSafeMediaVolumeEnabled(false, callingPackage);
Eric Laurentfde16d52012-12-03 14:42:39 -08005758 if (mPendingVolumeCommand != null) {
5759 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
5760 mPendingVolumeCommand.mIndex,
5761 mPendingVolumeCommand.mFlags,
John Spurlock90874332015-03-10 16:00:54 -04005762 mPendingVolumeCommand.mDevice,
5763 callingPackage);
Eric Laurentfde16d52012-12-03 14:42:39 -08005764 mPendingVolumeCommand = null;
5765 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005766 }
5767 }
5768
Jungshik Jang41d97462014-06-30 22:26:29 +09005769 //==========================================================================================
5770 // Hdmi Cec system audio mode.
John Spurlockbc82b122015-03-02 16:12:38 -05005771 // If Hdmi Cec's system audio mode is on, audio service should send the volume change
5772 // to HdmiControlService so that the audio receiver can handle it.
Jungshik Jang41d97462014-06-30 22:26:29 +09005773 //==========================================================================================
5774
Eric Laurent212532b2014-07-21 15:43:18 -07005775 private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
5776 public void onComplete(int status) {
5777 if (mHdmiManager != null) {
5778 synchronized (mHdmiManager) {
5779 mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
5780 // Television devices without CEC service apply software volume on HDMI output
5781 if (isPlatformTelevision() && !mHdmiCecSink) {
5782 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5783 }
5784 checkAllFixedVolumeDevices();
5785 }
5786 }
5787 }
5788 };
5789
Jungshik Jang41d97462014-06-30 22:26:29 +09005790 // If HDMI-CEC system audio is supported
5791 private boolean mHdmiSystemAudioSupported = false;
5792 // Set only when device is tv.
5793 private HdmiTvClient mHdmiTvClient;
Eric Laurent0b03f992014-11-18 18:08:02 -08005794 // true if the device has system feature PackageManager.FEATURE_LEANBACK.
Eric Laurent212532b2014-07-21 15:43:18 -07005795 // cached HdmiControlManager interface
5796 private HdmiControlManager mHdmiManager;
5797 // Set only when device is a set-top box.
5798 private HdmiPlaybackClient mHdmiPlaybackClient;
5799 // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5800 private boolean mHdmiCecSink;
5801
5802 private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
Jungshik Jang41d97462014-06-30 22:26:29 +09005803
5804 @Override
Jungshik Jang12307ca2014-07-15 19:27:56 +09005805 public int setHdmiSystemAudioSupported(boolean on) {
Eric Laurent212532b2014-07-21 15:43:18 -07005806 int device = AudioSystem.DEVICE_NONE;
5807 if (mHdmiManager != null) {
5808 synchronized (mHdmiManager) {
5809 if (mHdmiTvClient == null) {
5810 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5811 return device;
5812 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005813
Eric Laurent212532b2014-07-21 15:43:18 -07005814 synchronized (mHdmiTvClient) {
5815 if (mHdmiSystemAudioSupported != on) {
5816 mHdmiSystemAudioSupported = on;
5817 AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5818 on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5819 AudioSystem.FORCE_NONE);
5820 }
John Spurlock8a52c442015-03-26 14:23:58 -04005821 device = getDevicesForStream(AudioSystem.STREAM_MUSIC);
Eric Laurent212532b2014-07-21 15:43:18 -07005822 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005823 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005824 }
Eric Laurent212532b2014-07-21 15:43:18 -07005825 return device;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005826 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005827
Terry Heoe7d6d972014-09-04 21:05:28 +09005828 @Override
5829 public boolean isHdmiSystemAudioSupported() {
5830 return mHdmiSystemAudioSupported;
5831 }
5832
Eric Laurentdd45d012012-10-08 09:04:34 -07005833 //==========================================================================================
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005834 // Accessibility: taking touch exploration into account for selecting the default
5835 // stream override timeout when adjusting volume
5836 //==========================================================================================
5837 private static class StreamOverride
5838 implements AccessibilityManager.TouchExplorationStateChangeListener {
5839
5840 // AudioService.getActiveStreamType() will return:
5841 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
5842 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
5843 // stopped
Jean-Michel Triviccffda82015-05-21 18:23:57 -07005844 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 0;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005845 private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
5846
5847 static int sDelayMs;
5848
5849 static void init(Context ctxt) {
5850 AccessibilityManager accessibilityManager =
5851 (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
5852 updateDefaultStreamOverrideDelay(
5853 accessibilityManager.isTouchExplorationEnabled());
5854 accessibilityManager.addTouchExplorationStateChangeListener(
5855 new StreamOverride());
5856 }
5857
5858 @Override
5859 public void onTouchExplorationStateChanged(boolean enabled) {
5860 updateDefaultStreamOverrideDelay(enabled);
5861 }
5862
5863 private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
5864 if (touchExploreEnabled) {
5865 sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
5866 } else {
5867 sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
5868 }
5869 if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
5870 + " stream override delay is now " + sDelayMs + " ms");
5871 }
5872 }
5873
5874 //==========================================================================================
Eric Laurentdd45d012012-10-08 09:04:34 -07005875 // Camera shutter sound policy.
5876 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5877 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5878 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5879 //==========================================================================================
5880
5881 // cached value of com.android.internal.R.bool.config_camera_sound_forced
5882 private Boolean mCameraSoundForced;
5883
5884 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5885 public boolean isCameraSoundForced() {
5886 synchronized (mCameraSoundForced) {
5887 return mCameraSoundForced;
5888 }
5889 }
5890
5891 private static final String[] RINGER_MODE_NAMES = new String[] {
5892 "SILENT",
5893 "VIBRATE",
5894 "NORMAL"
5895 };
5896
5897 private void dumpRingerMode(PrintWriter pw) {
5898 pw.println("\nRinger mode: ");
John Spurlock661f2cf2014-11-17 10:29:10 -05005899 pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
5900 pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
John Spurlock50ced3f2015-05-11 16:00:09 -04005901 dumpRingerModeStreams(pw, "affected", mRingerModeAffectedStreams);
5902 dumpRingerModeStreams(pw, "muted", mRingerModeMutedStreams);
John Spurlock661f2cf2014-11-17 10:29:10 -05005903 pw.print("- delegate = "); pw.println(mRingerModeDelegate);
Eric Laurentdd45d012012-10-08 09:04:34 -07005904 }
5905
John Spurlock50ced3f2015-05-11 16:00:09 -04005906 private void dumpRingerModeStreams(PrintWriter pw, String type, int streams) {
5907 pw.print("- ringer mode "); pw.print(type); pw.print(" streams = 0x");
5908 pw.print(Integer.toHexString(streams));
5909 if (streams != 0) {
5910 pw.print(" (");
5911 boolean first = true;
5912 for (int i = 0; i < AudioSystem.STREAM_NAMES.length; i++) {
5913 final int stream = (1 << i);
5914 if ((streams & stream) != 0) {
5915 if (!first) pw.print(',');
5916 pw.print(AudioSystem.STREAM_NAMES[i]);
5917 streams &= ~stream;
5918 first = false;
5919 }
5920 }
5921 if (streams != 0) {
5922 if (!first) pw.print(',');
5923 pw.print(streams);
5924 }
5925 pw.print(')');
5926 }
5927 pw.println();
5928 }
5929
Dianne Hackborn632ca412012-06-14 19:34:10 -07005930 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005931 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07005932 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5933
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005934 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07005935 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07005936 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005937 pw.println("\nAudio routes:");
John Spurlock61560172015-02-06 19:46:04 -05005938 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
5939 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
John Spurlock35134602014-07-24 18:10:48 -04005940
5941 pw.println("\nOther state:");
John Spurlock3346a802014-05-20 16:25:37 -04005942 pw.print(" mVolumeController="); pw.println(mVolumeController);
John Spurlock35134602014-07-24 18:10:48 -04005943 pw.print(" mSafeMediaVolumeState=");
5944 pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
5945 pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
5946 pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
5947 pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005948 pw.print(" mMcc="); pw.println(mMcc);
John Spurlock5e783732015-02-19 10:28:59 -05005949 pw.print(" mCameraSoundForced="); pw.println(mCameraSoundForced);
John Spurlock661f2cf2014-11-17 10:29:10 -05005950 pw.print(" mHasVibrator="); pw.println(mHasVibrator);
John Spurlockcdb57ae2015-02-11 19:04:11 -05005951 pw.print(" mControllerService="); pw.println(mControllerService);
John Spurlocka48d7792015-03-03 17:35:57 -05005952 pw.print(" mVolumePolicy="); pw.println(mVolumePolicy);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005953
5954 dumpAudioPolicies(pw);
John Spurlock35134602014-07-24 18:10:48 -04005955 }
5956
5957 private static String safeMediaVolumeStateToString(Integer state) {
5958 switch(state) {
5959 case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
5960 case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
5961 case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
5962 case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
5963 }
5964 return null;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005965 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07005966
5967 // Inform AudioFlinger of our device's low RAM attribute
5968 private static void readAndSetLowRamDevice()
5969 {
5970 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
5971 if (status != 0) {
5972 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
5973 }
5974 }
John Spurlock3346a802014-05-20 16:25:37 -04005975
John Spurlockcdb57ae2015-02-11 19:04:11 -05005976 private void enforceVolumeController(String action) {
5977 if (mControllerService.mUid != 0 && Binder.getCallingUid() == mControllerService.mUid) {
5978 return;
5979 }
John Spurlock3346a802014-05-20 16:25:37 -04005980 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
5981 "Only SystemUI can " + action);
5982 }
5983
5984 @Override
5985 public void setVolumeController(final IVolumeController controller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005986 enforceVolumeController("set the volume controller");
John Spurlock3346a802014-05-20 16:25:37 -04005987
5988 // return early if things are not actually changing
5989 if (mVolumeController.isSameBinder(controller)) {
5990 return;
5991 }
5992
5993 // dismiss the old volume controller
5994 mVolumeController.postDismiss();
5995 if (controller != null) {
5996 // we are about to register a new controller, listen for its death
5997 try {
5998 controller.asBinder().linkToDeath(new DeathRecipient() {
5999 @Override
6000 public void binderDied() {
6001 if (mVolumeController.isSameBinder(controller)) {
6002 Log.w(TAG, "Current remote volume controller died, unregistering");
6003 setVolumeController(null);
6004 }
6005 }
6006 }, 0);
6007 } catch (RemoteException e) {
6008 // noop
6009 }
6010 }
6011 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04006012 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
6013 }
6014
6015 @Override
6016 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05006017 enforceVolumeController("notify about volume controller visibility");
John Spurlock33f4e042014-07-11 13:10:58 -04006018
6019 // return early if the controller is not current
6020 if (!mVolumeController.isSameBinder(controller)) {
6021 return;
6022 }
6023
6024 mVolumeController.setVisible(visible);
6025 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04006026 }
RoboErikd09bd0c2014-06-24 17:45:19 -07006027
John Spurlocka48d7792015-03-03 17:35:57 -05006028 @Override
6029 public void setVolumePolicy(VolumePolicy policy) {
6030 enforceVolumeController("set volume policy");
John Spurlockb02c7442015-04-14 09:32:25 -04006031 if (policy != null && !policy.equals(mVolumePolicy)) {
John Spurlocka48d7792015-03-03 17:35:57 -05006032 mVolumePolicy = policy;
John Spurlockb02c7442015-04-14 09:32:25 -04006033 if (DEBUG_VOL) Log.d(TAG, "Volume policy changed: " + mVolumePolicy);
John Spurlocka48d7792015-03-03 17:35:57 -05006034 }
6035 }
6036
RoboErikd09bd0c2014-06-24 17:45:19 -07006037 public static class VolumeController {
6038 private static final String TAG = "VolumeController";
6039
6040 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04006041 private boolean mVisible;
6042 private long mNextLongPress;
6043 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07006044
6045 public void setController(IVolumeController controller) {
6046 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04006047 mVisible = false;
6048 }
6049
6050 public void loadSettings(ContentResolver cr) {
6051 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
6052 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
6053 }
6054
RoboErik4197cb62015-01-21 15:45:32 -08006055 public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
6056 if (isMute) {
6057 return false;
6058 }
John Spurlock33f4e042014-07-11 13:10:58 -04006059 boolean suppress = false;
6060 if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
6061 final long now = SystemClock.uptimeMillis();
6062 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
6063 // ui will become visible
6064 if (mNextLongPress < now) {
6065 mNextLongPress = now + mLongPressTimeout;
6066 }
6067 suppress = true;
6068 } else if (mNextLongPress > 0) { // in a long-press
6069 if (now > mNextLongPress) {
6070 // long press triggered, no more suppression
6071 mNextLongPress = 0;
6072 } else {
6073 // keep suppressing until the long press triggers
6074 suppress = true;
6075 }
6076 }
6077 }
6078 return suppress;
6079 }
6080
6081 public void setVisible(boolean visible) {
6082 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07006083 }
6084
6085 public boolean isSameBinder(IVolumeController controller) {
6086 return Objects.equals(asBinder(), binder(controller));
6087 }
6088
6089 public IBinder asBinder() {
6090 return binder(mController);
6091 }
6092
6093 private static IBinder binder(IVolumeController controller) {
6094 return controller == null ? null : controller.asBinder();
6095 }
6096
6097 @Override
6098 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04006099 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07006100 }
6101
6102 public void postDisplaySafeVolumeWarning(int flags) {
6103 if (mController == null)
6104 return;
6105 try {
6106 mController.displaySafeVolumeWarning(flags);
6107 } catch (RemoteException e) {
6108 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
6109 }
6110 }
6111
6112 public void postVolumeChanged(int streamType, int flags) {
6113 if (mController == null)
6114 return;
6115 try {
6116 mController.volumeChanged(streamType, flags);
6117 } catch (RemoteException e) {
6118 Log.w(TAG, "Error calling volumeChanged", e);
6119 }
6120 }
6121
RoboErikd09bd0c2014-06-24 17:45:19 -07006122 public void postMasterMuteChanged(int flags) {
6123 if (mController == null)
6124 return;
6125 try {
6126 mController.masterMuteChanged(flags);
6127 } catch (RemoteException e) {
6128 Log.w(TAG, "Error calling masterMuteChanged", e);
6129 }
6130 }
6131
6132 public void setLayoutDirection(int layoutDirection) {
6133 if (mController == null)
6134 return;
6135 try {
6136 mController.setLayoutDirection(layoutDirection);
6137 } catch (RemoteException e) {
6138 Log.w(TAG, "Error calling setLayoutDirection", e);
6139 }
6140 }
6141
6142 public void postDismiss() {
6143 if (mController == null)
6144 return;
6145 try {
6146 mController.dismiss();
6147 } catch (RemoteException e) {
6148 Log.w(TAG, "Error calling dismiss", e);
6149 }
6150 }
6151 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006152
RoboErik0dac35a2014-08-12 15:48:49 -07006153 /**
6154 * Interface for system components to get some extra functionality through
6155 * LocalServices.
6156 */
6157 final class AudioServiceInternal extends AudioManagerInternal {
John Spurlock661f2cf2014-11-17 10:29:10 -05006158 @Override
6159 public void setRingerModeDelegate(RingerModeDelegate delegate) {
6160 mRingerModeDelegate = delegate;
6161 if (mRingerModeDelegate != null) {
John Spurlock50ced3f2015-05-11 16:00:09 -04006162 updateRingerModeAffectedStreams();
John Spurlock661f2cf2014-11-17 10:29:10 -05006163 setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
6164 }
6165 }
RoboErik272e1612014-09-05 11:39:29 -07006166
6167 @Override
6168 public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
6169 String callingPackage, int uid) {
6170 // direction and stream type swap here because the public
6171 // adjustSuggested has a different order than the other methods.
John Spurlock90874332015-03-10 16:00:54 -04006172 adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage,
6173 callingPackage, uid);
RoboErik272e1612014-09-05 11:39:29 -07006174 }
6175
RoboErik0dac35a2014-08-12 15:48:49 -07006176 @Override
6177 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
6178 String callingPackage, int uid) {
John Spurlock90874332015-03-10 16:00:54 -04006179 adjustStreamVolume(streamType, direction, flags, callingPackage,
6180 callingPackage, uid);
RoboErik0dac35a2014-08-12 15:48:49 -07006181 }
6182
6183 @Override
6184 public void setStreamVolumeForUid(int streamType, int direction, int flags,
6185 String callingPackage, int uid) {
John Spurlock90874332015-03-10 16:00:54 -04006186 setStreamVolume(streamType, direction, flags, callingPackage, callingPackage, uid);
RoboErik0dac35a2014-08-12 15:48:49 -07006187 }
RoboErik519c7742014-11-18 10:59:09 -08006188
6189 @Override
John Spurlock661f2cf2014-11-17 10:29:10 -05006190 public int getRingerModeInternal() {
6191 return AudioService.this.getRingerModeInternal();
6192 }
6193
6194 @Override
6195 public void setRingerModeInternal(int ringerMode, String caller) {
6196 AudioService.this.setRingerModeInternal(ringerMode, caller);
6197 }
John Spurlockcdb57ae2015-02-11 19:04:11 -05006198
6199 @Override
6200 public int getVolumeControllerUid() {
6201 return mControllerService.mUid;
6202 }
John Spurlock50ced3f2015-05-11 16:00:09 -04006203
6204 @Override
6205 public void updateRingerModeAffectedStreamsInternal() {
6206 synchronized (mSettingsLock) {
6207 if (updateRingerModeAffectedStreams()) {
6208 setRingerModeInt(getRingerModeInternal(), false);
6209 }
6210 }
6211 }
RoboErik0dac35a2014-08-12 15:48:49 -07006212 }
6213
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006214 //==========================================================================================
6215 // Audio policy management
6216 //==========================================================================================
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006217 public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
6218 boolean hasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006219 AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
6220
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006221 if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
6222 + " with config:" + policyConfig);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006223 String regId = null;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006224 // error handling
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006225 boolean hasPermissionForPolicy =
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006226 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006227 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
6228 if (!hasPermissionForPolicy) {
6229 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
6230 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006231 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006232 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006233
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006234 synchronized (mAudioPolicies) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006235 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006236 if (mAudioPolicies.containsKey(pcb.asBinder())) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006237 Slog.e(TAG, "Cannot re-register policy");
6238 return null;
6239 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006240 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
6241 pcb.asBinder().linkToDeath(app, 0/*flags*/);
6242 regId = app.getRegistrationId();
6243 mAudioPolicies.put(pcb.asBinder(), app);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006244 } catch (RemoteException e) {
6245 // audio policy owner has already died!
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006246 Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006247 " binder death", e);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006248 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006249 }
6250 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006251 return regId;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006252 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006253
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006254 public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
6255 if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006256 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006257 AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006258 if (app == null) {
6259 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
6260 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006261 return;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006262 } else {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006263 pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006264 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006265 app.release();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006266 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006267 // TODO implement clearing mix attribute matching info in native audio policy
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006268 }
6269
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006270 public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
6271 if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
6272 + " policy " + pcb.asBinder());
6273 // error handling
6274 boolean hasPermissionForPolicy =
6275 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
6276 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
6277 if (!hasPermissionForPolicy) {
6278 Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
6279 + Binder.getCallingPid() + " / uid "
6280 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
6281 return AudioManager.ERROR;
6282 }
6283
6284 synchronized (mAudioPolicies) {
6285 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
6286 Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
6287 return AudioManager.ERROR;
6288 }
6289 final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
6290 if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6291 // is there already one policy managing ducking?
Eric Laurent0867bed2015-05-20 14:49:08 -07006292 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006293 if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6294 Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
6295 return AudioManager.ERROR;
6296 }
6297 }
6298 }
6299 app.mFocusDuckBehavior = duckingBehavior;
6300 mMediaFocusControl.setDuckingInExtPolicyAvailable(
6301 duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
6302 }
6303 return AudioManager.SUCCESS;
6304 }
6305
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006306 private void dumpAudioPolicies(PrintWriter pw) {
6307 pw.println("\nAudio policies:");
6308 synchronized (mAudioPolicies) {
Eric Laurent0867bed2015-05-20 14:49:08 -07006309 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006310 pw.println(policy.toLogFriendlyString());
6311 }
6312 }
6313 }
6314
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006315 //======================
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08006316 // Audio policy callbacks from AudioSystem for dynamic policies
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006317 //======================
6318 private final AudioSystem.DynamicPolicyCallback mDynPolicyCallback =
6319 new AudioSystem.DynamicPolicyCallback() {
6320 public void onDynamicPolicyMixStateUpdate(String regId, int state) {
6321 if (!TextUtils.isEmpty(regId)) {
6322 sendMsg(mAudioHandler, MSG_DYN_POLICY_MIX_STATE_UPDATE, SENDMSG_QUEUE,
6323 state /*arg1*/, 0 /*arg2 ignored*/, regId /*obj*/, 0 /*delay*/);
6324 }
6325 }
6326 };
6327
6328 private void onDynPolicyMixStateUpdate(String regId, int state) {
6329 if (DEBUG_AP) Log.d(TAG, "onDynamicPolicyMixStateUpdate("+ regId + ", " + state +")");
6330 synchronized (mAudioPolicies) {
6331 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
6332 for (AudioMix mix : policy.getMixes()) {
6333 if (mix.getRegistration().equals(regId)) {
6334 try {
6335 policy.mPolicyCallback.notifyMixStateUpdate(regId, state);
6336 } catch (RemoteException e) {
6337 Log.e(TAG, "Can't call notifyMixStateUpdate() on IAudioPolicyCallback "
6338 + policy.mPolicyCallback.asBinder(), e);
6339 }
6340 return;
6341 }
6342 }
6343 }
6344 }
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08006345 }
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006346
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08006347 //======================
6348 // Audio policy callbacks from AudioSystem for recording configuration updates
6349 //======================
6350 private final RecordingActivityMonitor mRecordMonitor = new RecordingActivityMonitor();
6351
6352 public void registerRecordingCallback(IRecordingConfigDispatcher rcdb) {
6353 mRecordMonitor.registerRecordingCallback(rcdb);
6354 }
6355
6356 public void unregisterRecordingCallback(IRecordingConfigDispatcher rcdb) {
6357 mRecordMonitor.unregisterRecordingCallback(rcdb);
6358 }
6359
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07006360 public List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08006361 return mRecordMonitor.getActiveRecordingConfigurations();
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006362 }
6363
6364 //======================
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006365 // Audio policy proxy
6366 //======================
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006367 /**
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006368 * This internal class inherits from AudioPolicyConfig, each instance contains all the
6369 * mixes of an AudioPolicy and their configurations.
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006370 */
6371 public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006372 private static final String TAG = "AudioPolicyProxy";
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006373 IAudioPolicyCallback mPolicyCallback;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006374 boolean mHasFocusListener;
6375 /**
6376 * Audio focus ducking behavior for an audio policy.
6377 * This variable reflects the value that was successfully set in
6378 * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
6379 * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
6380 * is handling ducking for audio focus.
6381 */
6382 int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
6383
6384 AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
6385 boolean hasFocusListener) {
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006386 super(config);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006387 setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006388 mPolicyCallback = token;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006389 mHasFocusListener = hasFocusListener;
6390 if (mHasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006391 mMediaFocusControl.addFocusFollower(mPolicyCallback);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006392 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006393 connectMixes();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006394 }
6395
6396 public void binderDied() {
6397 synchronized (mAudioPolicies) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006398 Log.i(TAG, "audio policy " + mPolicyCallback + " died");
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006399 release();
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006400 mAudioPolicies.remove(mPolicyCallback.asBinder());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006401 }
6402 }
6403
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006404 String getRegistrationId() {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006405 return getRegistration();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006406 }
6407
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006408 void release() {
6409 if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6410 mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
6411 }
6412 if (mHasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006413 mMediaFocusControl.removeFocusFollower(mPolicyCallback);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006414 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006415 AudioSystem.registerPolicyMixes(mMixes, false);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006416 }
6417
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006418 void connectMixes() {
6419 AudioSystem.registerPolicyMixes(mMixes, true);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006420 }
6421 };
6422
6423 private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
6424 new HashMap<IBinder, AudioPolicyProxy>();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006425 private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
John Spurlockcdb57ae2015-02-11 19:04:11 -05006426
6427 private class ControllerService extends ContentObserver {
6428 private int mUid;
6429 private ComponentName mComponent;
6430
6431 public ControllerService() {
6432 super(null);
6433 }
6434
6435 @Override
6436 public String toString() {
6437 return String.format("{mUid=%d,mComponent=%s}", mUid, mComponent);
6438 }
6439
6440 public void init() {
6441 onChange(true);
6442 mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
6443 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT), false, this);
6444 }
6445
6446 @Override
6447 public void onChange(boolean selfChange) {
6448 mUid = 0;
6449 mComponent = null;
6450 final String setting = Settings.Secure.getString(mContentResolver,
6451 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
6452 if (setting == null) return;
6453 try {
6454 mComponent = ComponentName.unflattenFromString(setting);
6455 if (mComponent == null) return;
6456 mUid = mContext.getPackageManager()
6457 .getApplicationInfo(mComponent.getPackageName(), 0).uid;
6458 } catch (Exception e) {
6459 Log.w(TAG, "Error loading controller service", e);
6460 }
6461 if (DEBUG_VOL) Log.d(TAG, "Reloaded controller service: " + this);
6462 }
6463 }
Phil Burkac0f7042016-02-24 12:19:08 -08006464}