blob: 5a3639a972fcedaf96a080af7501edce5b8153bc [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;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070031import android.bluetooth.BluetoothA2dp;
32import android.bluetooth.BluetoothAdapter;
33import android.bluetooth.BluetoothClass;
34import android.bluetooth.BluetoothDevice;
35import android.bluetooth.BluetoothHeadset;
36import android.bluetooth.BluetoothProfile;
Nick Pellybd022f42009-08-14 18:33:38 -070037import android.content.BroadcastReceiver;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070038import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.content.ContentResolver;
40import android.content.Context;
41import android.content.Intent;
Eric Laurenta553c252009-07-17 12:17:14 -070042import android.content.IntentFilter;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070043import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.content.pm.PackageManager;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070045import android.content.pm.UserInfo;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -070046import android.content.res.Configuration;
Eric Laurente78fced2013-03-15 16:03:47 -070047import android.content.res.Resources;
48import android.content.res.XmlResourceParser;
Jason Parekhb1096152009-03-24 17:48:25 -070049import android.database.ContentObserver;
Jungshik Jang41d97462014-06-30 22:26:29 +090050import android.hardware.hdmi.HdmiControlManager;
Eric Laurent212532b2014-07-21 15:43:18 -070051import android.hardware.hdmi.HdmiPlaybackClient;
Jungshik Jang41d97462014-06-30 22:26:29 +090052import android.hardware.hdmi.HdmiTvClient;
Paul McLeanc837a452014-04-09 09:04:43 -070053import android.hardware.usb.UsbManager;
John Spurlock61560172015-02-06 19:46:04 -050054import android.media.AudioAttributes;
55import android.media.AudioDevicePort;
56import android.media.AudioSystem;
57import android.media.AudioFormat;
58import android.media.AudioManager;
59import android.media.AudioManagerInternal;
60import android.media.AudioPort;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -080061import android.media.AudioRecordConfiguration;
John Spurlock61560172015-02-06 19:46:04 -050062import android.media.AudioRoutesInfo;
John Spurlock61560172015-02-06 19:46:04 -050063import android.media.IAudioFocusDispatcher;
64import android.media.IAudioRoutesObserver;
65import android.media.IAudioService;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -080066import android.media.IRecordingConfigDispatcher;
John Spurlock61560172015-02-06 19:46:04 -050067import android.media.IRingtonePlayer;
68import android.media.IVolumeController;
69import android.media.MediaPlayer;
70import android.media.SoundPool;
John Spurlocka48d7792015-03-03 17:35:57 -050071import android.media.VolumePolicy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.media.MediaPlayer.OnCompletionListener;
73import android.media.MediaPlayer.OnErrorListener;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -070074import android.media.audiopolicy.AudioMix;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -080075import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070076import android.media.audiopolicy.AudioPolicyConfig;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -080077import android.media.audiopolicy.IAudioPolicyCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078import android.os.Binder;
Eric Laurentc18c9132013-04-12 17:24:56 -070079import android.os.Build;
Makoto Onukid45a4a22015-11-02 17:17:38 -080080import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081import android.os.Environment;
82import android.os.Handler;
83import android.os.IBinder;
84import android.os.Looper;
85import android.os.Message;
Jean-Michel Trivic6802222012-04-30 11:15:03 -070086import android.os.PowerManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070087import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088import android.os.RemoteException;
John Spurlock33f4e042014-07-11 13:10:58 -040089import android.os.SystemClock;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070090import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070091import android.os.UserHandle;
Fyodor Kupolovb5013302015-04-17 17:59:14 -070092import android.os.UserManager;
Makoto Onukid45a4a22015-11-02 17:17:38 -080093import android.os.UserManagerInternal;
94import android.os.UserManagerInternal.UserRestrictionsListener;
Eric Laurentbffc3d12012-05-07 17:43:49 -070095import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096import android.provider.Settings;
97import android.provider.Settings.System;
Tyler Gunnef9f6f92014-09-12 22:16:17 -070098import android.telecom.TelecomManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070099import android.text.TextUtils;
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700100import android.util.AndroidRuntimeException;
John Spurlock8c3dc852015-04-23 21:32:37 -0400101import android.util.ArrayMap;
102import android.util.ArraySet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103import android.util.Log;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400104import android.util.MathUtils;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -0700105import android.util.Slog;
John Spurlock2bb02ec2015-03-02 13:13:06 -0500106import android.util.SparseIntArray;
Jean-Michel Trivid327f212010-03-16 21:44:33 -0700107import android.view.KeyEvent;
RoboErik519c7742014-11-18 10:59:09 -0800108import android.view.OrientationEventListener;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700109import android.view.Surface;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700110import android.view.WindowManager;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700111import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112
Eric Laurente78fced2013-03-15 16:03:47 -0700113import com.android.internal.util.XmlUtils;
John Spurlock90874332015-03-10 16:00:54 -0400114import com.android.server.EventLogTags;
RoboErik0dac35a2014-08-12 15:48:49 -0700115import com.android.server.LocalServices;
Makoto Onukie1aef852015-10-15 17:28:35 -0700116import com.android.server.SystemService;
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700117import com.android.server.pm.UserManagerService;
Eric Laurente78fced2013-03-15 16:03:47 -0700118
119import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800121import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122import java.io.IOException;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800123import java.io.PrintWriter;
Eric Laurente78fced2013-03-15 16:03:47 -0700124import java.lang.reflect.Field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125import java.util.ArrayList;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700126import java.util.HashMap;
127import java.util.Iterator;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -0700128import java.util.List;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700129import java.util.NoSuchElementException;
RoboErikd09bd0c2014-06-24 17:45:19 -0700130import java.util.Objects;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131
132/**
133 * The implementation of the volume manager service.
134 * <p>
135 * This implementation focuses on delivering a responsive UI. Most methods are
136 * asynchronous to external calls. For example, the task of setting a volume
137 * will update our internal state, but in a separate thread will set the system
138 * volume and later persist to the database. Similarly, setting the ringer mode
139 * will update the state and broadcast a change and in a separate thread later
140 * persist the ringer mode.
141 *
142 * @hide
143 */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700144public class AudioService extends IAudioService.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145
146 private static final String TAG = "AudioService";
147
Jean-Michel Trivi339567d2014-07-29 09:53:34 -0700148 /** Debug audio mode */
149 protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -0700150
151 /** Debug audio policy feature */
152 protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);
153
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700154 /** Debug volumes */
John Spurlockae641c92014-06-30 18:11:40 -0400155 protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700156
Paul McLean394a8e12015-03-03 10:29:19 -0700157 /** debug calls to devices APIs */
158 protected static final boolean DEBUG_DEVICES = Log.isLoggable(TAG + ".DEVICES", Log.DEBUG);
159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 /** How long to delay before persisting a change in volume/ringer mode. */
RoboErik45edba12012-03-27 17:54:36 -0700161 private static final int PERSIST_DELAY = 500;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162
RoboErik5452e252015-02-06 15:33:53 -0800163 /** How long to delay after a volume down event before unmuting a stream */
164 private static final int UNMUTE_STREAM_DELAY = 350;
165
John Spurlock3346a802014-05-20 16:25:37 -0400166 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400167 * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
168 */
169 private static final int FLAG_ADJUST_VOLUME = 1;
170
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700171 private final Context mContext;
172 private final ContentResolver mContentResolver;
173 private final AppOpsManager mAppOps;
Eric Laurent212532b2014-07-21 15:43:18 -0700174
Eric Laurent212532b2014-07-21 15:43:18 -0700175 // the platform type affects volume and silent mode behavior
176 private final int mPlatformType;
177
178 private boolean isPlatformVoice() {
John Spurlock61560172015-02-06 19:46:04 -0500179 return mPlatformType == AudioSystem.PLATFORM_VOICE;
Eric Laurent212532b2014-07-21 15:43:18 -0700180 }
181
182 private boolean isPlatformTelevision() {
John Spurlock61560172015-02-06 19:46:04 -0500183 return mPlatformType == AudioSystem.PLATFORM_TELEVISION;
Eric Laurent212532b2014-07-21 15:43:18 -0700184 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800185
John Spurlock3346a802014-05-20 16:25:37 -0400186 /** The controller for the volume UI. */
187 private final VolumeController mVolumeController = new VolumeController();
John Spurlockcdb57ae2015-02-11 19:04:11 -0500188 private final ControllerService mControllerService = new ControllerService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189
190 // sendMsg() flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 /** If the msg is already queued, replace it with this one. */
192 private static final int SENDMSG_REPLACE = 0;
193 /** If the msg is already queued, ignore this one and leave the old. */
194 private static final int SENDMSG_NOOP = 1;
195 /** If the msg is already queued, queue this one and leave the old. */
196 private static final int SENDMSG_QUEUE = 2;
197
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700198 // AudioHandler messages
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800199 private static final int MSG_SET_DEVICE_VOLUME = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 private static final int MSG_PERSIST_VOLUME = 1;
201 private static final int MSG_PERSIST_RINGER_MODE = 3;
Andy Hunged0ea402015-10-30 14:11:46 -0700202 private static final int MSG_AUDIO_SERVER_DIED = 4;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700203 private static final int MSG_PLAY_SOUND_EFFECT = 5;
204 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
205 private static final int MSG_LOAD_SOUND_EFFECTS = 7;
206 private static final int MSG_SET_FORCE_USE = 8;
207 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
208 private static final int MSG_SET_ALL_VOLUMES = 10;
209 private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
210 private static final int MSG_REPORT_NEW_ROUTES = 12;
211 private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
212 private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
213 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
214 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
215 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
216 private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
217 private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
218 private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700219 private static final int MSG_SYSTEM_READY = 21;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400220 private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
Julia Reynoldsb53453f2014-08-22 11:42:43 -0400221 private static final int MSG_PERSIST_MICROPHONE_MUTE = 23;
RoboErik5452e252015-02-06 15:33:53 -0800222 private static final int MSG_UNMUTE_STREAM = 24;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -0700223 private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 25;
Eric Laurent0867bed2015-05-20 14:49:08 -0700224 private static final int MSG_INDICATE_SYSTEM_READY = 26;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700225 // start of messages handled under wakelock
226 // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
Jean-Michel Trivie12c39b2012-06-06 10:51:58 -0700227 // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700228 private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
Mike Lockwood0a40ec22014-05-21 10:08:50 -0700229 private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
230 private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700231 // end of messages handled under wakelock
Eric Laurentafbb0472011-12-15 09:04:23 -0800232
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -0700233 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
Eric Laurentdc03c612011-04-01 10:59:41 -0700234 // Timeout for connection to bluetooth headset service
235 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
236
Eric Laurent0867bed2015-05-20 14:49:08 -0700237 // retry delay in case of failure to indicate system ready to AudioFlinger
238 private static final int INDICATE_SYSTEM_READY_RETRY_DELAY_MS = 1000;
239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 /** @see AudioSystemThread */
241 private AudioSystemThread mAudioSystemThread;
242 /** @see AudioHandler */
243 private AudioHandler mAudioHandler;
244 /** @see VolumeStreamState */
245 private VolumeStreamState[] mStreamStates;
Jason Parekhb1096152009-03-24 17:48:25 -0700246 private SettingsObserver mSettingsObserver;
Eric Laurenta553c252009-07-17 12:17:14 -0700247
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700248 private int mMode = AudioSystem.MODE_NORMAL;
Glenn Kastenba195eb2011-12-13 09:30:40 -0800249 // protects mRingerMode
250 private final Object mSettingsLock = new Object();
Eric Laurent45c90ce2012-04-24 18:44:22 -0700251
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252 private SoundPool mSoundPool;
Glenn Kasten30c918c2011-11-10 17:56:41 -0800253 private final Object mSoundEffectsLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254 private static final int NUM_SOUNDPOOL_CHANNELS = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255
256 /* Sound effect file names */
257 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
Eric Laurente78fced2013-03-15 16:03:47 -0700258 private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259
260 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
261 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
262 * uses soundpool (second column) */
Eric Laurente78fced2013-03-15 16:03:47 -0700263 private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264
John Spurlockb6e19e32015-03-10 21:33:44 -0400265 /** Maximum volume index values for audio streams */
Eric Laurent91377de2014-10-10 15:24:04 -0700266 private static int[] MAX_STREAM_VOLUME = new int[] {
Eric Laurent6ee99522009-08-25 06:30:59 -0700267 5, // STREAM_VOICE_CALL
268 7, // STREAM_SYSTEM
269 7, // STREAM_RING
270 15, // STREAM_MUSIC
271 7, // STREAM_ALARM
272 7, // STREAM_NOTIFICATION
273 15, // STREAM_BLUETOOTH_SCO
274 7, // STREAM_SYSTEM_ENFORCED
275 15, // STREAM_DTMF
276 15 // STREAM_TTS
Jared Suttles59820132009-08-13 21:50:52 -0500277 };
Eric Laurent91377de2014-10-10 15:24:04 -0700278
John Spurlockb6e19e32015-03-10 21:33:44 -0400279 /** Minimum volume index values for audio streams */
280 private static int[] MIN_STREAM_VOLUME = new int[] {
281 1, // STREAM_VOICE_CALL
282 0, // STREAM_SYSTEM
283 0, // STREAM_RING
284 0, // STREAM_MUSIC
285 0, // STREAM_ALARM
286 0, // STREAM_NOTIFICATION
Eric Laurente4381ec2015-10-29 17:52:48 -0700287 0, // STREAM_BLUETOOTH_SCO
John Spurlockb6e19e32015-03-10 21:33:44 -0400288 0, // STREAM_SYSTEM_ENFORCED
289 0, // STREAM_DTMF
290 0 // STREAM_TTS
291 };
292
Eric Laurent6d517662012-04-23 18:42:39 -0700293 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
Eric Laurenta553c252009-07-17 12:17:14 -0700294 * of another stream: This avoids multiplying the volume settings for hidden
295 * stream types that follow other stream behavior for volume settings
Eric Laurent6d517662012-04-23 18:42:39 -0700296 * NOTE: do not create loops in aliases!
297 * Some streams alias to different streams according to device category (phone or tablet) or
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700298 * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
Eric Laurent212532b2014-07-21 15:43:18 -0700299 * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
300 * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
301 * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
302 private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700303 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
304 AudioSystem.STREAM_RING, // STREAM_SYSTEM
305 AudioSystem.STREAM_RING, // STREAM_RING
306 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
307 AudioSystem.STREAM_ALARM, // STREAM_ALARM
308 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
309 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
310 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
311 AudioSystem.STREAM_RING, // STREAM_DTMF
312 AudioSystem.STREAM_MUSIC // STREAM_TTS
Eric Laurenta553c252009-07-17 12:17:14 -0700313 };
Eric Laurent212532b2014-07-21 15:43:18 -0700314 private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
315 AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL
316 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
317 AudioSystem.STREAM_MUSIC, // STREAM_RING
318 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
319 AudioSystem.STREAM_MUSIC, // STREAM_ALARM
320 AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
321 AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO
322 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
323 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
324 AudioSystem.STREAM_MUSIC // STREAM_TTS
325 };
326 private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700327 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
John Spurlock4f0f1202014-08-05 13:28:33 -0400328 AudioSystem.STREAM_RING, // STREAM_SYSTEM
Eric Laurent6d517662012-04-23 18:42:39 -0700329 AudioSystem.STREAM_RING, // STREAM_RING
330 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
331 AudioSystem.STREAM_ALARM, // STREAM_ALARM
332 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
333 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
John Spurlock4f0f1202014-08-05 13:28:33 -0400334 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
335 AudioSystem.STREAM_RING, // STREAM_DTMF
Eric Laurent6d517662012-04-23 18:42:39 -0700336 AudioSystem.STREAM_MUSIC // STREAM_TTS
337 };
338 private int[] mStreamVolumeAlias;
Eric Laurenta553c252009-07-17 12:17:14 -0700339
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700340 /**
341 * Map AudioSystem.STREAM_* constants to app ops. This should be used
342 * after mapping through mStreamVolumeAlias.
343 */
John Spurlock59dc9c12015-03-02 11:20:15 -0500344 private static final int[] STREAM_VOLUME_OPS = new int[] {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700345 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL
346 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM
347 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING
348 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC
349 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM
350 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION
351 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO
352 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED
353 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF
354 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS
355 };
356
Eric Laurent83a017b2013-03-19 18:15:31 -0700357 private final boolean mUseFixedVolume;
358
Glenn Kasten30c918c2011-11-10 17:56:41 -0800359 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 public void onError(int error) {
361 switch (error) {
362 case AudioSystem.AUDIO_STATUS_SERVER_DIED:
Andy Hunged0ea402015-10-30 14:11:46 -0700363 sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED,
Eric Laurentdfb881f2013-07-18 14:41:39 -0700364 SENDMSG_NOOP, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 break;
366 default:
367 break;
368 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700369 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 };
371
372 /**
373 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
374 * {@link AudioManager#RINGER_MODE_SILENT}, or
375 * {@link AudioManager#RINGER_MODE_VIBRATE}.
376 */
Glenn Kastenba195eb2011-12-13 09:30:40 -0800377 // protected by mSettingsLock
John Spurlock661f2cf2014-11-17 10:29:10 -0500378 private int mRingerMode; // internal ringer mode, affects muting of underlying streams
379 private int mRingerModeExternal = -1; // reported ringer mode to outside clients (AudioManager)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380
Eric Laurent9bcf4012009-06-12 06:09:28 -0700381 /** @see System#MODE_RINGER_STREAMS_AFFECTED */
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700382 private int mRingerModeAffectedStreams = 0;
Eric Laurent9bcf4012009-06-12 06:09:28 -0700383
Eric Laurent5b4e6542010-03-19 20:02:21 -0700384 // Streams currently muted by ringer mode
385 private int mRingerModeMutedStreams;
386
John Spurlock3ce37252015-02-17 13:20:45 -0500387 /** Streams that can be muted. Do not resolve to aliases when checking.
388 * @see System#MUTE_STREAMS_AFFECTED */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 private int mMuteAffectedStreams;
390
391 /**
Eric Laurentbffc3d12012-05-07 17:43:49 -0700392 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
393 * mVibrateSetting is just maintained during deprecation period but vibration policy is
394 * now only controlled by mHasVibrator and mRingerMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 */
396 private int mVibrateSetting;
397
Eric Laurentbffc3d12012-05-07 17:43:49 -0700398 // Is there a vibrator
399 private final boolean mHasVibrator;
400
Eric Laurenta553c252009-07-17 12:17:14 -0700401 // Broadcast receiver for device connections intent broadcasts
402 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
403
Makoto Onukid45a4a22015-11-02 17:17:38 -0800404 /** Interface for UserManagerService. */
405 private final UserManagerInternal mUserManagerInternal;
406
407 private final UserRestrictionsListener mUserRestrictionsListener =
408 new AudioServiceUserRestrictionsListener();
409
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700410 // Devices currently connected
Paul McLean394a8e12015-03-03 10:29:19 -0700411 // Use makeDeviceListKey() to make a unique key for this list.
412 private class DeviceListSpec {
413 int mDeviceType;
414 String mDeviceName;
415 String mDeviceAddress;
416
417 public DeviceListSpec(int deviceType, String deviceName, String deviceAddress) {
418 mDeviceType = deviceType;
419 mDeviceName = deviceName;
420 mDeviceAddress = deviceAddress;
421 }
422
423 public String toString() {
424 return "[type:0x" + Integer.toHexString(mDeviceType) + " name:" + mDeviceName
425 + " address:" + mDeviceAddress + "]";
426 }
427 }
428
429 // Generate a unique key for the mConnectedDevices List by composing the device "type"
430 // and the "address" associated with a specific instance of that device type
431 private String makeDeviceListKey(int device, String deviceAddress) {
432 return "0x" + Integer.toHexString(device) + ":" + deviceAddress;
433 }
434
John Spurlock8c3dc852015-04-23 21:32:37 -0400435 private final ArrayMap<String, DeviceListSpec> mConnectedDevices = new ArrayMap<>();
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700436
437 // Forced device usage for communications
438 private int mForcedUseForComm;
439
Eric Laurent9272b4b2010-01-23 17:12:59 -0800440 // List of binder death handlers for setMode() client processes.
441 // The last process to have called setMode() is at the top of the list.
Glenn Kasten30c918c2011-11-10 17:56:41 -0800442 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
Eric Laurenteb14a782009-12-17 03:12:59 -0800443
Eric Laurent3def1ee2010-03-17 23:26:26 -0700444 // List of clients having issued a SCO start request
Glenn Kasten30c918c2011-11-10 17:56:41 -0800445 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
Eric Laurent3def1ee2010-03-17 23:26:26 -0700446
447 // BluetoothHeadset API to control SCO connection
448 private BluetoothHeadset mBluetoothHeadset;
449
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700450 // Bluetooth headset device
451 private BluetoothDevice mBluetoothHeadsetDevice;
Eric Laurent3def1ee2010-03-17 23:26:26 -0700452
Eric Laurent62ef7672010-11-24 10:58:32 -0800453 // Indicate if SCO audio connection is currently active and if the initiator is
454 // audio service (internal) or bluetooth headset (external)
455 private int mScoAudioState;
456 // SCO audio state is not active
457 private static final int SCO_STATE_INACTIVE = 0;
Eric Laurentdc03c612011-04-01 10:59:41 -0700458 // SCO audio activation request waiting for headset service to connect
459 private static final int SCO_STATE_ACTIVATE_REQ = 1;
Eric Laurent25fc29b2013-04-05 12:13:54 -0700460 // SCO audio state is active or starting due to a request from AudioManager API
Eric Laurentdc03c612011-04-01 10:59:41 -0700461 private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
462 // SCO audio deactivation request waiting for headset service to connect
463 private static final int SCO_STATE_DEACTIVATE_REQ = 5;
464
Eric Laurent62ef7672010-11-24 10:58:32 -0800465 // SCO audio state is active due to an action in BT handsfree (either voice recognition or
466 // in call audio)
467 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
Eric Laurentdc03c612011-04-01 10:59:41 -0700468 // Deactivation request for all SCO connections (initiated by audio mode change)
469 // waiting for headset service to connect
470 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
471
Eric Laurentc18c9132013-04-12 17:24:56 -0700472 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
473 // originated from an app targeting an API version before JB MR2 and raw audio after that.
474 private int mScoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -0700475 // SCO audio mode is undefined
476 private static final int SCO_MODE_UNDEFINED = -1;
Eric Laurentc18c9132013-04-12 17:24:56 -0700477 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
478 private static final int SCO_MODE_VIRTUAL_CALL = 0;
479 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
480 private static final int SCO_MODE_RAW = 1;
Liejun Taof4e51d82014-07-16 11:18:29 -0700481 // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
482 private static final int SCO_MODE_VR = 2;
483
484 private static final int SCO_MODE_MAX = 2;
Eric Laurentc18c9132013-04-12 17:24:56 -0700485
Eric Laurentdc03c612011-04-01 10:59:41 -0700486 // Current connection state indicated by bluetooth headset
487 private int mScoConnectionState;
Eric Laurent62ef7672010-11-24 10:58:32 -0800488
Eric Laurenta60e2122010-12-28 16:49:07 -0800489 // true if boot sequence has been completed
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700490 private boolean mSystemReady;
Yasuhiro Matsuda4ced7192015-07-10 22:08:44 +0900491 // true if Intent.ACTION_USER_SWITCHED has ever been received
492 private boolean mUserSwitchedReceived;
Eric Laurenta60e2122010-12-28 16:49:07 -0800493 // listener for SoundPool sample load completion indication
494 private SoundPoolCallback mSoundPoolCallBack;
495 // thread for SoundPool listener
496 private SoundPoolListenerThread mSoundPoolListenerThread;
497 // message looper for SoundPool listener
498 private Looper mSoundPoolLooper = null;
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700499 // volume applied to sound played with playSoundEffect()
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700500 private static int sSoundEffectVolumeDb;
Eric Laurent25101b02011-02-02 09:33:30 -0800501 // previous volume adjustment direction received by checkForRingerModeChange()
502 private int mPrevVolDirection = AudioManager.ADJUST_SAME;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700503 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
504 // is controlled by Vol keys.
505 private int mVolumeControlStream = -1;
506 private final Object mForceControlStreamLock = new Object();
507 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
508 // server process so in theory it is not necessary to monitor the client death.
509 // However it is good to be ready for future evolutions.
510 private ForceControlStreamClient mForceControlStreamClient = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700511 // Used to play ringtones outside system_server
512 private volatile IRingtonePlayer mRingtonePlayer;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800513
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700514 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
515
Eric Laurent78472112012-05-21 08:57:21 -0700516 // Request to override default use of A2DP for media.
517 private boolean mBluetoothA2dpEnabled;
518 private final Object mBluetoothA2dpEnabledLock = new Object();
519
Dianne Hackborn632ca412012-06-14 19:34:10 -0700520 // Monitoring of audio routes. Protected by mCurAudioRoutes.
521 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
522 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
523 = new RemoteCallbackList<IAudioRoutesObserver>();
524
Eric Laurent4bbcc652012-09-24 14:26:30 -0700525 // Devices for which the volume is fixed and VolumePanel slider should be disabled
Eric Laurent212532b2014-07-21 15:43:18 -0700526 int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700527 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Eric Laurent212532b2014-07-21 15:43:18 -0700528 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
529 AudioSystem.DEVICE_OUT_HDMI_ARC |
530 AudioSystem.DEVICE_OUT_SPDIF |
531 AudioSystem.DEVICE_OUT_AUX_LINE;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700532 int mFullVolumeDevices = 0;
Eric Laurent4bbcc652012-09-24 14:26:30 -0700533
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700534 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700535 private final boolean mMonitorOrientation;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700536 private final boolean mMonitorRotation;
Eric Laurentd640bd32012-09-28 18:01:48 -0700537
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700538 private boolean mDockAudioMediaEnabled = true;
539
Eric Laurent08ed1b92012-11-05 14:54:12 -0800540 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
541
Eric Laurentfde16d52012-12-03 14:42:39 -0800542 // Used when safe volume warning message display is requested by setStreamVolume(). In this
543 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
544 // and used later when/if disableSafeMediaVolume() is called.
545 private StreamVolumeCommand mPendingVolumeCommand;
546
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700547 private PowerManager.WakeLock mAudioEventWakeLock;
548
549 private final MediaFocusControl mMediaFocusControl;
550
John Du5a0cf7a2013-07-19 11:30:34 -0700551 // Reference to BluetoothA2dp to query for AbsoluteVolume.
552 private BluetoothA2dp mA2dp;
seunghwan.hong4fe77952014-10-29 17:43:20 +0900553 // lock always taken synchronized on mConnectedDevices
John Du5a0cf7a2013-07-19 11:30:34 -0700554 private final Object mA2dpAvrcpLock = new Object();
555 // If absolute volume is supported in AVRCP device
556 private boolean mAvrcpAbsVolSupported = false;
557
Eric Laurentadbe8bf2014-11-03 18:26:32 -0800558 private static Long mLastDeviceConnectMsgTime = new Long(0);
559
John Spurlock661f2cf2014-11-17 10:29:10 -0500560 private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
John Spurlocka48d7792015-03-03 17:35:57 -0500561 private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
John Spurlock07e72432015-03-13 11:46:52 -0400562 private long mLoweredFromNormalToVibrateTime;
John Spurlock661f2cf2014-11-17 10:29:10 -0500563
Paul McLean10804eb2015-01-28 11:16:35 -0800564 // Intent "extra" data keys.
565 public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName";
566 public static final String CONNECT_INTENT_KEY_STATE = "state";
567 public static final String CONNECT_INTENT_KEY_ADDRESS = "address";
568 public static final String CONNECT_INTENT_KEY_HAS_PLAYBACK = "hasPlayback";
569 public static final String CONNECT_INTENT_KEY_HAS_CAPTURE = "hasCapture";
570 public static final String CONNECT_INTENT_KEY_HAS_MIDI = "hasMIDI";
571 public static final String CONNECT_INTENT_KEY_DEVICE_CLASS = "class";
572
573 // Defines the format for the connection "address" for ALSA devices
574 public static String makeAlsaAddressString(int card, int device) {
575 return "card=" + card + ";device=" + device + ";";
576 }
577
Makoto Onukie1aef852015-10-15 17:28:35 -0700578 public static final class Lifecycle extends SystemService {
579 private AudioService mService;
580
581 public Lifecycle(Context context) {
582 super(context);
583 mService = new AudioService(context);
584 }
585
586 @Override
587 public void onStart() {
588 publishBinderService(Context.AUDIO_SERVICE, mService);
589 }
590
591 @Override
592 public void onBootPhase(int phase) {
593 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
594 mService.systemReady();
595 }
596 }
597 }
598
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 ///////////////////////////////////////////////////////////////////////////
600 // Construction
601 ///////////////////////////////////////////////////////////////////////////
602
603 /** @hide */
604 public AudioService(Context context) {
605 mContext = context;
606 mContentResolver = context.getContentResolver();
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700607 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700608
John Spurlock61560172015-02-06 19:46:04 -0500609 mPlatformType = AudioSystem.getPlatformType(context);
Jared Suttles59820132009-08-13 21:50:52 -0500610
Makoto Onukid45a4a22015-11-02 17:17:38 -0800611 mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
612
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700613 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700614 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700615
Eric Laurentbffc3d12012-05-07 17:43:49 -0700616 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
617 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
618
John Spurlockb6e19e32015-03-10 21:33:44 -0400619 // Initialize volume
Eric Laurent91377de2014-10-10 15:24:04 -0700620 int maxVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps",
621 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
622 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
623 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500624 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700625 }
626 maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
627 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
628 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
629 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500630 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700631 }
Jared Suttles59820132009-08-13 21:50:52 -0500632
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700633 sSoundEffectVolumeDb = context.getResources().getInteger(
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700634 com.android.internal.R.integer.config_soundEffectVolumeDb);
Eric Laurent25101b02011-02-02 09:33:30 -0800635
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700636 mForcedUseForComm = AudioSystem.FORCE_NONE;
Eric Laurentdd45d012012-10-08 09:04:34 -0700637
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800638 createAudioSystemThread();
Eric Laurentdd45d012012-10-08 09:04:34 -0700639
Eric Laurentdfb881f2013-07-18 14:41:39 -0700640 AudioSystem.setErrorCallback(mAudioSystemCallback);
641
John Spurlock5e783732015-02-19 10:28:59 -0500642 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -0700643 mCameraSoundForced = new Boolean(cameraSoundForced);
644 sendMsg(mAudioHandler,
645 MSG_SET_FORCE_USE,
646 SENDMSG_QUEUE,
647 AudioSystem.FOR_SYSTEM,
648 cameraSoundForced ?
649 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
650 null,
651 0);
652
Eric Laurent05274f32012-11-29 12:48:18 -0800653 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
654 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
655 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
656 // The default safe volume index read here will be replaced by the actual value when
657 // the mcc is read by onConfigureSafeVolume()
658 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
659 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
660
Eric Laurent83a017b2013-03-19 18:15:31 -0700661 mUseFixedVolume = mContext.getResources().getBoolean(
662 com.android.internal.R.bool.config_useFixedVolume);
663
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700664 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
665 // array initialized by updateStreamVolumeAlias()
John Spurlock90874332015-03-10 16:00:54 -0400666 updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 readPersistedSettings();
Eric Laurentc1d41662011-07-19 11:21:13 -0700668 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700669 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700670
Jean-Michel Trivid4de20d2015-11-04 14:45:54 -0800671 mMediaFocusControl = new MediaFocusControl(mContext);
John Spurlockb6e19e32015-03-10 21:33:44 -0400672
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700673 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700674
675 // Call setRingerModeInt() to apply correct mute
676 // state on streams affected by ringer mode.
677 mRingerModeMutedStreams = 0;
John Spurlock661f2cf2014-11-17 10:29:10 -0500678 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3891c4c2010-04-20 09:40:57 -0700679
Eric Laurenta553c252009-07-17 12:17:14 -0700680 // Register for device connection intent broadcasts.
681 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700682 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700683 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
684 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700685 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
686 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700687 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700688 intentFilter.addAction(Intent.ACTION_USER_BACKGROUND);
689 intentFilter.addAction(Intent.ACTION_USER_FOREGROUND);
Paul McLeanc837a452014-04-09 09:04:43 -0700690 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Eric Laurentb70b78a2016-01-13 19:16:04 -0800691 intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700692
Eric Laurentd640bd32012-09-28 18:01:48 -0700693 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700694 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700695 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
696 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700697 Log.v(TAG, "monitoring device orientation");
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700698 // initialize orientation in AudioSystem
699 setOrientationForAudioSystem();
700 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700701 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
702 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -0700703 RotationHelper.init(mContext, mAudioHandler);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700704 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700705
Fyodor Kupolovb5013302015-04-17 17:59:14 -0700706 context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null);
Jared Suttles59820132009-08-13 21:50:52 -0500707
RoboErik0dac35a2014-08-12 15:48:49 -0700708 LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
Makoto Onukid45a4a22015-11-02 17:17:38 -0800709
710 mUserManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -0800711
712 mRecordMonitor.initMonitor();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 }
714
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700715 public void systemReady() {
716 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
717 0, 0, null, 0);
718 }
719
720 public void onSystemReady() {
721 mSystemReady = true;
722 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
723 0, 0, null, 0);
724
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700725 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
726 resetBluetoothSco();
727 getBluetoothHeadset();
728 //FIXME: this is to maintain compatibility with deprecated intent
729 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
730 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
731 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
732 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
733 sendStickyBroadcastToAll(newIntent);
734
735 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
736 if (adapter != null) {
737 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
738 BluetoothProfile.A2DP);
739 }
740
Eric Laurent212532b2014-07-21 15:43:18 -0700741 mHdmiManager =
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900742 (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700743 if (mHdmiManager != null) {
744 synchronized (mHdmiManager) {
745 mHdmiTvClient = mHdmiManager.getTvClient();
Jungshik Jangc9ff9682014-09-15 17:41:06 +0900746 if (mHdmiTvClient != null) {
747 mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
748 }
Eric Laurent212532b2014-07-21 15:43:18 -0700749 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
750 mHdmiCecSink = false;
751 }
752 }
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900753
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700754 sendMsg(mAudioHandler,
755 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
756 SENDMSG_REPLACE,
757 0,
758 0,
John Spurlock90874332015-03-10 16:00:54 -0400759 TAG,
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700760 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700761
762 StreamOverride.init(mContext);
John Spurlockcdb57ae2015-02-11 19:04:11 -0500763 mControllerService.init();
Eric Laurent0867bed2015-05-20 14:49:08 -0700764 onIndicateSystemReady();
765 }
766
767 void onIndicateSystemReady() {
768 if (AudioSystem.systemReady() == AudioSystem.SUCCESS) {
769 return;
770 }
771 sendMsg(mAudioHandler,
772 MSG_INDICATE_SYSTEM_READY,
773 SENDMSG_REPLACE,
774 0,
775 0,
776 null,
777 INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
778 }
779
Andy Hunged0ea402015-10-30 14:11:46 -0700780 public void onAudioServerDied() {
Eric Laurent0867bed2015-05-20 14:49:08 -0700781 if (!mSystemReady ||
782 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Andy Hunged0ea402015-10-30 14:11:46 -0700783 Log.e(TAG, "Audioserver died.");
784 sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent0867bed2015-05-20 14:49:08 -0700785 null, 500);
786 return;
787 }
Andy Hunged0ea402015-10-30 14:11:46 -0700788 Log.e(TAG, "Audioserver started.");
Eric Laurent0867bed2015-05-20 14:49:08 -0700789
790 // indicate to audio HAL that we start the reconfiguration phase after a media
791 // server crash
792 // Note that we only execute this when the media server
793 // process restarts after a crash, not the first time it is started.
794 AudioSystem.setParameters("restarting=true");
795
796 readAndSetLowRamDevice();
797
798 // Restore device connection states
799 synchronized (mConnectedDevices) {
800 for (int i = 0; i < mConnectedDevices.size(); i++) {
801 DeviceListSpec spec = mConnectedDevices.valueAt(i);
802 AudioSystem.setDeviceConnectionState(
803 spec.mDeviceType,
804 AudioSystem.DEVICE_STATE_AVAILABLE,
805 spec.mDeviceAddress,
806 spec.mDeviceName);
807 }
808 }
809 // Restore call state
810 AudioSystem.setPhoneState(mMode);
811
812 // Restore forced usage for communcations and record
813 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
814 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
815 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
816 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
817
818 // Restore stream volumes
819 int numStreamTypes = AudioSystem.getNumStreamTypes();
820 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
821 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurente4381ec2015-10-29 17:52:48 -0700822 AudioSystem.initStreamVolume(
823 streamType, streamState.mIndexMin / 10, streamState.mIndexMax / 10);
Eric Laurent0867bed2015-05-20 14:49:08 -0700824
825 streamState.applyAllVolumes();
826 }
827
Andy Hungf04b84d2015-12-18 17:33:27 -0800828 // Restore mono mode
Andy Hung7b98e9a2016-02-25 18:34:50 -0800829 updateMasterMono(mContentResolver);
Andy Hungf04b84d2015-12-18 17:33:27 -0800830
Eric Laurent0867bed2015-05-20 14:49:08 -0700831 // Restore ringer mode
832 setRingerModeInt(getRingerModeInternal(), false);
833
834 // Reset device orientation (if monitored for this device)
835 if (mMonitorOrientation) {
836 setOrientationForAudioSystem();
837 }
838 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -0700839 RotationHelper.updateOrientation();
Eric Laurent0867bed2015-05-20 14:49:08 -0700840 }
841
842 synchronized (mBluetoothA2dpEnabledLock) {
843 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
844 mBluetoothA2dpEnabled ?
845 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
846 }
847
848 synchronized (mSettingsLock) {
849 AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
850 mDockAudioMediaEnabled ?
851 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
Phil Burkac0f7042016-02-24 12:19:08 -0800852 readEncodedSurroundMode(mContentResolver);
Eric Laurent0867bed2015-05-20 14:49:08 -0700853 }
854 if (mHdmiManager != null) {
855 synchronized (mHdmiManager) {
856 if (mHdmiTvClient != null) {
857 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
858 }
859 }
860 }
861
862 synchronized (mAudioPolicies) {
863 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
864 policy.connectMixes();
865 }
866 }
867
868 onIndicateSystemReady();
869 // indicate the end of reconfiguration phase to audio HAL
870 AudioSystem.setParameters("restarting=false");
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700871 }
872
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800873 private void createAudioSystemThread() {
874 mAudioSystemThread = new AudioSystemThread();
875 mAudioSystemThread.start();
876 waitForAudioHandlerCreation();
877 }
878
879 /** Waits for the volume handler to be created by the other thread. */
880 private void waitForAudioHandlerCreation() {
881 synchronized(this) {
882 while (mAudioHandler == null) {
883 try {
884 // Wait for mAudioHandler to be set by the other thread
885 wait();
886 } catch (InterruptedException e) {
887 Log.e(TAG, "Interrupted while waiting on volume handler.");
888 }
889 }
890 }
891 }
892
Eric Laurent24482012012-05-10 09:41:17 -0700893 private void checkAllAliasStreamVolumes() {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700894 synchronized (VolumeStreamState.class) {
895 int numStreamTypes = AudioSystem.getNumStreamTypes();
896 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
897 if (streamType != mStreamVolumeAlias[streamType]) {
898 mStreamStates[streamType].
John Spurlock90874332015-03-10 16:00:54 -0400899 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]],
900 TAG);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700901 }
902 // apply stream volume
RoboErik4197cb62015-01-21 15:45:32 -0800903 if (!mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700904 mStreamStates[streamType].applyAllVolumes();
905 }
Eric Laurent24482012012-05-10 09:41:17 -0700906 }
907 }
908 }
909
Eric Laurent212532b2014-07-21 15:43:18 -0700910 private void checkAllFixedVolumeDevices()
911 {
912 int numStreamTypes = AudioSystem.getNumStreamTypes();
913 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
914 mStreamStates[streamType].checkFixedVolumeDevices();
915 }
916 }
917
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700918 private void checkAllFixedVolumeDevices(int streamType) {
919 mStreamStates[streamType].checkFixedVolumeDevices();
920 }
921
John Spurlockb6e19e32015-03-10 21:33:44 -0400922 private void checkMuteAffectedStreams() {
923 // any stream with a min level > 0 is not muteable by definition
924 for (int i = 0; i < mStreamStates.length; i++) {
925 final VolumeStreamState vss = mStreamStates[i];
926 if (vss.mIndexMin > 0) {
927 mMuteAffectedStreams &= ~(1 << vss.mStreamType);
928 }
929 }
930 }
931
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800933 int numStreamTypes = AudioSystem.getNumStreamTypes();
934 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
935
936 for (int i = 0; i < numStreamTypes; i++) {
Eric Laurent6d517662012-04-23 18:42:39 -0700937 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -0700938 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800939
Eric Laurent212532b2014-07-21 15:43:18 -0700940 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -0700941 checkAllAliasStreamVolumes();
John Spurlockb6e19e32015-03-10 21:33:44 -0400942 checkMuteAffectedStreams();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800943 }
944
Eric Laurentbffc3d12012-05-07 17:43:49 -0700945 private void dumpStreamStates(PrintWriter pw) {
946 pw.println("\nStream volumes (device: index)");
947 int numStreamTypes = AudioSystem.getNumStreamTypes();
948 for (int i = 0; i < numStreamTypes; i++) {
John Spurlock61560172015-02-06 19:46:04 -0500949 pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":");
Eric Laurentbffc3d12012-05-07 17:43:49 -0700950 mStreamStates[i].dump(pw);
951 pw.println("");
952 }
Eric Laurentdd45d012012-10-08 09:04:34 -0700953 pw.print("\n- mute affected streams = 0x");
954 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -0700955 }
956
John Spurlock90874332015-03-10 16:00:54 -0400957 private void updateStreamVolumeAlias(boolean updateVolumes, String caller) {
Eric Laurent6d517662012-04-23 18:42:39 -0700958 int dtmfStreamAlias;
Eric Laurent212532b2014-07-21 15:43:18 -0700959
960 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -0500961 case AudioSystem.PLATFORM_VOICE:
Eric Laurent212532b2014-07-21 15:43:18 -0700962 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
Eric Laurent6d517662012-04-23 18:42:39 -0700963 dtmfStreamAlias = AudioSystem.STREAM_RING;
Eric Laurent212532b2014-07-21 15:43:18 -0700964 break;
John Spurlock61560172015-02-06 19:46:04 -0500965 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -0700966 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
967 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
968 break;
969 default:
970 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
Eric Laurent6d517662012-04-23 18:42:39 -0700971 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
972 }
Eric Laurent212532b2014-07-21 15:43:18 -0700973
974 if (isPlatformTelevision()) {
975 mRingerModeAffectedStreams = 0;
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700976 } else {
Eric Laurent212532b2014-07-21 15:43:18 -0700977 if (isInCommunication()) {
978 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
979 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
980 } else {
981 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
982 }
Eric Laurent6d517662012-04-23 18:42:39 -0700983 }
Eric Laurent212532b2014-07-21 15:43:18 -0700984
Eric Laurent6d517662012-04-23 18:42:39 -0700985 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
986 if (updateVolumes) {
John Spurlock90874332015-03-10 16:00:54 -0400987 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
988 caller);
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700989 // apply stream mute states according to new value of mRingerModeAffectedStreams
John Spurlock661f2cf2014-11-17 10:29:10 -0500990 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent6d517662012-04-23 18:42:39 -0700991 sendMsg(mAudioHandler,
992 MSG_SET_ALL_VOLUMES,
993 SENDMSG_QUEUE,
994 0,
995 0,
996 mStreamStates[AudioSystem.STREAM_DTMF], 0);
997 }
998 }
999
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001000 private void readDockAudioSettings(ContentResolver cr)
1001 {
1002 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -07001003 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001004
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001005 sendMsg(mAudioHandler,
1006 MSG_SET_FORCE_USE,
1007 SENDMSG_QUEUE,
1008 AudioSystem.FOR_DOCK,
1009 mDockAudioMediaEnabled ?
1010 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
1011 null,
1012 0);
1013 }
1014
Phil Burkac0f7042016-02-24 12:19:08 -08001015
Andy Hung7b98e9a2016-02-25 18:34:50 -08001016 private void updateMasterMono(ContentResolver cr)
1017 {
1018 final boolean masterMono = System.getIntForUser(
1019 cr, System.MASTER_MONO, 0 /* default */, UserHandle.USER_CURRENT) == 1;
1020 if (DEBUG_VOL) {
1021 Log.d(TAG, String.format("Master mono %b", masterMono));
1022 }
1023 AudioSystem.setMasterMono(masterMono);
1024 }
1025
Phil Burkac0f7042016-02-24 12:19:08 -08001026 private void readEncodedSurroundMode(ContentResolver cr)
1027 {
1028 int encodedSurroundMode = Settings.Global.getInt(
1029 cr, Settings.Global.ENCODED_SURROUND_OUTPUT,
1030 Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
1031 sendEncodedSurroundMode(encodedSurroundMode);
1032 }
1033
1034 private void sendEncodedSurroundMode(int encodedSurroundMode)
1035 {
1036 // initialize to guaranteed bad value
1037 int forceSetting = AudioSystem.NUM_FORCE_CONFIG;
1038 switch (encodedSurroundMode) {
1039 case Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO:
1040 forceSetting = AudioSystem.FORCE_NONE;
1041 break;
1042 case Settings.Global.ENCODED_SURROUND_OUTPUT_NEVER:
1043 forceSetting = AudioSystem.FORCE_ENCODED_SURROUND_NEVER;
1044 break;
1045 case Settings.Global.ENCODED_SURROUND_OUTPUT_ALWAYS:
1046 forceSetting = AudioSystem.FORCE_ENCODED_SURROUND_ALWAYS;
1047 break;
1048 default:
1049 Log.e(TAG, "updateSurroundSoundSettings: illegal value "
1050 + encodedSurroundMode);
1051 break;
1052 }
1053 if (forceSetting != AudioSystem.NUM_FORCE_CONFIG) {
1054 sendMsg(mAudioHandler,
1055 MSG_SET_FORCE_USE,
1056 SENDMSG_QUEUE,
1057 AudioSystem.FOR_ENCODED_SURROUND,
1058 forceSetting,
1059 null,
1060 0);
1061 }
1062 }
1063
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 private void readPersistedSettings() {
1065 final ContentResolver cr = mContentResolver;
1066
Eric Laurentbffc3d12012-05-07 17:43:49 -07001067 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07001068 Settings.Global.getInt(
1069 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -07001070 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -07001071 // sanity check in case the settings are restored from a device with incompatible
1072 // ringer modes
John Spurlock97559372014-10-24 16:27:36 -04001073 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001074 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -07001075 }
1076 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1077 ringerMode = AudioManager.RINGER_MODE_SILENT;
1078 }
1079 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07001080 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -08001081 }
Eric Laurent212532b2014-07-21 15:43:18 -07001082 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001083 ringerMode = AudioManager.RINGER_MODE_NORMAL;
1084 }
Glenn Kastenba195eb2011-12-13 09:30:40 -08001085 synchronized(mSettingsLock) {
1086 mRingerMode = ringerMode;
John Spurlock661f2cf2014-11-17 10:29:10 -05001087 if (mRingerModeExternal == -1) {
1088 mRingerModeExternal = mRingerMode;
1089 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001090
Eric Laurentdd45d012012-10-08 09:04:34 -07001091 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
1092 // are still needed while setVibrateSetting() and getVibrateSetting() are being
1093 // deprecated.
John Spurlock61560172015-02-06 19:46:04 -05001094 mVibrateSetting = AudioSystem.getValueForVibrateSetting(0,
Eric Laurentdd45d012012-10-08 09:04:34 -07001095 AudioManager.VIBRATE_TYPE_NOTIFICATION,
1096 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
1097 : AudioManager.VIBRATE_SETTING_OFF);
John Spurlock61560172015-02-06 19:46:04 -05001098 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting,
Eric Laurentdd45d012012-10-08 09:04:34 -07001099 AudioManager.VIBRATE_TYPE_RINGER,
1100 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
1101 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001102
Eric Laurent24e0d9b2013-10-03 18:15:07 -07001103 updateRingerModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07001104 readDockAudioSettings(cr);
Phil Burkac0f7042016-02-24 12:19:08 -08001105 readEncodedSurroundMode(cr);
Eric Laurent402f7f22011-02-04 12:30:32 -08001106 }
Eric Laurentc1d41662011-07-19 11:21:13 -07001107
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001108 mMuteAffectedStreams = System.getIntForUser(cr,
John Spurlock61560172015-02-06 19:46:04 -05001109 System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
John Spurlock24c05182015-02-05 12:30:36 -05001110 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001111
Makoto Onukid45a4a22015-11-02 17:17:38 -08001112 final int currentUser = getCurrentUserId();
1113
1114 // In addition to checking the system setting, also check the current user restriction.
1115 // Because of the delay before persisting VOLUME_MASTER_MUTE, there's a window where
1116 // DISALLOW_ADJUST_VOLUME will be ignored when it's set right before switching users.
1117 boolean masterMute = (System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
1118 0, UserHandle.USER_CURRENT) == 1)
1119 || mUserManagerInternal.getUserRestriction(
1120 currentUser, UserManager.DISALLOW_ADJUST_VOLUME);
Eric Laurent83a017b2013-03-19 18:15:31 -07001121 if (mUseFixedVolume) {
1122 masterMute = false;
1123 AudioSystem.setMasterVolume(1.0f);
1124 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08001125 if (DEBUG_VOL) {
1126 Log.d(TAG, String.format("Master mute %s, user=%d", masterMute, currentUser));
1127 }
Jae Seo1b434da2015-11-11 18:58:51 -08001128 setSystemAudioMute(masterMute);
Justin Koh57978ed2012-04-03 17:37:58 -07001129 AudioSystem.setMasterMute(masterMute);
1130 broadcastMasterMuteStatus(masterMute);
1131
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001132 boolean microphoneMute =
Makoto Onukid45a4a22015-11-02 17:17:38 -08001133 (System.getIntForUser(cr, System.MICROPHONE_MUTE, 0, UserHandle.USER_CURRENT) == 1)
1134 || mUserManagerInternal.getUserRestriction(
1135 currentUser, UserManager.DISALLOW_UNMUTE_MICROPHONE);
1136 if (DEBUG_VOL) {
1137 Log.d(TAG, String.format("Mic mute %s, user=%d", microphoneMute, currentUser));
1138 }
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001139 AudioSystem.muteMicrophone(microphoneMute);
1140
Andy Hung7b98e9a2016-02-25 18:34:50 -08001141 updateMasterMono(cr);
Andy Hungf04b84d2015-12-18 17:33:27 -08001142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143 // Each stream will read its own persisted settings
1144
John Spurlockbcc10872014-11-28 15:29:21 -05001145 // Broadcast the sticky intents
1146 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
1147 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148
1149 // Broadcast vibrate settings
1150 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
1151 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07001152
John Spurlock33f4e042014-07-11 13:10:58 -04001153 // Load settings for the volume controller
1154 mVolumeController.loadSettings(cr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155 }
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,
1296 streamState.mIsMuted);
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
1308 if (streamTypeAlias == AudioSystem.STREAM_MUSIC
1309 && (mRingerModeMutedStreams & (1 << AudioSystem.STREAM_MUSIC)) != 0) {
1310 adjustVolume = false;
1311 }
Eric Laurent3ef75492012-11-28 12:12:23 -08001312
Eric Laurent42b041e2013-03-29 11:36:03 -07001313 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001314
Eric Laurent42b041e2013-03-29 11:36:03 -07001315 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
RoboErik5452e252015-02-06 15:33:53 -08001316 mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001317
John Du5a0cf7a2013-07-19 11:30:34 -07001318 // Check if volume update should be send to AVRCP
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001319 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1320 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1321 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1322 synchronized (mA2dpAvrcpLock) {
1323 if (mA2dp != null && mAvrcpAbsVolSupported) {
1324 mA2dp.adjustAvrcpAbsoluteVolume(direction);
1325 }
John Du5a0cf7a2013-07-19 11:30:34 -07001326 }
1327 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001328
RoboErik4197cb62015-01-21 15:45:32 -08001329 if (isMuteAdjust) {
1330 boolean state;
1331 if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
1332 state = !streamState.mIsMuted;
1333 } else {
1334 state = direction == AudioManager.ADJUST_MUTE;
1335 }
1336 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1337 setSystemAudioMute(state);
1338 }
1339 for (int stream = 0; stream < mStreamStates.length; stream++) {
1340 if (streamTypeAlias == mStreamVolumeAlias[stream]) {
Sungmin Choi841ed0a2015-07-26 23:09:49 -07001341 if (!(readCameraSoundForced()
1342 && (mStreamStates[stream].getStreamType()
1343 == AudioSystem.STREAM_SYSTEM_ENFORCED))) {
1344 mStreamStates[stream].mute(state);
1345 }
RoboErik4197cb62015-01-21 15:45:32 -08001346 }
1347 }
1348 } else if ((direction == AudioManager.ADJUST_RAISE) &&
Eric Laurent42b041e2013-03-29 11:36:03 -07001349 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
RoboErik4197cb62015-01-21 15:45:32 -08001350 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -04001351 mVolumeController.postDisplaySafeVolumeWarning(flags);
John Spurlock90874332015-03-10 16:00:54 -04001352 } else if (streamState.adjustIndex(direction * step, device, caller)
1353 || streamState.mIsMuted) {
RoboErik4197cb62015-01-21 15:45:32 -08001354 // Post message to set system volume (it in turn will post a
1355 // message to persist).
1356 if (streamState.mIsMuted) {
1357 // Unmute the stream if it was previously muted
RoboErik5452e252015-02-06 15:33:53 -08001358 if (direction == AudioManager.ADJUST_RAISE) {
1359 // unmute immediately for volume up
1360 streamState.mute(false);
1361 } else if (direction == AudioManager.ADJUST_LOWER) {
John Spurlocka48d7792015-03-03 17:35:57 -05001362 if (mPlatformType == AudioSystem.PLATFORM_TELEVISION) {
1363 sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
1364 streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
1365 }
RoboErik5452e252015-02-06 15:33:53 -08001366 }
RoboErik4197cb62015-01-21 15:45:32 -08001367 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001368 sendMsg(mAudioHandler,
1369 MSG_SET_DEVICE_VOLUME,
1370 SENDMSG_QUEUE,
1371 device,
1372 0,
1373 streamState,
1374 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001375 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001376
RoboErik4197cb62015-01-21 15:45:32 -08001377 // Check if volume update should be sent to Hdmi system audio.
Jungshik Jang41d97462014-06-30 22:26:29 +09001378 int newIndex = mStreamStates[streamType].getIndex(device);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001379 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1380 setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
1381 }
Eric Laurent212532b2014-07-21 15:43:18 -07001382 if (mHdmiManager != null) {
1383 synchronized (mHdmiManager) {
Eric Laurent212532b2014-07-21 15:43:18 -07001384 // mHdmiCecSink true => mHdmiPlaybackClient != null
1385 if (mHdmiCecSink &&
1386 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1387 oldIndex != newIndex) {
1388 synchronized (mHdmiPlaybackClient) {
1389 int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
RoboErik4197cb62015-01-21 15:45:32 -08001390 KeyEvent.KEYCODE_VOLUME_UP;
Eric Laurent212532b2014-07-21 15:43:18 -07001391 mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1392 mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1393 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001394 }
1395 }
1396 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001397 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001398 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001399 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001400 }
1401
RoboErik5452e252015-02-06 15:33:53 -08001402 // Called after a delay when volume down is pressed while muted
1403 private void onUnmuteStream(int stream, int flags) {
1404 VolumeStreamState streamState = mStreamStates[stream];
1405 streamState.mute(false);
1406
1407 final int device = getDeviceForStream(stream);
1408 final int index = mStreamStates[stream].getIndex(device);
1409 sendVolumeUpdate(stream, index, index, flags);
1410 }
1411
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001412 private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
1413 if (mHdmiManager == null
1414 || mHdmiTvClient == null
1415 || oldVolume == newVolume
1416 || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
1417
1418 // Sets the audio volume of AVR when we are in system audio mode. The new volume info
1419 // is tranformed to HDMI-CEC commands and passed through CEC bus.
1420 synchronized (mHdmiManager) {
1421 if (!mHdmiSystemAudioSupported) return;
1422 synchronized (mHdmiTvClient) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001423 final long token = Binder.clearCallingIdentity();
1424 try {
Jinsuk Kim7a9ba422015-02-16 16:47:38 +09001425 mHdmiTvClient.setSystemAudioVolume(oldVolume, newVolume, maxVolume);
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001426 } finally {
1427 Binder.restoreCallingIdentity(token);
1428 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001429 }
1430 }
1431 }
1432
Eric Laurentfde16d52012-12-03 14:42:39 -08001433 // StreamVolumeCommand contains the information needed to defer the process of
1434 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1435 class StreamVolumeCommand {
1436 public final int mStreamType;
1437 public final int mIndex;
1438 public final int mFlags;
1439 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001440
Eric Laurentfde16d52012-12-03 14:42:39 -08001441 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1442 mStreamType = streamType;
1443 mIndex = index;
1444 mFlags = flags;
1445 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001446 }
John Spurlock35134602014-07-24 18:10:48 -04001447
1448 @Override
1449 public String toString() {
1450 return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1451 .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1452 .append(mDevice).append('}').toString();
1453 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001454 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001455
John Spurlock90874332015-03-10 16:00:54 -04001456 private void onSetStreamVolume(int streamType, int index, int flags, int device,
1457 String caller) {
John Spurlock75ae23c2015-06-02 16:26:43 -04001458 final int stream = mStreamVolumeAlias[streamType];
1459 setStreamVolumeInt(stream, index, device, false, caller);
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
John Spurlock86005342014-05-23 11:58:00 -04001467 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001468 } else {
1469 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1470 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001471 setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/);
Eric Laurent3ef75492012-11-28 12:12:23 -08001472 }
John Spurlock75ae23c2015-06-02 16:26:43 -04001473 // setting non-zero volume for a muted stream unmutes the stream and vice versa
1474 mStreamStates[stream].mute(index == 0);
Eric Laurentfde16d52012-12-03 14:42:39 -08001475 }
1476
1477 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001478 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
John Spurlock90874332015-03-10 16:00:54 -04001479 setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
1480 Binder.getCallingUid());
RoboErik0dac35a2014-08-12 15:48:49 -07001481 }
1482
1483 private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
John Spurlock90874332015-03-10 16:00:54 -04001484 String caller, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001485 if (mUseFixedVolume) {
1486 return;
1487 }
1488
Eric Laurentfde16d52012-12-03 14:42:39 -08001489 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001490 int streamTypeAlias = mStreamVolumeAlias[streamType];
1491 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001492
1493 final int device = getDeviceForStream(streamType);
1494 int oldIndex;
1495
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001496 // skip a2dp absolute volume control request when the device
1497 // is not an a2dp device
1498 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1499 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1500 return;
1501 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001502 // If we are being called by the system (e.g. hardware keys) check for current user
1503 // so we handle user restrictions correctly.
1504 if (uid == android.os.Process.SYSTEM_UID) {
1505 uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
1506 }
John Spurlock59dc9c12015-03-02 11:20:15 -05001507 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001508 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001509 return;
1510 }
1511
Eric Laurentfde16d52012-12-03 14:42:39 -08001512 synchronized (mSafeMediaVolumeState) {
1513 // reset any pending volume command
1514 mPendingVolumeCommand = null;
1515
Eric Laurent42b041e2013-03-29 11:36:03 -07001516 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001517
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001518 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001519
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001520 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1521 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1522 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1523 synchronized (mA2dpAvrcpLock) {
1524 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001525 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001526 }
John Du5a0cf7a2013-07-19 11:30:34 -07001527 }
1528 }
1529
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001530 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1531 setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
Jungshik Jang41d97462014-06-30 22:26:29 +09001532 }
1533
Eric Laurentfde16d52012-12-03 14:42:39 -08001534 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001535 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001536 ((device & mFixedVolumeDevices) != 0)) {
1537 flags |= AudioManager.FLAG_FIXED_VOLUME;
1538
1539 // volume is either 0 or max allowed for fixed volume devices
1540 if (index != 0) {
1541 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1542 (device & mSafeMediaVolumeDevices) != 0) {
1543 index = mSafeMediaVolumeIndex;
1544 } else {
1545 index = streamState.getMaxIndex();
1546 }
1547 }
1548 }
1549
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001550 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001551 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001552 mPendingVolumeCommand = new StreamVolumeCommand(
1553 streamType, index, flags, device);
1554 } else {
John Spurlock90874332015-03-10 16:00:54 -04001555 onSetStreamVolume(streamType, index, flags, device, caller);
Eric Laurent42b041e2013-03-29 11:36:03 -07001556 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001557 }
1558 }
Eric Laurent25101b02011-02-02 09:33:30 -08001559 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001560 }
1561
Eric Laurent45c90ce2012-04-24 18:44:22 -07001562 /** @see AudioManager#forceVolumeControlStream(int) */
1563 public void forceVolumeControlStream(int streamType, IBinder cb) {
1564 synchronized(mForceControlStreamLock) {
1565 mVolumeControlStream = streamType;
1566 if (mVolumeControlStream == -1) {
1567 if (mForceControlStreamClient != null) {
1568 mForceControlStreamClient.release();
1569 mForceControlStreamClient = null;
1570 }
1571 } else {
1572 mForceControlStreamClient = new ForceControlStreamClient(cb);
1573 }
1574 }
1575 }
1576
1577 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1578 private IBinder mCb; // To be notified of client's death
1579
1580 ForceControlStreamClient(IBinder cb) {
1581 if (cb != null) {
1582 try {
1583 cb.linkToDeath(this, 0);
1584 } catch (RemoteException e) {
1585 // Client has died!
1586 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1587 cb = null;
1588 }
1589 }
1590 mCb = cb;
1591 }
1592
1593 public void binderDied() {
1594 synchronized(mForceControlStreamLock) {
1595 Log.w(TAG, "SCO client died");
1596 if (mForceControlStreamClient != this) {
1597 Log.w(TAG, "unregistered control stream client died");
1598 } else {
1599 mForceControlStreamClient = null;
1600 mVolumeControlStream = -1;
1601 }
1602 }
1603 }
1604
1605 public void release() {
1606 if (mCb != null) {
1607 mCb.unlinkToDeath(this, 0);
1608 mCb = null;
1609 }
1610 }
1611 }
1612
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001613 private void sendBroadcastToAll(Intent intent) {
Christopher Tate267603f2015-01-20 14:21:21 -08001614 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
John Spurlock86490862015-02-25 11:22:52 -05001615 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001616 final long ident = Binder.clearCallingIdentity();
1617 try {
1618 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1619 } finally {
1620 Binder.restoreCallingIdentity(ident);
1621 }
1622 }
1623
1624 private void sendStickyBroadcastToAll(Intent intent) {
John Spurlock86490862015-02-25 11:22:52 -05001625 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001626 final long ident = Binder.clearCallingIdentity();
1627 try {
1628 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1629 } finally {
1630 Binder.restoreCallingIdentity(ident);
1631 }
1632 }
1633
Kenny Guy70e0c582015-06-30 19:18:28 +01001634 private int getCurrentUserId() {
1635 final long ident = Binder.clearCallingIdentity();
1636 try {
1637 UserInfo currentUser = ActivityManagerNative.getDefault().getCurrentUser();
1638 return currentUser.id;
1639 } catch (RemoteException e) {
1640 // Activity manager not running, nothing we can do assume user 0.
1641 } finally {
1642 Binder.restoreCallingIdentity(ident);
1643 }
Xiaohui Chen7c696362015-09-16 09:56:14 -07001644 return UserHandle.USER_SYSTEM;
Kenny Guy70e0c582015-06-30 19:18:28 +01001645 }
1646
Eric Laurent25101b02011-02-02 09:33:30 -08001647 // UI update and Broadcast Intent
1648 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
John Spurlock72966d62015-06-18 15:45:07 -04001649 streamType = mStreamVolumeAlias[streamType];
Eric Laurent25101b02011-02-02 09:33:30 -08001650
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001651 if (streamType == AudioSystem.STREAM_MUSIC) {
1652 flags = updateFlagsForSystemAudio(flags);
Jungshik Jang1a6be6e2014-09-16 11:04:54 +09001653 }
John Spurlock3346a802014-05-20 16:25:37 -04001654 mVolumeController.postVolumeChanged(streamType, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001655 }
1656
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001657 // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
1658 // receives volume notification from Audio Receiver.
1659 private int updateFlagsForSystemAudio(int flags) {
1660 if (mHdmiTvClient != null) {
1661 synchronized (mHdmiTvClient) {
1662 if (mHdmiSystemAudioSupported &&
1663 ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
1664 flags &= ~AudioManager.FLAG_SHOW_UI;
1665 }
1666 }
1667 }
1668 return flags;
1669 }
1670
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001671 // UI update and Broadcast Intent
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001672 private void sendMasterMuteUpdate(boolean muted, int flags) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001673 mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
Justin Koh57978ed2012-04-03 17:37:58 -07001674 broadcastMasterMuteStatus(muted);
1675 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001676
Justin Koh57978ed2012-04-03 17:37:58 -07001677 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001678 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1679 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001680 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1681 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001682 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001683 }
1684
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001685 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001686 * Sets the stream state's index, and posts a message to set system volume.
1687 * This will not call out to the UI. Assumes a valid stream type.
1688 *
1689 * @param streamType Type of the stream
1690 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001691 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 * @param force If true, set the volume even if the desired volume is same
1693 * as the current volume.
1694 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001695 private void setStreamVolumeInt(int streamType,
1696 int index,
1697 int device,
John Spurlock90874332015-03-10 16:00:54 -04001698 boolean force,
1699 String caller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001700 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07001701
John Spurlock90874332015-03-10 16:00:54 -04001702 if (streamState.setIndex(index, device, caller) || force) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001703 // Post message to set system volume (it in turn will post a message
1704 // to persist).
1705 sendMsg(mAudioHandler,
1706 MSG_SET_DEVICE_VOLUME,
1707 SENDMSG_QUEUE,
1708 device,
1709 0,
1710 streamState,
1711 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001712 }
1713 }
1714
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001715 private void setSystemAudioMute(boolean state) {
1716 if (mHdmiManager == null || mHdmiTvClient == null) return;
1717 synchronized (mHdmiManager) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001718 if (!mHdmiSystemAudioSupported) return;
1719 synchronized (mHdmiTvClient) {
1720 final long token = Binder.clearCallingIdentity();
1721 try {
1722 mHdmiTvClient.setSystemAudioMute(state);
1723 } finally {
1724 Binder.restoreCallingIdentity(token);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001725 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001726 }
1727 }
1728 }
1729
Eric Laurent25101b02011-02-02 09:33:30 -08001730 /** get stream mute state. */
1731 public boolean isStreamMute(int streamType) {
RoboErik7c82ced2014-12-04 17:39:08 -08001732 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1733 streamType = getActiveStreamType(streamType);
1734 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001735 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08001736 return mStreamStates[streamType].mIsMuted;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001737 }
Eric Laurent25101b02011-02-02 09:33:30 -08001738 }
1739
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07001740 private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
1741 private IBinder mICallback; // To be notified of client's death
1742
1743 RmtSbmxFullVolDeathHandler(IBinder cb) {
1744 mICallback = cb;
1745 try {
1746 cb.linkToDeath(this, 0/*flags*/);
1747 } catch (RemoteException e) {
1748 Log.e(TAG, "can't link to death", e);
1749 }
1750 }
1751
1752 boolean isHandlerFor(IBinder cb) {
1753 return mICallback.equals(cb);
1754 }
1755
1756 void forget() {
1757 try {
1758 mICallback.unlinkToDeath(this, 0/*flags*/);
1759 } catch (NoSuchElementException e) {
1760 Log.e(TAG, "error unlinking to death", e);
1761 }
1762 }
1763
1764 public void binderDied() {
1765 Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
1766 forceRemoteSubmixFullVolume(false, mICallback);
1767 }
1768 }
1769
1770 /**
1771 * call must be synchronized on mRmtSbmxFullVolDeathHandlers
1772 * @return true if there is a registered death handler, false otherwise */
1773 private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1774 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1775 while (it.hasNext()) {
1776 final RmtSbmxFullVolDeathHandler handler = it.next();
1777 if (handler.isHandlerFor(cb)) {
1778 handler.forget();
1779 mRmtSbmxFullVolDeathHandlers.remove(handler);
1780 return true;
1781 }
1782 }
1783 return false;
1784 }
1785
1786 /** call synchronized on mRmtSbmxFullVolDeathHandlers */
1787 private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1788 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1789 while (it.hasNext()) {
1790 if (it.next().isHandlerFor(cb)) {
1791 return true;
1792 }
1793 }
1794 return false;
1795 }
1796
1797 private int mRmtSbmxFullVolRefCount = 0;
1798 private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
1799 new ArrayList<RmtSbmxFullVolDeathHandler>();
1800
1801 public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
1802 if (cb == null) {
1803 return;
1804 }
1805 if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
1806 android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
1807 Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
1808 return;
1809 }
1810 synchronized(mRmtSbmxFullVolDeathHandlers) {
1811 boolean applyRequired = false;
1812 if (startForcing) {
1813 if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
1814 mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
1815 if (mRmtSbmxFullVolRefCount == 0) {
1816 mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1817 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1818 applyRequired = true;
1819 }
1820 mRmtSbmxFullVolRefCount++;
1821 }
1822 } else {
1823 if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
1824 mRmtSbmxFullVolRefCount--;
1825 if (mRmtSbmxFullVolRefCount == 0) {
1826 mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1827 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1828 applyRequired = true;
1829 }
1830 }
1831 }
1832 if (applyRequired) {
1833 // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
1834 checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
1835 mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
1836 }
1837 }
1838 }
1839
Kenny Guy70e0c582015-06-30 19:18:28 +01001840 private void setMasterMuteInternal(boolean mute, int flags, String callingPackage, int uid,
1841 int userId) {
1842 // If we are being called by the system check for user we are going to change
1843 // so we handle user restrictions correctly.
1844 if (uid == android.os.Process.SYSTEM_UID) {
1845 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
1846 }
Makoto Onuki4f160732015-10-27 17:15:38 -07001847 // If OP_AUDIO_MASTER_VOLUME is set, disallow unmuting.
1848 if (!mute && mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
RoboErik7c82ced2014-12-04 17:39:08 -08001849 != AppOpsManager.MODE_ALLOWED) {
Julia Reynolds4a21b252014-06-04 11:11:43 -04001850 return;
1851 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001852 if (userId != UserHandle.getCallingUserId() &&
1853 mContext.checkCallingOrSelfPermission(
1854 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1855 != PackageManager.PERMISSION_GRANTED) {
1856 return;
1857 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08001858 setMasterMuteInternalNoCallerCheck(mute, flags, userId);
1859 }
1860
1861 private void setMasterMuteInternalNoCallerCheck(boolean mute, int flags, int userId) {
1862 if (DEBUG_VOL) {
1863 Log.d(TAG, String.format("Master mute %s, %d, user=%d", mute, flags, userId));
1864 }
1865 if (mUseFixedVolume) {
1866 return; // If using fixed volume, we don't mute.
1867 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001868 if (getCurrentUserId() == userId) {
1869 if (mute != AudioSystem.getMasterMute()) {
1870 setSystemAudioMute(mute);
1871 AudioSystem.setMasterMute(mute);
1872 // Post a persist master volume msg
1873 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, mute ? 1
1874 : 0, userId, null, PERSIST_DELAY);
1875 sendMasterMuteUpdate(mute, flags);
RoboErik7c82ced2014-12-04 17:39:08 -08001876
Kenny Guy70e0c582015-06-30 19:18:28 +01001877 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1878 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute);
1879 sendBroadcastToAll(intent);
1880 }
1881 } else {
1882 // If not the current user just persist the setting which will be loaded
1883 // on user switch.
1884 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, mute ? 1
1885 : 0, userId, null, PERSIST_DELAY);
Jason Simmons1ce5b262012-02-02 13:00:17 -08001886 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08001887 }
1888
1889 /** get master mute state. */
1890 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08001891 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001892 }
1893
Kenny Guy70e0c582015-06-30 19:18:28 +01001894 public void setMasterMute(boolean mute, int flags, String callingPackage, int userId) {
1895 setMasterMuteInternal(mute, flags, callingPackage, Binder.getCallingUid(),
1896 userId);
John Spurlockee5ad722015-03-03 16:17:21 -05001897 }
1898
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001899 /** @see AudioManager#getStreamVolume(int) */
1900 public int getStreamVolume(int streamType) {
1901 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001902 int device = getDeviceForStream(streamType);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001903 synchronized (VolumeStreamState.class) {
1904 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001905
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001906 // by convention getStreamVolume() returns 0 when a stream is muted.
RoboErik4197cb62015-01-21 15:45:32 -08001907 if (mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001908 index = 0;
1909 }
1910 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
1911 (device & mFixedVolumeDevices) != 0) {
1912 index = mStreamStates[streamType].getMaxIndex();
1913 }
1914 return (index + 5) / 10;
Eric Laurent42b041e2013-03-29 11:36:03 -07001915 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001916 }
1917
1918 /** @see AudioManager#getStreamMaxVolume(int) */
1919 public int getStreamMaxVolume(int streamType) {
1920 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07001921 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001922 }
1923
John Spurlockb6e19e32015-03-10 21:33:44 -04001924 /** @see AudioManager#getStreamMinVolume(int) */
1925 public int getStreamMinVolume(int streamType) {
1926 ensureValidStreamType(streamType);
1927 return (mStreamStates[streamType].getMinIndex() + 5) / 10;
1928 }
1929
Eric Laurent25101b02011-02-02 09:33:30 -08001930 /** Get last audible volume before stream was muted. */
1931 public int getLastAudibleStreamVolume(int streamType) {
1932 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001933 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001934 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08001935 }
1936
John Spurlockee5ad722015-03-03 16:17:21 -05001937 /** @see AudioManager#getUiSoundsStreamType() */
1938 public int getUiSoundsStreamType() {
John Spurlock4f0f1202014-08-05 13:28:33 -04001939 return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
Eric Laurent6d517662012-04-23 18:42:39 -07001940 }
1941
Makoto Onukid45a4a22015-11-02 17:17:38 -08001942 /** @see AudioManager#setMicrophoneMute(boolean) */
1943 @Override
Kenny Guy70e0c582015-06-30 19:18:28 +01001944 public void setMicrophoneMute(boolean on, String callingPackage, int userId) {
1945 // If we are being called by the system check for user we are going to change
1946 // so we handle user restrictions correctly.
1947 int uid = Binder.getCallingUid();
1948 if (uid == android.os.Process.SYSTEM_UID) {
1949 uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
1950 }
Makoto Onuki4f160732015-10-27 17:15:38 -07001951 // If OP_MUTE_MICROPHONE is set, disallow unmuting.
1952 if (!on && mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, uid, callingPackage)
Kenny Guy70e0c582015-06-30 19:18:28 +01001953 != AppOpsManager.MODE_ALLOWED) {
Emily Bernier22c921a2014-05-28 11:01:32 -04001954 return;
1955 }
Jean-Michel Trivi4a4fea02014-08-29 18:14:09 -07001956 if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
1957 return;
1958 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001959 if (userId != UserHandle.getCallingUserId() &&
1960 mContext.checkCallingOrSelfPermission(
1961 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1962 != PackageManager.PERMISSION_GRANTED) {
1963 return;
1964 }
Makoto Onukid45a4a22015-11-02 17:17:38 -08001965 setMicrophoneMuteNoCallerCheck(on, userId);
1966 }
Emily Bernier22c921a2014-05-28 11:01:32 -04001967
Makoto Onukid45a4a22015-11-02 17:17:38 -08001968 private void setMicrophoneMuteNoCallerCheck(boolean on, int userId) {
1969 if (DEBUG_VOL) {
1970 Log.d(TAG, String.format("Mic mute %s, user=%d", on, userId));
1971 }
Kenny Guy70e0c582015-06-30 19:18:28 +01001972 // If mute is for current user actually mute, else just persist the setting
1973 // which will be loaded on user switch.
1974 if (getCurrentUserId() == userId) {
1975 AudioSystem.muteMicrophone(on);
1976 }
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001977 // Post a persist microphone msg.
1978 sendMsg(mAudioHandler, MSG_PERSIST_MICROPHONE_MUTE, SENDMSG_REPLACE, on ? 1
Kenny Guy70e0c582015-06-30 19:18:28 +01001979 : 0, userId, null, PERSIST_DELAY);
Emily Bernier22c921a2014-05-28 11:01:32 -04001980 }
1981
John Spurlock661f2cf2014-11-17 10:29:10 -05001982 @Override
1983 public int getRingerModeExternal() {
1984 synchronized(mSettingsLock) {
1985 return mRingerModeExternal;
1986 }
1987 }
1988
1989 @Override
1990 public int getRingerModeInternal() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001991 synchronized(mSettingsLock) {
1992 return mRingerMode;
1993 }
1994 }
1995
1996 private void ensureValidRingerMode(int ringerMode) {
John Spurlock97559372014-10-24 16:27:36 -04001997 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001998 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1999 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002000 }
2001
John Spurlock97559372014-10-24 16:27:36 -04002002 /** @see AudioManager#isValidRingerMode(int) */
2003 public boolean isValidRingerMode(int ringerMode) {
2004 return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
2005 }
2006
John Spurlock661f2cf2014-11-17 10:29:10 -05002007 public void setRingerModeExternal(int ringerMode, String caller) {
John Spurlockaf88a192014-12-23 16:14:44 -05002008 setRingerMode(ringerMode, caller, true /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05002009 }
2010
2011 public void setRingerModeInternal(int ringerMode, String caller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05002012 enforceVolumeController("setRingerModeInternal");
John Spurlockaf88a192014-12-23 16:14:44 -05002013 setRingerMode(ringerMode, caller, false /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05002014 }
2015
2016 private void setRingerMode(int ringerMode, String caller, boolean external) {
Eric Laurent212532b2014-07-21 15:43:18 -07002017 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07002018 return;
2019 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002020 if (caller == null || caller.length() == 0) {
2021 throw new IllegalArgumentException("Bad caller: " + caller);
2022 }
John Spurlock97559372014-10-24 16:27:36 -04002023 ensureValidRingerMode(ringerMode);
Eric Laurent24482012012-05-10 09:41:17 -07002024 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
2025 ringerMode = AudioManager.RINGER_MODE_SILENT;
2026 }
John Spurlockaf88a192014-12-23 16:14:44 -05002027 final long identity = Binder.clearCallingIdentity();
2028 try {
2029 synchronized (mSettingsLock) {
2030 final int ringerModeInternal = getRingerModeInternal();
2031 final int ringerModeExternal = getRingerModeExternal();
2032 if (external) {
2033 setRingerModeExt(ringerMode);
2034 if (mRingerModeDelegate != null) {
2035 ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
John Spurlocka48d7792015-03-03 17:35:57 -05002036 ringerMode, caller, ringerModeInternal, mVolumePolicy);
John Spurlockaf88a192014-12-23 16:14:44 -05002037 }
2038 if (ringerMode != ringerModeInternal) {
2039 setRingerModeInt(ringerMode, true /*persist*/);
2040 }
2041 } else /*internal*/ {
2042 if (ringerMode != ringerModeInternal) {
2043 setRingerModeInt(ringerMode, true /*persist*/);
2044 }
2045 if (mRingerModeDelegate != null) {
2046 ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
John Spurlocka48d7792015-03-03 17:35:57 -05002047 ringerMode, caller, ringerModeExternal, mVolumePolicy);
John Spurlockaf88a192014-12-23 16:14:44 -05002048 }
2049 setRingerModeExt(ringerMode);
John Spurlock57627792014-12-11 11:29:54 -05002050 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002051 }
John Spurlockaf88a192014-12-23 16:14:44 -05002052 } finally {
2053 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 }
2055 }
2056
John Spurlock661f2cf2014-11-17 10:29:10 -05002057 private void setRingerModeExt(int ringerMode) {
2058 synchronized(mSettingsLock) {
2059 if (ringerMode == mRingerModeExternal) return;
2060 mRingerModeExternal = ringerMode;
John Spurlocke5b42d92014-10-15 12:03:48 -04002061 }
John Spurlock661f2cf2014-11-17 10:29:10 -05002062 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05002063 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
John Spurlocke5b42d92014-10-15 12:03:48 -04002064 }
2065
John Spurlock50ced3f2015-05-11 16:00:09 -04002066 private void muteRingerModeStreams() {
Eric Laurent5b4e6542010-03-19 20:02:21 -07002067 // Mute stream if not previously muted by ringer mode and ringer mode
2068 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
2069 // Unmute stream if previously muted by ringer mode and ringer mode
2070 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07002071 int numStreamTypes = AudioSystem.getNumStreamTypes();
John Spurlock50ced3f2015-05-11 16:00:09 -04002072 final boolean ringerModeMute = mRingerMode == AudioManager.RINGER_MODE_VIBRATE
2073 || mRingerMode == AudioManager.RINGER_MODE_SILENT;
Eric Laurent5b4e6542010-03-19 20:02:21 -07002074 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002075 final boolean isMuted = isStreamMutedByRingerMode(streamType);
2076 final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
2077 if (isMuted == shouldMute) continue;
2078 if (!shouldMute) {
2079 // unmute
2080 // ring and notifications volume should never be 0 when not silenced
John Spurlockd9c75db2015-04-28 11:19:13 -04002081 if (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
John Spurlock661f2cf2014-11-17 10:29:10 -05002082 synchronized (VolumeStreamState.class) {
John Spurlocka48d7792015-03-03 17:35:57 -05002083 final VolumeStreamState vss = mStreamStates[streamType];
2084 for (int i = 0; i < vss.mIndexMap.size(); i++) {
2085 int device = vss.mIndexMap.keyAt(i);
2086 int value = vss.mIndexMap.valueAt(i);
John Spurlock2bb02ec2015-03-02 13:13:06 -05002087 if (value == 0) {
John Spurlocka48d7792015-03-03 17:35:57 -05002088 vss.setIndex(10, device, TAG);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002089 }
2090 }
Eric Laurent9e0d25f2015-02-12 17:28:53 -08002091 // Persist volume for stream ring when it is changed here
2092 final int device = getDeviceForStream(streamType);
2093 sendMsg(mAudioHandler,
2094 MSG_PERSIST_VOLUME,
2095 SENDMSG_QUEUE,
2096 device,
2097 0,
2098 mStreamStates[streamType],
2099 PERSIST_DELAY);
Eric Laurentb024c302011-10-14 17:19:27 -07002100 }
Eric Laurent9bcf4012009-06-12 06:09:28 -07002101 }
RoboErik4197cb62015-01-21 15:45:32 -08002102 mStreamStates[streamType].mute(false);
John Spurlock661f2cf2014-11-17 10:29:10 -05002103 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent5b4e6542010-03-19 20:02:21 -07002104 } else {
John Spurlock661f2cf2014-11-17 10:29:10 -05002105 // mute
RoboErik4197cb62015-01-21 15:45:32 -08002106 mStreamStates[streamType].mute(true);
John Spurlock661f2cf2014-11-17 10:29:10 -05002107 mRingerModeMutedStreams |= (1 << streamType);
Jason Parekhb1096152009-03-24 17:48:25 -07002108 }
2109 }
John Spurlock50ced3f2015-05-11 16:00:09 -04002110 }
2111
2112 private void setRingerModeInt(int ringerMode, boolean persist) {
2113 final boolean change;
2114 synchronized(mSettingsLock) {
2115 change = mRingerMode != ringerMode;
2116 mRingerMode = ringerMode;
2117 }
2118
2119 muteRingerModeStreams();
Eric Laurenta553c252009-07-17 12:17:14 -07002120
Jason Parekhb1096152009-03-24 17:48:25 -07002121 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07002122 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002123 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07002124 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
2125 }
John Spurlockbcc10872014-11-28 15:29:21 -05002126 if (change) {
2127 // Send sticky broadcast
2128 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
2129 }
Jason Parekhb1096152009-03-24 17:48:25 -07002130 }
2131
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002132 /** @see AudioManager#shouldVibrate(int) */
2133 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002134 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002135
2136 switch (getVibrateSetting(vibrateType)) {
2137
2138 case AudioManager.VIBRATE_SETTING_ON:
John Spurlock57627792014-12-11 11:29:54 -05002139 return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002140
2141 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
John Spurlock57627792014-12-11 11:29:54 -05002142 return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002143
2144 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04002145 // return false, even for incoming calls
2146 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002147
2148 default:
2149 return false;
2150 }
2151 }
2152
2153 /** @see AudioManager#getVibrateSetting(int) */
2154 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002155 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002156 return (mVibrateSetting >> (vibrateType * 2)) & 3;
2157 }
2158
2159 /** @see AudioManager#setVibrateSetting(int, int) */
2160 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
2161
Eric Laurentbffc3d12012-05-07 17:43:49 -07002162 if (!mHasVibrator) return;
2163
John Spurlock61560172015-02-06 19:46:04 -05002164 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
2165 vibrateSetting);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002166
2167 // Broadcast change
2168 broadcastVibrateSetting(vibrateType);
2169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002170 }
2171
Eric Laurent9272b4b2010-01-23 17:12:59 -08002172 private class SetModeDeathHandler implements IBinder.DeathRecipient {
2173 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002174 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002175 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
2176
Eric Laurent9f103de2011-09-08 15:04:23 -07002177 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08002178 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07002179 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002180 }
2181
2182 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07002183 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002184 synchronized(mSetModeDeathHandlers) {
2185 Log.w(TAG, "setMode() client died");
2186 int index = mSetModeDeathHandlers.indexOf(this);
2187 if (index < 0) {
2188 Log.w(TAG, "unregistered setMode() client died");
2189 } else {
John Spurlock90874332015-03-10 16:00:54 -04002190 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid, TAG);
Eric Laurent9272b4b2010-01-23 17:12:59 -08002191 }
2192 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002193 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2194 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002195 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07002196 final long ident = Binder.clearCallingIdentity();
2197 disconnectBluetoothSco(newModeOwnerPid);
2198 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07002199 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08002200 }
2201
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002202 public int getPid() {
2203 return mPid;
2204 }
2205
Eric Laurent9272b4b2010-01-23 17:12:59 -08002206 public void setMode(int mode) {
2207 mMode = mode;
2208 }
2209
2210 public int getMode() {
2211 return mMode;
2212 }
2213
2214 public IBinder getBinder() {
2215 return mCb;
2216 }
2217 }
2218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002219 /** @see AudioManager#setMode(int) */
John Spurlock90874332015-03-10 16:00:54 -04002220 public void setMode(int mode, IBinder cb, String callingPackage) {
2221 if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ", callingPackage=" + callingPackage + ")"); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002222 if (!checkAudioSettingsPermission("setMode()")) {
2223 return;
2224 }
Eric Laurenta553c252009-07-17 12:17:14 -07002225
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07002226 if ( (mode == AudioSystem.MODE_IN_CALL) &&
2227 (mContext.checkCallingOrSelfPermission(
2228 android.Manifest.permission.MODIFY_PHONE_STATE)
2229 != PackageManager.PERMISSION_GRANTED)) {
2230 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
2231 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
2232 return;
2233 }
2234
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08002235 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07002236 return;
2237 }
2238
Eric Laurentd7454be2011-09-14 08:45:58 -07002239 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002240 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07002241 if (mode == AudioSystem.MODE_CURRENT) {
2242 mode = mMode;
2243 }
John Spurlock90874332015-03-10 16:00:54 -04002244 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid(), callingPackage);
Eric Laurent9f103de2011-09-08 15:04:23 -07002245 }
2246 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2247 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002248 if (newModeOwnerPid != 0) {
2249 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07002250 }
2251 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002252
Eric Laurent9f103de2011-09-08 15:04:23 -07002253 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07002254 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07002255 // any mode other than NORMAL.
John Spurlock90874332015-03-10 16:00:54 -04002256 private int setModeInt(int mode, IBinder cb, int pid, String caller) {
2257 if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ", caller="
2258 + caller + ")"); }
Eric Laurentd7454be2011-09-14 08:45:58 -07002259 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002260 if (cb == null) {
2261 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07002262 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07002263 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002264
Eric Laurent9f103de2011-09-08 15:04:23 -07002265 SetModeDeathHandler hdlr = null;
2266 Iterator iter = mSetModeDeathHandlers.iterator();
2267 while (iter.hasNext()) {
2268 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
2269 if (h.getPid() == pid) {
2270 hdlr = h;
2271 // Remove from client list so that it is re-inserted at top of list
2272 iter.remove();
2273 hdlr.getBinder().unlinkToDeath(hdlr, 0);
2274 break;
2275 }
2276 }
2277 int status = AudioSystem.AUDIO_STATUS_OK;
2278 do {
2279 if (mode == AudioSystem.MODE_NORMAL) {
2280 // get new mode from client at top the list if any
2281 if (!mSetModeDeathHandlers.isEmpty()) {
2282 hdlr = mSetModeDeathHandlers.get(0);
2283 cb = hdlr.getBinder();
2284 mode = hdlr.getMode();
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002285 if (DEBUG_MODE) {
2286 Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
2287 + hdlr.mPid);
2288 }
Eric Laurentb9c9d262009-05-06 08:13:20 -07002289 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002290 } else {
2291 if (hdlr == null) {
2292 hdlr = new SetModeDeathHandler(cb, pid);
2293 }
2294 // Register for client death notification
2295 try {
2296 cb.linkToDeath(hdlr, 0);
2297 } catch (RemoteException e) {
2298 // Client has died!
2299 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
2300 }
2301
2302 // Last client to call setMode() is always at top of client list
2303 // as required by SetModeDeathHandler.binderDied()
2304 mSetModeDeathHandlers.add(0, hdlr);
2305 hdlr.setMode(mode);
2306 }
2307
2308 if (mode != mMode) {
2309 status = AudioSystem.setPhoneState(mode);
2310 if (status == AudioSystem.AUDIO_STATUS_OK) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002311 if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002312 mMode = mode;
2313 } else {
2314 if (hdlr != null) {
2315 mSetModeDeathHandlers.remove(hdlr);
2316 cb.unlinkToDeath(hdlr, 0);
2317 }
2318 // force reading new top of mSetModeDeathHandlers stack
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002319 if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002320 mode = AudioSystem.MODE_NORMAL;
2321 }
2322 } else {
2323 status = AudioSystem.AUDIO_STATUS_OK;
2324 }
2325 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
2326
2327 if (status == AudioSystem.AUDIO_STATUS_OK) {
2328 if (mode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002329 if (mSetModeDeathHandlers.isEmpty()) {
2330 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
2331 } else {
2332 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2333 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002334 }
2335 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002336 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07002337 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
John Spurlock90874332015-03-10 16:00:54 -04002338 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, caller);
Eric Laurent6d517662012-04-23 18:42:39 -07002339
John Spurlock90874332015-03-10 16:00:54 -04002340 updateStreamVolumeAlias(true /*updateVolumes*/, caller);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002341 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002342 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002343 }
2344
2345 /** @see AudioManager#getMode() */
2346 public int getMode() {
2347 return mMode;
2348 }
2349
Eric Laurente78fced2013-03-15 16:03:47 -07002350 //==========================================================================================
2351 // Sound Effects
2352 //==========================================================================================
2353
2354 private static final String TAG_AUDIO_ASSETS = "audio_assets";
2355 private static final String ATTR_VERSION = "version";
2356 private static final String TAG_GROUP = "group";
2357 private static final String ATTR_GROUP_NAME = "name";
2358 private static final String TAG_ASSET = "asset";
2359 private static final String ATTR_ASSET_ID = "id";
2360 private static final String ATTR_ASSET_FILE = "file";
2361
2362 private static final String ASSET_FILE_VERSION = "1.0";
2363 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
2364
Glenn Kasten167d1a22013-07-23 16:24:41 -07002365 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002366
2367 class LoadSoundEffectReply {
2368 public int mStatus = 1;
2369 };
2370
Eric Laurente78fced2013-03-15 16:03:47 -07002371 private void loadTouchSoundAssetDefaults() {
2372 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
2373 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
2374 SOUND_EFFECT_FILES_MAP[i][0] = 0;
2375 SOUND_EFFECT_FILES_MAP[i][1] = -1;
2376 }
2377 }
2378
2379 private void loadTouchSoundAssets() {
2380 XmlResourceParser parser = null;
2381
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002382 // only load assets once.
2383 if (!SOUND_EFFECT_FILES.isEmpty()) {
2384 return;
2385 }
2386
Eric Laurente78fced2013-03-15 16:03:47 -07002387 loadTouchSoundAssetDefaults();
2388
2389 try {
2390 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
2391
2392 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
2393 String version = parser.getAttributeValue(null, ATTR_VERSION);
2394 boolean inTouchSoundsGroup = false;
2395
2396 if (ASSET_FILE_VERSION.equals(version)) {
2397 while (true) {
2398 XmlUtils.nextElement(parser);
2399 String element = parser.getName();
2400 if (element == null) {
2401 break;
2402 }
2403 if (element.equals(TAG_GROUP)) {
2404 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
2405 if (GROUP_TOUCH_SOUNDS.equals(name)) {
2406 inTouchSoundsGroup = true;
2407 break;
2408 }
2409 }
2410 }
2411 while (inTouchSoundsGroup) {
2412 XmlUtils.nextElement(parser);
2413 String element = parser.getName();
2414 if (element == null) {
2415 break;
2416 }
2417 if (element.equals(TAG_ASSET)) {
2418 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
2419 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
2420 int fx;
2421
2422 try {
2423 Field field = AudioManager.class.getField(id);
2424 fx = field.getInt(null);
2425 } catch (Exception e) {
2426 Log.w(TAG, "Invalid touch sound ID: "+id);
2427 continue;
2428 }
2429
2430 int i = SOUND_EFFECT_FILES.indexOf(file);
2431 if (i == -1) {
2432 i = SOUND_EFFECT_FILES.size();
2433 SOUND_EFFECT_FILES.add(file);
2434 }
2435 SOUND_EFFECT_FILES_MAP[fx][0] = i;
2436 } else {
2437 break;
2438 }
2439 }
2440 }
2441 } catch (Resources.NotFoundException e) {
2442 Log.w(TAG, "audio assets file not found", e);
2443 } catch (XmlPullParserException e) {
2444 Log.w(TAG, "XML parser exception reading touch sound assets", e);
2445 } catch (IOException e) {
2446 Log.w(TAG, "I/O exception reading touch sound assets", e);
2447 } finally {
2448 if (parser != null) {
2449 parser.close();
2450 }
2451 }
2452 }
2453
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002454 /** @see AudioManager#playSoundEffect(int) */
2455 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002456 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002457 }
2458
2459 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002460 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07002461 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
2462 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
2463 return;
2464 }
2465
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002466 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002467 effectType, (int) (volume * 1000), null, 0);
2468 }
2469
2470 /**
2471 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08002472 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002473 */
2474 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002475 int attempts = 3;
2476 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08002477
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002478 synchronized (reply) {
2479 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
2480 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08002481 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07002482 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002483 } catch (InterruptedException e) {
2484 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08002485 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002486 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002487 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002488 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002489 }
2490
2491 /**
2492 * Unloads samples from the sound pool.
2493 * This method can be called to free some memory when
2494 * sound effects are disabled.
2495 */
2496 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002497 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002498 }
2499
Eric Laurenta60e2122010-12-28 16:49:07 -08002500 class SoundPoolListenerThread extends Thread {
2501 public SoundPoolListenerThread() {
2502 super("SoundPoolListenerThread");
2503 }
2504
2505 @Override
2506 public void run() {
2507
2508 Looper.prepare();
2509 mSoundPoolLooper = Looper.myLooper();
2510
2511 synchronized (mSoundEffectsLock) {
2512 if (mSoundPool != null) {
2513 mSoundPoolCallBack = new SoundPoolCallback();
2514 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2515 }
2516 mSoundEffectsLock.notify();
2517 }
2518 Looper.loop();
2519 }
2520 }
2521
2522 private final class SoundPoolCallback implements
2523 android.media.SoundPool.OnLoadCompleteListener {
2524
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002525 int mStatus = 1; // 1 means neither error nor last sample loaded yet
2526 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08002527
2528 public int status() {
2529 return mStatus;
2530 }
2531
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002532 public void setSamples(int[] samples) {
2533 for (int i = 0; i < samples.length; i++) {
2534 // do not wait ack for samples rejected upfront by SoundPool
2535 if (samples[i] > 0) {
2536 mSamples.add(samples[i]);
2537 }
2538 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002539 }
2540
2541 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2542 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002543 int i = mSamples.indexOf(sampleId);
2544 if (i >= 0) {
2545 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08002546 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002547 if ((status != 0) || mSamples. isEmpty()) {
2548 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08002549 mSoundEffectsLock.notify();
2550 }
2551 }
2552 }
2553 }
2554
Eric Laurent4050c932009-07-08 02:52:14 -07002555 /** @see AudioManager#reloadAudioSettings() */
2556 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002557 readAudioSettings(false /*userSwitch*/);
2558 }
2559
2560 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07002561 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2562 readPersistedSettings();
2563
2564 // restore volume settings
2565 int numStreamTypes = AudioSystem.getNumStreamTypes();
2566 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2567 VolumeStreamState streamState = mStreamStates[streamType];
2568
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002569 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2570 continue;
2571 }
2572
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002573 streamState.readSettings();
2574 synchronized (VolumeStreamState.class) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002575 // unmute stream that was muted but is not affect by mute anymore
RoboErik4197cb62015-01-21 15:45:32 -08002576 if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07002577 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
RoboErik4197cb62015-01-21 15:45:32 -08002578 streamState.mIsMuted = false;
Eric Laurent4050c932009-07-08 02:52:14 -07002579 }
Eric Laurent4050c932009-07-08 02:52:14 -07002580 }
2581 }
2582
Eric Laurent33902db2012-10-07 16:15:07 -07002583 // apply new ringer mode before checking volume for alias streams so that streams
2584 // muted by ringer mode have the correct volume
John Spurlock661f2cf2014-11-17 10:29:10 -05002585 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent33902db2012-10-07 16:15:07 -07002586
Eric Laurent212532b2014-07-21 15:43:18 -07002587 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07002588 checkAllAliasStreamVolumes();
John Spurlockb6e19e32015-03-10 21:33:44 -04002589 checkMuteAffectedStreams();
Eric Laurent24482012012-05-10 09:41:17 -07002590
Eric Laurentd640bd32012-09-28 18:01:48 -07002591 synchronized (mSafeMediaVolumeState) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002592 mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2593 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2594 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
Eric Laurentd640bd32012-09-28 18:01:48 -07002595 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
John Spurlock90874332015-03-10 16:00:54 -04002596 enforceSafeMediaVolume(TAG);
Eric Laurentf1a457d2012-09-20 16:27:23 -07002597 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07002598 }
Eric Laurent4050c932009-07-08 02:52:14 -07002599 }
2600
Dianne Hackborn961cae92013-03-20 14:59:43 -07002601 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002602 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002603 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2604 return;
2605 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002606
2607 if (on) {
2608 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2609 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2610 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
2611 }
2612 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2613 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2614 mForcedUseForComm = AudioSystem.FORCE_NONE;
2615 }
Eric Laurentfa640152011-03-12 15:59:51 -08002616
Eric Laurentafbb0472011-12-15 09:04:23 -08002617 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002618 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002619 }
2620
2621 /** @see AudioManager#isSpeakerphoneOn() */
2622 public boolean isSpeakerphoneOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002623 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002624 }
2625
Dianne Hackborn961cae92013-03-20 14:59:43 -07002626 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurent48221252015-09-24 18:41:48 -07002627 public void setBluetoothScoOn(boolean on) {
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002628 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2629 return;
2630 }
Eric Laurent48221252015-09-24 18:41:48 -07002631 setBluetoothScoOnInt(on);
2632 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002633
Eric Laurent48221252015-09-24 18:41:48 -07002634 public void setBluetoothScoOnInt(boolean on) {
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002635 if (on) {
2636 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2637 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2638 mForcedUseForComm = AudioSystem.FORCE_NONE;
2639 }
Eric Laurentfa640152011-03-12 15:59:51 -08002640
Eric Laurentafbb0472011-12-15 09:04:23 -08002641 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002642 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08002643 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002644 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002645 }
2646
2647 /** @see AudioManager#isBluetoothScoOn() */
2648 public boolean isBluetoothScoOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002649 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002650 }
2651
Dianne Hackborn961cae92013-03-20 14:59:43 -07002652 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07002653 public void setBluetoothA2dpOn(boolean on) {
Eric Laurentc390bed2012-07-03 12:24:05 -07002654 synchronized (mBluetoothA2dpEnabledLock) {
2655 mBluetoothA2dpEnabled = on;
2656 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2657 AudioSystem.FOR_MEDIA,
2658 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2659 null, 0);
2660 }
Eric Laurent78472112012-05-21 08:57:21 -07002661 }
2662
2663 /** @see AudioManager#isBluetoothA2dpOn() */
2664 public boolean isBluetoothA2dpOn() {
2665 synchronized (mBluetoothA2dpEnabledLock) {
2666 return mBluetoothA2dpEnabled;
2667 }
2668 }
2669
Eric Laurent3def1ee2010-03-17 23:26:26 -07002670 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07002671 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
2672 int scoAudioMode =
2673 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
Liejun Taof4e51d82014-07-16 11:18:29 -07002674 SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
Eric Laurent83900752014-05-15 15:14:22 -07002675 startBluetoothScoInt(cb, scoAudioMode);
2676 }
2677
2678 /** @see AudioManager#startBluetoothScoVirtualCall() */
2679 public void startBluetoothScoVirtualCall(IBinder cb) {
2680 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
2681 }
2682
2683 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07002684 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002685 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002686 return;
2687 }
Eric Laurent854938a2011-02-22 12:05:20 -08002688 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002689 // The calling identity must be cleared before calling ScoClient.incCount().
2690 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2691 // and this must be done on behalf of system server to make sure permissions are granted.
2692 // The caller identity must be cleared after getScoClient() because it is needed if a new
2693 // client is created.
2694 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07002695 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08002696 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002697 }
2698
2699 /** @see AudioManager#stopBluetoothSco() */
2700 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07002701 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002702 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002703 return;
2704 }
Eric Laurent854938a2011-02-22 12:05:20 -08002705 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002706 // The calling identity must be cleared before calling ScoClient.decCount().
2707 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2708 // and this must be done on behalf of system server to make sure permissions are granted.
2709 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08002710 if (client != null) {
2711 client.decCount();
2712 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08002713 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002714 }
2715
Eric Laurent78472112012-05-21 08:57:21 -07002716
Eric Laurent3def1ee2010-03-17 23:26:26 -07002717 private class ScoClient implements IBinder.DeathRecipient {
2718 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002719 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002720 private int mStartcount; // number of SCO connections started by this client
2721
2722 ScoClient(IBinder cb) {
2723 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002724 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002725 mStartcount = 0;
2726 }
2727
2728 public void binderDied() {
2729 synchronized(mScoClients) {
2730 Log.w(TAG, "SCO client died");
2731 int index = mScoClients.indexOf(this);
2732 if (index < 0) {
2733 Log.w(TAG, "unregistered SCO client died");
2734 } else {
2735 clearCount(true);
2736 mScoClients.remove(this);
2737 }
2738 }
2739 }
2740
Eric Laurent83900752014-05-15 15:14:22 -07002741 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002742 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07002743 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002744 if (mStartcount == 0) {
2745 try {
2746 mCb.linkToDeath(this, 0);
2747 } catch (RemoteException e) {
2748 // client has already died!
2749 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
2750 }
2751 }
2752 mStartcount++;
2753 }
2754 }
2755
2756 public void decCount() {
2757 synchronized(mScoClients) {
2758 if (mStartcount == 0) {
2759 Log.w(TAG, "ScoClient.decCount() already 0");
2760 } else {
2761 mStartcount--;
2762 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002763 try {
2764 mCb.unlinkToDeath(this, 0);
2765 } catch (NoSuchElementException e) {
2766 Log.w(TAG, "decCount() going to 0 but not registered to binder");
2767 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002768 }
Eric Laurentc18c9132013-04-12 17:24:56 -07002769 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002770 }
2771 }
2772 }
2773
2774 public void clearCount(boolean stopSco) {
2775 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002776 if (mStartcount != 0) {
2777 try {
2778 mCb.unlinkToDeath(this, 0);
2779 } catch (NoSuchElementException e) {
2780 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2781 }
2782 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002783 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002784 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002785 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002786 }
2787 }
2788 }
2789
2790 public int getCount() {
2791 return mStartcount;
2792 }
2793
2794 public IBinder getBinder() {
2795 return mCb;
2796 }
2797
Eric Laurentd7454be2011-09-14 08:45:58 -07002798 public int getPid() {
2799 return mCreatorPid;
2800 }
2801
Eric Laurent3def1ee2010-03-17 23:26:26 -07002802 public int totalCount() {
2803 synchronized(mScoClients) {
2804 int count = 0;
2805 int size = mScoClients.size();
2806 for (int i = 0; i < size; i++) {
2807 count += mScoClients.get(i).getCount();
2808 }
2809 return count;
2810 }
2811 }
2812
Eric Laurent83900752014-05-15 15:14:22 -07002813 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08002814 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07002815 if (totalCount() == 0) {
2816 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2817 // Make sure that the state transitions to CONNECTING even if we cannot initiate
2818 // the connection.
2819 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2820 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002821 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07002822 synchronized(mSetModeDeathHandlers) {
2823 if ((mSetModeDeathHandlers.isEmpty() ||
2824 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2825 (mScoAudioState == SCO_STATE_INACTIVE ||
2826 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2827 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07002828 mScoAudioMode = scoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -07002829 if (scoAudioMode == SCO_MODE_UNDEFINED) {
Andre Eisenbach570cc532014-10-28 17:03:18 -07002830 if (mBluetoothHeadsetDevice != null) {
2831 mScoAudioMode = new Integer(Settings.Global.getInt(
2832 mContentResolver,
2833 "bluetooth_sco_channel_"+
2834 mBluetoothHeadsetDevice.getAddress(),
2835 SCO_MODE_VIRTUAL_CALL));
2836 if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2837 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2838 }
2839 } else {
2840 mScoAudioMode = SCO_MODE_RAW;
Liejun Taof4e51d82014-07-16 11:18:29 -07002841 }
2842 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002843 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002844 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002845 if (mScoAudioMode == SCO_MODE_RAW) {
2846 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002847 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002848 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2849 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002850 } else if (mScoAudioMode == SCO_MODE_VR) {
2851 status = mBluetoothHeadset.startVoiceRecognition(
2852 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002853 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002854
Eric Laurentc18c9132013-04-12 17:24:56 -07002855 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07002856 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2857 } else {
2858 broadcastScoConnectionState(
2859 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2860 }
2861 } else if (getBluetoothHeadset()) {
2862 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07002863 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002864 } else {
2865 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2866 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002867 }
2868 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07002869 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002870 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002871 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002872 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002873 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2874 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2875 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07002876 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002877 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002878 if (mScoAudioMode == SCO_MODE_RAW) {
2879 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002880 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002881 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2882 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002883 } else if (mScoAudioMode == SCO_MODE_VR) {
2884 status = mBluetoothHeadset.stopVoiceRecognition(
2885 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002886 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002887
Eric Laurentc18c9132013-04-12 17:24:56 -07002888 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002889 mScoAudioState = SCO_STATE_INACTIVE;
2890 broadcastScoConnectionState(
2891 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2892 }
2893 } else if (getBluetoothHeadset()) {
2894 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2895 }
2896 } else {
2897 mScoAudioState = SCO_STATE_INACTIVE;
2898 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2899 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002900 }
2901 }
2902 }
2903 }
2904
Eric Laurent62ef7672010-11-24 10:58:32 -08002905 private void checkScoAudioState() {
2906 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002907 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08002908 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2909 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2910 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2911 }
2912 }
2913
Eric Laurent854938a2011-02-22 12:05:20 -08002914 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002915 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002916 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002917 int size = mScoClients.size();
2918 for (int i = 0; i < size; i++) {
2919 client = mScoClients.get(i);
2920 if (client.getBinder() == cb)
2921 return client;
2922 }
Eric Laurent854938a2011-02-22 12:05:20 -08002923 if (create) {
2924 client = new ScoClient(cb);
2925 mScoClients.add(client);
2926 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002927 return client;
2928 }
2929 }
2930
Eric Laurentd7454be2011-09-14 08:45:58 -07002931 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002932 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002933 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002934 int size = mScoClients.size();
2935 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08002936 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07002937 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08002938 cl.clearCount(stopSco);
2939 } else {
2940 savedClient = cl;
2941 }
2942 }
2943 mScoClients.clear();
2944 if (savedClient != null) {
2945 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002946 }
2947 }
2948 }
2949
Eric Laurentdc03c612011-04-01 10:59:41 -07002950 private boolean getBluetoothHeadset() {
2951 boolean result = false;
2952 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2953 if (adapter != null) {
2954 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2955 BluetoothProfile.HEADSET);
2956 }
2957 // If we could not get a bluetooth headset proxy, send a failure message
2958 // without delay to reset the SCO audio state and clear SCO clients.
2959 // If we could get a proxy, send a delayed failure message that will reset our state
2960 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08002961 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002962 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2963 return result;
2964 }
2965
Eric Laurentd7454be2011-09-14 08:45:58 -07002966 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002967 synchronized(mScoClients) {
2968 checkScoAudioState();
2969 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2970 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2971 if (mBluetoothHeadsetDevice != null) {
2972 if (mBluetoothHeadset != null) {
2973 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07002974 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002975 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002976 SENDMSG_REPLACE, 0, 0, null, 0);
2977 }
2978 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2979 getBluetoothHeadset()) {
2980 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2981 }
2982 }
2983 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07002984 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07002985 }
2986 }
2987 }
2988
2989 private void resetBluetoothSco() {
2990 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002991 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07002992 mScoAudioState = SCO_STATE_INACTIVE;
2993 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2994 }
Eric Laurent48221252015-09-24 18:41:48 -07002995 AudioSystem.setParameters("A2dpSuspended=false");
2996 setBluetoothScoOnInt(false);
Eric Laurentdc03c612011-04-01 10:59:41 -07002997 }
2998
2999 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08003000 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
3001 SENDMSG_QUEUE, state, 0, null, 0);
3002 }
3003
3004 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07003005 if (state != mScoConnectionState) {
3006 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
3007 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
3008 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
3009 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003010 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07003011 mScoConnectionState = state;
3012 }
3013 }
3014
Eric Laurent98859b22015-06-12 14:35:59 -07003015 void setBtScoDeviceConnectionState(BluetoothDevice btDevice, int state) {
3016 if (btDevice == null) {
3017 return;
3018 }
3019
3020 String address = btDevice.getAddress();
3021 BluetoothClass btClass = btDevice.getBluetoothClass();
3022 int outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
3023 int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
3024 if (btClass != null) {
3025 switch (btClass.getDeviceClass()) {
3026 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
3027 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
3028 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
3029 break;
3030 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
3031 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
3032 break;
3033 }
3034 }
3035
3036 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
3037 address = "";
3038 }
3039
3040 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
3041
3042 String btDeviceName = btDevice.getName();
3043 boolean success =
3044 handleDeviceConnection(connected, outDevice, address, btDeviceName) &&
3045 handleDeviceConnection(connected, inDevice, address, btDeviceName);
3046 if (success) {
3047 synchronized (mScoClients) {
3048 if (connected) {
3049 mBluetoothHeadsetDevice = btDevice;
3050 } else {
3051 mBluetoothHeadsetDevice = null;
3052 resetBluetoothSco();
3053 }
3054 }
3055 }
3056 }
3057
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07003058 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
3059 new BluetoothProfile.ServiceListener() {
3060 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003061 BluetoothDevice btDevice;
3062 List<BluetoothDevice> deviceList;
3063 switch(profile) {
3064 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09003065 synchronized (mConnectedDevices) {
3066 synchronized (mA2dpAvrcpLock) {
3067 mA2dp = (BluetoothA2dp) proxy;
3068 deviceList = mA2dp.getConnectedDevices();
3069 if (deviceList.size() > 0) {
3070 btDevice = deviceList.get(0);
John Du5a0cf7a2013-07-19 11:30:34 -07003071 int state = mA2dp.getConnectionState(btDevice);
3072 int delay = checkSendBecomingNoisyIntent(
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003073 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3074 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
John Du5a0cf7a2013-07-19 11:30:34 -07003075 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003076 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07003077 state,
3078 0,
3079 btDevice,
3080 delay);
3081 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003082 }
Eric Laurent62ef7672010-11-24 10:58:32 -08003083 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003084 break;
3085
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003086 case BluetoothProfile.A2DP_SINK:
3087 deviceList = proxy.getConnectedDevices();
3088 if (deviceList.size() > 0) {
3089 btDevice = deviceList.get(0);
3090 synchronized (mConnectedDevices) {
3091 int state = proxy.getConnectionState(btDevice);
3092 queueMsgUnderWakeLock(mAudioHandler,
3093 MSG_SET_A2DP_SRC_CONNECTION_STATE,
3094 state,
3095 0,
3096 btDevice,
3097 0 /* delay */);
3098 }
3099 }
3100 break;
3101
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003102 case BluetoothProfile.HEADSET:
3103 synchronized (mScoClients) {
3104 // Discard timeout message
3105 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
3106 mBluetoothHeadset = (BluetoothHeadset) proxy;
3107 deviceList = mBluetoothHeadset.getConnectedDevices();
3108 if (deviceList.size() > 0) {
3109 mBluetoothHeadsetDevice = deviceList.get(0);
3110 } else {
3111 mBluetoothHeadsetDevice = null;
3112 }
3113 // Refresh SCO audio state
3114 checkScoAudioState();
3115 // Continue pending action if any
3116 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
3117 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
3118 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
3119 boolean status = false;
3120 if (mBluetoothHeadsetDevice != null) {
3121 switch (mScoAudioState) {
3122 case SCO_STATE_ACTIVATE_REQ:
3123 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07003124 if (mScoAudioMode == SCO_MODE_RAW) {
3125 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003126 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003127 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
3128 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003129 } else if (mScoAudioMode == SCO_MODE_VR) {
3130 status = mBluetoothHeadset.startVoiceRecognition(
3131 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003132 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003133 break;
3134 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07003135 if (mScoAudioMode == SCO_MODE_RAW) {
3136 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07003137 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07003138 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
3139 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07003140 } else if (mScoAudioMode == SCO_MODE_VR) {
3141 status = mBluetoothHeadset.stopVoiceRecognition(
3142 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07003143 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003144 break;
3145 case SCO_STATE_DEACTIVATE_EXT_REQ:
3146 status = mBluetoothHeadset.stopVoiceRecognition(
3147 mBluetoothHeadsetDevice);
3148 }
3149 }
3150 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08003151 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003152 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07003153 }
3154 }
Eric Laurentdc03c612011-04-01 10:59:41 -07003155 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003156 break;
3157
3158 default:
3159 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003160 }
3161 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07003162 public void onServiceDisconnected(int profile) {
Eric Laurentb70b78a2016-01-13 19:16:04 -08003163
Paul McLean394a8e12015-03-03 10:29:19 -07003164 switch (profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003165 case BluetoothProfile.A2DP:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003166 disconnectA2dp();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003167 break;
3168
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003169 case BluetoothProfile.A2DP_SINK:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003170 disconnectA2dpSink();
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003171 break;
3172
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003173 case BluetoothProfile.HEADSET:
Eric Laurentb70b78a2016-01-13 19:16:04 -08003174 disconnectHeadset();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08003175 break;
3176
3177 default:
3178 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07003179 }
3180 }
3181 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003182
Eric Laurentb70b78a2016-01-13 19:16:04 -08003183 void disconnectAllBluetoothProfiles() {
3184 disconnectA2dp();
3185 disconnectA2dpSink();
3186 disconnectHeadset();
3187 }
3188
3189 void disconnectA2dp() {
3190 synchronized (mConnectedDevices) {
3191 synchronized (mA2dpAvrcpLock) {
3192 ArraySet<String> toRemove = null;
3193 // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
3194 for (int i = 0; i < mConnectedDevices.size(); i++) {
3195 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
3196 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
3197 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
3198 toRemove.add(deviceSpec.mDeviceAddress);
3199 }
3200 }
3201 if (toRemove != null) {
3202 int delay = checkSendBecomingNoisyIntent(
3203 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3204 0);
3205 for (int i = 0; i < toRemove.size(); i++) {
3206 makeA2dpDeviceUnavailableLater(toRemove.valueAt(i), delay);
3207 }
3208 }
3209 }
3210 }
3211 }
3212
3213 void disconnectA2dpSink() {
3214 synchronized (mConnectedDevices) {
3215 ArraySet<String> toRemove = null;
3216 // Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
3217 for(int i = 0; i < mConnectedDevices.size(); i++) {
3218 DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
3219 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) {
3220 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
3221 toRemove.add(deviceSpec.mDeviceAddress);
3222 }
3223 }
3224 if (toRemove != null) {
3225 for (int i = 0; i < toRemove.size(); i++) {
3226 makeA2dpSrcUnavailable(toRemove.valueAt(i));
3227 }
3228 }
3229 }
3230 }
3231
3232 void disconnectHeadset() {
3233 synchronized (mScoClients) {
3234 if (mBluetoothHeadsetDevice != null) {
3235 setBtScoDeviceConnectionState(mBluetoothHeadsetDevice,
3236 BluetoothProfile.STATE_DISCONNECTED);
3237 }
3238 mBluetoothHeadset = null;
3239 }
3240 }
3241
John Spurlock90874332015-03-10 16:00:54 -04003242 private void onCheckMusicActive(String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07003243 synchronized (mSafeMediaVolumeState) {
3244 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07003245 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
3246
3247 if ((device & mSafeMediaVolumeDevices) != 0) {
3248 sendMsg(mAudioHandler,
3249 MSG_CHECK_MUSIC_ACTIVE,
3250 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07003251 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07003252 0,
John Spurlock90874332015-03-10 16:00:54 -04003253 caller,
Eric Laurentc34dcc12012-09-10 13:51:52 -07003254 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07003255 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07003256 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
3257 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07003258 // Approximate cumulative active music time
3259 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
3260 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
John Spurlock90874332015-03-10 16:00:54 -04003261 setSafeMediaVolumeEnabled(true, caller);
Eric Laurentc34dcc12012-09-10 13:51:52 -07003262 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07003263 }
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003264 saveMusicActiveMs();
Eric Laurentc34dcc12012-09-10 13:51:52 -07003265 }
3266 }
3267 }
3268 }
3269 }
3270
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003271 private void saveMusicActiveMs() {
3272 mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
3273 }
3274
John Spurlock90874332015-03-10 16:00:54 -04003275 private void onConfigureSafeVolume(boolean force, String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07003276 synchronized (mSafeMediaVolumeState) {
3277 int mcc = mContext.getResources().getConfiguration().mcc;
3278 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
3279 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
3280 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
John Spurlock35134602014-07-24 18:10:48 -04003281 boolean safeMediaVolumeEnabled =
3282 SystemProperties.getBoolean("audio.safemedia.force", false)
3283 || mContext.getResources().getBoolean(
3284 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08003285
Ricardo Garcia3a30a762015-06-23 15:54:45 -07003286 boolean safeMediaVolumeBypass =
3287 SystemProperties.getBoolean("audio.safemedia.bypass", false);
3288
Eric Laurent05274f32012-11-29 12:48:18 -08003289 // The persisted state is either "disabled" or "active": this is the state applied
3290 // next time we boot and cannot be "inactive"
3291 int persistedState;
Ricardo Garcia3a30a762015-06-23 15:54:45 -07003292 if (safeMediaVolumeEnabled && !safeMediaVolumeBypass) {
Eric Laurent05274f32012-11-29 12:48:18 -08003293 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
3294 // The state can already be "inactive" here if the user has forced it before
3295 // the 30 seconds timeout for forced configuration. In this case we don't reset
3296 // it to "active".
3297 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003298 if (mMusicActiveMs == 0) {
3299 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
John Spurlock90874332015-03-10 16:00:54 -04003300 enforceSafeMediaVolume(caller);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003301 } else {
3302 // We have existing playback time recorded, already confirmed.
3303 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
3304 }
Eric Laurent05274f32012-11-29 12:48:18 -08003305 }
Eric Laurentd640bd32012-09-28 18:01:48 -07003306 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08003307 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07003308 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
3309 }
3310 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08003311 sendMsg(mAudioHandler,
3312 MSG_PERSIST_SAFE_VOLUME_STATE,
3313 SENDMSG_QUEUE,
3314 persistedState,
3315 0,
3316 null,
3317 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07003318 }
3319 }
3320 }
3321
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003322 ///////////////////////////////////////////////////////////////////////////
3323 // Internal methods
3324 ///////////////////////////////////////////////////////////////////////////
3325
3326 /**
3327 * Checks if the adjustment should change ringer mode instead of just
3328 * adjusting volume. If so, this will set the proper ringer mode and volume
3329 * indices on the stream states.
3330 */
John Spurlocka48d7792015-03-03 17:35:57 -05003331 private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted) {
3332 final boolean isTv = mPlatformType == AudioSystem.PLATFORM_TELEVISION;
John Spurlocka11b4af2014-06-01 11:52:23 -04003333 int result = FLAG_ADJUST_VOLUME;
John Spurlock661f2cf2014-11-17 10:29:10 -05003334 int ringerMode = getRingerModeInternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003335
Eric Laurentbffc3d12012-05-07 17:43:49 -07003336 switch (ringerMode) {
3337 case RINGER_MODE_NORMAL:
3338 if (direction == AudioManager.ADJUST_LOWER) {
3339 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07003340 // "step" is the delta in internal index units corresponding to a
3341 // change of 1 in UI index units.
3342 // Because of rounding when rescaling from one stream index range to its alias
3343 // index range, we cannot simply test oldIndex == step:
3344 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
3345 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003346 ringerMode = RINGER_MODE_VIBRATE;
John Spurlock07e72432015-03-13 11:46:52 -04003347 mLoweredFromNormalToVibrateTime = SystemClock.uptimeMillis();
Eric Laurentbffc3d12012-05-07 17:43:49 -07003348 }
3349 } else {
John Spurlockd9c75db2015-04-28 11:19:13 -04003350 if (oldIndex == step && mVolumePolicy.volumeDownToEnterSilent) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003351 ringerMode = RINGER_MODE_SILENT;
3352 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07003353 }
John Spurlocka48d7792015-03-03 17:35:57 -05003354 } else if (isTv && (direction == AudioManager.ADJUST_TOGGLE_MUTE
3355 || direction == AudioManager.ADJUST_MUTE)) {
RoboErik5452e252015-02-06 15:33:53 -08003356 if (mHasVibrator) {
3357 ringerMode = RINGER_MODE_VIBRATE;
3358 } else {
3359 ringerMode = RINGER_MODE_SILENT;
3360 }
3361 // Setting the ringer mode will toggle mute
3362 result &= ~FLAG_ADJUST_VOLUME;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003363 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003364 break;
3365 case RINGER_MODE_VIBRATE:
3366 if (!mHasVibrator) {
3367 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
3368 "but no vibrator is present");
3369 break;
3370 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003371 if ((direction == AudioManager.ADJUST_LOWER)) {
RoboErik5452e252015-02-06 15:33:53 -08003372 // This is the case we were muted with the volume turned up
John Spurlocka48d7792015-03-03 17:35:57 -05003373 if (isTv && oldIndex >= 2 * step && isMuted) {
RoboErik5452e252015-02-06 15:33:53 -08003374 ringerMode = RINGER_MODE_NORMAL;
3375 } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
John Spurlocka48d7792015-03-03 17:35:57 -05003376 if (mVolumePolicy.volumeDownToEnterSilent) {
John Spurlock07e72432015-03-13 11:46:52 -04003377 final long diff = SystemClock.uptimeMillis()
3378 - mLoweredFromNormalToVibrateTime;
John Spurlockd9c75db2015-04-28 11:19:13 -04003379 if (diff > mVolumePolicy.vibrateToSilentDebounce
3380 && mRingerModeDelegate.canVolumeDownEnterSilent()) {
John Spurlock07e72432015-03-13 11:46:52 -04003381 ringerMode = RINGER_MODE_SILENT;
3382 }
John Spurlock795a5142014-12-08 14:09:35 -05003383 } else {
3384 result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
3385 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003386 }
RoboErik5452e252015-02-06 15:33:53 -08003387 } else if (direction == AudioManager.ADJUST_RAISE
3388 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3389 || direction == AudioManager.ADJUST_UNMUTE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003390 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07003391 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003392 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003393 break;
3394 case RINGER_MODE_SILENT:
John Spurlocka48d7792015-03-03 17:35:57 -05003395 if (isTv && direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
RoboErik5452e252015-02-06 15:33:53 -08003396 // This is the case we were muted with the volume turned up
3397 ringerMode = RINGER_MODE_NORMAL;
3398 } else if (direction == AudioManager.ADJUST_RAISE
3399 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3400 || direction == AudioManager.ADJUST_UNMUTE) {
John Spurlocka48d7792015-03-03 17:35:57 -05003401 if (!mVolumePolicy.volumeUpToExitSilent) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003402 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003403 } else {
RoboErik5452e252015-02-06 15:33:53 -08003404 if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003405 ringerMode = RINGER_MODE_VIBRATE;
3406 } else {
RoboErik5452e252015-02-06 15:33:53 -08003407 // If we don't have a vibrator or they were toggling mute
3408 // go straight back to normal.
John Spurlocka11b4af2014-06-01 11:52:23 -04003409 ringerMode = RINGER_MODE_NORMAL;
3410 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003411 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05003412 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003413 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003414 break;
3415 default:
3416 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
3417 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003418 }
3419
John Spurlock661f2cf2014-11-17 10:29:10 -05003420 setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003421
Eric Laurent25101b02011-02-02 09:33:30 -08003422 mPrevVolDirection = direction;
3423
John Spurlocka11b4af2014-06-01 11:52:23 -04003424 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003425 }
3426
John Spurlock3346a802014-05-20 16:25:37 -04003427 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003428 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07003429 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003430 }
3431
Eric Laurent5b4e6542010-03-19 20:02:21 -07003432 private boolean isStreamMutedByRingerMode(int streamType) {
3433 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
3434 }
3435
John Spurlock50ced3f2015-05-11 16:00:09 -04003436 private boolean updateRingerModeAffectedStreams() {
3437 int ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003438 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3439 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
3440 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
3441 UserHandle.USER_CURRENT);
3442
John Spurlock50ced3f2015-05-11 16:00:09 -04003443 if (mPlatformType == AudioSystem.PLATFORM_TELEVISION) {
3444 ringerModeAffectedStreams = 0;
3445 } else if (mRingerModeDelegate != null) {
3446 ringerModeAffectedStreams = mRingerModeDelegate
3447 .getRingerModeAffectedStreams(ringerModeAffectedStreams);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003448 }
3449 synchronized (mCameraSoundForced) {
3450 if (mCameraSoundForced) {
3451 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3452 } else {
3453 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3454 }
3455 }
3456 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
3457 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
3458 } else {
3459 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
3460 }
3461
3462 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3463 Settings.System.putIntForUser(mContentResolver,
3464 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3465 ringerModeAffectedStreams,
3466 UserHandle.USER_CURRENT);
3467 mRingerModeAffectedStreams = ringerModeAffectedStreams;
3468 return true;
3469 }
3470 return false;
3471 }
3472
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05003473 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003474 public boolean isStreamAffectedByMute(int streamType) {
3475 return (mMuteAffectedStreams & (1 << streamType)) != 0;
3476 }
3477
3478 private void ensureValidDirection(int direction) {
RoboErik4197cb62015-01-21 15:45:32 -08003479 switch (direction) {
3480 case AudioManager.ADJUST_LOWER:
3481 case AudioManager.ADJUST_RAISE:
3482 case AudioManager.ADJUST_SAME:
3483 case AudioManager.ADJUST_MUTE:
3484 case AudioManager.ADJUST_UNMUTE:
3485 case AudioManager.ADJUST_TOGGLE_MUTE:
3486 break;
3487 default:
3488 throw new IllegalArgumentException("Bad direction " + direction);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003489 }
3490 }
3491
3492 private void ensureValidStreamType(int streamType) {
3493 if (streamType < 0 || streamType >= mStreamStates.length) {
3494 throw new IllegalArgumentException("Bad stream type " + streamType);
3495 }
3496 }
3497
RoboErik4197cb62015-01-21 15:45:32 -08003498 private boolean isMuteAdjust(int adjust) {
3499 return adjust == AudioManager.ADJUST_MUTE || adjust == AudioManager.ADJUST_UNMUTE
3500 || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
3501 }
3502
Eric Laurent6d517662012-04-23 18:42:39 -07003503 private boolean isInCommunication() {
Nancy Chen0eb1e402014-08-21 22:52:29 -07003504 boolean IsInCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003505
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003506 TelecomManager telecomManager =
3507 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
Eric Laurent38edfda2014-12-18 17:38:04 -08003508
3509 final long ident = Binder.clearCallingIdentity();
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003510 IsInCall = telecomManager.isInCall();
Eric Laurent38edfda2014-12-18 17:38:04 -08003511 Binder.restoreCallingIdentity(ident);
Santos Cordon9eb45932014-06-27 12:28:43 -07003512
Nancy Chen0eb1e402014-08-21 22:52:29 -07003513 return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
Eric Laurent6d517662012-04-23 18:42:39 -07003514 }
Eric Laurent25101b02011-02-02 09:33:30 -08003515
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003516 /**
3517 * For code clarity for getActiveStreamType(int)
3518 * @param delay_ms max time since last STREAM_MUSIC activity to consider
3519 * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
3520 * in the last "delay_ms" ms.
3521 */
3522 private boolean isAfMusicActiveRecently(int delay_ms) {
3523 return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
3524 || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
3525 }
3526
Eric Laurent6d517662012-04-23 18:42:39 -07003527 private int getActiveStreamType(int suggestedStreamType) {
Eric Laurent212532b2014-07-21 15:43:18 -07003528 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003529 case AudioSystem.PLATFORM_VOICE:
Eric Laurent6d517662012-04-23 18:42:39 -07003530 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003531 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3532 == AudioSystem.FORCE_BT_SCO) {
3533 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
3534 return AudioSystem.STREAM_BLUETOOTH_SCO;
3535 } else {
3536 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
3537 return AudioSystem.STREAM_VOICE_CALL;
3538 }
Eric Laurent25101b02011-02-02 09:33:30 -08003539 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003540 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003541 if (DEBUG_VOL)
3542 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3543 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003544 } else {
3545 if (DEBUG_VOL)
3546 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
3547 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003548 }
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003549 } else if (isAfMusicActiveRecently(0)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003550 if (DEBUG_VOL)
3551 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3552 return AudioSystem.STREAM_MUSIC;
Eric Laurent25101b02011-02-02 09:33:30 -08003553 }
Eric Laurent212532b2014-07-21 15:43:18 -07003554 break;
John Spurlock61560172015-02-06 19:46:04 -05003555 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -07003556 if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
RoboErik2811dd32014-08-12 09:48:13 -07003557 // TV always defaults to STREAM_MUSIC
Eric Laurent212532b2014-07-21 15:43:18 -07003558 return AudioSystem.STREAM_MUSIC;
Eric Laurent212532b2014-07-21 15:43:18 -07003559 }
3560 break;
3561 default:
Eric Laurent6d517662012-04-23 18:42:39 -07003562 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003563 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3564 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003565 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08003566 return AudioSystem.STREAM_BLUETOOTH_SCO;
3567 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003568 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08003569 return AudioSystem.STREAM_VOICE_CALL;
3570 }
3571 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003572 StreamOverride.sDelayMs) ||
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003573 AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003574 StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003575 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08003576 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003577 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003578 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003579 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
3580 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003581 } else {
John Spurlockeb1d88d2014-07-19 14:49:19 -04003582 if (DEBUG_VOL) Log.v(TAG,
3583 "getActiveStreamType: using STREAM_NOTIFICATION as default");
3584 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003585 }
Joe Onoratoc7fcba42011-01-05 16:53:11 -08003586 }
Eric Laurent212532b2014-07-21 15:43:18 -07003587 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003588 }
Eric Laurent212532b2014-07-21 15:43:18 -07003589 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
3590 + suggestedStreamType);
3591 return suggestedStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003592 }
3593
John Spurlockbcc10872014-11-28 15:29:21 -05003594 private void broadcastRingerMode(String action, int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003595 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05003596 Intent broadcast = new Intent(action);
Glenn Kastenba195eb2011-12-13 09:30:40 -08003597 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003598 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
3599 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003600 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003601 }
3602
3603 private void broadcastVibrateSetting(int vibrateType) {
3604 // Send broadcast
3605 if (ActivityManagerNative.isSystemReady()) {
3606 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
3607 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
3608 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003609 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003610 }
3611 }
3612
3613 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003614 /**
3615 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
3616 * Note that the wake lock needs to be released after the message has been handled.
3617 */
3618 private void queueMsgUnderWakeLock(Handler handler, int msg,
3619 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003620 final long ident = Binder.clearCallingIdentity();
3621 // Always acquire the wake lock as AudioService because it is released by the
3622 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003623 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003624 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003625 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
3626 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003627
Eric Laurentafbb0472011-12-15 09:04:23 -08003628 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003629 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003630
3631 if (existingMsgPolicy == SENDMSG_REPLACE) {
3632 handler.removeMessages(msg);
3633 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
3634 return;
3635 }
Eric Laurentadbe8bf2014-11-03 18:26:32 -08003636 synchronized (mLastDeviceConnectMsgTime) {
3637 long time = SystemClock.uptimeMillis() + delay;
3638 handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
3639 if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
3640 msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
3641 msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
3642 mLastDeviceConnectMsgTime = time;
3643 }
3644 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003645 }
3646
3647 boolean checkAudioSettingsPermission(String method) {
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07003648 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003649 == PackageManager.PERMISSION_GRANTED) {
3650 return true;
3651 }
3652 String msg = "Audio Settings Permission Denial: " + method + " from pid="
3653 + Binder.getCallingPid()
3654 + ", uid=" + Binder.getCallingUid();
3655 Log.w(TAG, msg);
3656 return false;
3657 }
3658
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003659 private int getDeviceForStream(int stream) {
John Spurlock8a52c442015-03-26 14:23:58 -04003660 int device = getDevicesForStream(stream);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003661 if ((device & (device - 1)) != 0) {
3662 // Multiple device selection is either:
3663 // - speaker + one other device: give priority to speaker in this case.
3664 // - one A2DP device + another device: happens with duplicated output. In this case
3665 // retain the device on the A2DP output as the other must not correspond to an active
3666 // selection if not the speaker.
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003667 // - HDMI-CEC system audio mode only output: give priority to available item in order.
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003668 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
3669 device = AudioSystem.DEVICE_OUT_SPEAKER;
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003670 } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
3671 device = AudioSystem.DEVICE_OUT_HDMI_ARC;
3672 } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
3673 device = AudioSystem.DEVICE_OUT_SPDIF;
3674 } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
3675 device = AudioSystem.DEVICE_OUT_AUX_LINE;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003676 } else {
3677 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
3678 }
3679 }
3680 return device;
3681 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003682
John Spurlock8a52c442015-03-26 14:23:58 -04003683 private int getDevicesForStream(int stream) {
3684 return getDevicesForStream(stream, true /*checkOthers*/);
3685 }
3686
3687 private int getDevicesForStream(int stream, boolean checkOthers) {
3688 ensureValidStreamType(stream);
3689 synchronized (VolumeStreamState.class) {
3690 return mStreamStates[stream].observeDevicesForStream_syncVSS(checkOthers);
3691 }
3692 }
3693
3694 private void observeDevicesForStreams(int skipStream) {
3695 synchronized (VolumeStreamState.class) {
3696 for (int stream = 0; stream < mStreamStates.length; stream++) {
3697 if (stream != skipStream) {
3698 mStreamStates[stream].observeDevicesForStream_syncVSS(false /*checkOthers*/);
3699 }
3700 }
3701 }
3702 }
3703
Paul McLean10804eb2015-01-28 11:16:35 -08003704 /*
3705 * A class just for packaging up a set of connection parameters.
3706 */
3707 private class WiredDeviceConnectionState {
John Spurlock90874332015-03-10 16:00:54 -04003708 public final int mType;
3709 public final int mState;
3710 public final String mAddress;
3711 public final String mName;
3712 public final String mCaller;
Paul McLean10804eb2015-01-28 11:16:35 -08003713
John Spurlock90874332015-03-10 16:00:54 -04003714 public WiredDeviceConnectionState(int type, int state, String address, String name,
3715 String caller) {
Paul McLean10804eb2015-01-28 11:16:35 -08003716 mType = type;
3717 mState = state;
3718 mAddress = address;
3719 mName = name;
John Spurlock90874332015-03-10 16:00:54 -04003720 mCaller = caller;
Paul McLean10804eb2015-01-28 11:16:35 -08003721 }
3722 }
3723
John Spurlock90874332015-03-10 16:00:54 -04003724 public void setWiredDeviceConnectionState(int type, int state, String address, String name,
3725 String caller) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003726 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07003727 if (DEBUG_DEVICES) {
3728 Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
3729 + address + ")");
3730 }
Paul McLean10804eb2015-01-28 11:16:35 -08003731 int delay = checkSendBecomingNoisyIntent(type, state);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003732 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003733 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Paul McLean10804eb2015-01-28 11:16:35 -08003734 0,
3735 0,
John Spurlock90874332015-03-10 16:00:54 -04003736 new WiredDeviceConnectionState(type, state, address, name, caller),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003737 delay);
3738 }
3739 }
3740
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003741 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003742 {
3743 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003744 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
3745 throw new IllegalArgumentException("invalid profile " + profile);
3746 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003747 synchronized (mConnectedDevices) {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003748 if (profile == BluetoothProfile.A2DP) {
3749 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3750 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
3751 } else {
3752 delay = 0;
3753 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003754 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003755 (profile == BluetoothProfile.A2DP ?
3756 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003757 state,
3758 0,
3759 device,
3760 delay);
3761 }
3762 return delay;
3763 }
3764
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003765 ///////////////////////////////////////////////////////////////////////////
3766 // Inner classes
3767 ///////////////////////////////////////////////////////////////////////////
3768
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003769 // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
3770 // 1 mScoclient OR mSafeMediaVolumeState
3771 // 2 mSetModeDeathHandlers
3772 // 3 mSettingsLock
3773 // 4 VolumeStreamState.class
3774 // 5 mCameraSoundForced
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003775 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003776 private final int mStreamType;
John Spurlockb6e19e32015-03-10 21:33:44 -04003777 private final int mIndexMin;
3778 private final int mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003779
RoboErik4197cb62015-01-21 15:45:32 -08003780 private boolean mIsMuted;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003781 private String mVolumeIndexSettingName;
John Spurlock8a52c442015-03-26 14:23:58 -04003782 private int mObservedDevices;
John Spurlockb6e19e32015-03-10 21:33:44 -04003783
John Spurlock2bb02ec2015-03-02 13:13:06 -05003784 private final SparseIntArray mIndexMap = new SparseIntArray(8);
John Spurlockf63860c2015-02-19 09:46:27 -05003785 private final Intent mVolumeChanged;
John Spurlock8a52c442015-03-26 14:23:58 -04003786 private final Intent mStreamDevicesChanged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003787
Eric Laurenta553c252009-07-17 12:17:14 -07003788 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003789
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003790 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003791
3792 mStreamType = streamType;
John Spurlockb6e19e32015-03-10 21:33:44 -04003793 mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;
3794 mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;
3795 AudioSystem.initStreamVolume(streamType, mIndexMin / 10, mIndexMax / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003796
Eric Laurent33902db2012-10-07 16:15:07 -07003797 readSettings();
John Spurlockf63860c2015-02-19 09:46:27 -05003798 mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
3799 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
John Spurlock8a52c442015-03-26 14:23:58 -04003800 mStreamDevicesChanged = new Intent(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
3801 mStreamDevicesChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
3802 }
3803
3804 public int observeDevicesForStream_syncVSS(boolean checkOthers) {
3805 final int devices = AudioSystem.getDevicesForStream(mStreamType);
3806 if (devices == mObservedDevices) {
3807 return devices;
3808 }
3809 final int prevDevices = mObservedDevices;
3810 mObservedDevices = devices;
3811 if (checkOthers) {
3812 // one stream's devices have changed, check the others
3813 observeDevicesForStreams(mStreamType);
3814 }
3815 // log base stream changes to the event log
3816 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
3817 EventLogTags.writeStreamDevicesChanged(mStreamType, prevDevices, devices);
3818 }
3819 sendBroadcastToAll(mStreamDevicesChanged
3820 .putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, prevDevices)
3821 .putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, devices));
3822 return devices;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003823 }
3824
Eric Laurent42b041e2013-03-29 11:36:03 -07003825 public String getSettingNameForDevice(int device) {
3826 String name = mVolumeIndexSettingName;
Eric Laurent948d3272014-05-16 15:18:45 -07003827 String suffix = AudioSystem.getOutputDeviceName(device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003828 if (suffix.isEmpty()) {
3829 return name;
3830 }
3831 return name + "_" + suffix;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003832 }
3833
Eric Laurentfdbee862014-05-12 15:26:12 -07003834 public void readSettings() {
3835 synchronized (VolumeStreamState.class) {
John Spurlockee5ad722015-03-03 16:17:21 -05003836 // force maximum volume on all streams if fixed volume property is set
3837 if (mUseFixedVolume) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003838 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07003839 return;
3840 }
3841 // do not read system stream volume from settings: this stream is always aliased
3842 // to another stream type and its volume is never persisted. Values in settings can
3843 // only be stale values
3844 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3845 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
John Spurlock61560172015-02-06 19:46:04 -05003846 int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
Eric Laurentfdbee862014-05-12 15:26:12 -07003847 synchronized (mCameraSoundForced) {
3848 if (mCameraSoundForced) {
3849 index = mIndexMax;
3850 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003851 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003852 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003853 return;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003854 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003855
Eric Laurentfdbee862014-05-12 15:26:12 -07003856 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
3857
3858 for (int i = 0; remainingDevices != 0; i++) {
3859 int device = (1 << i);
3860 if ((device & remainingDevices) == 0) {
3861 continue;
3862 }
3863 remainingDevices &= ~device;
3864
3865 // retrieve current volume for device
3866 String name = getSettingNameForDevice(device);
3867 // if no volume stored for current stream and device, use default volume if default
3868 // device, continue otherwise
3869 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
John Spurlock61560172015-02-06 19:46:04 -05003870 AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
Eric Laurentfdbee862014-05-12 15:26:12 -07003871 int index = Settings.System.getIntForUser(
3872 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3873 if (index == -1) {
3874 continue;
3875 }
3876
John Spurlock2bb02ec2015-03-02 13:13:06 -05003877 mIndexMap.put(device, getValidIndex(10 * index));
Eric Laurentdd45d012012-10-08 09:04:34 -07003878 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003879 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003880 }
3881
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003882 // must be called while synchronized VolumeStreamState.class
3883 public void applyDeviceVolume_syncVSS(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003884 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003885 if (mIsMuted) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003886 index = 0;
Liejun Tao4565a472016-01-20 17:52:20 -06003887 } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported) {
3888 /* Special handling for Bluetooth Absolute Volume scenario
3889 * If we send full audio gain, some accessories are too loud even at its lowest
3890 * volume. We are not able to enumerate all such accessories, so here is the
3891 * workaround from phone side.
3892 * For the lowest volume steps 1 and 2, restrict audio gain to 50% and 75%.
3893 * For volume step 0, set audio gain to 0 as some accessories won't mute on their end.
3894 */
3895 int i = (getIndex(device) + 5)/10;
3896 if (i == 0) {
3897 // 0% for volume 0
3898 index = 0;
3899 } else if (i == 1) {
3900 // 50% for volume 1
3901 index = (int)(mIndexMax * 0.5) /10;
3902 } else if (i == 2) {
3903 // 75% for volume 2
3904 index = (int)(mIndexMax * 0.75) /10;
3905 } else {
3906 // otherwise, full gain
3907 index = (mIndexMax + 5)/10;
3908 }
3909 } else if ((device & mFullVolumeDevices) != 0) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003910 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07003911 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07003912 index = (getIndex(device) + 5)/10;
3913 }
3914 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003915 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003916
Eric Laurentfdbee862014-05-12 15:26:12 -07003917 public void applyAllVolumes() {
3918 synchronized (VolumeStreamState.class) {
3919 // apply default volume first: by convention this will reset all
3920 // devices volumes in audio policy manager to the supplied value
3921 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003922 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003923 index = 0;
3924 } else {
3925 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3926 }
3927 AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3928 // then apply device specific volumes
John Spurlock2bb02ec2015-03-02 13:13:06 -05003929 for (int i = 0; i < mIndexMap.size(); i++) {
3930 int device = mIndexMap.keyAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07003931 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
RoboErik4197cb62015-01-21 15:45:32 -08003932 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003933 index = 0;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003934 } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3935 mAvrcpAbsVolSupported)
3936 || ((device & mFullVolumeDevices) != 0))
3937 {
Eric Laurentfdbee862014-05-12 15:26:12 -07003938 index = (mIndexMax + 5)/10;
3939 } else {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003940 index = (mIndexMap.valueAt(i) + 5)/10;
Eric Laurentfdbee862014-05-12 15:26:12 -07003941 }
3942 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07003943 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003944 }
3945 }
3946 }
3947
John Spurlock90874332015-03-10 16:00:54 -04003948 public boolean adjustIndex(int deltaIndex, int device, String caller) {
3949 return setIndex(getIndex(device) + deltaIndex, device, caller);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003950 }
3951
John Spurlock90874332015-03-10 16:00:54 -04003952 public boolean setIndex(int index, int device, String caller) {
John Spurlockf63860c2015-02-19 09:46:27 -05003953 boolean changed = false;
3954 int oldIndex;
Eric Laurentfdbee862014-05-12 15:26:12 -07003955 synchronized (VolumeStreamState.class) {
John Spurlockf63860c2015-02-19 09:46:27 -05003956 oldIndex = getIndex(device);
Eric Laurentfdbee862014-05-12 15:26:12 -07003957 index = getValidIndex(index);
3958 synchronized (mCameraSoundForced) {
3959 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3960 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07003961 }
3962 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003963 mIndexMap.put(device, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003964
John Spurlockf63860c2015-02-19 09:46:27 -05003965 changed = oldIndex != index;
3966 if (changed) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003967 // Apply change to all streams using this one as alias
3968 // if changing volume of current device, also change volume of current
3969 // device on aliased stream
3970 boolean currentDevice = (device == getDeviceForStream(mStreamType));
3971 int numStreamTypes = AudioSystem.getNumStreamTypes();
3972 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3973 if (streamType != mStreamType &&
3974 mStreamVolumeAlias[streamType] == mStreamType) {
3975 int scaledIndex = rescaleIndex(index, mStreamType, streamType);
John Spurlock90874332015-03-10 16:00:54 -04003976 mStreamStates[streamType].setIndex(scaledIndex, device, caller);
Eric Laurentfdbee862014-05-12 15:26:12 -07003977 if (currentDevice) {
3978 mStreamStates[streamType].setIndex(scaledIndex,
John Spurlock90874332015-03-10 16:00:54 -04003979 getDeviceForStream(streamType), caller);
Eric Laurentfdbee862014-05-12 15:26:12 -07003980 }
3981 }
3982 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003983 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003984 }
John Spurlockf63860c2015-02-19 09:46:27 -05003985 if (changed) {
3986 oldIndex = (oldIndex + 5) / 10;
3987 index = (index + 5) / 10;
John Spurlock90874332015-03-10 16:00:54 -04003988 // log base stream changes to the event log
3989 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
3990 if (caller == null) {
3991 Log.w(TAG, "No caller for volume_changed event", new Throwable());
3992 }
3993 EventLogTags.writeVolumeChanged(mStreamType, oldIndex, index, mIndexMax / 10,
3994 caller);
3995 }
3996 // fire changed intents for all streams
John Spurlockf63860c2015-02-19 09:46:27 -05003997 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
3998 mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
Jean-Michel Trivi560877d2015-06-25 17:38:35 -07003999 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
4000 mStreamVolumeAlias[mStreamType]);
John Spurlockf63860c2015-02-19 09:46:27 -05004001 sendBroadcastToAll(mVolumeChanged);
4002 }
4003 return changed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004004 }
4005
Eric Laurentfdbee862014-05-12 15:26:12 -07004006 public int getIndex(int device) {
4007 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004008 int index = mIndexMap.get(device, -1);
4009 if (index == -1) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004010 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
John Spurlock2bb02ec2015-03-02 13:13:06 -05004011 index = mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurentfdbee862014-05-12 15:26:12 -07004012 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05004013 return index;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004014 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07004015 }
4016
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004017 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07004018 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004019 }
4020
John Spurlockb6e19e32015-03-10 21:33:44 -04004021 public int getMinIndex() {
4022 return mIndexMin;
4023 }
4024
John Spurlock90874332015-03-10 16:00:54 -04004025 public void setAllIndexes(VolumeStreamState srcStream, String caller) {
Eric Laurentfdbee862014-05-12 15:26:12 -07004026 synchronized (VolumeStreamState.class) {
4027 int srcStreamType = srcStream.getStreamType();
4028 // apply default device volume from source stream to all devices first in case
4029 // some devices are present in this stream state but not in source stream state
4030 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004031 index = rescaleIndex(index, srcStreamType, mStreamType);
John Spurlock2bb02ec2015-03-02 13:13:06 -05004032 for (int i = 0; i < mIndexMap.size(); i++) {
4033 mIndexMap.put(mIndexMap.keyAt(i), index);
Eric Laurentfdbee862014-05-12 15:26:12 -07004034 }
4035 // Now apply actual volume for devices in source stream state
John Spurlock2bb02ec2015-03-02 13:13:06 -05004036 SparseIntArray srcMap = srcStream.mIndexMap;
4037 for (int i = 0; i < srcMap.size(); i++) {
4038 int device = srcMap.keyAt(i);
4039 index = srcMap.valueAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07004040 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07004041
John Spurlock90874332015-03-10 16:00:54 -04004042 setIndex(index, device, caller);
Eric Laurentfdbee862014-05-12 15:26:12 -07004043 }
Eric Laurent6d517662012-04-23 18:42:39 -07004044 }
4045 }
4046
Eric Laurentfdbee862014-05-12 15:26:12 -07004047 public void setAllIndexesToMax() {
4048 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004049 for (int i = 0; i < mIndexMap.size(); i++) {
4050 mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07004051 }
Eric Laurentdd45d012012-10-08 09:04:34 -07004052 }
Eric Laurentdd45d012012-10-08 09:04:34 -07004053 }
4054
RoboErik4197cb62015-01-21 15:45:32 -08004055 public void mute(boolean state) {
John Spurlock22b9ee12015-02-18 22:51:44 -05004056 boolean changed = false;
Eric Laurentfdbee862014-05-12 15:26:12 -07004057 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08004058 if (state != mIsMuted) {
John Spurlock22b9ee12015-02-18 22:51:44 -05004059 changed = true;
RoboErik4197cb62015-01-21 15:45:32 -08004060 mIsMuted = state;
John Spurlock22b9ee12015-02-18 22:51:44 -05004061
RoboErik4197cb62015-01-21 15:45:32 -08004062 // Set the new mute volume. This propagates the values to
4063 // the audio system, otherwise the volume won't be changed
4064 // at the lower level.
4065 sendMsg(mAudioHandler,
4066 MSG_SET_ALL_VOLUMES,
4067 SENDMSG_QUEUE,
4068 0,
4069 0,
4070 this, 0);
Eric Laurentfdbee862014-05-12 15:26:12 -07004071 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004072 }
John Spurlock22b9ee12015-02-18 22:51:44 -05004073 if (changed) {
4074 // Stream mute changed, fire the intent.
4075 Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
4076 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
4077 intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
4078 sendBroadcastToAll(intent);
4079 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004080 }
4081
Eric Laurent6d517662012-04-23 18:42:39 -07004082 public int getStreamType() {
4083 return mStreamType;
4084 }
4085
Eric Laurent212532b2014-07-21 15:43:18 -07004086 public void checkFixedVolumeDevices() {
4087 synchronized (VolumeStreamState.class) {
4088 // ignore settings for fixed volume devices: volume should always be at max or 0
4089 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004090 for (int i = 0; i < mIndexMap.size(); i++) {
4091 int device = mIndexMap.keyAt(i);
4092 int index = mIndexMap.valueAt(i);
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07004093 if (((device & mFullVolumeDevices) != 0)
4094 || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05004095 mIndexMap.put(device, mIndexMax);
Eric Laurent212532b2014-07-21 15:43:18 -07004096 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004097 applyDeviceVolume_syncVSS(device);
Eric Laurent212532b2014-07-21 15:43:18 -07004098 }
4099 }
4100 }
4101 }
4102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004103 private int getValidIndex(int index) {
John Spurlockb6e19e32015-03-10 21:33:44 -04004104 if (index < mIndexMin) {
4105 return mIndexMin;
John Spurlockee5ad722015-03-03 16:17:21 -05004106 } else if (mUseFixedVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07004107 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004108 }
4109
4110 return index;
4111 }
4112
Eric Laurentbffc3d12012-05-07 17:43:49 -07004113 private void dump(PrintWriter pw) {
RoboErik4197cb62015-01-21 15:45:32 -08004114 pw.print(" Muted: ");
4115 pw.println(mIsMuted);
John Spurlockb6e19e32015-03-10 21:33:44 -04004116 pw.print(" Min: ");
4117 pw.println((mIndexMin + 5) / 10);
John Spurlock2b29bc42014-08-26 16:40:35 -04004118 pw.print(" Max: ");
4119 pw.println((mIndexMax + 5) / 10);
Eric Laurentbffc3d12012-05-07 17:43:49 -07004120 pw.print(" Current: ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05004121 for (int i = 0; i < mIndexMap.size(); i++) {
4122 if (i > 0) {
4123 pw.print(", ");
4124 }
4125 final int device = mIndexMap.keyAt(i);
John Spurlock2b29bc42014-08-26 16:40:35 -04004126 pw.print(Integer.toHexString(device));
4127 final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
4128 : AudioSystem.getOutputDeviceName(device);
4129 if (!deviceName.isEmpty()) {
4130 pw.print(" (");
4131 pw.print(deviceName);
4132 pw.print(")");
4133 }
4134 pw.print(": ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05004135 final int index = (mIndexMap.valueAt(i) + 5) / 10;
John Spurlock2b29bc42014-08-26 16:40:35 -04004136 pw.print(index);
Eric Laurentbffc3d12012-05-07 17:43:49 -07004137 }
John Spurlockb32fc972015-03-05 13:58:00 -05004138 pw.println();
4139 pw.print(" Devices: ");
John Spurlock8a52c442015-03-26 14:23:58 -04004140 final int devices = getDevicesForStream(mStreamType);
John Spurlockb32fc972015-03-05 13:58:00 -05004141 int device, i = 0, n = 0;
John Spurlock1ff1e6e2015-03-09 14:21:20 -04004142 // iterate all devices from 1 to DEVICE_OUT_DEFAULT exclusive
4143 // (the default device is not returned by getDevicesForStream)
4144 while ((device = 1 << i) != AudioSystem.DEVICE_OUT_DEFAULT) {
John Spurlockb32fc972015-03-05 13:58:00 -05004145 if ((devices & device) != 0) {
4146 if (n++ > 0) {
4147 pw.print(", ");
4148 }
4149 pw.print(AudioSystem.getOutputDeviceName(device));
4150 }
4151 i++;
4152 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07004153 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004154 }
4155
4156 /** Thread that handles native AudioSystem control. */
4157 private class AudioSystemThread extends Thread {
4158 AudioSystemThread() {
4159 super("AudioService");
4160 }
4161
4162 @Override
4163 public void run() {
4164 // Set this thread up so the handler will work on it
4165 Looper.prepare();
4166
4167 synchronized(AudioService.this) {
4168 mAudioHandler = new AudioHandler();
4169
4170 // Notify that the handler has been created
4171 AudioService.this.notify();
4172 }
4173
4174 // Listen for volume change requests that are set by VolumePanel
4175 Looper.loop();
4176 }
4177 }
4178
4179 /** Handles internal volume messages in separate volume thread. */
4180 private class AudioHandler extends Handler {
4181
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004182 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004183
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004184 synchronized (VolumeStreamState.class) {
4185 // Apply volume
4186 streamState.applyDeviceVolume_syncVSS(device);
Eric Laurenta553c252009-07-17 12:17:14 -07004187
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004188 // Apply change to all streams using this one as alias
4189 int numStreamTypes = AudioSystem.getNumStreamTypes();
4190 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4191 if (streamType != streamState.mStreamType &&
4192 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
4193 // Make sure volume is also maxed out on A2DP device for aliased stream
4194 // that may have a different device selected
4195 int streamDevice = getDeviceForStream(streamType);
4196 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
4197 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
4198 mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
4199 }
4200 mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
Eric Laurentcd772d02013-10-30 18:31:07 -07004201 }
Eric Laurenta553c252009-07-17 12:17:14 -07004202 }
4203 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004204 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08004205 sendMsg(mAudioHandler,
4206 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08004207 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004208 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07004209 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08004210 streamState,
4211 PERSIST_DELAY);
4212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004213 }
4214
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004215 private void setAllVolumes(VolumeStreamState streamState) {
4216
4217 // Apply volume
4218 streamState.applyAllVolumes();
4219
4220 // Apply change to all streams using this one as alias
4221 int numStreamTypes = AudioSystem.getNumStreamTypes();
4222 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
4223 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07004224 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004225 mStreamStates[streamType].applyAllVolumes();
4226 }
4227 }
4228 }
4229
Eric Laurent42b041e2013-03-29 11:36:03 -07004230 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07004231 if (mUseFixedVolume) {
4232 return;
4233 }
Eric Laurent212532b2014-07-21 15:43:18 -07004234 if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
4235 return;
4236 }
Eric Laurent42b041e2013-03-29 11:36:03 -07004237 System.putIntForUser(mContentResolver,
4238 streamState.getSettingNameForDevice(device),
4239 (streamState.getIndex(device) + 5)/ 10,
4240 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004241 }
4242
Glenn Kastenba195eb2011-12-13 09:30:40 -08004243 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07004244 if (mUseFixedVolume) {
4245 return;
4246 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07004247 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004248 }
4249
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004250 private boolean onLoadSoundEffects() {
4251 int status;
4252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004253 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004254 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004255 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
4256 return false;
4257 }
4258
4259 if (mSoundPool != null) {
4260 return true;
4261 }
4262
4263 loadTouchSoundAssets();
4264
Jean-Michel Trivi55a30c42014-07-20 17:56:11 -07004265 mSoundPool = new SoundPool.Builder()
4266 .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
4267 .setAudioAttributes(new AudioAttributes.Builder()
4268 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
4269 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
4270 .build())
4271 .build();
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004272 mSoundPoolCallBack = null;
4273 mSoundPoolListenerThread = new SoundPoolListenerThread();
4274 mSoundPoolListenerThread.start();
4275 int attempts = 3;
4276 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
4277 try {
4278 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07004279 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004280 } catch (InterruptedException e) {
4281 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
4282 }
4283 }
4284
4285 if (mSoundPoolCallBack == null) {
4286 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
4287 if (mSoundPoolLooper != null) {
4288 mSoundPoolLooper.quit();
4289 mSoundPoolLooper = null;
4290 }
4291 mSoundPoolListenerThread = null;
4292 mSoundPool.release();
4293 mSoundPool = null;
4294 return false;
4295 }
4296 /*
4297 * poolId table: The value -1 in this table indicates that corresponding
4298 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
4299 * Once loaded, the value in poolId is the sample ID and the same
4300 * sample can be reused for another effect using the same file.
4301 */
4302 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4303 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4304 poolId[fileIdx] = -1;
4305 }
4306 /*
4307 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
4308 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
4309 * this indicates we have a valid sample loaded for this effect.
4310 */
4311
4312 int numSamples = 0;
4313 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4314 // Do not load sample if this effect uses the MediaPlayer
4315 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
4316 continue;
4317 }
4318 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
4319 String filePath = Environment.getRootDirectory()
4320 + SOUND_EFFECTS_PATH
4321 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
4322 int sampleId = mSoundPool.load(filePath, 0);
4323 if (sampleId <= 0) {
4324 Log.w(TAG, "Soundpool could not load file: "+filePath);
4325 } else {
4326 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
4327 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
4328 numSamples++;
4329 }
4330 } else {
4331 SOUND_EFFECT_FILES_MAP[effect][1] =
4332 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
4333 }
4334 }
4335 // wait for all samples to be loaded
4336 if (numSamples > 0) {
4337 mSoundPoolCallBack.setSamples(poolId);
4338
4339 attempts = 3;
4340 status = 1;
4341 while ((status == 1) && (attempts-- > 0)) {
4342 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07004343 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004344 status = mSoundPoolCallBack.status();
4345 } catch (InterruptedException e) {
4346 Log.w(TAG, "Interrupted while waiting sound pool callback.");
4347 }
4348 }
4349 } else {
4350 status = -1;
4351 }
4352
4353 if (mSoundPoolLooper != null) {
4354 mSoundPoolLooper.quit();
4355 mSoundPoolLooper = null;
4356 }
4357 mSoundPoolListenerThread = null;
4358 if (status != 0) {
4359 Log.w(TAG,
4360 "onLoadSoundEffects(), Error "+status+ " while loading samples");
4361 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4362 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
4363 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4364 }
4365 }
4366
4367 mSoundPool.release();
4368 mSoundPool = null;
4369 }
4370 }
4371 return (status == 0);
4372 }
4373
4374 /**
4375 * Unloads samples from the sound pool.
4376 * This method can be called to free some memory when
4377 * sound effects are disabled.
4378 */
4379 private void onUnloadSoundEffects() {
4380 synchronized (mSoundEffectsLock) {
4381 if (mSoundPool == null) {
4382 return;
4383 }
4384
4385 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4386 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4387 poolId[fileIdx] = 0;
4388 }
4389
4390 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4391 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
4392 continue;
4393 }
4394 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
4395 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
4396 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4397 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
4398 }
4399 }
4400 mSoundPool.release();
4401 mSoundPool = null;
4402 }
4403 }
4404
4405 private void onPlaySoundEffect(int effectType, int volume) {
4406 synchronized (mSoundEffectsLock) {
4407
4408 onLoadSoundEffects();
4409
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004410 if (mSoundPool == null) {
4411 return;
4412 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004413 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08004414 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004415 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07004416 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004417 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07004418 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004419 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004420
4421 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004422 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
4423 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004424 } else {
4425 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004426 try {
Eric Laurente78fced2013-03-15 16:03:47 -07004427 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
4428 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004429 mediaPlayer.setDataSource(filePath);
4430 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
4431 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08004432 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004433 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
4434 public void onCompletion(MediaPlayer mp) {
4435 cleanupPlayer(mp);
4436 }
4437 });
4438 mediaPlayer.setOnErrorListener(new OnErrorListener() {
4439 public boolean onError(MediaPlayer mp, int what, int extra) {
4440 cleanupPlayer(mp);
4441 return true;
4442 }
4443 });
4444 mediaPlayer.start();
4445 } catch (IOException ex) {
4446 Log.w(TAG, "MediaPlayer IOException: "+ex);
4447 } catch (IllegalArgumentException ex) {
4448 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
4449 } catch (IllegalStateException ex) {
4450 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004451 }
4452 }
4453 }
4454 }
4455
4456 private void cleanupPlayer(MediaPlayer mp) {
4457 if (mp != null) {
4458 try {
4459 mp.stop();
4460 mp.release();
4461 } catch (IllegalStateException ex) {
4462 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
4463 }
4464 }
4465 }
4466
Eric Laurentfa640152011-03-12 15:59:51 -08004467 private void setForceUse(int usage, int config) {
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004468 synchronized (mConnectedDevices) {
4469 setForceUseInt_SyncDevices(usage, config);
4470 }
Eric Laurentfa640152011-03-12 15:59:51 -08004471 }
4472
Eric Laurent05274f32012-11-29 12:48:18 -08004473 private void onPersistSafeVolumeState(int state) {
4474 Settings.Global.putInt(mContentResolver,
4475 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
4476 state);
4477 }
4478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004479 @Override
4480 public void handleMessage(Message msg) {
Eric Laurentafbb0472011-12-15 09:04:23 -08004481 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004482
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004483 case MSG_SET_DEVICE_VOLUME:
4484 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
4485 break;
4486
4487 case MSG_SET_ALL_VOLUMES:
4488 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004489 break;
4490
4491 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07004492 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004493 break;
4494
Justin Koh57978ed2012-04-03 17:37:58 -07004495 case MSG_PERSIST_MASTER_VOLUME_MUTE:
Eric Laurent83a017b2013-03-19 18:15:31 -07004496 if (mUseFixedVolume) {
4497 return;
4498 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004499 Settings.System.putIntForUser(mContentResolver,
4500 Settings.System.VOLUME_MASTER_MUTE,
4501 msg.arg1,
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004502 msg.arg2);
Justin Koh57978ed2012-04-03 17:37:58 -07004503 break;
4504
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004505 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08004506 // note that the value persisted is the current ringer mode, not the
4507 // value of ringer mode as of the time the request was made to persist
John Spurlock661f2cf2014-11-17 10:29:10 -05004508 persistRingerMode(getRingerModeInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004509 break;
4510
Andy Hunged0ea402015-10-30 14:11:46 -07004511 case MSG_AUDIO_SERVER_DIED:
4512 onAudioServerDied();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004513 break;
4514
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004515 case MSG_UNLOAD_SOUND_EFFECTS:
4516 onUnloadSoundEffects();
4517 break;
4518
Eric Laurent117b7bb2011-01-16 17:07:27 -08004519 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004520 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
4521 // can take several dozens of milliseconds to complete
4522 boolean loaded = onLoadSoundEffects();
4523 if (msg.obj != null) {
4524 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
4525 synchronized (reply) {
4526 reply.mStatus = loaded ? 0 : -1;
4527 reply.notify();
4528 }
4529 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08004530 break;
4531
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004532 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004533 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004534 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004535
4536 case MSG_BTA2DP_DOCK_TIMEOUT:
4537 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004538 synchronized (mConnectedDevices) {
4539 makeA2dpDeviceUnavailableNow( (String) msg.obj );
4540 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004541 break;
Eric Laurentfa640152011-03-12 15:59:51 -08004542
4543 case MSG_SET_FORCE_USE:
Eric Laurentc390bed2012-07-03 12:24:05 -07004544 case MSG_SET_FORCE_BT_A2DP_USE:
Eric Laurentfa640152011-03-12 15:59:51 -08004545 setForceUse(msg.arg1, msg.arg2);
4546 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07004547
Eric Laurentdc03c612011-04-01 10:59:41 -07004548 case MSG_BT_HEADSET_CNCT_FAILED:
4549 resetBluetoothSco();
4550 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004551
4552 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
Paul McLean10804eb2015-01-28 11:16:35 -08004553 { WiredDeviceConnectionState connectState =
4554 (WiredDeviceConnectionState)msg.obj;
4555 onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
John Spurlock90874332015-03-10 16:00:54 -04004556 connectState.mAddress, connectState.mName, connectState.mCaller);
Paul McLean10804eb2015-01-28 11:16:35 -08004557 mAudioEventWakeLock.release();
4558 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004559 break;
4560
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004561 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
4562 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
4563 mAudioEventWakeLock.release();
4564 break;
4565
4566 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
4567 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004568 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004569 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004570
4571 case MSG_REPORT_NEW_ROUTES: {
4572 int N = mRoutesObservers.beginBroadcast();
4573 if (N > 0) {
4574 AudioRoutesInfo routes;
4575 synchronized (mCurAudioRoutes) {
4576 routes = new AudioRoutesInfo(mCurAudioRoutes);
4577 }
4578 while (N > 0) {
4579 N--;
4580 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
4581 try {
4582 obs.dispatchAudioRoutesChanged(routes);
4583 } catch (RemoteException e) {
4584 }
4585 }
4586 }
4587 mRoutesObservers.finishBroadcast();
John Spurlock8a52c442015-03-26 14:23:58 -04004588 observeDevicesForStreams(-1);
Dianne Hackborn632ca412012-06-14 19:34:10 -07004589 break;
4590 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004591
Eric Laurentc34dcc12012-09-10 13:51:52 -07004592 case MSG_CHECK_MUSIC_ACTIVE:
John Spurlock90874332015-03-10 16:00:54 -04004593 onCheckMusicActive((String) msg.obj);
Eric Laurentc34dcc12012-09-10 13:51:52 -07004594 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004595
4596 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
4597 onSendBecomingNoisyIntent();
4598 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07004599
4600 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
4601 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
John Spurlock90874332015-03-10 16:00:54 -04004602 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED),
4603 (String) msg.obj);
Eric Laurentd640bd32012-09-28 18:01:48 -07004604 break;
Eric Laurent05274f32012-11-29 12:48:18 -08004605 case MSG_PERSIST_SAFE_VOLUME_STATE:
4606 onPersistSafeVolumeState(msg.arg1);
4607 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08004608
Eric Laurent2a57ca92013-03-07 17:29:27 -08004609 case MSG_BROADCAST_BT_CONNECTION_STATE:
4610 onBroadcastScoConnectionState(msg.arg1);
4611 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004612
4613 case MSG_SYSTEM_READY:
4614 onSystemReady();
4615 break;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004616
Eric Laurent0867bed2015-05-20 14:49:08 -07004617 case MSG_INDICATE_SYSTEM_READY:
4618 onIndicateSystemReady();
4619 break;
4620
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004621 case MSG_PERSIST_MUSIC_ACTIVE_MS:
4622 final int musicActiveMs = msg.arg1;
4623 Settings.Secure.putIntForUser(mContentResolver,
4624 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
4625 UserHandle.USER_CURRENT);
4626 break;
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004627 case MSG_PERSIST_MICROPHONE_MUTE:
4628 Settings.System.putIntForUser(mContentResolver,
4629 Settings.System.MICROPHONE_MUTE,
4630 msg.arg1,
4631 msg.arg2);
4632 break;
RoboErik5452e252015-02-06 15:33:53 -08004633 case MSG_UNMUTE_STREAM:
4634 onUnmuteStream(msg.arg1, msg.arg2);
4635 break;
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07004636 case MSG_DYN_POLICY_MIX_STATE_UPDATE:
4637 onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1);
4638 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004639 }
4640 }
4641 }
4642
Jason Parekhb1096152009-03-24 17:48:25 -07004643 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07004644
Jason Parekhb1096152009-03-24 17:48:25 -07004645 SettingsObserver() {
4646 super(new Handler());
4647 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4648 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004649 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4650 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Andy Hung7b98e9a2016-02-25 18:34:50 -08004651 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4652 Settings.System.MASTER_MONO), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07004653 }
4654
4655 @Override
4656 public void onChange(boolean selfChange) {
4657 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08004658 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
4659 // However there appear to be some missing locks around mRingerModeMutedStreams
4660 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
4661 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07004662 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004663 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07004664 /*
4665 * Ensure all stream types that should be affected by ringer mode
4666 * are in the proper state.
4667 */
John Spurlock661f2cf2014-11-17 10:29:10 -05004668 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurenta553c252009-07-17 12:17:14 -07004669 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004670 readDockAudioSettings(mContentResolver);
Andy Hung7b98e9a2016-02-25 18:34:50 -08004671 updateMasterMono(mContentResolver);
Phil Burkac0f7042016-02-24 12:19:08 -08004672 readEncodedSurroundMode(mContentResolver);
Eric Laurenta553c252009-07-17 12:17:14 -07004673 }
Jason Parekhb1096152009-03-24 17:48:25 -07004674 }
Jason Parekhb1096152009-03-24 17:48:25 -07004675 }
Eric Laurenta553c252009-07-17 12:17:14 -07004676
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004677 // must be called synchronized on mConnectedDevices
Paul McLean20eec5b2015-05-09 13:02:18 -07004678 private void makeA2dpDeviceAvailable(String address, String name) {
Eric Laurent78472112012-05-21 08:57:21 -07004679 // enable A2DP before notifying A2DP connection to avoid unecessary processing in
4680 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004681 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4682 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4683 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Eric Laurent78472112012-05-21 08:57:21 -07004684 setBluetoothA2dpOnInt(true);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004685 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004686 AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004687 // Reset A2DP suspend state each time a new sink is connected
4688 AudioSystem.setParameters("A2dpSuspended=false");
Paul McLean394a8e12015-03-03 10:29:19 -07004689 mConnectedDevices.put(
4690 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
Paul McLean20eec5b2015-05-09 13:02:18 -07004691 new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
Paul McLean394a8e12015-03-03 10:29:19 -07004692 address));
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004693 }
4694
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004695 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004696 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07004697 }
4698
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004699 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004700 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004701 synchronized (mA2dpAvrcpLock) {
4702 mAvrcpAbsVolSupported = false;
4703 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004704 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004705 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004706 mConnectedDevices.remove(
4707 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
RoboErik5535ea82014-09-25 14:53:16 -07004708 synchronized (mCurAudioRoutes) {
4709 // Remove A2DP routes as well
John Spurlock61560172015-02-06 19:46:04 -05004710 if (mCurAudioRoutes.bluetoothName != null) {
4711 mCurAudioRoutes.bluetoothName = null;
RoboErik5535ea82014-09-25 14:53:16 -07004712 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4713 SENDMSG_NOOP, 0, 0, null, 0);
4714 }
4715 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004716 }
4717
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004718 // must be called synchronized on mConnectedDevices
Eric Laurentd138e4e2015-05-15 16:41:15 -07004719 private void makeA2dpDeviceUnavailableLater(String address, int delayMs) {
Eric Laurent3b591262010-04-20 07:01:00 -07004720 // prevent any activity on the A2DP audio output to avoid unwanted
4721 // reconnection of the sink.
4722 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004723 // the device will be made unavailable later, so consider it disconnected right away
Paul McLean394a8e12015-03-03 10:29:19 -07004724 mConnectedDevices.remove(
4725 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004726 // send the delayed message to make the device unavailable later
4727 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
Eric Laurentd138e4e2015-05-15 16:41:15 -07004728 mAudioHandler.sendMessageDelayed(msg, delayMs);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004729
4730 }
4731
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004732 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004733 private void makeA2dpSrcAvailable(String address) {
4734 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004735 AudioSystem.DEVICE_STATE_AVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004736 mConnectedDevices.put(
4737 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
Paul McLean20eec5b2015-05-09 13:02:18 -07004738 new DeviceListSpec(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "",
Paul McLean394a8e12015-03-03 10:29:19 -07004739 address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004740 }
4741
4742 // must be called synchronized on mConnectedDevices
4743 private void makeA2dpSrcUnavailable(String address) {
4744 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean20eec5b2015-05-09 13:02:18 -07004745 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
Paul McLean394a8e12015-03-03 10:29:19 -07004746 mConnectedDevices.remove(
4747 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004748 }
4749
4750 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004751 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004752 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4753 }
4754
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004755 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004756 private boolean hasScheduledA2dpDockTimeout() {
4757 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4758 }
4759
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004760 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004761 {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004762 if (DEBUG_VOL) {
4763 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
4764 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004765 if (btDevice == null) {
4766 return;
4767 }
4768 String address = btDevice.getAddress();
4769 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4770 address = "";
4771 }
John Du5a0cf7a2013-07-19 11:30:34 -07004772
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004773 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004774 String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4775 btDevice.getAddress());
4776 DeviceListSpec deviceSpec = mConnectedDevices.get(key);
4777 boolean isConnected = deviceSpec != null;
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004778
4779 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4780 if (btDevice.isBluetoothDock()) {
4781 if (state == BluetoothProfile.STATE_DISCONNECTED) {
4782 // introduction of a delay for transient disconnections of docks when
4783 // power is rapidly turned off/on, this message will be canceled if
4784 // we reconnect the dock under a preset delay
Eric Laurentd138e4e2015-05-15 16:41:15 -07004785 makeA2dpDeviceUnavailableLater(address, BTA2DP_DOCK_TIMEOUT_MILLIS);
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004786 // the next time isConnected is evaluated, it will be false for the dock
4787 }
4788 } else {
4789 makeA2dpDeviceUnavailableNow(address);
4790 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07004791 synchronized (mCurAudioRoutes) {
John Spurlock61560172015-02-06 19:46:04 -05004792 if (mCurAudioRoutes.bluetoothName != null) {
4793 mCurAudioRoutes.bluetoothName = null;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004794 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4795 SENDMSG_NOOP, 0, 0, null, 0);
4796 }
4797 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004798 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4799 if (btDevice.isBluetoothDock()) {
4800 // this could be a reconnection after a transient disconnection
4801 cancelA2dpDeviceTimeout();
4802 mDockAddress = address;
4803 } else {
4804 // this could be a connection of another A2DP device before the timeout of
4805 // a dock: cancel the dock timeout, and make the dock unavailable now
4806 if(hasScheduledA2dpDockTimeout()) {
4807 cancelA2dpDeviceTimeout();
4808 makeA2dpDeviceUnavailableNow(mDockAddress);
4809 }
4810 }
Paul McLean20eec5b2015-05-09 13:02:18 -07004811 makeA2dpDeviceAvailable(address, btDevice.getName());
Dianne Hackborn632ca412012-06-14 19:34:10 -07004812 synchronized (mCurAudioRoutes) {
4813 String name = btDevice.getAliasName();
John Spurlock61560172015-02-06 19:46:04 -05004814 if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
4815 mCurAudioRoutes.bluetoothName = name;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004816 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4817 SENDMSG_NOOP, 0, 0, null, 0);
4818 }
4819 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004820 }
4821 }
4822 }
4823
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004824 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
4825 {
4826 if (DEBUG_VOL) {
4827 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
4828 }
4829 if (btDevice == null) {
4830 return;
4831 }
4832 String address = btDevice.getAddress();
4833 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4834 address = "";
4835 }
4836
4837 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004838 String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
4839 DeviceListSpec deviceSpec = mConnectedDevices.get(key);
4840 boolean isConnected = deviceSpec != null;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004841
4842 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4843 makeA2dpSrcUnavailable(address);
4844 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4845 makeA2dpSrcAvailable(address);
4846 }
4847 }
4848 }
4849
John Du5a0cf7a2013-07-19 11:30:34 -07004850 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
4851 // address is not used for now, but may be used when multiple a2dp devices are supported
4852 synchronized (mA2dpAvrcpLock) {
4853 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004854 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07004855 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4856 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4857 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4858 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4859 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07004860 }
4861 }
4862
Paul McLean394a8e12015-03-03 10:29:19 -07004863 private boolean handleDeviceConnection(boolean connect, int device, String address,
4864 String deviceName) {
4865 if (DEBUG_DEVICES) {
4866 Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device)
4867 + " address:" + address + " name:" + deviceName + ")");
4868 }
Eric Laurent59f48272012-04-05 19:42:21 -07004869 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004870 String deviceKey = makeDeviceListKey(device, address);
4871 if (DEBUG_DEVICES) {
4872 Slog.i(TAG, "deviceKey:" + deviceKey);
4873 }
4874 DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
4875 boolean isConnected = deviceSpec != null;
4876 if (DEBUG_DEVICES) {
4877 Slog.i(TAG, "deviceSpec:" + deviceSpec + " is(already)Connected:" + isConnected);
4878 }
4879 if (connect && !isConnected) {
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07004880 final int res = AudioSystem.setDeviceConnectionState(device,
4881 AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);
4882 if (res != AudioSystem.AUDIO_STATUS_OK) {
4883 Slog.e(TAG, "not connecting device 0x" + Integer.toHexString(device) +
4884 " due to command error " + res );
4885 return false;
4886 }
Paul McLean394a8e12015-03-03 10:29:19 -07004887 mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
4888 return true;
4889 } else if (!connect && isConnected) {
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07004890 AudioSystem.setDeviceConnectionState(device,
4891 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName);
4892 // always remove even if disconnection failed
Paul McLean394a8e12015-03-03 10:29:19 -07004893 mConnectedDevices.remove(deviceKey);
4894 return true;
Eric Laurent59f48272012-04-05 19:42:21 -07004895 }
4896 }
4897 return false;
4898 }
4899
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004900 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4901 // sent if none of these devices is connected.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004902 // Access synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004903 int mBecomingNoisyIntentDevices =
4904 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07004905 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07004906 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004907 AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004908
4909 // must be called before removing the device from mConnectedDevices
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004910 // Called synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004911 private int checkSendBecomingNoisyIntent(int device, int state) {
4912 int delay = 0;
4913 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4914 int devices = 0;
John Spurlock8c3dc852015-04-23 21:32:37 -04004915 for (int i = 0; i < mConnectedDevices.size(); i++) {
4916 int dev = mConnectedDevices.valueAt(i).mDeviceType;
Paul McLean394a8e12015-03-03 10:29:19 -07004917 if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
4918 && ((dev & mBecomingNoisyIntentDevices) != 0)) {
4919 devices |= dev;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004920 }
4921 }
4922 if (devices == device) {
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004923 sendMsg(mAudioHandler,
4924 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4925 SENDMSG_REPLACE,
4926 0,
4927 0,
4928 null,
4929 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004930 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004931 }
4932 }
4933
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004934 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
4935 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004936 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004937 synchronized (mLastDeviceConnectMsgTime) {
4938 long time = SystemClock.uptimeMillis();
4939 if (mLastDeviceConnectMsgTime > time) {
Matthew Xiec525cf72015-01-22 20:13:17 -08004940 delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004941 }
4942 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004943 }
4944 return delay;
4945 }
4946
Paul McLean394a8e12015-03-03 10:29:19 -07004947 private void sendDeviceConnectionIntent(int device, int state, String address,
4948 String deviceName) {
4949 if (DEBUG_DEVICES) {
4950 Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
4951 " state:0x" + Integer.toHexString(state) + " address:" + address +
4952 " name:" + deviceName + ");");
4953 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004954 Intent intent = new Intent();
4955
Paul McLean10804eb2015-01-28 11:16:35 -08004956 intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
4957 intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
4958 intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
4959
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004960 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4961
Dianne Hackborn632ca412012-06-14 19:34:10 -07004962 int connType = 0;
4963
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004964 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004965 connType = AudioRoutesInfo.MAIN_HEADSET;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004966 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4967 intent.putExtra("microphone", 1);
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004968 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
4969 device == AudioSystem.DEVICE_OUT_LINE) {
4970 /*do apps care about line-out vs headphones?*/
Dianne Hackborn632ca412012-06-14 19:34:10 -07004971 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004972 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4973 intent.putExtra("microphone", 0);
Eric Laurent6fa42452015-01-09 15:09:40 -08004974 } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
4975 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004976 connType = AudioRoutesInfo.MAIN_HDMI;
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004977 configureHdmiPlugIntent(intent, state);
Paul McLean10804eb2015-01-28 11:16:35 -08004978 } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE) {
4979 connType = AudioRoutesInfo.MAIN_USB;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004980 }
4981
Dianne Hackborn632ca412012-06-14 19:34:10 -07004982 synchronized (mCurAudioRoutes) {
4983 if (connType != 0) {
John Spurlock61560172015-02-06 19:46:04 -05004984 int newConn = mCurAudioRoutes.mainType;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004985 if (state != 0) {
4986 newConn |= connType;
4987 } else {
4988 newConn &= ~connType;
4989 }
John Spurlock61560172015-02-06 19:46:04 -05004990 if (newConn != mCurAudioRoutes.mainType) {
4991 mCurAudioRoutes.mainType = newConn;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004992 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4993 SENDMSG_NOOP, 0, 0, null, 0);
4994 }
4995 }
4996 }
4997
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004998 final long ident = Binder.clearCallingIdentity();
4999 try {
5000 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
5001 } finally {
5002 Binder.restoreCallingIdentity(ident);
5003 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005004 }
5005
Paul McLean10804eb2015-01-28 11:16:35 -08005006 private void onSetWiredDeviceConnectionState(int device, int state, String address,
John Spurlock90874332015-03-10 16:00:54 -04005007 String deviceName, String caller) {
Paul McLean394a8e12015-03-03 10:29:19 -07005008 if (DEBUG_DEVICES) {
John Spurlock90874332015-03-10 16:00:54 -04005009 Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
5010 + " state:" + Integer.toHexString(state)
5011 + " address:" + address
5012 + " deviceName:" + deviceName
5013 + " caller: " + caller + ");");
Paul McLean394a8e12015-03-03 10:29:19 -07005014 }
Paul McLean10804eb2015-01-28 11:16:35 -08005015
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005016 synchronized (mConnectedDevices) {
5017 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05005018 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
5019 (device == AudioSystem.DEVICE_OUT_LINE))) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005020 setBluetoothA2dpOnInt(true);
5021 }
Eric Laurentae4506e2014-05-29 16:04:32 -07005022 boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
5023 (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
5024 ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
Jean-Michel Trivi6d00e412015-08-03 17:26:01 -07005025 if (!handleDeviceConnection(state == 1, device, address, deviceName)) {
5026 // change of connection state failed, bailout
5027 return;
5028 }
Eric Laurentf1a457d2012-09-20 16:27:23 -07005029 if (state != 0) {
5030 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05005031 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
5032 (device == AudioSystem.DEVICE_OUT_LINE)) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07005033 setBluetoothA2dpOnInt(false);
5034 }
5035 if ((device & mSafeMediaVolumeDevices) != 0) {
5036 sendMsg(mAudioHandler,
5037 MSG_CHECK_MUSIC_ACTIVE,
5038 SENDMSG_REPLACE,
5039 0,
5040 0,
John Spurlock90874332015-03-10 16:00:54 -04005041 caller,
Eric Laurentf1a457d2012-09-20 16:27:23 -07005042 MUSIC_ACTIVE_POLL_PERIOD_MS);
5043 }
Eric Laurent212532b2014-07-21 15:43:18 -07005044 // Television devices without CEC service apply software volume on HDMI output
5045 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
5046 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
5047 checkAllFixedVolumeDevices();
5048 if (mHdmiManager != null) {
5049 synchronized (mHdmiManager) {
5050 if (mHdmiPlaybackClient != null) {
5051 mHdmiCecSink = false;
5052 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
5053 }
5054 }
5055 }
5056 }
5057 } else {
5058 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
5059 if (mHdmiManager != null) {
5060 synchronized (mHdmiManager) {
5061 mHdmiCecSink = false;
5062 }
5063 }
5064 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005065 }
Paul McLean10804eb2015-01-28 11:16:35 -08005066 if (!isUsb && device != AudioSystem.DEVICE_IN_WIRED_HEADSET) {
5067 sendDeviceConnectionIntent(device, state, address, deviceName);
Mike Lockwooddb454842012-09-18 11:16:57 -07005068 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005069 }
5070 }
5071
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005072 private void configureHdmiPlugIntent(Intent intent, int state) {
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005073 intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
5074 intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005075 if (state == 1) {
5076 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
5077 int[] portGeneration = new int[1];
5078 int status = AudioSystem.listAudioPorts(ports, portGeneration);
5079 if (status == AudioManager.SUCCESS) {
5080 for (AudioPort port : ports) {
5081 if (port instanceof AudioDevicePort) {
5082 final AudioDevicePort devicePort = (AudioDevicePort) port;
Eric Laurent6fa42452015-01-09 15:09:40 -08005083 if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
5084 devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005085 // format the list of supported encodings
Eric Laurentcae34662015-05-19 16:46:52 -07005086 int[] formats = AudioFormat.filterPublicFormats(devicePort.formats());
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005087 if (formats.length > 0) {
5088 ArrayList<Integer> encodingList = new ArrayList(1);
5089 for (int format : formats) {
5090 // a format in the list can be 0, skip it
5091 if (format != AudioFormat.ENCODING_INVALID) {
5092 encodingList.add(format);
5093 }
5094 }
5095 int[] encodingArray = new int[encodingList.size()];
5096 for (int i = 0 ; i < encodingArray.length ; i++) {
5097 encodingArray[i] = encodingList.get(i);
5098 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005099 intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005100 }
5101 // find the maximum supported number of channels
5102 int maxChannels = 0;
5103 for (int mask : devicePort.channelMasks()) {
5104 int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
5105 if (channelCount > maxChannels) {
5106 maxChannels = channelCount;
5107 }
5108 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07005109 intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07005110 }
5111 }
5112 }
5113 }
5114 }
5115 }
5116
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07005117 /* cache of the address of the last dock the device was connected to */
5118 private String mDockAddress;
5119
Eric Laurenta553c252009-07-17 12:17:14 -07005120 /**
5121 * Receiver for misc intent broadcasts the Phone app cares about.
5122 */
5123 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
5124 @Override
5125 public void onReceive(Context context, Intent intent) {
5126 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07005127 int outDevice;
5128 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07005129 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07005130
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08005131 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
5132 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
5133 Intent.EXTRA_DOCK_STATE_UNDOCKED);
5134 int config;
5135 switch (dockState) {
5136 case Intent.EXTRA_DOCK_STATE_DESK:
5137 config = AudioSystem.FORCE_BT_DESK_DOCK;
5138 break;
5139 case Intent.EXTRA_DOCK_STATE_CAR:
5140 config = AudioSystem.FORCE_BT_CAR_DOCK;
5141 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05005142 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08005143 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05005144 break;
5145 case Intent.EXTRA_DOCK_STATE_HE_DESK:
5146 config = AudioSystem.FORCE_DIGITAL_DOCK;
5147 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08005148 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
5149 default:
5150 config = AudioSystem.FORCE_NONE;
5151 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08005152 // Low end docks have a menu to enable or disable audio
5153 // (see mDockAudioMediaEnabled)
5154 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
5155 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
5156 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
5157 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
5158 }
5159 mDockState = dockState;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07005160 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
Eric Laurent59f48272012-04-05 19:42:21 -07005161 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07005162 BluetoothProfile.STATE_DISCONNECTED);
Eric Laurentdca56b92011-09-02 14:20:56 -07005163 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Eric Laurent0867bed2015-05-20 14:49:08 -07005164
Eric Laurent98859b22015-06-12 14:35:59 -07005165 setBtScoDeviceConnectionState(btDevice, state);
Paul McLeandf361462014-04-10 16:02:55 -07005166 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005167 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07005168 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005169 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005170 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07005171 // broadcast intent if the connection was initated by AudioService
5172 if (!mScoClients.isEmpty() &&
5173 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
5174 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
5175 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005176 broadcast = true;
5177 }
5178 switch (btState) {
5179 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07005180 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07005181 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5182 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5183 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005184 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005185 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005186 break;
5187 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07005188 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08005189 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07005190 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08005191 break;
5192 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07005193 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5194 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5195 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08005196 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005197 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005198 default:
5199 // do not broadcast CONNECTING or invalid state
5200 broadcast = false;
5201 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07005202 }
5203 }
Eric Laurent62ef7672010-11-24 10:58:32 -08005204 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07005205 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07005206 //FIXME: this is to maintain compatibility with deprecated intent
5207 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08005208 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07005209 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07005210 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08005211 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005212 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06005213 if (mMonitorRotation) {
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005214 RotationHelper.enable();
Jon Eklund318f0fe2014-01-23 17:53:48 -06005215 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005216 AudioSystem.setParameters("screen_state=on");
5217 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06005218 if (mMonitorRotation) {
5219 //reduce wakeups (save current) by only listening when display is on
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005220 RotationHelper.disable();
Jon Eklund318f0fe2014-01-23 17:53:48 -06005221 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07005222 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07005223 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005224 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07005225 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Yasuhiro Matsuda4ced7192015-07-10 22:08:44 +09005226 if (mUserSwitchedReceived) {
5227 // attempt to stop music playback for background user except on first user
5228 // switch (i.e. first boot)
5229 sendMsg(mAudioHandler,
5230 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
5231 SENDMSG_REPLACE,
5232 0,
5233 0,
5234 null,
5235 0);
5236 }
5237 mUserSwitchedReceived = true;
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07005238 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005239 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07005240
Eric Laurent5bfaeae2012-09-21 18:44:48 -07005241 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07005242 readAudioSettings(true /*userSwitch*/);
5243 // preserve STREAM_MUSIC volume from one user to the next.
5244 sendMsg(mAudioHandler,
5245 MSG_SET_ALL_VOLUMES,
5246 SENDMSG_QUEUE,
5247 0,
5248 0,
5249 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005250 } else if (action.equals(Intent.ACTION_USER_BACKGROUND)) {
5251 // Disable audio recording for the background user/profile
5252 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
5253 if (userId >= 0) {
5254 // TODO Kill recording streams instead of killing processes holding permission
5255 UserInfo userInfo = UserManagerService.getInstance().getUserInfo(userId);
5256 killBackgroundUserProcessesWithRecordAudioPermission(userInfo);
5257 }
Makoto Onukiac65e1e2015-11-20 15:33:17 -08005258 UserManagerService.getInstance().setUserRestriction(
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005259 UserManager.DISALLOW_RECORD_AUDIO, true, userId);
5260 } else if (action.equals(Intent.ACTION_USER_FOREGROUND)) {
5261 // Enable audio recording for foreground user/profile
5262 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
Makoto Onukiac65e1e2015-11-20 15:33:17 -08005263 UserManagerService.getInstance().setUserRestriction(
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005264 UserManager.DISALLOW_RECORD_AUDIO, false, userId);
Eric Laurentb70b78a2016-01-13 19:16:04 -08005265 } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
5266 state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
5267 if (state == BluetoothAdapter.STATE_OFF ||
5268 state == BluetoothAdapter.STATE_TURNING_OFF) {
5269 disconnectAllBluetoothProfiles();
5270 }
Eric Laurenta553c252009-07-17 12:17:14 -07005271 }
5272 }
Paul McLeanc837a452014-04-09 09:04:43 -07005273 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005274
Makoto Onukid45a4a22015-11-02 17:17:38 -08005275 private class AudioServiceUserRestrictionsListener implements UserRestrictionsListener {
5276
5277 @Override
5278 public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
5279 Bundle prevRestrictions) {
5280 // Update mic mute state.
5281 {
5282 final boolean wasRestricted =
5283 prevRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
5284 final boolean isRestricted =
5285 newRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE);
5286 if (wasRestricted != isRestricted) {
5287 setMicrophoneMuteNoCallerCheck(isRestricted, userId);
5288 }
5289 }
5290
5291 // Update speaker mute state.
5292 {
5293 final boolean wasRestricted =
5294 prevRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME);
5295 final boolean isRestricted =
5296 newRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME);
5297 if (wasRestricted != isRestricted) {
5298 setMasterMuteInternalNoCallerCheck(isRestricted, /* flags =*/ 0, userId);
5299 }
5300 }
5301 }
5302 } // end class AudioServiceUserRestrictionsListener
5303
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005304 private void killBackgroundUserProcessesWithRecordAudioPermission(UserInfo oldUser) {
5305 PackageManager pm = mContext.getPackageManager();
5306 // Find the home activity of the user. It should not be killed to avoid expensive restart,
5307 // when the user switches back. For managed profiles, we should kill all recording apps
5308 ComponentName homeActivityName = null;
5309 if (!oldUser.isManagedProfile()) {
5310 homeActivityName = LocalServices.getService(ActivityManagerInternal.class)
5311 .getHomeActivityForUser(oldUser.id);
5312 }
5313 final String[] permissions = { Manifest.permission.RECORD_AUDIO };
5314 List<PackageInfo> packages;
5315 try {
5316 packages = AppGlobals.getPackageManager()
5317 .getPackagesHoldingPermissions(permissions, 0, oldUser.id).getList();
5318 } catch (RemoteException e) {
5319 throw new AndroidRuntimeException(e);
5320 }
5321 for (int j = packages.size() - 1; j >= 0; j--) {
5322 PackageInfo pkg = packages.get(j);
Fyodor Kupolovbcb6c1e2015-05-11 12:05:15 -07005323 // Skip system processes
5324 if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
5325 continue;
5326 }
Amith Yamasanic1cbaab2015-07-21 11:46:14 -07005327 // Skip packages that have permission to interact across users
5328 if (pm.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS, pkg.packageName)
5329 == PackageManager.PERMISSION_GRANTED) {
5330 continue;
5331 }
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005332 if (homeActivityName != null
5333 && pkg.packageName.equals(homeActivityName.getPackageName())
5334 && pkg.applicationInfo.isSystemApp()) {
5335 continue;
5336 }
5337 try {
Svetoslavaa41add2015-08-06 15:03:55 -07005338 final int uid = pkg.applicationInfo.uid;
5339 ActivityManagerNative.getDefault().killUid(UserHandle.getAppId(uid),
5340 UserHandle.getUserId(uid),
Fyodor Kupolovb5013302015-04-17 17:59:14 -07005341 "killBackgroundUserProcessesWithAudioRecordPermission");
5342 } catch (RemoteException e) {
5343 Log.w(TAG, "Error calling killUid", e);
5344 }
5345 }
5346 }
5347
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005348
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005349 //==========================================================================================
5350 // Audio Focus
5351 //==========================================================================================
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005352 public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005353 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005354 IAudioPolicyCallback pcb) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005355 // permission checks
5356 if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
John Spurlock61560172015-02-06 19:46:04 -05005357 if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005358 if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
5359 android.Manifest.permission.MODIFY_PHONE_STATE)) {
5360 Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
5361 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5362 }
5363 } else {
5364 // only a registered audio policy can be used to lock focus
5365 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005366 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
5367 Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005368 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5369 }
5370 }
5371 }
5372 }
5373
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005374 return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
5375 clientId, callingPackageName, flags);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005376 }
5377
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005378 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
5379 return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005380 }
5381
5382 public void unregisterAudioFocusClient(String clientId) {
5383 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005384 }
5385
Jean-Michel Trivi23805662013-07-31 14:19:18 -07005386 public int getCurrentAudioFocus() {
5387 return mMediaFocusControl.getCurrentAudioFocus();
5388 }
5389
John Spurlock5e783732015-02-19 10:28:59 -05005390 private boolean readCameraSoundForced() {
5391 return SystemProperties.getBoolean("audio.camerasound.force", false) ||
5392 mContext.getResources().getBoolean(
5393 com.android.internal.R.bool.config_camera_sound_forced);
5394 }
5395
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005396 //==========================================================================================
5397 // Device orientation
5398 //==========================================================================================
5399 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005400 * Handles device configuration changes that may map to a change in the orientation
5401 * or orientation.
5402 * Monitoring orientation and rotation is optional, and is defined by the definition and value
5403 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005404 */
5405 private void handleConfigurationChanged(Context context) {
5406 try {
5407 // reading new orientation "safely" (i.e. under try catch) in case anything
5408 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07005409 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005410 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07005411 if (mMonitorOrientation) {
5412 int newOrientation = config.orientation;
5413 if (newOrientation != mDeviceOrientation) {
5414 mDeviceOrientation = newOrientation;
5415 setOrientationForAudioSystem();
5416 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005417 }
Eric Laurentd640bd32012-09-28 18:01:48 -07005418 sendMsg(mAudioHandler,
5419 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
5420 SENDMSG_REPLACE,
5421 0,
5422 0,
John Spurlock90874332015-03-10 16:00:54 -04005423 TAG,
Eric Laurentd640bd32012-09-28 18:01:48 -07005424 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07005425
John Spurlock5e783732015-02-19 10:28:59 -05005426 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -07005427 synchronized (mSettingsLock) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005428 boolean cameraSoundForcedChanged = false;
Eric Laurentdd45d012012-10-08 09:04:34 -07005429 synchronized (mCameraSoundForced) {
5430 if (cameraSoundForced != mCameraSoundForced) {
5431 mCameraSoundForced = cameraSoundForced;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005432 cameraSoundForcedChanged = true;
Eric Laurentdd45d012012-10-08 09:04:34 -07005433 }
5434 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005435 if (cameraSoundForcedChanged) {
5436 if (!isPlatformTelevision()) {
5437 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
5438 if (cameraSoundForced) {
5439 s.setAllIndexesToMax();
5440 mRingerModeAffectedStreams &=
5441 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5442 } else {
John Spurlock90874332015-03-10 16:00:54 -04005443 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005444 mRingerModeAffectedStreams |=
5445 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5446 }
5447 // take new state into account for streams muted by ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05005448 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005449 }
5450
5451 sendMsg(mAudioHandler,
5452 MSG_SET_FORCE_USE,
5453 SENDMSG_QUEUE,
5454 AudioSystem.FOR_SYSTEM,
5455 cameraSoundForced ?
5456 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
5457 null,
5458 0);
5459
5460 sendMsg(mAudioHandler,
5461 MSG_SET_ALL_VOLUMES,
5462 SENDMSG_QUEUE,
5463 0,
5464 0,
5465 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
5466 }
Eric Laurentdd45d012012-10-08 09:04:34 -07005467 }
John Spurlock3346a802014-05-20 16:25:37 -04005468 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005469 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005470 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005471 }
5472 }
5473
Jean-Michel Trivi24806db2015-10-01 15:00:59 -07005474 //TODO move to an external "orientation helper" class
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005475 private void setOrientationForAudioSystem() {
5476 switch (mDeviceOrientation) {
5477 case Configuration.ORIENTATION_LANDSCAPE:
5478 //Log.i(TAG, "orientation is landscape");
5479 AudioSystem.setParameters("orientation=landscape");
5480 break;
5481 case Configuration.ORIENTATION_PORTRAIT:
5482 //Log.i(TAG, "orientation is portrait");
5483 AudioSystem.setParameters("orientation=portrait");
5484 break;
5485 case Configuration.ORIENTATION_SQUARE:
5486 //Log.i(TAG, "orientation is square");
5487 AudioSystem.setParameters("orientation=square");
5488 break;
5489 case Configuration.ORIENTATION_UNDEFINED:
5490 //Log.i(TAG, "orientation is undefined");
5491 AudioSystem.setParameters("orientation=undefined");
5492 break;
5493 default:
5494 Log.e(TAG, "Unknown orientation");
5495 }
5496 }
5497
Eric Laurent78472112012-05-21 08:57:21 -07005498 // Handles request to override default use of A2DP for media.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005499 // Must be called synchronized on mConnectedDevices
Eric Laurent78472112012-05-21 08:57:21 -07005500 public void setBluetoothA2dpOnInt(boolean on) {
5501 synchronized (mBluetoothA2dpEnabledLock) {
5502 mBluetoothA2dpEnabled = on;
Eric Laurentc390bed2012-07-03 12:24:05 -07005503 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005504 setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
Eric Laurentc390bed2012-07-03 12:24:05 -07005505 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
Eric Laurent78472112012-05-21 08:57:21 -07005506 }
5507 }
5508
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005509 // Must be called synchronized on mConnectedDevices
5510 private void setForceUseInt_SyncDevices(int usage, int config) {
5511 switch (usage) {
5512 case AudioSystem.FOR_MEDIA:
5513 if (config == AudioSystem.FORCE_NO_BT_A2DP) {
5514 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ALL_A2DP;
5515 } else { // config == AudioSystem.FORCE_NONE
5516 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
5517 }
5518 break;
5519 case AudioSystem.FOR_DOCK:
5520 if (config == AudioSystem.FORCE_ANALOG_DOCK) {
5521 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5522 } else { // config == AudioSystem.FORCE_NONE
5523 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5524 }
5525 break;
5526 default:
5527 // usage doesn't affect the broadcast of ACTION_AUDIO_BECOMING_NOISY
5528 }
5529 AudioSystem.setForceUse(usage, config);
5530 }
5531
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005532 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07005533 public void setRingtonePlayer(IRingtonePlayer player) {
5534 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5535 mRingtonePlayer = player;
5536 }
5537
5538 @Override
5539 public IRingtonePlayer getRingtonePlayer() {
5540 return mRingtonePlayer;
5541 }
5542
5543 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07005544 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5545 synchronized (mCurAudioRoutes) {
5546 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5547 mRoutesObservers.register(observer);
5548 return routes;
5549 }
5550 }
5551
Eric Laurentc34dcc12012-09-10 13:51:52 -07005552
5553 //==========================================================================================
5554 // Safe media volume management.
5555 // MUSIC stream volume level is limited when headphones are connected according to safety
5556 // regulation. When the user attempts to raise the volume above the limit, a warning is
5557 // displayed and the user has to acknowlegde before the volume is actually changed.
5558 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
5559 // property. Platforms with a different limit must set this property accordingly in their
5560 // overlay.
5561 //==========================================================================================
5562
Eric Laurentd640bd32012-09-28 18:01:48 -07005563 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
5564 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
5565 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
5566 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
5567 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
5568 // (when user opts out).
John Spurlock35134602014-07-24 18:10:48 -04005569 private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
5570 private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
5571 private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed
5572 private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
Eric Laurentd640bd32012-09-28 18:01:48 -07005573 private Integer mSafeMediaVolumeState;
5574
5575 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005576 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07005577 private int mSafeMediaVolumeIndex;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005578 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
5579 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
5580 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
5581 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
5582 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
5583 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
5584 private int mMusicActiveMs;
5585 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
5586 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07005587 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07005588
John Spurlock90874332015-03-10 16:00:54 -04005589 private void setSafeMediaVolumeEnabled(boolean on, String caller) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005590 synchronized (mSafeMediaVolumeState) {
5591 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
5592 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
5593 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
5594 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
John Spurlock90874332015-03-10 16:00:54 -04005595 enforceSafeMediaVolume(caller);
Eric Laurentd640bd32012-09-28 18:01:48 -07005596 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
5597 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005598 mMusicActiveMs = 1; // nonzero = confirmed
5599 saveMusicActiveMs();
Eric Laurentd640bd32012-09-28 18:01:48 -07005600 sendMsg(mAudioHandler,
5601 MSG_CHECK_MUSIC_ACTIVE,
5602 SENDMSG_REPLACE,
5603 0,
5604 0,
John Spurlock90874332015-03-10 16:00:54 -04005605 caller,
Eric Laurentd640bd32012-09-28 18:01:48 -07005606 MUSIC_ACTIVE_POLL_PERIOD_MS);
5607 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005608 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005609 }
5610 }
5611
John Spurlock90874332015-03-10 16:00:54 -04005612 private void enforceSafeMediaVolume(String caller) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005613 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07005614 int devices = mSafeMediaVolumeDevices;
5615 int i = 0;
5616
5617 while (devices != 0) {
5618 int device = 1 << i++;
5619 if ((device & devices) == 0) {
5620 continue;
5621 }
Eric Laurent42b041e2013-03-29 11:36:03 -07005622 int index = streamState.getIndex(device);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005623 if (index > mSafeMediaVolumeIndex) {
John Spurlock90874332015-03-10 16:00:54 -04005624 streamState.setIndex(mSafeMediaVolumeIndex, device, caller);
Eric Laurent42b041e2013-03-29 11:36:03 -07005625 sendMsg(mAudioHandler,
5626 MSG_SET_DEVICE_VOLUME,
5627 SENDMSG_QUEUE,
5628 device,
5629 0,
5630 streamState,
5631 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005632 }
5633 devices &= ~device;
5634 }
5635 }
5636
5637 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005638 synchronized (mSafeMediaVolumeState) {
5639 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07005640 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
5641 ((device & mSafeMediaVolumeDevices) != 0) &&
5642 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005643 return false;
5644 }
5645 return true;
5646 }
5647 }
5648
John Spurlock3346a802014-05-20 16:25:37 -04005649 @Override
John Spurlock90874332015-03-10 16:00:54 -04005650 public void disableSafeMediaVolume(String callingPackage) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005651 enforceVolumeController("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07005652 synchronized (mSafeMediaVolumeState) {
John Spurlock90874332015-03-10 16:00:54 -04005653 setSafeMediaVolumeEnabled(false, callingPackage);
Eric Laurentfde16d52012-12-03 14:42:39 -08005654 if (mPendingVolumeCommand != null) {
5655 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
5656 mPendingVolumeCommand.mIndex,
5657 mPendingVolumeCommand.mFlags,
John Spurlock90874332015-03-10 16:00:54 -04005658 mPendingVolumeCommand.mDevice,
5659 callingPackage);
Eric Laurentfde16d52012-12-03 14:42:39 -08005660 mPendingVolumeCommand = null;
5661 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005662 }
5663 }
5664
Jungshik Jang41d97462014-06-30 22:26:29 +09005665 //==========================================================================================
5666 // Hdmi Cec system audio mode.
John Spurlockbc82b122015-03-02 16:12:38 -05005667 // If Hdmi Cec's system audio mode is on, audio service should send the volume change
5668 // to HdmiControlService so that the audio receiver can handle it.
Jungshik Jang41d97462014-06-30 22:26:29 +09005669 //==========================================================================================
5670
Eric Laurent212532b2014-07-21 15:43:18 -07005671 private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
5672 public void onComplete(int status) {
5673 if (mHdmiManager != null) {
5674 synchronized (mHdmiManager) {
5675 mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
5676 // Television devices without CEC service apply software volume on HDMI output
5677 if (isPlatformTelevision() && !mHdmiCecSink) {
5678 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5679 }
5680 checkAllFixedVolumeDevices();
5681 }
5682 }
5683 }
5684 };
5685
Jungshik Jang41d97462014-06-30 22:26:29 +09005686 // If HDMI-CEC system audio is supported
5687 private boolean mHdmiSystemAudioSupported = false;
5688 // Set only when device is tv.
5689 private HdmiTvClient mHdmiTvClient;
Eric Laurent0b03f992014-11-18 18:08:02 -08005690 // true if the device has system feature PackageManager.FEATURE_LEANBACK.
Eric Laurent212532b2014-07-21 15:43:18 -07005691 // cached HdmiControlManager interface
5692 private HdmiControlManager mHdmiManager;
5693 // Set only when device is a set-top box.
5694 private HdmiPlaybackClient mHdmiPlaybackClient;
5695 // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5696 private boolean mHdmiCecSink;
5697
5698 private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
Jungshik Jang41d97462014-06-30 22:26:29 +09005699
5700 @Override
Jungshik Jang12307ca2014-07-15 19:27:56 +09005701 public int setHdmiSystemAudioSupported(boolean on) {
Eric Laurent212532b2014-07-21 15:43:18 -07005702 int device = AudioSystem.DEVICE_NONE;
5703 if (mHdmiManager != null) {
5704 synchronized (mHdmiManager) {
5705 if (mHdmiTvClient == null) {
5706 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5707 return device;
5708 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005709
Eric Laurent212532b2014-07-21 15:43:18 -07005710 synchronized (mHdmiTvClient) {
5711 if (mHdmiSystemAudioSupported != on) {
5712 mHdmiSystemAudioSupported = on;
5713 AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5714 on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5715 AudioSystem.FORCE_NONE);
5716 }
John Spurlock8a52c442015-03-26 14:23:58 -04005717 device = getDevicesForStream(AudioSystem.STREAM_MUSIC);
Eric Laurent212532b2014-07-21 15:43:18 -07005718 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005719 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005720 }
Eric Laurent212532b2014-07-21 15:43:18 -07005721 return device;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005722 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005723
Terry Heoe7d6d972014-09-04 21:05:28 +09005724 @Override
5725 public boolean isHdmiSystemAudioSupported() {
5726 return mHdmiSystemAudioSupported;
5727 }
5728
Eric Laurentdd45d012012-10-08 09:04:34 -07005729 //==========================================================================================
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005730 // Accessibility: taking touch exploration into account for selecting the default
5731 // stream override timeout when adjusting volume
5732 //==========================================================================================
5733 private static class StreamOverride
5734 implements AccessibilityManager.TouchExplorationStateChangeListener {
5735
5736 // AudioService.getActiveStreamType() will return:
5737 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
5738 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
5739 // stopped
Jean-Michel Triviccffda82015-05-21 18:23:57 -07005740 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 0;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005741 private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
5742
5743 static int sDelayMs;
5744
5745 static void init(Context ctxt) {
5746 AccessibilityManager accessibilityManager =
5747 (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
5748 updateDefaultStreamOverrideDelay(
5749 accessibilityManager.isTouchExplorationEnabled());
5750 accessibilityManager.addTouchExplorationStateChangeListener(
5751 new StreamOverride());
5752 }
5753
5754 @Override
5755 public void onTouchExplorationStateChanged(boolean enabled) {
5756 updateDefaultStreamOverrideDelay(enabled);
5757 }
5758
5759 private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
5760 if (touchExploreEnabled) {
5761 sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
5762 } else {
5763 sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
5764 }
5765 if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
5766 + " stream override delay is now " + sDelayMs + " ms");
5767 }
5768 }
5769
5770 //==========================================================================================
Eric Laurentdd45d012012-10-08 09:04:34 -07005771 // Camera shutter sound policy.
5772 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5773 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5774 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5775 //==========================================================================================
5776
5777 // cached value of com.android.internal.R.bool.config_camera_sound_forced
5778 private Boolean mCameraSoundForced;
5779
5780 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5781 public boolean isCameraSoundForced() {
5782 synchronized (mCameraSoundForced) {
5783 return mCameraSoundForced;
5784 }
5785 }
5786
5787 private static final String[] RINGER_MODE_NAMES = new String[] {
5788 "SILENT",
5789 "VIBRATE",
5790 "NORMAL"
5791 };
5792
5793 private void dumpRingerMode(PrintWriter pw) {
5794 pw.println("\nRinger mode: ");
John Spurlock661f2cf2014-11-17 10:29:10 -05005795 pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
5796 pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
John Spurlock50ced3f2015-05-11 16:00:09 -04005797 dumpRingerModeStreams(pw, "affected", mRingerModeAffectedStreams);
5798 dumpRingerModeStreams(pw, "muted", mRingerModeMutedStreams);
John Spurlock661f2cf2014-11-17 10:29:10 -05005799 pw.print("- delegate = "); pw.println(mRingerModeDelegate);
Eric Laurentdd45d012012-10-08 09:04:34 -07005800 }
5801
John Spurlock50ced3f2015-05-11 16:00:09 -04005802 private void dumpRingerModeStreams(PrintWriter pw, String type, int streams) {
5803 pw.print("- ringer mode "); pw.print(type); pw.print(" streams = 0x");
5804 pw.print(Integer.toHexString(streams));
5805 if (streams != 0) {
5806 pw.print(" (");
5807 boolean first = true;
5808 for (int i = 0; i < AudioSystem.STREAM_NAMES.length; i++) {
5809 final int stream = (1 << i);
5810 if ((streams & stream) != 0) {
5811 if (!first) pw.print(',');
5812 pw.print(AudioSystem.STREAM_NAMES[i]);
5813 streams &= ~stream;
5814 first = false;
5815 }
5816 }
5817 if (streams != 0) {
5818 if (!first) pw.print(',');
5819 pw.print(streams);
5820 }
5821 pw.print(')');
5822 }
5823 pw.println();
5824 }
5825
Dianne Hackborn632ca412012-06-14 19:34:10 -07005826 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005827 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07005828 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5829
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005830 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07005831 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07005832 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005833 pw.println("\nAudio routes:");
John Spurlock61560172015-02-06 19:46:04 -05005834 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
5835 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
John Spurlock35134602014-07-24 18:10:48 -04005836
5837 pw.println("\nOther state:");
John Spurlock3346a802014-05-20 16:25:37 -04005838 pw.print(" mVolumeController="); pw.println(mVolumeController);
John Spurlock35134602014-07-24 18:10:48 -04005839 pw.print(" mSafeMediaVolumeState=");
5840 pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
5841 pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
5842 pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
5843 pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005844 pw.print(" mMcc="); pw.println(mMcc);
John Spurlock5e783732015-02-19 10:28:59 -05005845 pw.print(" mCameraSoundForced="); pw.println(mCameraSoundForced);
John Spurlock661f2cf2014-11-17 10:29:10 -05005846 pw.print(" mHasVibrator="); pw.println(mHasVibrator);
John Spurlockcdb57ae2015-02-11 19:04:11 -05005847 pw.print(" mControllerService="); pw.println(mControllerService);
John Spurlocka48d7792015-03-03 17:35:57 -05005848 pw.print(" mVolumePolicy="); pw.println(mVolumePolicy);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005849
5850 dumpAudioPolicies(pw);
John Spurlock35134602014-07-24 18:10:48 -04005851 }
5852
5853 private static String safeMediaVolumeStateToString(Integer state) {
5854 switch(state) {
5855 case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
5856 case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
5857 case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
5858 case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
5859 }
5860 return null;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005861 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07005862
5863 // Inform AudioFlinger of our device's low RAM attribute
5864 private static void readAndSetLowRamDevice()
5865 {
5866 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
5867 if (status != 0) {
5868 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
5869 }
5870 }
John Spurlock3346a802014-05-20 16:25:37 -04005871
John Spurlockcdb57ae2015-02-11 19:04:11 -05005872 private void enforceVolumeController(String action) {
5873 if (mControllerService.mUid != 0 && Binder.getCallingUid() == mControllerService.mUid) {
5874 return;
5875 }
John Spurlock3346a802014-05-20 16:25:37 -04005876 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
5877 "Only SystemUI can " + action);
5878 }
5879
5880 @Override
5881 public void setVolumeController(final IVolumeController controller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005882 enforceVolumeController("set the volume controller");
John Spurlock3346a802014-05-20 16:25:37 -04005883
5884 // return early if things are not actually changing
5885 if (mVolumeController.isSameBinder(controller)) {
5886 return;
5887 }
5888
5889 // dismiss the old volume controller
5890 mVolumeController.postDismiss();
5891 if (controller != null) {
5892 // we are about to register a new controller, listen for its death
5893 try {
5894 controller.asBinder().linkToDeath(new DeathRecipient() {
5895 @Override
5896 public void binderDied() {
5897 if (mVolumeController.isSameBinder(controller)) {
5898 Log.w(TAG, "Current remote volume controller died, unregistering");
5899 setVolumeController(null);
5900 }
5901 }
5902 }, 0);
5903 } catch (RemoteException e) {
5904 // noop
5905 }
5906 }
5907 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04005908 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
5909 }
5910
5911 @Override
5912 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005913 enforceVolumeController("notify about volume controller visibility");
John Spurlock33f4e042014-07-11 13:10:58 -04005914
5915 // return early if the controller is not current
5916 if (!mVolumeController.isSameBinder(controller)) {
5917 return;
5918 }
5919
5920 mVolumeController.setVisible(visible);
5921 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04005922 }
RoboErikd09bd0c2014-06-24 17:45:19 -07005923
John Spurlocka48d7792015-03-03 17:35:57 -05005924 @Override
5925 public void setVolumePolicy(VolumePolicy policy) {
5926 enforceVolumeController("set volume policy");
John Spurlockb02c7442015-04-14 09:32:25 -04005927 if (policy != null && !policy.equals(mVolumePolicy)) {
John Spurlocka48d7792015-03-03 17:35:57 -05005928 mVolumePolicy = policy;
John Spurlockb02c7442015-04-14 09:32:25 -04005929 if (DEBUG_VOL) Log.d(TAG, "Volume policy changed: " + mVolumePolicy);
John Spurlocka48d7792015-03-03 17:35:57 -05005930 }
5931 }
5932
RoboErikd09bd0c2014-06-24 17:45:19 -07005933 public static class VolumeController {
5934 private static final String TAG = "VolumeController";
5935
5936 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04005937 private boolean mVisible;
5938 private long mNextLongPress;
5939 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07005940
5941 public void setController(IVolumeController controller) {
5942 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04005943 mVisible = false;
5944 }
5945
5946 public void loadSettings(ContentResolver cr) {
5947 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
5948 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
5949 }
5950
RoboErik4197cb62015-01-21 15:45:32 -08005951 public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
5952 if (isMute) {
5953 return false;
5954 }
John Spurlock33f4e042014-07-11 13:10:58 -04005955 boolean suppress = false;
5956 if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
5957 final long now = SystemClock.uptimeMillis();
5958 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
5959 // ui will become visible
5960 if (mNextLongPress < now) {
5961 mNextLongPress = now + mLongPressTimeout;
5962 }
5963 suppress = true;
5964 } else if (mNextLongPress > 0) { // in a long-press
5965 if (now > mNextLongPress) {
5966 // long press triggered, no more suppression
5967 mNextLongPress = 0;
5968 } else {
5969 // keep suppressing until the long press triggers
5970 suppress = true;
5971 }
5972 }
5973 }
5974 return suppress;
5975 }
5976
5977 public void setVisible(boolean visible) {
5978 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07005979 }
5980
5981 public boolean isSameBinder(IVolumeController controller) {
5982 return Objects.equals(asBinder(), binder(controller));
5983 }
5984
5985 public IBinder asBinder() {
5986 return binder(mController);
5987 }
5988
5989 private static IBinder binder(IVolumeController controller) {
5990 return controller == null ? null : controller.asBinder();
5991 }
5992
5993 @Override
5994 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04005995 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07005996 }
5997
5998 public void postDisplaySafeVolumeWarning(int flags) {
5999 if (mController == null)
6000 return;
6001 try {
6002 mController.displaySafeVolumeWarning(flags);
6003 } catch (RemoteException e) {
6004 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
6005 }
6006 }
6007
6008 public void postVolumeChanged(int streamType, int flags) {
6009 if (mController == null)
6010 return;
6011 try {
6012 mController.volumeChanged(streamType, flags);
6013 } catch (RemoteException e) {
6014 Log.w(TAG, "Error calling volumeChanged", e);
6015 }
6016 }
6017
RoboErikd09bd0c2014-06-24 17:45:19 -07006018 public void postMasterMuteChanged(int flags) {
6019 if (mController == null)
6020 return;
6021 try {
6022 mController.masterMuteChanged(flags);
6023 } catch (RemoteException e) {
6024 Log.w(TAG, "Error calling masterMuteChanged", e);
6025 }
6026 }
6027
6028 public void setLayoutDirection(int layoutDirection) {
6029 if (mController == null)
6030 return;
6031 try {
6032 mController.setLayoutDirection(layoutDirection);
6033 } catch (RemoteException e) {
6034 Log.w(TAG, "Error calling setLayoutDirection", e);
6035 }
6036 }
6037
6038 public void postDismiss() {
6039 if (mController == null)
6040 return;
6041 try {
6042 mController.dismiss();
6043 } catch (RemoteException e) {
6044 Log.w(TAG, "Error calling dismiss", e);
6045 }
6046 }
6047 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006048
RoboErik0dac35a2014-08-12 15:48:49 -07006049 /**
6050 * Interface for system components to get some extra functionality through
6051 * LocalServices.
6052 */
6053 final class AudioServiceInternal extends AudioManagerInternal {
John Spurlock661f2cf2014-11-17 10:29:10 -05006054 @Override
6055 public void setRingerModeDelegate(RingerModeDelegate delegate) {
6056 mRingerModeDelegate = delegate;
6057 if (mRingerModeDelegate != null) {
John Spurlock50ced3f2015-05-11 16:00:09 -04006058 updateRingerModeAffectedStreams();
John Spurlock661f2cf2014-11-17 10:29:10 -05006059 setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
6060 }
6061 }
RoboErik272e1612014-09-05 11:39:29 -07006062
6063 @Override
6064 public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
6065 String callingPackage, int uid) {
6066 // direction and stream type swap here because the public
6067 // adjustSuggested has a different order than the other methods.
John Spurlock90874332015-03-10 16:00:54 -04006068 adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage,
6069 callingPackage, uid);
RoboErik272e1612014-09-05 11:39:29 -07006070 }
6071
RoboErik0dac35a2014-08-12 15:48:49 -07006072 @Override
6073 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
6074 String callingPackage, int uid) {
John Spurlock90874332015-03-10 16:00:54 -04006075 adjustStreamVolume(streamType, direction, flags, callingPackage,
6076 callingPackage, uid);
RoboErik0dac35a2014-08-12 15:48:49 -07006077 }
6078
6079 @Override
6080 public void setStreamVolumeForUid(int streamType, int direction, int flags,
6081 String callingPackage, int uid) {
John Spurlock90874332015-03-10 16:00:54 -04006082 setStreamVolume(streamType, direction, flags, callingPackage, callingPackage, uid);
RoboErik0dac35a2014-08-12 15:48:49 -07006083 }
RoboErik519c7742014-11-18 10:59:09 -08006084
6085 @Override
John Spurlock661f2cf2014-11-17 10:29:10 -05006086 public int getRingerModeInternal() {
6087 return AudioService.this.getRingerModeInternal();
6088 }
6089
6090 @Override
6091 public void setRingerModeInternal(int ringerMode, String caller) {
6092 AudioService.this.setRingerModeInternal(ringerMode, caller);
6093 }
John Spurlockcdb57ae2015-02-11 19:04:11 -05006094
6095 @Override
6096 public int getVolumeControllerUid() {
6097 return mControllerService.mUid;
6098 }
John Spurlock50ced3f2015-05-11 16:00:09 -04006099
6100 @Override
6101 public void updateRingerModeAffectedStreamsInternal() {
6102 synchronized (mSettingsLock) {
6103 if (updateRingerModeAffectedStreams()) {
6104 setRingerModeInt(getRingerModeInternal(), false);
6105 }
6106 }
6107 }
RoboErik0dac35a2014-08-12 15:48:49 -07006108 }
6109
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006110 //==========================================================================================
6111 // Audio policy management
6112 //==========================================================================================
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006113 public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
6114 boolean hasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006115 AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
6116
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006117 if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
6118 + " with config:" + policyConfig);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006119 String regId = null;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006120 // error handling
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006121 boolean hasPermissionForPolicy =
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006122 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006123 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
6124 if (!hasPermissionForPolicy) {
6125 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
6126 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006127 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006128 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006129
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006130 synchronized (mAudioPolicies) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006131 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006132 if (mAudioPolicies.containsKey(pcb.asBinder())) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006133 Slog.e(TAG, "Cannot re-register policy");
6134 return null;
6135 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006136 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
6137 pcb.asBinder().linkToDeath(app, 0/*flags*/);
6138 regId = app.getRegistrationId();
6139 mAudioPolicies.put(pcb.asBinder(), app);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006140 } catch (RemoteException e) {
6141 // audio policy owner has already died!
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006142 Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006143 " binder death", e);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006144 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006145 }
6146 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006147 return regId;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006148 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006149
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006150 public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
6151 if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006152 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006153 AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006154 if (app == null) {
6155 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
6156 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006157 return;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006158 } else {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006159 pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006160 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006161 app.release();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006162 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006163 // TODO implement clearing mix attribute matching info in native audio policy
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006164 }
6165
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006166 public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
6167 if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
6168 + " policy " + pcb.asBinder());
6169 // error handling
6170 boolean hasPermissionForPolicy =
6171 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
6172 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
6173 if (!hasPermissionForPolicy) {
6174 Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
6175 + Binder.getCallingPid() + " / uid "
6176 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
6177 return AudioManager.ERROR;
6178 }
6179
6180 synchronized (mAudioPolicies) {
6181 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
6182 Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
6183 return AudioManager.ERROR;
6184 }
6185 final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
6186 if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6187 // is there already one policy managing ducking?
Eric Laurent0867bed2015-05-20 14:49:08 -07006188 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006189 if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6190 Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
6191 return AudioManager.ERROR;
6192 }
6193 }
6194 }
6195 app.mFocusDuckBehavior = duckingBehavior;
6196 mMediaFocusControl.setDuckingInExtPolicyAvailable(
6197 duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
6198 }
6199 return AudioManager.SUCCESS;
6200 }
6201
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006202 private void dumpAudioPolicies(PrintWriter pw) {
6203 pw.println("\nAudio policies:");
6204 synchronized (mAudioPolicies) {
Eric Laurent0867bed2015-05-20 14:49:08 -07006205 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006206 pw.println(policy.toLogFriendlyString());
6207 }
6208 }
6209 }
6210
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006211 //======================
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08006212 // Audio policy callbacks from AudioSystem for dynamic policies
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006213 //======================
6214 private final AudioSystem.DynamicPolicyCallback mDynPolicyCallback =
6215 new AudioSystem.DynamicPolicyCallback() {
6216 public void onDynamicPolicyMixStateUpdate(String regId, int state) {
6217 if (!TextUtils.isEmpty(regId)) {
6218 sendMsg(mAudioHandler, MSG_DYN_POLICY_MIX_STATE_UPDATE, SENDMSG_QUEUE,
6219 state /*arg1*/, 0 /*arg2 ignored*/, regId /*obj*/, 0 /*delay*/);
6220 }
6221 }
6222 };
6223
6224 private void onDynPolicyMixStateUpdate(String regId, int state) {
6225 if (DEBUG_AP) Log.d(TAG, "onDynamicPolicyMixStateUpdate("+ regId + ", " + state +")");
6226 synchronized (mAudioPolicies) {
6227 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
6228 for (AudioMix mix : policy.getMixes()) {
6229 if (mix.getRegistration().equals(regId)) {
6230 try {
6231 policy.mPolicyCallback.notifyMixStateUpdate(regId, state);
6232 } catch (RemoteException e) {
6233 Log.e(TAG, "Can't call notifyMixStateUpdate() on IAudioPolicyCallback "
6234 + policy.mPolicyCallback.asBinder(), e);
6235 }
6236 return;
6237 }
6238 }
6239 }
6240 }
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08006241 }
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006242
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08006243 //======================
6244 // Audio policy callbacks from AudioSystem for recording configuration updates
6245 //======================
6246 private final RecordingActivityMonitor mRecordMonitor = new RecordingActivityMonitor();
6247
6248 public void registerRecordingCallback(IRecordingConfigDispatcher rcdb) {
6249 mRecordMonitor.registerRecordingCallback(rcdb);
6250 }
6251
6252 public void unregisterRecordingCallback(IRecordingConfigDispatcher rcdb) {
6253 mRecordMonitor.unregisterRecordingCallback(rcdb);
6254 }
6255
6256 public AudioRecordConfiguration[] getActiveRecordConfigurations() {
6257 return mRecordMonitor.getActiveRecordConfigurations();
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006258 }
6259
6260 //======================
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08006261 // Audio policy proxy
6262 //======================
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006263 /**
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006264 * This internal class inherits from AudioPolicyConfig, each instance contains all the
6265 * mixes of an AudioPolicy and their configurations.
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006266 */
6267 public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006268 private static final String TAG = "AudioPolicyProxy";
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006269 IAudioPolicyCallback mPolicyCallback;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006270 boolean mHasFocusListener;
6271 /**
6272 * Audio focus ducking behavior for an audio policy.
6273 * This variable reflects the value that was successfully set in
6274 * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
6275 * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
6276 * is handling ducking for audio focus.
6277 */
6278 int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
6279
6280 AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
6281 boolean hasFocusListener) {
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006282 super(config);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006283 setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006284 mPolicyCallback = token;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006285 mHasFocusListener = hasFocusListener;
6286 if (mHasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006287 mMediaFocusControl.addFocusFollower(mPolicyCallback);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006288 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006289 connectMixes();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006290 }
6291
6292 public void binderDied() {
6293 synchronized (mAudioPolicies) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006294 Log.i(TAG, "audio policy " + mPolicyCallback + " died");
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006295 release();
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006296 mAudioPolicies.remove(mPolicyCallback.asBinder());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006297 }
6298 }
6299
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006300 String getRegistrationId() {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08006301 return getRegistration();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006302 }
6303
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006304 void release() {
6305 if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
6306 mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
6307 }
6308 if (mHasFocusListener) {
Jean-Michel Trivi5a561092015-04-23 18:48:08 -07006309 mMediaFocusControl.removeFocusFollower(mPolicyCallback);
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08006310 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006311 AudioSystem.registerPolicyMixes(mMixes, false);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006312 }
6313
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08006314 void connectMixes() {
6315 AudioSystem.registerPolicyMixes(mMixes, true);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006316 }
6317 };
6318
6319 private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
6320 new HashMap<IBinder, AudioPolicyProxy>();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07006321 private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
John Spurlockcdb57ae2015-02-11 19:04:11 -05006322
6323 private class ControllerService extends ContentObserver {
6324 private int mUid;
6325 private ComponentName mComponent;
6326
6327 public ControllerService() {
6328 super(null);
6329 }
6330
6331 @Override
6332 public String toString() {
6333 return String.format("{mUid=%d,mComponent=%s}", mUid, mComponent);
6334 }
6335
6336 public void init() {
6337 onChange(true);
6338 mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
6339 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT), false, this);
6340 }
6341
6342 @Override
6343 public void onChange(boolean selfChange) {
6344 mUid = 0;
6345 mComponent = null;
6346 final String setting = Settings.Secure.getString(mContentResolver,
6347 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
6348 if (setting == null) return;
6349 try {
6350 mComponent = ComponentName.unflattenFromString(setting);
6351 if (mComponent == null) return;
6352 mUid = mContext.getPackageManager()
6353 .getApplicationInfo(mComponent.getPackageName(), 0).uid;
6354 } catch (Exception e) {
6355 Log.w(TAG, "Error loading controller service", e);
6356 }
6357 if (DEBUG_VOL) Log.d(TAG, "Reloaded controller service: " + this);
6358 }
6359 }
Phil Burkac0f7042016-02-24 12:19:08 -08006360}