blob: 6ce6ea9617e677c9dac536818cacac106a331b74 [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;
23
Glenn Kastenfd116ad2013-07-12 17:10:39 -070024import android.app.ActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.app.ActivityManagerNative;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -070026import android.app.AppOpsManager;
Amith Yamasani6243edd2011-12-05 19:58:48 -080027import android.app.KeyguardManager;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070028import android.bluetooth.BluetoothA2dp;
29import android.bluetooth.BluetoothAdapter;
30import android.bluetooth.BluetoothClass;
31import android.bluetooth.BluetoothDevice;
32import android.bluetooth.BluetoothHeadset;
33import android.bluetooth.BluetoothProfile;
Nick Pellybd022f42009-08-14 18:33:38 -070034import android.content.BroadcastReceiver;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070035import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.content.ContentResolver;
37import android.content.Context;
38import android.content.Intent;
Eric Laurenta553c252009-07-17 12:17:14 -070039import android.content.IntentFilter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.content.pm.PackageManager;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -070041import android.content.res.Configuration;
Eric Laurente78fced2013-03-15 16:03:47 -070042import android.content.res.Resources;
43import android.content.res.XmlResourceParser;
Jason Parekhb1096152009-03-24 17:48:25 -070044import android.database.ContentObserver;
Jungshik Jang41d97462014-06-30 22:26:29 +090045import android.hardware.hdmi.HdmiControlManager;
Eric Laurent212532b2014-07-21 15:43:18 -070046import android.hardware.hdmi.HdmiPlaybackClient;
Jungshik Jang41d97462014-06-30 22:26:29 +090047import android.hardware.hdmi.HdmiTvClient;
Paul McLeanc837a452014-04-09 09:04:43 -070048import android.hardware.usb.UsbManager;
John Spurlock61560172015-02-06 19:46:04 -050049import android.media.AudioAttributes;
50import android.media.AudioDevicePort;
51import android.media.AudioSystem;
52import android.media.AudioFormat;
53import android.media.AudioManager;
54import android.media.AudioManagerInternal;
55import android.media.AudioPort;
56import android.media.AudioRoutesInfo;
57import android.media.AudioSystem;
58import android.media.IAudioFocusDispatcher;
59import android.media.IAudioRoutesObserver;
60import android.media.IAudioService;
61import android.media.IRemoteControlDisplay;
62import android.media.IRingtonePlayer;
63import android.media.IVolumeController;
64import android.media.MediaPlayer;
65import android.media.SoundPool;
66import android.media.AudioAttributes.Builder;
67import android.media.AudioManagerInternal.RingerModeDelegate;
68import android.media.AudioSystem.ErrorCallback;
69import android.media.IAudioService.Stub;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070import android.media.MediaPlayer.OnCompletionListener;
71import android.media.MediaPlayer.OnErrorListener;
John Spurlock61560172015-02-06 19:46:04 -050072import android.media.SoundPool.OnLoadCompleteListener;
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -070073import android.media.audiopolicy.AudioMix;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -080074import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070075import android.media.audiopolicy.AudioPolicyConfig;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -080076import android.media.audiopolicy.IAudioPolicyCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077import android.os.Binder;
Eric Laurentc18c9132013-04-12 17:24:56 -070078import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079import android.os.Environment;
80import android.os.Handler;
81import android.os.IBinder;
82import android.os.Looper;
83import android.os.Message;
Jean-Michel Trivic6802222012-04-30 11:15:03 -070084import android.os.PowerManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070085import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086import android.os.RemoteException;
John Spurlock33f4e042014-07-11 13:10:58 -040087import android.os.SystemClock;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070088import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070089import android.os.UserHandle;
Eric Laurentbffc3d12012-05-07 17:43:49 -070090import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091import android.provider.Settings;
92import android.provider.Settings.System;
Tyler Gunnef9f6f92014-09-12 22:16:17 -070093import android.telecom.TelecomManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070094import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095import android.util.Log;
John Spurlockaa5ee4d2014-07-25 13:05:12 -040096import android.util.MathUtils;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070097import android.util.Slog;
John Spurlock2bb02ec2015-03-02 13:13:06 -050098import android.util.SparseIntArray;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070099import android.view.KeyEvent;
RoboErik519c7742014-11-18 10:59:09 -0800100import android.view.OrientationEventListener;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700101import android.view.Surface;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700102import android.view.WindowManager;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700103import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104
Eric Laurente78fced2013-03-15 16:03:47 -0700105import com.android.internal.util.XmlUtils;
RoboErik0dac35a2014-08-12 15:48:49 -0700106import com.android.server.LocalServices;
Eric Laurente78fced2013-03-15 16:03:47 -0700107
108import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800110import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111import java.io.IOException;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800112import java.io.PrintWriter;
Eric Laurente78fced2013-03-15 16:03:47 -0700113import java.lang.reflect.Field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114import java.util.ArrayList;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700115import java.util.HashMap;
116import java.util.Iterator;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -0700117import java.util.List;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700118import java.util.Map;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700119import java.util.NoSuchElementException;
RoboErikd09bd0c2014-06-24 17:45:19 -0700120import java.util.Objects;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700121import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122
123/**
124 * The implementation of the volume manager service.
125 * <p>
126 * This implementation focuses on delivering a responsive UI. Most methods are
127 * asynchronous to external calls. For example, the task of setting a volume
128 * will update our internal state, but in a separate thread will set the system
129 * volume and later persist to the database. Similarly, setting the ringer mode
130 * will update the state and broadcast a change and in a separate thread later
131 * persist the ringer mode.
132 *
133 * @hide
134 */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700135public class AudioService extends IAudioService.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136
137 private static final String TAG = "AudioService";
138
Jean-Michel Trivi339567d2014-07-29 09:53:34 -0700139 /** Debug audio mode */
140 protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -0700141
142 /** Debug audio policy feature */
143 protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);
144
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700145 /** Debug volumes */
John Spurlockae641c92014-06-30 18:11:40 -0400146 protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700147
RoboErik430fc482014-06-12 15:49:20 -0700148 /** debug calls to media session apis */
John Spurlockae641c92014-06-30 18:11:40 -0400149 private static final boolean DEBUG_SESSIONS = Log.isLoggable(TAG + ".SESSIONS", Log.DEBUG);
RoboErik8a2cfc32014-05-16 11:19:38 -0700150
John Spurlock86005342014-05-23 11:58:00 -0400151 /** Allow volume changes to set ringer mode to silent? */
152 private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
153
John Spurlocka11b4af2014-06-01 11:52:23 -0400154 /** In silent mode, are volume adjustments (raises) prevented? */
155 private static final boolean PREVENT_VOLUME_ADJUSTMENT_IF_SILENT = true;
156
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 /** How long to delay before persisting a change in volume/ringer mode. */
RoboErik45edba12012-03-27 17:54:36 -0700158 private static final int PERSIST_DELAY = 500;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159
RoboErik5452e252015-02-06 15:33:53 -0800160 /** How long to delay after a volume down event before unmuting a stream */
161 private static final int UNMUTE_STREAM_DELAY = 350;
162
John Spurlock3346a802014-05-20 16:25:37 -0400163 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400164 * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
165 */
166 private static final int FLAG_ADJUST_VOLUME = 1;
167
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700168 private final Context mContext;
169 private final ContentResolver mContentResolver;
170 private final AppOpsManager mAppOps;
Eric Laurent212532b2014-07-21 15:43:18 -0700171
Eric Laurent212532b2014-07-21 15:43:18 -0700172 // the platform type affects volume and silent mode behavior
173 private final int mPlatformType;
174
175 private boolean isPlatformVoice() {
John Spurlock61560172015-02-06 19:46:04 -0500176 return mPlatformType == AudioSystem.PLATFORM_VOICE;
Eric Laurent212532b2014-07-21 15:43:18 -0700177 }
178
179 private boolean isPlatformTelevision() {
John Spurlock61560172015-02-06 19:46:04 -0500180 return mPlatformType == AudioSystem.PLATFORM_TELEVISION;
Eric Laurent212532b2014-07-21 15:43:18 -0700181 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800182
John Spurlock3346a802014-05-20 16:25:37 -0400183 /** The controller for the volume UI. */
184 private final VolumeController mVolumeController = new VolumeController();
John Spurlockcdb57ae2015-02-11 19:04:11 -0500185 private final ControllerService mControllerService = new ControllerService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186
187 // sendMsg() flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 /** If the msg is already queued, replace it with this one. */
189 private static final int SENDMSG_REPLACE = 0;
190 /** If the msg is already queued, ignore this one and leave the old. */
191 private static final int SENDMSG_NOOP = 1;
192 /** If the msg is already queued, queue this one and leave the old. */
193 private static final int SENDMSG_QUEUE = 2;
194
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700195 // AudioHandler messages
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800196 private static final int MSG_SET_DEVICE_VOLUME = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 private static final int MSG_PERSIST_VOLUME = 1;
Mike Lockwood5c55a052011-12-15 17:21:44 -0500198 private static final int MSG_PERSIST_MASTER_VOLUME = 2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 private static final int MSG_PERSIST_RINGER_MODE = 3;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700200 private static final int MSG_MEDIA_SERVER_DIED = 4;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700201 private static final int MSG_PLAY_SOUND_EFFECT = 5;
202 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
203 private static final int MSG_LOAD_SOUND_EFFECTS = 7;
204 private static final int MSG_SET_FORCE_USE = 8;
205 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
206 private static final int MSG_SET_ALL_VOLUMES = 10;
207 private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
208 private static final int MSG_REPORT_NEW_ROUTES = 12;
209 private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
210 private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
211 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
212 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
213 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
214 private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
215 private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
216 private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700217 private static final int MSG_SYSTEM_READY = 21;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400218 private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
Julia Reynoldsb53453f2014-08-22 11:42:43 -0400219 private static final int MSG_PERSIST_MICROPHONE_MUTE = 23;
RoboErik5452e252015-02-06 15:33:53 -0800220 private static final int MSG_UNMUTE_STREAM = 24;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700221 // start of messages handled under wakelock
222 // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
Jean-Michel Trivie12c39b2012-06-06 10:51:58 -0700223 // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700224 private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
Mike Lockwood0a40ec22014-05-21 10:08:50 -0700225 private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
226 private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700227 // end of messages handled under wakelock
Eric Laurentafbb0472011-12-15 09:04:23 -0800228
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -0700229 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
Eric Laurentdc03c612011-04-01 10:59:41 -0700230 // Timeout for connection to bluetooth headset service
231 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
232
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233 /** @see AudioSystemThread */
234 private AudioSystemThread mAudioSystemThread;
235 /** @see AudioHandler */
236 private AudioHandler mAudioHandler;
237 /** @see VolumeStreamState */
238 private VolumeStreamState[] mStreamStates;
Jason Parekhb1096152009-03-24 17:48:25 -0700239 private SettingsObserver mSettingsObserver;
Eric Laurenta553c252009-07-17 12:17:14 -0700240
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700241 private int mMode = AudioSystem.MODE_NORMAL;
Glenn Kastenba195eb2011-12-13 09:30:40 -0800242 // protects mRingerMode
243 private final Object mSettingsLock = new Object();
Eric Laurent45c90ce2012-04-24 18:44:22 -0700244
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245 private SoundPool mSoundPool;
Glenn Kasten30c918c2011-11-10 17:56:41 -0800246 private final Object mSoundEffectsLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 private static final int NUM_SOUNDPOOL_CHANNELS = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248
Mike Lockwood47676902011-11-08 10:31:21 -0800249 // Internally master volume is a float in the 0.0 - 1.0 range,
250 // but to support integer based AudioManager API we translate it to 0 - 100
251 private static final int MAX_MASTER_VOLUME = 100;
252
Lei Zhang6c798972012-03-02 11:40:12 -0800253 // Maximum volume adjust steps allowed in a single batch call.
254 private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256 /* 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
Jared Suttles59820132009-08-13 21:50:52 -0500265 /** @hide 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
Eric Laurent6d517662012-04-23 18:42:39 -0700279 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
Eric Laurenta553c252009-07-17 12:17:14 -0700280 * of another stream: This avoids multiplying the volume settings for hidden
281 * stream types that follow other stream behavior for volume settings
Eric Laurent6d517662012-04-23 18:42:39 -0700282 * NOTE: do not create loops in aliases!
283 * Some streams alias to different streams according to device category (phone or tablet) or
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700284 * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
Eric Laurent212532b2014-07-21 15:43:18 -0700285 * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
286 * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
287 * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
288 private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700289 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
290 AudioSystem.STREAM_RING, // STREAM_SYSTEM
291 AudioSystem.STREAM_RING, // STREAM_RING
292 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
293 AudioSystem.STREAM_ALARM, // STREAM_ALARM
294 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
295 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
296 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
297 AudioSystem.STREAM_RING, // STREAM_DTMF
298 AudioSystem.STREAM_MUSIC // STREAM_TTS
Eric Laurenta553c252009-07-17 12:17:14 -0700299 };
Eric Laurent212532b2014-07-21 15:43:18 -0700300 private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
301 AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL
302 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
303 AudioSystem.STREAM_MUSIC, // STREAM_RING
304 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
305 AudioSystem.STREAM_MUSIC, // STREAM_ALARM
306 AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
307 AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO
308 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
309 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
310 AudioSystem.STREAM_MUSIC // STREAM_TTS
311 };
312 private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700313 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
John Spurlock4f0f1202014-08-05 13:28:33 -0400314 AudioSystem.STREAM_RING, // STREAM_SYSTEM
Eric Laurent6d517662012-04-23 18:42:39 -0700315 AudioSystem.STREAM_RING, // STREAM_RING
316 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
317 AudioSystem.STREAM_ALARM, // STREAM_ALARM
318 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
319 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
John Spurlock4f0f1202014-08-05 13:28:33 -0400320 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
321 AudioSystem.STREAM_RING, // STREAM_DTMF
Eric Laurent6d517662012-04-23 18:42:39 -0700322 AudioSystem.STREAM_MUSIC // STREAM_TTS
323 };
324 private int[] mStreamVolumeAlias;
Eric Laurenta553c252009-07-17 12:17:14 -0700325
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700326 /**
327 * Map AudioSystem.STREAM_* constants to app ops. This should be used
328 * after mapping through mStreamVolumeAlias.
329 */
330 private static final int[] STEAM_VOLUME_OPS = new int[] {
331 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL
332 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM
333 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING
334 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC
335 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM
336 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION
337 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO
338 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED
339 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF
340 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS
341 };
342
Eric Laurent83a017b2013-03-19 18:15:31 -0700343 private final boolean mUseFixedVolume;
344
Glenn Kasten30c918c2011-11-10 17:56:41 -0800345 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 public void onError(int error) {
347 switch (error) {
348 case AudioSystem.AUDIO_STATUS_SERVER_DIED:
Eric Laurentdfb881f2013-07-18 14:41:39 -0700349 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
350 SENDMSG_NOOP, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 break;
352 default:
353 break;
354 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700355 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356 };
357
358 /**
359 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
360 * {@link AudioManager#RINGER_MODE_SILENT}, or
361 * {@link AudioManager#RINGER_MODE_VIBRATE}.
362 */
Glenn Kastenba195eb2011-12-13 09:30:40 -0800363 // protected by mSettingsLock
John Spurlock661f2cf2014-11-17 10:29:10 -0500364 private int mRingerMode; // internal ringer mode, affects muting of underlying streams
365 private int mRingerModeExternal = -1; // reported ringer mode to outside clients (AudioManager)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366
Eric Laurent9bcf4012009-06-12 06:09:28 -0700367 /** @see System#MODE_RINGER_STREAMS_AFFECTED */
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700368 private int mRingerModeAffectedStreams = 0;
Eric Laurent9bcf4012009-06-12 06:09:28 -0700369
Eric Laurent5b4e6542010-03-19 20:02:21 -0700370 // Streams currently muted by ringer mode
371 private int mRingerModeMutedStreams;
372
John Spurlock3ce37252015-02-17 13:20:45 -0500373 /** Streams that can be muted. Do not resolve to aliases when checking.
374 * @see System#MUTE_STREAMS_AFFECTED */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 private int mMuteAffectedStreams;
376
377 /**
Eric Laurentbffc3d12012-05-07 17:43:49 -0700378 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
379 * mVibrateSetting is just maintained during deprecation period but vibration policy is
380 * now only controlled by mHasVibrator and mRingerMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 */
382 private int mVibrateSetting;
383
Eric Laurentbffc3d12012-05-07 17:43:49 -0700384 // Is there a vibrator
385 private final boolean mHasVibrator;
386
Eric Laurenta553c252009-07-17 12:17:14 -0700387 // Broadcast receiver for device connections intent broadcasts
388 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
389
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700390 // Devices currently connected
Glenn Kasten30c918c2011-11-10 17:56:41 -0800391 private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700392
393 // Forced device usage for communications
394 private int mForcedUseForComm;
395
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500396 // True if we have master volume support
397 private final boolean mUseMasterVolume;
398
Mike Lockwood97606472012-02-09 11:24:10 -0800399 private final int[] mMasterVolumeRamp;
400
Eric Laurent9272b4b2010-01-23 17:12:59 -0800401 // List of binder death handlers for setMode() client processes.
402 // The last process to have called setMode() is at the top of the list.
Glenn Kasten30c918c2011-11-10 17:56:41 -0800403 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
Eric Laurenteb14a782009-12-17 03:12:59 -0800404
Eric Laurent3def1ee2010-03-17 23:26:26 -0700405 // List of clients having issued a SCO start request
Glenn Kasten30c918c2011-11-10 17:56:41 -0800406 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
Eric Laurent3def1ee2010-03-17 23:26:26 -0700407
408 // BluetoothHeadset API to control SCO connection
409 private BluetoothHeadset mBluetoothHeadset;
410
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700411 // Bluetooth headset device
412 private BluetoothDevice mBluetoothHeadsetDevice;
Eric Laurent3def1ee2010-03-17 23:26:26 -0700413
Eric Laurent62ef7672010-11-24 10:58:32 -0800414 // Indicate if SCO audio connection is currently active and if the initiator is
415 // audio service (internal) or bluetooth headset (external)
416 private int mScoAudioState;
417 // SCO audio state is not active
418 private static final int SCO_STATE_INACTIVE = 0;
Eric Laurentdc03c612011-04-01 10:59:41 -0700419 // SCO audio activation request waiting for headset service to connect
420 private static final int SCO_STATE_ACTIVATE_REQ = 1;
Eric Laurent25fc29b2013-04-05 12:13:54 -0700421 // SCO audio state is active or starting due to a request from AudioManager API
Eric Laurentdc03c612011-04-01 10:59:41 -0700422 private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
423 // SCO audio deactivation request waiting for headset service to connect
424 private static final int SCO_STATE_DEACTIVATE_REQ = 5;
425
Eric Laurent62ef7672010-11-24 10:58:32 -0800426 // SCO audio state is active due to an action in BT handsfree (either voice recognition or
427 // in call audio)
428 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
Eric Laurentdc03c612011-04-01 10:59:41 -0700429 // Deactivation request for all SCO connections (initiated by audio mode change)
430 // waiting for headset service to connect
431 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
432
Eric Laurentc18c9132013-04-12 17:24:56 -0700433 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
434 // originated from an app targeting an API version before JB MR2 and raw audio after that.
435 private int mScoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -0700436 // SCO audio mode is undefined
437 private static final int SCO_MODE_UNDEFINED = -1;
Eric Laurentc18c9132013-04-12 17:24:56 -0700438 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
439 private static final int SCO_MODE_VIRTUAL_CALL = 0;
440 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
441 private static final int SCO_MODE_RAW = 1;
Liejun Taof4e51d82014-07-16 11:18:29 -0700442 // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
443 private static final int SCO_MODE_VR = 2;
444
445 private static final int SCO_MODE_MAX = 2;
Eric Laurentc18c9132013-04-12 17:24:56 -0700446
Eric Laurentdc03c612011-04-01 10:59:41 -0700447 // Current connection state indicated by bluetooth headset
448 private int mScoConnectionState;
Eric Laurent62ef7672010-11-24 10:58:32 -0800449
Eric Laurenta60e2122010-12-28 16:49:07 -0800450 // true if boot sequence has been completed
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700451 private boolean mSystemReady;
Eric Laurenta60e2122010-12-28 16:49:07 -0800452 // listener for SoundPool sample load completion indication
453 private SoundPoolCallback mSoundPoolCallBack;
454 // thread for SoundPool listener
455 private SoundPoolListenerThread mSoundPoolListenerThread;
456 // message looper for SoundPool listener
457 private Looper mSoundPoolLooper = null;
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700458 // volume applied to sound played with playSoundEffect()
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700459 private static int sSoundEffectVolumeDb;
Eric Laurent25101b02011-02-02 09:33:30 -0800460 // previous volume adjustment direction received by checkForRingerModeChange()
461 private int mPrevVolDirection = AudioManager.ADJUST_SAME;
Amith Yamasani6243edd2011-12-05 19:58:48 -0800462 // Keyguard manager proxy
463 private KeyguardManager mKeyguardManager;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700464 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
465 // is controlled by Vol keys.
466 private int mVolumeControlStream = -1;
467 private final Object mForceControlStreamLock = new Object();
468 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
469 // server process so in theory it is not necessary to monitor the client death.
470 // However it is good to be ready for future evolutions.
471 private ForceControlStreamClient mForceControlStreamClient = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700472 // Used to play ringtones outside system_server
473 private volatile IRingtonePlayer mRingtonePlayer;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800474
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700475 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700476 private int mDeviceRotation = Surface.ROTATION_0;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700477
Eric Laurent78472112012-05-21 08:57:21 -0700478 // Request to override default use of A2DP for media.
479 private boolean mBluetoothA2dpEnabled;
480 private final Object mBluetoothA2dpEnabledLock = new Object();
481
Dianne Hackborn632ca412012-06-14 19:34:10 -0700482 // Monitoring of audio routes. Protected by mCurAudioRoutes.
483 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
484 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
485 = new RemoteCallbackList<IAudioRoutesObserver>();
486
Eric Laurent4bbcc652012-09-24 14:26:30 -0700487 // Devices for which the volume is fixed and VolumePanel slider should be disabled
Eric Laurent212532b2014-07-21 15:43:18 -0700488 int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700489 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Eric Laurent212532b2014-07-21 15:43:18 -0700490 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
491 AudioSystem.DEVICE_OUT_HDMI_ARC |
492 AudioSystem.DEVICE_OUT_SPDIF |
493 AudioSystem.DEVICE_OUT_AUX_LINE;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700494 int mFullVolumeDevices = 0;
Eric Laurent4bbcc652012-09-24 14:26:30 -0700495
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700496 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700497 private final boolean mMonitorOrientation;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700498 private final boolean mMonitorRotation;
Eric Laurentd640bd32012-09-28 18:01:48 -0700499
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700500 private boolean mDockAudioMediaEnabled = true;
501
Eric Laurent08ed1b92012-11-05 14:54:12 -0800502 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
503
Eric Laurentfde16d52012-12-03 14:42:39 -0800504 // Used when safe volume warning message display is requested by setStreamVolume(). In this
505 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
506 // and used later when/if disableSafeMediaVolume() is called.
507 private StreamVolumeCommand mPendingVolumeCommand;
508
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700509 private PowerManager.WakeLock mAudioEventWakeLock;
510
511 private final MediaFocusControl mMediaFocusControl;
512
John Du5a0cf7a2013-07-19 11:30:34 -0700513 // Reference to BluetoothA2dp to query for AbsoluteVolume.
514 private BluetoothA2dp mA2dp;
seunghwan.hong4fe77952014-10-29 17:43:20 +0900515 // lock always taken synchronized on mConnectedDevices
John Du5a0cf7a2013-07-19 11:30:34 -0700516 private final Object mA2dpAvrcpLock = new Object();
517 // If absolute volume is supported in AVRCP device
518 private boolean mAvrcpAbsVolSupported = false;
519
Jon Eklund318f0fe2014-01-23 17:53:48 -0600520 private AudioOrientationEventListener mOrientationListener;
521
Eric Laurentadbe8bf2014-11-03 18:26:32 -0800522 private static Long mLastDeviceConnectMsgTime = new Long(0);
523
John Spurlock661f2cf2014-11-17 10:29:10 -0500524 private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
525
Paul McLean10804eb2015-01-28 11:16:35 -0800526 // Intent "extra" data keys.
527 public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName";
528 public static final String CONNECT_INTENT_KEY_STATE = "state";
529 public static final String CONNECT_INTENT_KEY_ADDRESS = "address";
530 public static final String CONNECT_INTENT_KEY_HAS_PLAYBACK = "hasPlayback";
531 public static final String CONNECT_INTENT_KEY_HAS_CAPTURE = "hasCapture";
532 public static final String CONNECT_INTENT_KEY_HAS_MIDI = "hasMIDI";
533 public static final String CONNECT_INTENT_KEY_DEVICE_CLASS = "class";
534
535 // Defines the format for the connection "address" for ALSA devices
536 public static String makeAlsaAddressString(int card, int device) {
537 return "card=" + card + ";device=" + device + ";";
538 }
539
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800540 ///////////////////////////////////////////////////////////////////////////
541 // Construction
542 ///////////////////////////////////////////////////////////////////////////
543
544 /** @hide */
545 public AudioService(Context context) {
546 mContext = context;
547 mContentResolver = context.getContentResolver();
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700548 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700549
John Spurlock61560172015-02-06 19:46:04 -0500550 mPlatformType = AudioSystem.getPlatformType(context);
Jared Suttles59820132009-08-13 21:50:52 -0500551
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700552 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700553 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700554
Eric Laurentbffc3d12012-05-07 17:43:49 -0700555 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
556 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
557
Jared Suttles59820132009-08-13 21:50:52 -0500558 // Intialized volume
Eric Laurent91377de2014-10-10 15:24:04 -0700559 int maxVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps",
560 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
561 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
562 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500563 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700564 }
565 maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
566 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
567 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
568 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500569 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700570 }
Jared Suttles59820132009-08-13 21:50:52 -0500571
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700572 sSoundEffectVolumeDb = context.getResources().getInteger(
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700573 com.android.internal.R.integer.config_soundEffectVolumeDb);
Eric Laurent25101b02011-02-02 09:33:30 -0800574
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700575 mForcedUseForComm = AudioSystem.FORCE_NONE;
Eric Laurentdd45d012012-10-08 09:04:34 -0700576
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577 createAudioSystemThread();
Eric Laurentdd45d012012-10-08 09:04:34 -0700578
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700579 mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
John Spurlock3346a802014-05-20 16:25:37 -0400580 mContext, mVolumeController, this);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700581
Eric Laurentdfb881f2013-07-18 14:41:39 -0700582 AudioSystem.setErrorCallback(mAudioSystemCallback);
583
John Spurlock5e783732015-02-19 10:28:59 -0500584 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -0700585 mCameraSoundForced = new Boolean(cameraSoundForced);
586 sendMsg(mAudioHandler,
587 MSG_SET_FORCE_USE,
588 SENDMSG_QUEUE,
589 AudioSystem.FOR_SYSTEM,
590 cameraSoundForced ?
591 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
592 null,
593 0);
594
Eric Laurent05274f32012-11-29 12:48:18 -0800595 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
596 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
597 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
598 // The default safe volume index read here will be replaced by the actual value when
599 // the mcc is read by onConfigureSafeVolume()
600 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
601 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
602
Eric Laurent83a017b2013-03-19 18:15:31 -0700603 mUseFixedVolume = mContext.getResources().getBoolean(
604 com.android.internal.R.bool.config_useFixedVolume);
Wally Yauda392902014-11-28 12:40:30 -0800605 mUseMasterVolume = context.getResources().getBoolean(
606 com.android.internal.R.bool.config_useMasterVolume);
607 mMasterVolumeRamp = context.getResources().getIntArray(
608 com.android.internal.R.array.config_masterVolumeRamp);
Eric Laurent83a017b2013-03-19 18:15:31 -0700609
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700610 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
611 // array initialized by updateStreamVolumeAlias()
612 updateStreamVolumeAlias(false /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 readPersistedSettings();
Eric Laurentc1d41662011-07-19 11:21:13 -0700614 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700615 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700616
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700617 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700618
619 // Call setRingerModeInt() to apply correct mute
620 // state on streams affected by ringer mode.
621 mRingerModeMutedStreams = 0;
John Spurlock661f2cf2014-11-17 10:29:10 -0500622 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3891c4c2010-04-20 09:40:57 -0700623
Eric Laurenta553c252009-07-17 12:17:14 -0700624 // Register for device connection intent broadcasts.
625 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700626 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700627 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
628 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700629 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
630 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700631 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Paul McLeanc837a452014-04-09 09:04:43 -0700632 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700633
Eric Laurentd640bd32012-09-28 18:01:48 -0700634 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700635 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700636 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
637 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700638 Log.v(TAG, "monitoring device orientation");
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700639 // initialize orientation in AudioSystem
640 setOrientationForAudioSystem();
641 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700642 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
643 if (mMonitorRotation) {
644 mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
645 .getDefaultDisplay().getRotation();
646 Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
Jon Eklund318f0fe2014-01-23 17:53:48 -0600647
648 mOrientationListener = new AudioOrientationEventListener(mContext);
649 mOrientationListener.enable();
650
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700651 // initialize rotation in AudioSystem
652 setRotationForAudioSystem();
653 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700654
Eric Laurenta553c252009-07-17 12:17:14 -0700655 context.registerReceiver(mReceiver, intentFilter);
Jared Suttles59820132009-08-13 21:50:52 -0500656
Mike Lockwood90631542012-01-06 11:20:37 -0500657 restoreMasterVolume();
Mike Lockwood97606472012-02-09 11:24:10 -0800658
RoboErik0dac35a2014-08-12 15:48:49 -0700659 LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660 }
661
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700662 public void systemReady() {
663 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
664 0, 0, null, 0);
665 }
666
667 public void onSystemReady() {
668 mSystemReady = true;
669 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
670 0, 0, null, 0);
671
672 mKeyguardManager =
673 (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
674 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
675 resetBluetoothSco();
676 getBluetoothHeadset();
677 //FIXME: this is to maintain compatibility with deprecated intent
678 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
679 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
680 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
681 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
682 sendStickyBroadcastToAll(newIntent);
683
684 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
685 if (adapter != null) {
686 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
687 BluetoothProfile.A2DP);
688 }
689
Eric Laurent212532b2014-07-21 15:43:18 -0700690 mHdmiManager =
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900691 (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700692 if (mHdmiManager != null) {
693 synchronized (mHdmiManager) {
694 mHdmiTvClient = mHdmiManager.getTvClient();
Jungshik Jangc9ff9682014-09-15 17:41:06 +0900695 if (mHdmiTvClient != null) {
696 mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
697 }
Eric Laurent212532b2014-07-21 15:43:18 -0700698 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
699 mHdmiCecSink = false;
700 }
701 }
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900702
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700703 sendMsg(mAudioHandler,
704 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
705 SENDMSG_REPLACE,
706 0,
707 0,
708 null,
709 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700710
711 StreamOverride.init(mContext);
John Spurlockcdb57ae2015-02-11 19:04:11 -0500712 mControllerService.init();
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700713 }
714
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 private void createAudioSystemThread() {
716 mAudioSystemThread = new AudioSystemThread();
717 mAudioSystemThread.start();
718 waitForAudioHandlerCreation();
719 }
720
721 /** Waits for the volume handler to be created by the other thread. */
722 private void waitForAudioHandlerCreation() {
723 synchronized(this) {
724 while (mAudioHandler == null) {
725 try {
726 // Wait for mAudioHandler to be set by the other thread
727 wait();
728 } catch (InterruptedException e) {
729 Log.e(TAG, "Interrupted while waiting on volume handler.");
730 }
731 }
732 }
733 }
734
Eric Laurent24482012012-05-10 09:41:17 -0700735 private void checkAllAliasStreamVolumes() {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700736 synchronized (VolumeStreamState.class) {
737 int numStreamTypes = AudioSystem.getNumStreamTypes();
738 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
739 if (streamType != mStreamVolumeAlias[streamType]) {
740 mStreamStates[streamType].
Eric Laurent42b041e2013-03-29 11:36:03 -0700741 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700742 }
743 // apply stream volume
RoboErik4197cb62015-01-21 15:45:32 -0800744 if (!mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700745 mStreamStates[streamType].applyAllVolumes();
746 }
Eric Laurent24482012012-05-10 09:41:17 -0700747 }
748 }
749 }
750
Eric Laurent212532b2014-07-21 15:43:18 -0700751 private void checkAllFixedVolumeDevices()
752 {
753 int numStreamTypes = AudioSystem.getNumStreamTypes();
754 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
755 mStreamStates[streamType].checkFixedVolumeDevices();
756 }
757 }
758
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700759 private void checkAllFixedVolumeDevices(int streamType) {
760 mStreamStates[streamType].checkFixedVolumeDevices();
761 }
762
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 int numStreamTypes = AudioSystem.getNumStreamTypes();
765 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
766
767 for (int i = 0; i < numStreamTypes; i++) {
Eric Laurent6d517662012-04-23 18:42:39 -0700768 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -0700769 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770
Eric Laurent212532b2014-07-21 15:43:18 -0700771 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -0700772 checkAllAliasStreamVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 }
774
Eric Laurentbffc3d12012-05-07 17:43:49 -0700775 private void dumpStreamStates(PrintWriter pw) {
776 pw.println("\nStream volumes (device: index)");
777 int numStreamTypes = AudioSystem.getNumStreamTypes();
778 for (int i = 0; i < numStreamTypes; i++) {
John Spurlock61560172015-02-06 19:46:04 -0500779 pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":");
Eric Laurentbffc3d12012-05-07 17:43:49 -0700780 mStreamStates[i].dump(pw);
781 pw.println("");
782 }
Eric Laurentdd45d012012-10-08 09:04:34 -0700783 pw.print("\n- mute affected streams = 0x");
784 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -0700785 }
786
Eric Laurent6d517662012-04-23 18:42:39 -0700787 private void updateStreamVolumeAlias(boolean updateVolumes) {
788 int dtmfStreamAlias;
Eric Laurent212532b2014-07-21 15:43:18 -0700789
790 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -0500791 case AudioSystem.PLATFORM_VOICE:
Eric Laurent212532b2014-07-21 15:43:18 -0700792 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
Eric Laurent6d517662012-04-23 18:42:39 -0700793 dtmfStreamAlias = AudioSystem.STREAM_RING;
Eric Laurent212532b2014-07-21 15:43:18 -0700794 break;
John Spurlock61560172015-02-06 19:46:04 -0500795 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -0700796 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
797 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
798 break;
799 default:
800 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
Eric Laurent6d517662012-04-23 18:42:39 -0700801 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
802 }
Eric Laurent212532b2014-07-21 15:43:18 -0700803
804 if (isPlatformTelevision()) {
805 mRingerModeAffectedStreams = 0;
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700806 } else {
Eric Laurent212532b2014-07-21 15:43:18 -0700807 if (isInCommunication()) {
808 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
809 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
810 } else {
811 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
812 }
Eric Laurent6d517662012-04-23 18:42:39 -0700813 }
Eric Laurent212532b2014-07-21 15:43:18 -0700814
Eric Laurent6d517662012-04-23 18:42:39 -0700815 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
816 if (updateVolumes) {
Eric Laurent42b041e2013-03-29 11:36:03 -0700817 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700818 // apply stream mute states according to new value of mRingerModeAffectedStreams
John Spurlock661f2cf2014-11-17 10:29:10 -0500819 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent6d517662012-04-23 18:42:39 -0700820 sendMsg(mAudioHandler,
821 MSG_SET_ALL_VOLUMES,
822 SENDMSG_QUEUE,
823 0,
824 0,
825 mStreamStates[AudioSystem.STREAM_DTMF], 0);
826 }
827 }
828
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700829 private void readDockAudioSettings(ContentResolver cr)
830 {
831 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -0700832 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700833
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700834 sendMsg(mAudioHandler,
835 MSG_SET_FORCE_USE,
836 SENDMSG_QUEUE,
837 AudioSystem.FOR_DOCK,
838 mDockAudioMediaEnabled ?
839 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
840 null,
841 0);
842 }
843
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 private void readPersistedSettings() {
845 final ContentResolver cr = mContentResolver;
846
Eric Laurentbffc3d12012-05-07 17:43:49 -0700847 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700848 Settings.Global.getInt(
849 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -0700850 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -0700851 // sanity check in case the settings are restored from a device with incompatible
852 // ringer modes
John Spurlock97559372014-10-24 16:27:36 -0400853 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -0800854 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700855 }
856 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
857 ringerMode = AudioManager.RINGER_MODE_SILENT;
858 }
859 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700860 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -0800861 }
Eric Laurent212532b2014-07-21 15:43:18 -0700862 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -0700863 ringerMode = AudioManager.RINGER_MODE_NORMAL;
864 }
Glenn Kastenba195eb2011-12-13 09:30:40 -0800865 synchronized(mSettingsLock) {
866 mRingerMode = ringerMode;
John Spurlock661f2cf2014-11-17 10:29:10 -0500867 if (mRingerModeExternal == -1) {
868 mRingerModeExternal = mRingerMode;
869 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800870
Eric Laurentdd45d012012-10-08 09:04:34 -0700871 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
872 // are still needed while setVibrateSetting() and getVibrateSetting() are being
873 // deprecated.
John Spurlock61560172015-02-06 19:46:04 -0500874 mVibrateSetting = AudioSystem.getValueForVibrateSetting(0,
Eric Laurentdd45d012012-10-08 09:04:34 -0700875 AudioManager.VIBRATE_TYPE_NOTIFICATION,
876 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
877 : AudioManager.VIBRATE_SETTING_OFF);
John Spurlock61560172015-02-06 19:46:04 -0500878 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting,
Eric Laurentdd45d012012-10-08 09:04:34 -0700879 AudioManager.VIBRATE_TYPE_RINGER,
880 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
881 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800882
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700883 updateRingerModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700884 readDockAudioSettings(cr);
Eric Laurent402f7f22011-02-04 12:30:32 -0800885 }
Eric Laurentc1d41662011-07-19 11:21:13 -0700886
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700887 mMuteAffectedStreams = System.getIntForUser(cr,
John Spurlock61560172015-02-06 19:46:04 -0500888 System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
John Spurlock24c05182015-02-05 12:30:36 -0500889 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800890
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700891 boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
892 0, UserHandle.USER_CURRENT) == 1;
Eric Laurent83a017b2013-03-19 18:15:31 -0700893 if (mUseFixedVolume) {
894 masterMute = false;
895 AudioSystem.setMasterVolume(1.0f);
896 }
Justin Koh57978ed2012-04-03 17:37:58 -0700897 AudioSystem.setMasterMute(masterMute);
898 broadcastMasterMuteStatus(masterMute);
899
Julia Reynoldsb53453f2014-08-22 11:42:43 -0400900 boolean microphoneMute =
901 System.getIntForUser(cr, System.MICROPHONE_MUTE, 0, UserHandle.USER_CURRENT) == 1;
902 AudioSystem.muteMicrophone(microphoneMute);
903
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800904 // Each stream will read its own persisted settings
905
John Spurlockbcc10872014-11-28 15:29:21 -0500906 // Broadcast the sticky intents
907 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
908 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800909
910 // Broadcast vibrate settings
911 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
912 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -0700913
John Spurlock33f4e042014-07-11 13:10:58 -0400914 // Load settings for the volume controller
915 mVolumeController.loadSettings(cr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916 }
917
Eric Laurenta553c252009-07-17 12:17:14 -0700918 private int rescaleIndex(int index, int srcStream, int dstStream) {
919 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
920 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800921
Jon Eklund318f0fe2014-01-23 17:53:48 -0600922 private class AudioOrientationEventListener
923 extends OrientationEventListener {
924 public AudioOrientationEventListener(Context context) {
925 super(context);
926 }
927
928 @Override
929 public void onOrientationChanged(int orientation) {
930 //Even though we're responding to phone orientation events,
931 //use display rotation so audio stays in sync with video/dialogs
932 int newRotation = ((WindowManager) mContext.getSystemService(
933 Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
934 if (newRotation != mDeviceRotation) {
935 mDeviceRotation = newRotation;
936 setRotationForAudioSystem();
937 }
938 }
939 }
940
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 ///////////////////////////////////////////////////////////////////////////
942 // IPC methods
943 ///////////////////////////////////////////////////////////////////////////
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800944 /** @see AudioManager#adjustVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700945 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
946 String callingPackage) {
RoboErik272e1612014-09-05 11:39:29 -0700947 adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
948 Binder.getCallingUid());
949 }
950
951 private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
952 String callingPackage, int uid) {
John Spurlockae641c92014-06-30 18:11:40 -0400953 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType
954 + ", flags=" + flags);
Eric Laurent402f7f22011-02-04 12:30:32 -0800955 int streamType;
RoboErik4197cb62015-01-21 15:45:32 -0800956 boolean isMute = isMuteAdjust(direction);
Eric Laurent45c90ce2012-04-24 18:44:22 -0700957 if (mVolumeControlStream != -1) {
958 streamType = mVolumeControlStream;
Eric Laurent402f7f22011-02-04 12:30:32 -0800959 } else {
960 streamType = getActiveStreamType(suggestedStreamType);
961 }
John Spurlock33f4e042014-07-11 13:10:58 -0400962 final int resolvedStream = mStreamVolumeAlias[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963
RoboErik2811dd32014-08-12 09:48:13 -0700964 // Play sounds on STREAM_RING only.
965 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
John Spurlock33f4e042014-07-11 13:10:58 -0400966 resolvedStream != AudioSystem.STREAM_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 flags &= ~AudioManager.FLAG_PLAY_SOUND;
968 }
969
John Spurlock33f4e042014-07-11 13:10:58 -0400970 // For notifications/ring, show the ui before making any adjustments
RoboErik4197cb62015-01-21 15:45:32 -0800971 // Don't suppress mute/unmute requests
972 if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
John Spurlock33f4e042014-07-11 13:10:58 -0400973 direction = 0;
974 flags &= ~AudioManager.FLAG_PLAY_SOUND;
975 flags &= ~AudioManager.FLAG_VIBRATE;
976 if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
977 }
978
RoboErik272e1612014-09-05 11:39:29 -0700979 adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800980 }
981
982 /** @see AudioManager#adjustStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700983 public void adjustStreamVolume(int streamType, int direction, int flags,
984 String callingPackage) {
RoboErik0dac35a2014-08-12 15:48:49 -0700985 adjustStreamVolume(streamType, direction, flags, callingPackage, Binder.getCallingUid());
986 }
987
988 private void adjustStreamVolume(int streamType, int direction, int flags,
989 String callingPackage, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -0700990 if (mUseFixedVolume) {
991 return;
992 }
John Spurlockae641c92014-06-30 18:11:40 -0400993 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction
994 + ", flags="+flags);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700995
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 ensureValidDirection(direction);
997 ensureValidStreamType(streamType);
998
RoboErik4197cb62015-01-21 15:45:32 -0800999 boolean isMuteAdjust = isMuteAdjust(direction);
1000
John Spurlock3ce37252015-02-17 13:20:45 -05001001 if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
1002 return;
1003 }
1004
Eric Laurent96a33d12011-11-08 10:31:57 -08001005 // use stream type alias here so that streams with same alias have the same behavior,
1006 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
1007 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
Eric Laurent6d517662012-04-23 18:42:39 -07001008 int streamTypeAlias = mStreamVolumeAlias[streamType];
RoboErik4197cb62015-01-21 15:45:32 -08001009
Eric Laurentb024c302011-10-14 17:19:27 -07001010 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001011
1012 final int device = getDeviceForStream(streamTypeAlias);
Eric Laurent3ef75492012-11-28 12:12:23 -08001013
Eric Laurent42b041e2013-03-29 11:36:03 -07001014 int aliasIndex = streamState.getIndex(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 boolean adjustVolume = true;
Eric Laurent3ef75492012-11-28 12:12:23 -08001016 int step;
Eric Laurent24482012012-05-10 09:41:17 -07001017
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001018 // skip a2dp absolute volume control request when the device
1019 // is not an a2dp device
1020 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1021 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1022 return;
1023 }
1024
RoboErik0dac35a2014-08-12 15:48:49 -07001025 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
1026 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001027 return;
1028 }
1029
Eric Laurentfde16d52012-12-03 14:42:39 -08001030 // reset any pending volume command
1031 synchronized (mSafeMediaVolumeState) {
1032 mPendingVolumeCommand = null;
1033 }
1034
Eric Laurent3ef75492012-11-28 12:12:23 -08001035 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1036 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1037 ((device & mFixedVolumeDevices) != 0)) {
1038 flags |= AudioManager.FLAG_FIXED_VOLUME;
1039
1040 // Always toggle between max safe volume and 0 for fixed volume devices where safe
1041 // volume is enforced, and max and 0 for the others.
1042 // This is simulated by stepping by the full allowed volume range
1043 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1044 (device & mSafeMediaVolumeDevices) != 0) {
1045 step = mSafeMediaVolumeIndex;
1046 } else {
1047 step = streamState.getMaxIndex();
1048 }
1049 if (aliasIndex != 0) {
1050 aliasIndex = step;
1051 }
1052 } else {
1053 // convert one UI step (+/-1) into a number of internal units on the stream alias
1054 step = rescaleIndex(10, streamType, streamTypeAlias);
1055 }
1056
Eric Laurent42b041e2013-03-29 11:36:03 -07001057 // If either the client forces allowing ringer modes for this adjustment,
1058 // or the stream type is one that is affected by ringer modes
1059 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1060 (streamTypeAlias == getMasterStreamType())) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001061 int ringerMode = getRingerModeInternal();
Eric Laurent42b041e2013-03-29 11:36:03 -07001062 // do not vibrate if already in vibrate mode
1063 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
1064 flags &= ~AudioManager.FLAG_VIBRATE;
Eric Laurent3ef75492012-11-28 12:12:23 -08001065 }
RoboErik5452e252015-02-06 15:33:53 -08001066 // Check if the ringer mode handles this adjustment. If it does we don't
1067 // need to adjust the volume further.
1068 final int result = checkForRingerModeChange(aliasIndex, direction, step, streamState.mIsMuted);
John Spurlocka11b4af2014-06-01 11:52:23 -04001069 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
1070 // If suppressing a volume adjustment in silent mode, display the UI hint
1071 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
1072 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
1073 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001074 // If suppressing a volume down adjustment in vibrate mode, display the UI hint
1075 if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
1076 flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
1077 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001078 }
Eric Laurent3ef75492012-11-28 12:12:23 -08001079
Eric Laurent42b041e2013-03-29 11:36:03 -07001080 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001081
Eric Laurent42b041e2013-03-29 11:36:03 -07001082 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
RoboErik5452e252015-02-06 15:33:53 -08001083 mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001084
John Du5a0cf7a2013-07-19 11:30:34 -07001085 // Check if volume update should be send to AVRCP
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001086 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1087 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1088 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1089 synchronized (mA2dpAvrcpLock) {
1090 if (mA2dp != null && mAvrcpAbsVolSupported) {
1091 mA2dp.adjustAvrcpAbsoluteVolume(direction);
1092 }
John Du5a0cf7a2013-07-19 11:30:34 -07001093 }
1094 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001095
RoboErik4197cb62015-01-21 15:45:32 -08001096 if (isMuteAdjust) {
1097 boolean state;
1098 if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
1099 state = !streamState.mIsMuted;
1100 } else {
1101 state = direction == AudioManager.ADJUST_MUTE;
1102 }
1103 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1104 setSystemAudioMute(state);
1105 }
1106 for (int stream = 0; stream < mStreamStates.length; stream++) {
1107 if (streamTypeAlias == mStreamVolumeAlias[stream]) {
1108 mStreamStates[stream].mute(state);
RoboErik4197cb62015-01-21 15:45:32 -08001109 }
1110 }
1111 } else if ((direction == AudioManager.ADJUST_RAISE) &&
Eric Laurent42b041e2013-03-29 11:36:03 -07001112 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
RoboErik4197cb62015-01-21 15:45:32 -08001113 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -04001114 mVolumeController.postDisplaySafeVolumeWarning(flags);
RoboErik4197cb62015-01-21 15:45:32 -08001115 } else if (streamState.adjustIndex(direction * step, device) || streamState.mIsMuted) {
1116 // Post message to set system volume (it in turn will post a
1117 // message to persist).
1118 if (streamState.mIsMuted) {
1119 // Unmute the stream if it was previously muted
RoboErik5452e252015-02-06 15:33:53 -08001120 if (direction == AudioManager.ADJUST_RAISE) {
1121 // unmute immediately for volume up
1122 streamState.mute(false);
1123 } else if (direction == AudioManager.ADJUST_LOWER) {
1124 sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
1125 streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
1126 }
RoboErik4197cb62015-01-21 15:45:32 -08001127 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001128 sendMsg(mAudioHandler,
1129 MSG_SET_DEVICE_VOLUME,
1130 SENDMSG_QUEUE,
1131 device,
1132 0,
1133 streamState,
1134 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001135 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001136
RoboErik4197cb62015-01-21 15:45:32 -08001137 // Check if volume update should be sent to Hdmi system audio.
Jungshik Jang41d97462014-06-30 22:26:29 +09001138 int newIndex = mStreamStates[streamType].getIndex(device);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001139 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1140 setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
1141 }
Eric Laurent212532b2014-07-21 15:43:18 -07001142 if (mHdmiManager != null) {
1143 synchronized (mHdmiManager) {
Eric Laurent212532b2014-07-21 15:43:18 -07001144 // mHdmiCecSink true => mHdmiPlaybackClient != null
1145 if (mHdmiCecSink &&
1146 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1147 oldIndex != newIndex) {
1148 synchronized (mHdmiPlaybackClient) {
1149 int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
RoboErik4197cb62015-01-21 15:45:32 -08001150 KeyEvent.KEYCODE_VOLUME_UP;
Eric Laurent212532b2014-07-21 15:43:18 -07001151 mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1152 mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1153 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001154 }
1155 }
1156 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001157 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001158 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001159 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001160 }
1161
RoboErik5452e252015-02-06 15:33:53 -08001162 // Called after a delay when volume down is pressed while muted
1163 private void onUnmuteStream(int stream, int flags) {
1164 VolumeStreamState streamState = mStreamStates[stream];
1165 streamState.mute(false);
1166
1167 final int device = getDeviceForStream(stream);
1168 final int index = mStreamStates[stream].getIndex(device);
1169 sendVolumeUpdate(stream, index, index, flags);
1170 }
1171
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001172 private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
1173 if (mHdmiManager == null
1174 || mHdmiTvClient == null
1175 || oldVolume == newVolume
1176 || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
1177
1178 // Sets the audio volume of AVR when we are in system audio mode. The new volume info
1179 // is tranformed to HDMI-CEC commands and passed through CEC bus.
1180 synchronized (mHdmiManager) {
1181 if (!mHdmiSystemAudioSupported) return;
1182 synchronized (mHdmiTvClient) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001183 final long token = Binder.clearCallingIdentity();
1184 try {
Jinsuk Kim7a9ba422015-02-16 16:47:38 +09001185 mHdmiTvClient.setSystemAudioVolume(oldVolume, newVolume, maxVolume);
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001186 } finally {
1187 Binder.restoreCallingIdentity(token);
1188 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001189 }
1190 }
1191 }
1192
Dianne Hackborn961cae92013-03-20 14:59:43 -07001193 /** @see AudioManager#adjustMasterVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001194 public void adjustMasterVolume(int steps, int flags, String callingPackage) {
RoboErik519c7742014-11-18 10:59:09 -08001195 adjustMasterVolume(steps, flags, callingPackage, Binder.getCallingUid());
1196 }
1197
1198 public void adjustMasterVolume(int steps, int flags, String callingPackage, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001199 if (mUseFixedVolume) {
1200 return;
1201 }
RoboErik4197cb62015-01-21 15:45:32 -08001202 if (isMuteAdjust(steps)) {
1203 setMasterMuteInternal(steps, flags, callingPackage, uid);
1204 return;
1205 }
Lei Zhang6c798972012-03-02 11:40:12 -08001206 ensureValidSteps(steps);
Mike Lockwood97606472012-02-09 11:24:10 -08001207 int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1208 int delta = 0;
Lei Zhang6c798972012-03-02 11:40:12 -08001209 int numSteps = Math.abs(steps);
1210 int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
1211 for (int i = 0; i < numSteps; ++i) {
1212 delta = findVolumeDelta(direction, volume);
1213 volume += delta;
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001214 }
RoboErik24b082f2012-02-24 14:21:16 -08001215
Lei Zhang6c798972012-03-02 11:40:12 -08001216 //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
RoboErik519c7742014-11-18 10:59:09 -08001217 setMasterVolume(volume, flags, callingPackage, uid);
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001218 }
1219
Eric Laurentfde16d52012-12-03 14:42:39 -08001220 // StreamVolumeCommand contains the information needed to defer the process of
1221 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1222 class StreamVolumeCommand {
1223 public final int mStreamType;
1224 public final int mIndex;
1225 public final int mFlags;
1226 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001227
Eric Laurentfde16d52012-12-03 14:42:39 -08001228 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1229 mStreamType = streamType;
1230 mIndex = index;
1231 mFlags = flags;
1232 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001233 }
John Spurlock35134602014-07-24 18:10:48 -04001234
1235 @Override
1236 public String toString() {
1237 return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1238 .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1239 .append(mDevice).append('}').toString();
1240 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001241 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001242
Eric Laurentfde16d52012-12-03 14:42:39 -08001243 private void onSetStreamVolume(int streamType, int index, int flags, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001244 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
Eric Laurent3ef75492012-11-28 12:12:23 -08001245 // setting volume on master stream type also controls silent mode
1246 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1247 (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
1248 int newRingerMode;
1249 if (index == 0) {
1250 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlock86005342014-05-23 11:58:00 -04001251 : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
1252 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001253 } else {
1254 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1255 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001256 setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/);
Eric Laurent3ef75492012-11-28 12:12:23 -08001257 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001258 }
1259
1260 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001261 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
RoboErik0dac35a2014-08-12 15:48:49 -07001262 setStreamVolume(streamType, index, flags, callingPackage, Binder.getCallingUid());
1263 }
1264
1265 private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
1266 int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001267 if (mUseFixedVolume) {
1268 return;
1269 }
1270
Eric Laurentfde16d52012-12-03 14:42:39 -08001271 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001272 int streamTypeAlias = mStreamVolumeAlias[streamType];
1273 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001274
1275 final int device = getDeviceForStream(streamType);
1276 int oldIndex;
1277
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001278 // skip a2dp absolute volume control request when the device
1279 // is not an a2dp device
1280 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1281 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1282 return;
1283 }
1284
RoboErik0dac35a2014-08-12 15:48:49 -07001285 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
1286 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001287 return;
1288 }
1289
Eric Laurentfde16d52012-12-03 14:42:39 -08001290 synchronized (mSafeMediaVolumeState) {
1291 // reset any pending volume command
1292 mPendingVolumeCommand = null;
1293
Eric Laurent42b041e2013-03-29 11:36:03 -07001294 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001295
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001296 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001297
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001298 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1299 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1300 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1301 synchronized (mA2dpAvrcpLock) {
1302 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001303 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001304 }
John Du5a0cf7a2013-07-19 11:30:34 -07001305 }
1306 }
1307
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001308 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1309 setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
Jungshik Jang41d97462014-06-30 22:26:29 +09001310 }
1311
Eric Laurentfde16d52012-12-03 14:42:39 -08001312 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001313 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001314 ((device & mFixedVolumeDevices) != 0)) {
1315 flags |= AudioManager.FLAG_FIXED_VOLUME;
1316
1317 // volume is either 0 or max allowed for fixed volume devices
1318 if (index != 0) {
1319 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1320 (device & mSafeMediaVolumeDevices) != 0) {
1321 index = mSafeMediaVolumeIndex;
1322 } else {
1323 index = streamState.getMaxIndex();
1324 }
1325 }
1326 }
1327
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001328 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001329 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001330 mPendingVolumeCommand = new StreamVolumeCommand(
1331 streamType, index, flags, device);
1332 } else {
1333 onSetStreamVolume(streamType, index, flags, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07001334 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001335 }
1336 }
Eric Laurent25101b02011-02-02 09:33:30 -08001337 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001338 }
1339
Eric Laurent45c90ce2012-04-24 18:44:22 -07001340 /** @see AudioManager#forceVolumeControlStream(int) */
1341 public void forceVolumeControlStream(int streamType, IBinder cb) {
1342 synchronized(mForceControlStreamLock) {
1343 mVolumeControlStream = streamType;
1344 if (mVolumeControlStream == -1) {
1345 if (mForceControlStreamClient != null) {
1346 mForceControlStreamClient.release();
1347 mForceControlStreamClient = null;
1348 }
1349 } else {
1350 mForceControlStreamClient = new ForceControlStreamClient(cb);
1351 }
1352 }
1353 }
1354
1355 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1356 private IBinder mCb; // To be notified of client's death
1357
1358 ForceControlStreamClient(IBinder cb) {
1359 if (cb != null) {
1360 try {
1361 cb.linkToDeath(this, 0);
1362 } catch (RemoteException e) {
1363 // Client has died!
1364 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1365 cb = null;
1366 }
1367 }
1368 mCb = cb;
1369 }
1370
1371 public void binderDied() {
1372 synchronized(mForceControlStreamLock) {
1373 Log.w(TAG, "SCO client died");
1374 if (mForceControlStreamClient != this) {
1375 Log.w(TAG, "unregistered control stream client died");
1376 } else {
1377 mForceControlStreamClient = null;
1378 mVolumeControlStream = -1;
1379 }
1380 }
1381 }
1382
1383 public void release() {
1384 if (mCb != null) {
1385 mCb.unlinkToDeath(this, 0);
1386 mCb = null;
1387 }
1388 }
1389 }
1390
Lei Zhang6c798972012-03-02 11:40:12 -08001391 private int findVolumeDelta(int direction, int volume) {
1392 int delta = 0;
1393 if (direction == AudioManager.ADJUST_RAISE) {
1394 if (volume == MAX_MASTER_VOLUME) {
1395 return 0;
1396 }
1397 // This is the default value if we make it to the end
1398 delta = mMasterVolumeRamp[1];
1399 // If we're raising the volume move down the ramp array until we
1400 // find the volume we're above and use that groups delta.
1401 for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
1402 if (volume >= mMasterVolumeRamp[i - 1]) {
1403 delta = mMasterVolumeRamp[i];
1404 break;
1405 }
1406 }
1407 } else if (direction == AudioManager.ADJUST_LOWER){
1408 if (volume == 0) {
1409 return 0;
1410 }
1411 int length = mMasterVolumeRamp.length;
1412 // This is the default value if we make it to the end
1413 delta = -mMasterVolumeRamp[length - 1];
1414 // If we're lowering the volume move up the ramp array until we
1415 // find the volume we're below and use the group below it's delta
1416 for (int i = 2; i < length; i += 2) {
1417 if (volume <= mMasterVolumeRamp[i]) {
1418 delta = -mMasterVolumeRamp[i - 1];
1419 break;
1420 }
1421 }
1422 }
1423 return delta;
1424 }
1425
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001426 private void sendBroadcastToAll(Intent intent) {
Christopher Tate267603f2015-01-20 14:21:21 -08001427 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
John Spurlock86490862015-02-25 11:22:52 -05001428 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001429 final long ident = Binder.clearCallingIdentity();
1430 try {
1431 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1432 } finally {
1433 Binder.restoreCallingIdentity(ident);
1434 }
1435 }
1436
1437 private void sendStickyBroadcastToAll(Intent intent) {
John Spurlock86490862015-02-25 11:22:52 -05001438 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001439 final long ident = Binder.clearCallingIdentity();
1440 try {
1441 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1442 } finally {
1443 Binder.restoreCallingIdentity(ident);
1444 }
1445 }
1446
Eric Laurent25101b02011-02-02 09:33:30 -08001447 // UI update and Broadcast Intent
1448 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
Eric Laurent212532b2014-07-21 15:43:18 -07001449 if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) {
Eric Laurent25101b02011-02-02 09:33:30 -08001450 streamType = AudioSystem.STREAM_NOTIFICATION;
1451 }
1452
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001453 if (streamType == AudioSystem.STREAM_MUSIC) {
1454 flags = updateFlagsForSystemAudio(flags);
Jungshik Jang1a6be6e2014-09-16 11:04:54 +09001455 }
John Spurlock3346a802014-05-20 16:25:37 -04001456 mVolumeController.postVolumeChanged(streamType, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001457 }
1458
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001459 // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
1460 // receives volume notification from Audio Receiver.
1461 private int updateFlagsForSystemAudio(int flags) {
1462 if (mHdmiTvClient != null) {
1463 synchronized (mHdmiTvClient) {
1464 if (mHdmiSystemAudioSupported &&
1465 ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
1466 flags &= ~AudioManager.FLAG_SHOW_UI;
1467 }
1468 }
1469 }
1470 return flags;
1471 }
1472
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001473 // UI update and Broadcast Intent
1474 private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001475 mVolumeController.postMasterVolumeChanged(updateFlagsForSystemAudio(flags));
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001476
1477 Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
1478 intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
1479 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001480 sendBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001481 }
1482
1483 // UI update and Broadcast Intent
1484 private void sendMasterMuteUpdate(boolean muted, int flags) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001485 mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
Justin Koh57978ed2012-04-03 17:37:58 -07001486 broadcastMasterMuteStatus(muted);
1487 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001488
Justin Koh57978ed2012-04-03 17:37:58 -07001489 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001490 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1491 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001492 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1493 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001494 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001495 }
1496
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001497 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001498 * Sets the stream state's index, and posts a message to set system volume.
1499 * This will not call out to the UI. Assumes a valid stream type.
1500 *
1501 * @param streamType Type of the stream
1502 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001503 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001504 * @param force If true, set the volume even if the desired volume is same
1505 * as the current volume.
1506 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001507 private void setStreamVolumeInt(int streamType,
1508 int index,
1509 int device,
Eric Laurent42b041e2013-03-29 11:36:03 -07001510 boolean force) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001511 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07001512
Eric Laurent42b041e2013-03-29 11:36:03 -07001513 if (streamState.setIndex(index, device) || force) {
1514 // Post message to set system volume (it in turn will post a message
1515 // to persist).
1516 sendMsg(mAudioHandler,
1517 MSG_SET_DEVICE_VOLUME,
1518 SENDMSG_QUEUE,
1519 device,
1520 0,
1521 streamState,
1522 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001523 }
1524 }
1525
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001526 private void setSystemAudioMute(boolean state) {
1527 if (mHdmiManager == null || mHdmiTvClient == null) return;
1528 synchronized (mHdmiManager) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001529 if (!mHdmiSystemAudioSupported) return;
1530 synchronized (mHdmiTvClient) {
1531 final long token = Binder.clearCallingIdentity();
1532 try {
1533 mHdmiTvClient.setSystemAudioMute(state);
1534 } finally {
1535 Binder.restoreCallingIdentity(token);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001536 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001537 }
1538 }
1539 }
1540
Eric Laurent25101b02011-02-02 09:33:30 -08001541 /** get stream mute state. */
1542 public boolean isStreamMute(int streamType) {
RoboErik7c82ced2014-12-04 17:39:08 -08001543 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1544 streamType = getActiveStreamType(streamType);
1545 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001546 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08001547 return mStreamStates[streamType].mIsMuted;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001548 }
Eric Laurent25101b02011-02-02 09:33:30 -08001549 }
1550
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07001551 private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
1552 private IBinder mICallback; // To be notified of client's death
1553
1554 RmtSbmxFullVolDeathHandler(IBinder cb) {
1555 mICallback = cb;
1556 try {
1557 cb.linkToDeath(this, 0/*flags*/);
1558 } catch (RemoteException e) {
1559 Log.e(TAG, "can't link to death", e);
1560 }
1561 }
1562
1563 boolean isHandlerFor(IBinder cb) {
1564 return mICallback.equals(cb);
1565 }
1566
1567 void forget() {
1568 try {
1569 mICallback.unlinkToDeath(this, 0/*flags*/);
1570 } catch (NoSuchElementException e) {
1571 Log.e(TAG, "error unlinking to death", e);
1572 }
1573 }
1574
1575 public void binderDied() {
1576 Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
1577 forceRemoteSubmixFullVolume(false, mICallback);
1578 }
1579 }
1580
1581 /**
1582 * call must be synchronized on mRmtSbmxFullVolDeathHandlers
1583 * @return true if there is a registered death handler, false otherwise */
1584 private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1585 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1586 while (it.hasNext()) {
1587 final RmtSbmxFullVolDeathHandler handler = it.next();
1588 if (handler.isHandlerFor(cb)) {
1589 handler.forget();
1590 mRmtSbmxFullVolDeathHandlers.remove(handler);
1591 return true;
1592 }
1593 }
1594 return false;
1595 }
1596
1597 /** call synchronized on mRmtSbmxFullVolDeathHandlers */
1598 private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1599 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1600 while (it.hasNext()) {
1601 if (it.next().isHandlerFor(cb)) {
1602 return true;
1603 }
1604 }
1605 return false;
1606 }
1607
1608 private int mRmtSbmxFullVolRefCount = 0;
1609 private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
1610 new ArrayList<RmtSbmxFullVolDeathHandler>();
1611
1612 public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
1613 if (cb == null) {
1614 return;
1615 }
1616 if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
1617 android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
1618 Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
1619 return;
1620 }
1621 synchronized(mRmtSbmxFullVolDeathHandlers) {
1622 boolean applyRequired = false;
1623 if (startForcing) {
1624 if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
1625 mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
1626 if (mRmtSbmxFullVolRefCount == 0) {
1627 mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1628 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1629 applyRequired = true;
1630 }
1631 mRmtSbmxFullVolRefCount++;
1632 }
1633 } else {
1634 if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
1635 mRmtSbmxFullVolRefCount--;
1636 if (mRmtSbmxFullVolRefCount == 0) {
1637 mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1638 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1639 applyRequired = true;
1640 }
1641 }
1642 }
1643 if (applyRequired) {
1644 // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
1645 checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
1646 mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
1647 }
1648 }
1649 }
1650
RoboErik4197cb62015-01-21 15:45:32 -08001651 private void setMasterMuteInternal(int adjust, int flags, String callingPackage, int uid) {
RoboErik7c82ced2014-12-04 17:39:08 -08001652 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
1653 != AppOpsManager.MODE_ALLOWED) {
Julia Reynolds4a21b252014-06-04 11:11:43 -04001654 return;
1655 }
RoboErik4197cb62015-01-21 15:45:32 -08001656 boolean state;
1657 if (adjust == AudioManager.ADJUST_TOGGLE_MUTE) {
1658 state = !AudioSystem.getMasterMute();
1659 } else {
1660 state = adjust == AudioManager.ADJUST_MUTE;
1661 }
Jason Simmons1ce5b262012-02-02 13:00:17 -08001662 if (state != AudioSystem.getMasterMute()) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001663 setSystemAudioMute(state);
Jason Simmons1ce5b262012-02-02 13:00:17 -08001664 AudioSystem.setMasterMute(state);
Justin Koh57978ed2012-04-03 17:37:58 -07001665 // Post a persist master volume msg
Justin Koh75cf9e12012-04-04 15:27:37 -07001666 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001667 : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
Justin Koh0273af52012-04-04 18:29:50 -07001668 sendMasterMuteUpdate(state, flags);
RoboErik7c82ced2014-12-04 17:39:08 -08001669
1670 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1671 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, state);
1672 sendBroadcastToAll(intent);
Jason Simmons1ce5b262012-02-02 13:00:17 -08001673 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08001674 }
1675
1676 /** get master mute state. */
1677 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08001678 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001679 }
1680
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07001681 protected static int getMaxStreamVolume(int streamType) {
1682 return MAX_STREAM_VOLUME[streamType];
1683 }
1684
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001685 /** @see AudioManager#getStreamVolume(int) */
1686 public int getStreamVolume(int streamType) {
1687 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001688 int device = getDeviceForStream(streamType);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001689 synchronized (VolumeStreamState.class) {
1690 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001691
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001692 // by convention getStreamVolume() returns 0 when a stream is muted.
RoboErik4197cb62015-01-21 15:45:32 -08001693 if (mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001694 index = 0;
1695 }
1696 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
1697 (device & mFixedVolumeDevices) != 0) {
1698 index = mStreamStates[streamType].getMaxIndex();
1699 }
1700 return (index + 5) / 10;
Eric Laurent42b041e2013-03-29 11:36:03 -07001701 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001702 }
1703
RoboErik519c7742014-11-18 10:59:09 -08001704 @Override
Mike Lockwood47676902011-11-08 10:31:21 -08001705 public int getMasterVolume() {
Mike Lockwoodce952c82011-11-14 10:47:42 -08001706 if (isMasterMute()) return 0;
1707 return getLastAudibleMasterVolume();
Mike Lockwood8dc1dab2011-10-27 09:52:41 -04001708 }
1709
RoboErik519c7742014-11-18 10:59:09 -08001710 @Override
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001711 public void setMasterVolume(int volume, int flags, String callingPackage) {
RoboErik519c7742014-11-18 10:59:09 -08001712 setMasterVolume(volume, flags, callingPackage, Binder.getCallingUid());
1713 }
1714
1715 public void setMasterVolume(int volume, int flags, String callingPackage, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001716 if (mUseFixedVolume) {
1717 return;
1718 }
1719
RoboErik519c7742014-11-18 10:59:09 -08001720 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
1721 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001722 return;
1723 }
1724
Mike Lockwood97606472012-02-09 11:24:10 -08001725 if (volume < 0) {
1726 volume = 0;
1727 } else if (volume > MAX_MASTER_VOLUME) {
1728 volume = MAX_MASTER_VOLUME;
1729 }
Mike Lockwood5c55a052011-12-15 17:21:44 -05001730 doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
1731 }
1732
1733 private void doSetMasterVolume(float volume, int flags) {
1734 // don't allow changing master volume when muted
1735 if (!AudioSystem.getMasterMute()) {
1736 int oldVolume = getMasterVolume();
1737 AudioSystem.setMasterVolume(volume);
1738
1739 int newVolume = getMasterVolume();
1740 if (newVolume != oldVolume) {
1741 // Post a persist master volume msg
1742 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
1743 Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001744 setSystemAudioVolume(oldVolume, newVolume, getMasterMaxVolume(), flags);
Mike Lockwood5c55a052011-12-15 17:21:44 -05001745 }
Justin Koh3caba512012-04-02 15:32:18 -07001746 // Send the volume update regardless whether there was a change.
1747 sendMasterVolumeUpdate(flags, oldVolume, newVolume);
Mike Lockwood5c55a052011-12-15 17:21:44 -05001748 }
Mike Lockwood8dc1dab2011-10-27 09:52:41 -04001749 }
1750
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001751 /** @see AudioManager#getStreamMaxVolume(int) */
1752 public int getStreamMaxVolume(int streamType) {
1753 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07001754 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 }
1756
Mike Lockwood47676902011-11-08 10:31:21 -08001757 public int getMasterMaxVolume() {
1758 return MAX_MASTER_VOLUME;
1759 }
Eric Laurent25101b02011-02-02 09:33:30 -08001760
1761 /** Get last audible volume before stream was muted. */
1762 public int getLastAudibleStreamVolume(int streamType) {
1763 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001764 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001765 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08001766 }
1767
Mike Lockwoodce952c82011-11-14 10:47:42 -08001768 /** Get last audible master volume before it was muted. */
1769 public int getLastAudibleMasterVolume() {
1770 return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1771 }
1772
Dianne Hackborn961cae92013-03-20 14:59:43 -07001773 /** @see AudioManager#getMasterStreamType() */
Eric Laurent6d517662012-04-23 18:42:39 -07001774 public int getMasterStreamType() {
John Spurlock4f0f1202014-08-05 13:28:33 -04001775 return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
Eric Laurent6d517662012-04-23 18:42:39 -07001776 }
1777
Emily Bernier22c921a2014-05-28 11:01:32 -04001778 /** @see AudioManager#setMicrophoneMute(boolean) */
1779 public void setMicrophoneMute(boolean on, String callingPackage) {
1780 if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(),
1781 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1782 return;
1783 }
Jean-Michel Trivi4a4fea02014-08-29 18:14:09 -07001784 if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
1785 return;
1786 }
Emily Bernier22c921a2014-05-28 11:01:32 -04001787
1788 AudioSystem.muteMicrophone(on);
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001789 // Post a persist microphone msg.
1790 sendMsg(mAudioHandler, MSG_PERSIST_MICROPHONE_MUTE, SENDMSG_REPLACE, on ? 1
1791 : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
Emily Bernier22c921a2014-05-28 11:01:32 -04001792 }
1793
John Spurlock661f2cf2014-11-17 10:29:10 -05001794 @Override
1795 public int getRingerModeExternal() {
1796 synchronized(mSettingsLock) {
1797 return mRingerModeExternal;
1798 }
1799 }
1800
1801 @Override
1802 public int getRingerModeInternal() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001803 synchronized(mSettingsLock) {
1804 return mRingerMode;
1805 }
1806 }
1807
1808 private void ensureValidRingerMode(int ringerMode) {
John Spurlock97559372014-10-24 16:27:36 -04001809 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001810 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1811 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001812 }
1813
John Spurlock97559372014-10-24 16:27:36 -04001814 /** @see AudioManager#isValidRingerMode(int) */
1815 public boolean isValidRingerMode(int ringerMode) {
1816 return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
1817 }
1818
John Spurlock661f2cf2014-11-17 10:29:10 -05001819 public void setRingerModeExternal(int ringerMode, String caller) {
John Spurlockaf88a192014-12-23 16:14:44 -05001820 setRingerMode(ringerMode, caller, true /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05001821 }
1822
1823 public void setRingerModeInternal(int ringerMode, String caller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05001824 enforceVolumeController("setRingerModeInternal");
John Spurlockaf88a192014-12-23 16:14:44 -05001825 setRingerMode(ringerMode, caller, false /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05001826 }
1827
1828 private void setRingerMode(int ringerMode, String caller, boolean external) {
Eric Laurent212532b2014-07-21 15:43:18 -07001829 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001830 return;
1831 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001832 if (caller == null || caller.length() == 0) {
1833 throw new IllegalArgumentException("Bad caller: " + caller);
1834 }
John Spurlock97559372014-10-24 16:27:36 -04001835 ensureValidRingerMode(ringerMode);
Eric Laurent24482012012-05-10 09:41:17 -07001836 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1837 ringerMode = AudioManager.RINGER_MODE_SILENT;
1838 }
John Spurlockaf88a192014-12-23 16:14:44 -05001839 final long identity = Binder.clearCallingIdentity();
1840 try {
1841 synchronized (mSettingsLock) {
1842 final int ringerModeInternal = getRingerModeInternal();
1843 final int ringerModeExternal = getRingerModeExternal();
1844 if (external) {
1845 setRingerModeExt(ringerMode);
1846 if (mRingerModeDelegate != null) {
1847 ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
1848 ringerMode, caller, ringerModeInternal);
1849 }
1850 if (ringerMode != ringerModeInternal) {
1851 setRingerModeInt(ringerMode, true /*persist*/);
1852 }
1853 } else /*internal*/ {
1854 if (ringerMode != ringerModeInternal) {
1855 setRingerModeInt(ringerMode, true /*persist*/);
1856 }
1857 if (mRingerModeDelegate != null) {
1858 ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
1859 ringerMode, caller, ringerModeExternal);
1860 }
1861 setRingerModeExt(ringerMode);
John Spurlock57627792014-12-11 11:29:54 -05001862 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001863 }
John Spurlockaf88a192014-12-23 16:14:44 -05001864 } finally {
1865 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001866 }
1867 }
1868
John Spurlock661f2cf2014-11-17 10:29:10 -05001869 private void setRingerModeExt(int ringerMode) {
1870 synchronized(mSettingsLock) {
1871 if (ringerMode == mRingerModeExternal) return;
1872 mRingerModeExternal = ringerMode;
John Spurlocke5b42d92014-10-15 12:03:48 -04001873 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001874 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05001875 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
John Spurlocke5b42d92014-10-15 12:03:48 -04001876 }
1877
Eric Laurent4050c932009-07-08 02:52:14 -07001878 private void setRingerModeInt(int ringerMode, boolean persist) {
John Spurlockbcc10872014-11-28 15:29:21 -05001879 final boolean change;
Glenn Kastenba195eb2011-12-13 09:30:40 -08001880 synchronized(mSettingsLock) {
John Spurlockbcc10872014-11-28 15:29:21 -05001881 change = mRingerMode != ringerMode;
Glenn Kastenba195eb2011-12-13 09:30:40 -08001882 mRingerMode = ringerMode;
1883 }
Jason Parekhb1096152009-03-24 17:48:25 -07001884
Eric Laurent5b4e6542010-03-19 20:02:21 -07001885 // Mute stream if not previously muted by ringer mode and ringer mode
1886 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
1887 // Unmute stream if previously muted by ringer mode and ringer mode
1888 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07001889 int numStreamTypes = AudioSystem.getNumStreamTypes();
John Spurlock661f2cf2014-11-17 10:29:10 -05001890 final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE
1891 || ringerMode == AudioManager.RINGER_MODE_SILENT;
Eric Laurent5b4e6542010-03-19 20:02:21 -07001892 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001893 final boolean isMuted = isStreamMutedByRingerMode(streamType);
1894 final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
1895 if (isMuted == shouldMute) continue;
1896 if (!shouldMute) {
1897 // unmute
1898 // ring and notifications volume should never be 0 when not silenced
1899 // on voice capable devices or devices that support vibration
1900 if ((isPlatformVoice() || mHasVibrator) &&
1901 mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
1902 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05001903 SparseIntArray indexMap = mStreamStates[streamType].mIndexMap;
1904 for (int i = 0; i < indexMap.size(); i++) {
1905 int device = indexMap.keyAt(i);
1906 int value = indexMap.valueAt(i);
1907 if (value == 0) {
1908 indexMap.put(device, 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001909 }
1910 }
Eric Laurent9e0d25f2015-02-12 17:28:53 -08001911 // Persist volume for stream ring when it is changed here
1912 final int device = getDeviceForStream(streamType);
1913 sendMsg(mAudioHandler,
1914 MSG_PERSIST_VOLUME,
1915 SENDMSG_QUEUE,
1916 device,
1917 0,
1918 mStreamStates[streamType],
1919 PERSIST_DELAY);
Eric Laurentb024c302011-10-14 17:19:27 -07001920 }
Eric Laurent9bcf4012009-06-12 06:09:28 -07001921 }
RoboErik4197cb62015-01-21 15:45:32 -08001922 mStreamStates[streamType].mute(false);
John Spurlock661f2cf2014-11-17 10:29:10 -05001923 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent5b4e6542010-03-19 20:02:21 -07001924 } else {
John Spurlock661f2cf2014-11-17 10:29:10 -05001925 // mute
RoboErik4197cb62015-01-21 15:45:32 -08001926 mStreamStates[streamType].mute(true);
John Spurlock661f2cf2014-11-17 10:29:10 -05001927 mRingerModeMutedStreams |= (1 << streamType);
Jason Parekhb1096152009-03-24 17:48:25 -07001928 }
1929 }
Eric Laurenta553c252009-07-17 12:17:14 -07001930
Jason Parekhb1096152009-03-24 17:48:25 -07001931 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07001932 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08001933 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07001934 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
1935 }
John Spurlockbcc10872014-11-28 15:29:21 -05001936 if (change) {
1937 // Send sticky broadcast
1938 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
1939 }
Jason Parekhb1096152009-03-24 17:48:25 -07001940 }
1941
Mike Lockwood90631542012-01-06 11:20:37 -05001942 private void restoreMasterVolume() {
Eric Laurent83a017b2013-03-19 18:15:31 -07001943 if (mUseFixedVolume) {
1944 AudioSystem.setMasterVolume(1.0f);
1945 return;
1946 }
Mike Lockwood90631542012-01-06 11:20:37 -05001947 if (mUseMasterVolume) {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001948 float volume = Settings.System.getFloatForUser(mContentResolver,
1949 Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
Mike Lockwood90631542012-01-06 11:20:37 -05001950 if (volume >= 0.0f) {
1951 AudioSystem.setMasterVolume(volume);
1952 }
1953 }
1954 }
1955
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001956 /** @see AudioManager#shouldVibrate(int) */
1957 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001958 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001959
1960 switch (getVibrateSetting(vibrateType)) {
1961
1962 case AudioManager.VIBRATE_SETTING_ON:
John Spurlock57627792014-12-11 11:29:54 -05001963 return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001964
1965 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
John Spurlock57627792014-12-11 11:29:54 -05001966 return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001967
1968 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04001969 // return false, even for incoming calls
1970 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001971
1972 default:
1973 return false;
1974 }
1975 }
1976
1977 /** @see AudioManager#getVibrateSetting(int) */
1978 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001979 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001980 return (mVibrateSetting >> (vibrateType * 2)) & 3;
1981 }
1982
1983 /** @see AudioManager#setVibrateSetting(int, int) */
1984 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
1985
Eric Laurentbffc3d12012-05-07 17:43:49 -07001986 if (!mHasVibrator) return;
1987
John Spurlock61560172015-02-06 19:46:04 -05001988 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
1989 vibrateSetting);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001990
1991 // Broadcast change
1992 broadcastVibrateSetting(vibrateType);
1993
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001994 }
1995
Eric Laurent9272b4b2010-01-23 17:12:59 -08001996 private class SetModeDeathHandler implements IBinder.DeathRecipient {
1997 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07001998 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001999 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
2000
Eric Laurent9f103de2011-09-08 15:04:23 -07002001 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08002002 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07002003 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002004 }
2005
2006 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07002007 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002008 synchronized(mSetModeDeathHandlers) {
2009 Log.w(TAG, "setMode() client died");
2010 int index = mSetModeDeathHandlers.indexOf(this);
2011 if (index < 0) {
2012 Log.w(TAG, "unregistered setMode() client died");
2013 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07002014 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
Eric Laurent9272b4b2010-01-23 17:12:59 -08002015 }
2016 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002017 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2018 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002019 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07002020 final long ident = Binder.clearCallingIdentity();
2021 disconnectBluetoothSco(newModeOwnerPid);
2022 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07002023 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08002024 }
2025
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002026 public int getPid() {
2027 return mPid;
2028 }
2029
Eric Laurent9272b4b2010-01-23 17:12:59 -08002030 public void setMode(int mode) {
2031 mMode = mode;
2032 }
2033
2034 public int getMode() {
2035 return mMode;
2036 }
2037
2038 public IBinder getBinder() {
2039 return mCb;
2040 }
2041 }
2042
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002043 /** @see AudioManager#setMode(int) */
Eric Laurent9272b4b2010-01-23 17:12:59 -08002044 public void setMode(int mode, IBinder cb) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002045 if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ")"); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002046 if (!checkAudioSettingsPermission("setMode()")) {
2047 return;
2048 }
Eric Laurenta553c252009-07-17 12:17:14 -07002049
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07002050 if ( (mode == AudioSystem.MODE_IN_CALL) &&
2051 (mContext.checkCallingOrSelfPermission(
2052 android.Manifest.permission.MODIFY_PHONE_STATE)
2053 != PackageManager.PERMISSION_GRANTED)) {
2054 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
2055 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
2056 return;
2057 }
2058
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08002059 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07002060 return;
2061 }
2062
Eric Laurentd7454be2011-09-14 08:45:58 -07002063 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002064 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07002065 if (mode == AudioSystem.MODE_CURRENT) {
2066 mode = mMode;
2067 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002068 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
Eric Laurent9f103de2011-09-08 15:04:23 -07002069 }
2070 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2071 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002072 if (newModeOwnerPid != 0) {
2073 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07002074 }
2075 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002076
Eric Laurent9f103de2011-09-08 15:04:23 -07002077 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07002078 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07002079 // any mode other than NORMAL.
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07002080 private int setModeInt(int mode, IBinder cb, int pid) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002081 if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ")"); }
Eric Laurentd7454be2011-09-14 08:45:58 -07002082 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002083 if (cb == null) {
2084 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07002085 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07002086 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002087
Eric Laurent9f103de2011-09-08 15:04:23 -07002088 SetModeDeathHandler hdlr = null;
2089 Iterator iter = mSetModeDeathHandlers.iterator();
2090 while (iter.hasNext()) {
2091 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
2092 if (h.getPid() == pid) {
2093 hdlr = h;
2094 // Remove from client list so that it is re-inserted at top of list
2095 iter.remove();
2096 hdlr.getBinder().unlinkToDeath(hdlr, 0);
2097 break;
2098 }
2099 }
2100 int status = AudioSystem.AUDIO_STATUS_OK;
2101 do {
2102 if (mode == AudioSystem.MODE_NORMAL) {
2103 // get new mode from client at top the list if any
2104 if (!mSetModeDeathHandlers.isEmpty()) {
2105 hdlr = mSetModeDeathHandlers.get(0);
2106 cb = hdlr.getBinder();
2107 mode = hdlr.getMode();
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002108 if (DEBUG_MODE) {
2109 Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
2110 + hdlr.mPid);
2111 }
Eric Laurentb9c9d262009-05-06 08:13:20 -07002112 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002113 } else {
2114 if (hdlr == null) {
2115 hdlr = new SetModeDeathHandler(cb, pid);
2116 }
2117 // Register for client death notification
2118 try {
2119 cb.linkToDeath(hdlr, 0);
2120 } catch (RemoteException e) {
2121 // Client has died!
2122 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
2123 }
2124
2125 // Last client to call setMode() is always at top of client list
2126 // as required by SetModeDeathHandler.binderDied()
2127 mSetModeDeathHandlers.add(0, hdlr);
2128 hdlr.setMode(mode);
2129 }
2130
2131 if (mode != mMode) {
2132 status = AudioSystem.setPhoneState(mode);
2133 if (status == AudioSystem.AUDIO_STATUS_OK) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002134 if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002135 mMode = mode;
2136 } else {
2137 if (hdlr != null) {
2138 mSetModeDeathHandlers.remove(hdlr);
2139 cb.unlinkToDeath(hdlr, 0);
2140 }
2141 // force reading new top of mSetModeDeathHandlers stack
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002142 if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002143 mode = AudioSystem.MODE_NORMAL;
2144 }
2145 } else {
2146 status = AudioSystem.AUDIO_STATUS_OK;
2147 }
2148 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
2149
2150 if (status == AudioSystem.AUDIO_STATUS_OK) {
2151 if (mode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002152 if (mSetModeDeathHandlers.isEmpty()) {
2153 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
2154 } else {
2155 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2156 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002157 }
2158 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002159 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07002160 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
2161 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
Eric Laurent6d517662012-04-23 18:42:39 -07002162
2163 updateStreamVolumeAlias(true /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002164 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002165 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002166 }
2167
2168 /** @see AudioManager#getMode() */
2169 public int getMode() {
2170 return mMode;
2171 }
2172
Eric Laurente78fced2013-03-15 16:03:47 -07002173 //==========================================================================================
2174 // Sound Effects
2175 //==========================================================================================
2176
2177 private static final String TAG_AUDIO_ASSETS = "audio_assets";
2178 private static final String ATTR_VERSION = "version";
2179 private static final String TAG_GROUP = "group";
2180 private static final String ATTR_GROUP_NAME = "name";
2181 private static final String TAG_ASSET = "asset";
2182 private static final String ATTR_ASSET_ID = "id";
2183 private static final String ATTR_ASSET_FILE = "file";
2184
2185 private static final String ASSET_FILE_VERSION = "1.0";
2186 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
2187
Glenn Kasten167d1a22013-07-23 16:24:41 -07002188 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002189
2190 class LoadSoundEffectReply {
2191 public int mStatus = 1;
2192 };
2193
Eric Laurente78fced2013-03-15 16:03:47 -07002194 private void loadTouchSoundAssetDefaults() {
2195 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
2196 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
2197 SOUND_EFFECT_FILES_MAP[i][0] = 0;
2198 SOUND_EFFECT_FILES_MAP[i][1] = -1;
2199 }
2200 }
2201
2202 private void loadTouchSoundAssets() {
2203 XmlResourceParser parser = null;
2204
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002205 // only load assets once.
2206 if (!SOUND_EFFECT_FILES.isEmpty()) {
2207 return;
2208 }
2209
Eric Laurente78fced2013-03-15 16:03:47 -07002210 loadTouchSoundAssetDefaults();
2211
2212 try {
2213 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
2214
2215 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
2216 String version = parser.getAttributeValue(null, ATTR_VERSION);
2217 boolean inTouchSoundsGroup = false;
2218
2219 if (ASSET_FILE_VERSION.equals(version)) {
2220 while (true) {
2221 XmlUtils.nextElement(parser);
2222 String element = parser.getName();
2223 if (element == null) {
2224 break;
2225 }
2226 if (element.equals(TAG_GROUP)) {
2227 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
2228 if (GROUP_TOUCH_SOUNDS.equals(name)) {
2229 inTouchSoundsGroup = true;
2230 break;
2231 }
2232 }
2233 }
2234 while (inTouchSoundsGroup) {
2235 XmlUtils.nextElement(parser);
2236 String element = parser.getName();
2237 if (element == null) {
2238 break;
2239 }
2240 if (element.equals(TAG_ASSET)) {
2241 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
2242 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
2243 int fx;
2244
2245 try {
2246 Field field = AudioManager.class.getField(id);
2247 fx = field.getInt(null);
2248 } catch (Exception e) {
2249 Log.w(TAG, "Invalid touch sound ID: "+id);
2250 continue;
2251 }
2252
2253 int i = SOUND_EFFECT_FILES.indexOf(file);
2254 if (i == -1) {
2255 i = SOUND_EFFECT_FILES.size();
2256 SOUND_EFFECT_FILES.add(file);
2257 }
2258 SOUND_EFFECT_FILES_MAP[fx][0] = i;
2259 } else {
2260 break;
2261 }
2262 }
2263 }
2264 } catch (Resources.NotFoundException e) {
2265 Log.w(TAG, "audio assets file not found", e);
2266 } catch (XmlPullParserException e) {
2267 Log.w(TAG, "XML parser exception reading touch sound assets", e);
2268 } catch (IOException e) {
2269 Log.w(TAG, "I/O exception reading touch sound assets", e);
2270 } finally {
2271 if (parser != null) {
2272 parser.close();
2273 }
2274 }
2275 }
2276
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002277 /** @see AudioManager#playSoundEffect(int) */
2278 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002279 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002280 }
2281
2282 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002283 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07002284 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
2285 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
2286 return;
2287 }
2288
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002289 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002290 effectType, (int) (volume * 1000), null, 0);
2291 }
2292
2293 /**
2294 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08002295 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002296 */
2297 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002298 int attempts = 3;
2299 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08002300
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002301 synchronized (reply) {
2302 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
2303 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08002304 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07002305 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002306 } catch (InterruptedException e) {
2307 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08002308 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002309 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002310 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002311 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002312 }
2313
2314 /**
2315 * Unloads samples from the sound pool.
2316 * This method can be called to free some memory when
2317 * sound effects are disabled.
2318 */
2319 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002320 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002321 }
2322
Eric Laurenta60e2122010-12-28 16:49:07 -08002323 class SoundPoolListenerThread extends Thread {
2324 public SoundPoolListenerThread() {
2325 super("SoundPoolListenerThread");
2326 }
2327
2328 @Override
2329 public void run() {
2330
2331 Looper.prepare();
2332 mSoundPoolLooper = Looper.myLooper();
2333
2334 synchronized (mSoundEffectsLock) {
2335 if (mSoundPool != null) {
2336 mSoundPoolCallBack = new SoundPoolCallback();
2337 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2338 }
2339 mSoundEffectsLock.notify();
2340 }
2341 Looper.loop();
2342 }
2343 }
2344
2345 private final class SoundPoolCallback implements
2346 android.media.SoundPool.OnLoadCompleteListener {
2347
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002348 int mStatus = 1; // 1 means neither error nor last sample loaded yet
2349 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08002350
2351 public int status() {
2352 return mStatus;
2353 }
2354
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002355 public void setSamples(int[] samples) {
2356 for (int i = 0; i < samples.length; i++) {
2357 // do not wait ack for samples rejected upfront by SoundPool
2358 if (samples[i] > 0) {
2359 mSamples.add(samples[i]);
2360 }
2361 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002362 }
2363
2364 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2365 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002366 int i = mSamples.indexOf(sampleId);
2367 if (i >= 0) {
2368 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08002369 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002370 if ((status != 0) || mSamples. isEmpty()) {
2371 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08002372 mSoundEffectsLock.notify();
2373 }
2374 }
2375 }
2376 }
2377
Eric Laurent4050c932009-07-08 02:52:14 -07002378 /** @see AudioManager#reloadAudioSettings() */
2379 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002380 readAudioSettings(false /*userSwitch*/);
2381 }
2382
2383 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07002384 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2385 readPersistedSettings();
2386
2387 // restore volume settings
2388 int numStreamTypes = AudioSystem.getNumStreamTypes();
2389 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2390 VolumeStreamState streamState = mStreamStates[streamType];
2391
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002392 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2393 continue;
2394 }
2395
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002396 streamState.readSettings();
2397 synchronized (VolumeStreamState.class) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002398 // unmute stream that was muted but is not affect by mute anymore
RoboErik4197cb62015-01-21 15:45:32 -08002399 if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07002400 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
RoboErik4197cb62015-01-21 15:45:32 -08002401 streamState.mIsMuted = false;
Eric Laurent4050c932009-07-08 02:52:14 -07002402 }
Eric Laurent4050c932009-07-08 02:52:14 -07002403 }
2404 }
2405
Eric Laurent33902db2012-10-07 16:15:07 -07002406 // apply new ringer mode before checking volume for alias streams so that streams
2407 // muted by ringer mode have the correct volume
John Spurlock661f2cf2014-11-17 10:29:10 -05002408 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent33902db2012-10-07 16:15:07 -07002409
Eric Laurent212532b2014-07-21 15:43:18 -07002410 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07002411 checkAllAliasStreamVolumes();
2412
Eric Laurentd640bd32012-09-28 18:01:48 -07002413 synchronized (mSafeMediaVolumeState) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002414 mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2415 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2416 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
Eric Laurentd640bd32012-09-28 18:01:48 -07002417 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07002418 enforceSafeMediaVolume();
2419 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07002420 }
Eric Laurent4050c932009-07-08 02:52:14 -07002421 }
2422
Dianne Hackborn961cae92013-03-20 14:59:43 -07002423 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002424 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002425 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2426 return;
2427 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002428
2429 if (on) {
2430 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2431 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2432 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
2433 }
2434 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2435 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2436 mForcedUseForComm = AudioSystem.FORCE_NONE;
2437 }
Eric Laurentfa640152011-03-12 15:59:51 -08002438
Eric Laurentafbb0472011-12-15 09:04:23 -08002439 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002440 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002441 }
2442
2443 /** @see AudioManager#isSpeakerphoneOn() */
2444 public boolean isSpeakerphoneOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002445 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002446 }
2447
Dianne Hackborn961cae92013-03-20 14:59:43 -07002448 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002449 public void setBluetoothScoOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002450 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2451 return;
2452 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002453
2454 if (on) {
2455 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2456 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2457 mForcedUseForComm = AudioSystem.FORCE_NONE;
2458 }
Eric Laurentfa640152011-03-12 15:59:51 -08002459
Eric Laurentafbb0472011-12-15 09:04:23 -08002460 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002461 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08002462 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002463 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002464 }
2465
2466 /** @see AudioManager#isBluetoothScoOn() */
2467 public boolean isBluetoothScoOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002468 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002469 }
2470
Dianne Hackborn961cae92013-03-20 14:59:43 -07002471 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07002472 public void setBluetoothA2dpOn(boolean on) {
Eric Laurentc390bed2012-07-03 12:24:05 -07002473 synchronized (mBluetoothA2dpEnabledLock) {
2474 mBluetoothA2dpEnabled = on;
2475 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2476 AudioSystem.FOR_MEDIA,
2477 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2478 null, 0);
2479 }
Eric Laurent78472112012-05-21 08:57:21 -07002480 }
2481
2482 /** @see AudioManager#isBluetoothA2dpOn() */
2483 public boolean isBluetoothA2dpOn() {
2484 synchronized (mBluetoothA2dpEnabledLock) {
2485 return mBluetoothA2dpEnabled;
2486 }
2487 }
2488
Eric Laurent3def1ee2010-03-17 23:26:26 -07002489 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07002490 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
2491 int scoAudioMode =
2492 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
Liejun Taof4e51d82014-07-16 11:18:29 -07002493 SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
Eric Laurent83900752014-05-15 15:14:22 -07002494 startBluetoothScoInt(cb, scoAudioMode);
2495 }
2496
2497 /** @see AudioManager#startBluetoothScoVirtualCall() */
2498 public void startBluetoothScoVirtualCall(IBinder cb) {
2499 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
2500 }
2501
2502 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07002503 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002504 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002505 return;
2506 }
Eric Laurent854938a2011-02-22 12:05:20 -08002507 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002508 // The calling identity must be cleared before calling ScoClient.incCount().
2509 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2510 // and this must be done on behalf of system server to make sure permissions are granted.
2511 // The caller identity must be cleared after getScoClient() because it is needed if a new
2512 // client is created.
2513 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07002514 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08002515 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002516 }
2517
2518 /** @see AudioManager#stopBluetoothSco() */
2519 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07002520 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002521 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002522 return;
2523 }
Eric Laurent854938a2011-02-22 12:05:20 -08002524 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002525 // The calling identity must be cleared before calling ScoClient.decCount().
2526 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2527 // and this must be done on behalf of system server to make sure permissions are granted.
2528 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08002529 if (client != null) {
2530 client.decCount();
2531 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08002532 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002533 }
2534
Eric Laurent78472112012-05-21 08:57:21 -07002535
Eric Laurent3def1ee2010-03-17 23:26:26 -07002536 private class ScoClient implements IBinder.DeathRecipient {
2537 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002538 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002539 private int mStartcount; // number of SCO connections started by this client
2540
2541 ScoClient(IBinder cb) {
2542 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002543 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002544 mStartcount = 0;
2545 }
2546
2547 public void binderDied() {
2548 synchronized(mScoClients) {
2549 Log.w(TAG, "SCO client died");
2550 int index = mScoClients.indexOf(this);
2551 if (index < 0) {
2552 Log.w(TAG, "unregistered SCO client died");
2553 } else {
2554 clearCount(true);
2555 mScoClients.remove(this);
2556 }
2557 }
2558 }
2559
Eric Laurent83900752014-05-15 15:14:22 -07002560 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002561 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07002562 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002563 if (mStartcount == 0) {
2564 try {
2565 mCb.linkToDeath(this, 0);
2566 } catch (RemoteException e) {
2567 // client has already died!
2568 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
2569 }
2570 }
2571 mStartcount++;
2572 }
2573 }
2574
2575 public void decCount() {
2576 synchronized(mScoClients) {
2577 if (mStartcount == 0) {
2578 Log.w(TAG, "ScoClient.decCount() already 0");
2579 } else {
2580 mStartcount--;
2581 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002582 try {
2583 mCb.unlinkToDeath(this, 0);
2584 } catch (NoSuchElementException e) {
2585 Log.w(TAG, "decCount() going to 0 but not registered to binder");
2586 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002587 }
Eric Laurentc18c9132013-04-12 17:24:56 -07002588 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002589 }
2590 }
2591 }
2592
2593 public void clearCount(boolean stopSco) {
2594 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002595 if (mStartcount != 0) {
2596 try {
2597 mCb.unlinkToDeath(this, 0);
2598 } catch (NoSuchElementException e) {
2599 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2600 }
2601 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002602 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002603 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002604 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002605 }
2606 }
2607 }
2608
2609 public int getCount() {
2610 return mStartcount;
2611 }
2612
2613 public IBinder getBinder() {
2614 return mCb;
2615 }
2616
Eric Laurentd7454be2011-09-14 08:45:58 -07002617 public int getPid() {
2618 return mCreatorPid;
2619 }
2620
Eric Laurent3def1ee2010-03-17 23:26:26 -07002621 public int totalCount() {
2622 synchronized(mScoClients) {
2623 int count = 0;
2624 int size = mScoClients.size();
2625 for (int i = 0; i < size; i++) {
2626 count += mScoClients.get(i).getCount();
2627 }
2628 return count;
2629 }
2630 }
2631
Eric Laurent83900752014-05-15 15:14:22 -07002632 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08002633 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07002634 if (totalCount() == 0) {
2635 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2636 // Make sure that the state transitions to CONNECTING even if we cannot initiate
2637 // the connection.
2638 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2639 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002640 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07002641 synchronized(mSetModeDeathHandlers) {
2642 if ((mSetModeDeathHandlers.isEmpty() ||
2643 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2644 (mScoAudioState == SCO_STATE_INACTIVE ||
2645 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2646 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07002647 mScoAudioMode = scoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -07002648 if (scoAudioMode == SCO_MODE_UNDEFINED) {
Andre Eisenbach570cc532014-10-28 17:03:18 -07002649 if (mBluetoothHeadsetDevice != null) {
2650 mScoAudioMode = new Integer(Settings.Global.getInt(
2651 mContentResolver,
2652 "bluetooth_sco_channel_"+
2653 mBluetoothHeadsetDevice.getAddress(),
2654 SCO_MODE_VIRTUAL_CALL));
2655 if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2656 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2657 }
2658 } else {
2659 mScoAudioMode = SCO_MODE_RAW;
Liejun Taof4e51d82014-07-16 11:18:29 -07002660 }
2661 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002662 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002663 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002664 if (mScoAudioMode == SCO_MODE_RAW) {
2665 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002666 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002667 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2668 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002669 } else if (mScoAudioMode == SCO_MODE_VR) {
2670 status = mBluetoothHeadset.startVoiceRecognition(
2671 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002672 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002673
Eric Laurentc18c9132013-04-12 17:24:56 -07002674 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07002675 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2676 } else {
2677 broadcastScoConnectionState(
2678 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2679 }
2680 } else if (getBluetoothHeadset()) {
2681 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07002682 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002683 } else {
2684 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2685 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002686 }
2687 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07002688 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002689 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002690 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002691 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002692 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2693 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2694 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07002695 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002696 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002697 if (mScoAudioMode == SCO_MODE_RAW) {
2698 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002699 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002700 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2701 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002702 } else if (mScoAudioMode == SCO_MODE_VR) {
2703 status = mBluetoothHeadset.stopVoiceRecognition(
2704 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002705 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002706
Eric Laurentc18c9132013-04-12 17:24:56 -07002707 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002708 mScoAudioState = SCO_STATE_INACTIVE;
2709 broadcastScoConnectionState(
2710 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2711 }
2712 } else if (getBluetoothHeadset()) {
2713 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2714 }
2715 } else {
2716 mScoAudioState = SCO_STATE_INACTIVE;
2717 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2718 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002719 }
2720 }
2721 }
2722 }
2723
Eric Laurent62ef7672010-11-24 10:58:32 -08002724 private void checkScoAudioState() {
2725 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002726 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08002727 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2728 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2729 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2730 }
2731 }
2732
Eric Laurent854938a2011-02-22 12:05:20 -08002733 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002734 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002735 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002736 int size = mScoClients.size();
2737 for (int i = 0; i < size; i++) {
2738 client = mScoClients.get(i);
2739 if (client.getBinder() == cb)
2740 return client;
2741 }
Eric Laurent854938a2011-02-22 12:05:20 -08002742 if (create) {
2743 client = new ScoClient(cb);
2744 mScoClients.add(client);
2745 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002746 return client;
2747 }
2748 }
2749
Eric Laurentd7454be2011-09-14 08:45:58 -07002750 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002751 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002752 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002753 int size = mScoClients.size();
2754 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08002755 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07002756 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08002757 cl.clearCount(stopSco);
2758 } else {
2759 savedClient = cl;
2760 }
2761 }
2762 mScoClients.clear();
2763 if (savedClient != null) {
2764 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002765 }
2766 }
2767 }
2768
Eric Laurentdc03c612011-04-01 10:59:41 -07002769 private boolean getBluetoothHeadset() {
2770 boolean result = false;
2771 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2772 if (adapter != null) {
2773 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2774 BluetoothProfile.HEADSET);
2775 }
2776 // If we could not get a bluetooth headset proxy, send a failure message
2777 // without delay to reset the SCO audio state and clear SCO clients.
2778 // If we could get a proxy, send a delayed failure message that will reset our state
2779 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08002780 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002781 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2782 return result;
2783 }
2784
Eric Laurentd7454be2011-09-14 08:45:58 -07002785 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002786 synchronized(mScoClients) {
2787 checkScoAudioState();
2788 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2789 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2790 if (mBluetoothHeadsetDevice != null) {
2791 if (mBluetoothHeadset != null) {
2792 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07002793 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002794 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002795 SENDMSG_REPLACE, 0, 0, null, 0);
2796 }
2797 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2798 getBluetoothHeadset()) {
2799 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2800 }
2801 }
2802 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07002803 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07002804 }
2805 }
2806 }
2807
2808 private void resetBluetoothSco() {
2809 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002810 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07002811 mScoAudioState = SCO_STATE_INACTIVE;
2812 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2813 }
2814 }
2815
2816 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08002817 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
2818 SENDMSG_QUEUE, state, 0, null, 0);
2819 }
2820
2821 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002822 if (state != mScoConnectionState) {
2823 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2824 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2825 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2826 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002827 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07002828 mScoConnectionState = state;
2829 }
2830 }
2831
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002832 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
2833 new BluetoothProfile.ServiceListener() {
2834 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002835 BluetoothDevice btDevice;
2836 List<BluetoothDevice> deviceList;
2837 switch(profile) {
2838 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09002839 synchronized (mConnectedDevices) {
2840 synchronized (mA2dpAvrcpLock) {
2841 mA2dp = (BluetoothA2dp) proxy;
2842 deviceList = mA2dp.getConnectedDevices();
2843 if (deviceList.size() > 0) {
2844 btDevice = deviceList.get(0);
John Du5a0cf7a2013-07-19 11:30:34 -07002845 int state = mA2dp.getConnectionState(btDevice);
2846 int delay = checkSendBecomingNoisyIntent(
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002847 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2848 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
John Du5a0cf7a2013-07-19 11:30:34 -07002849 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002850 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07002851 state,
2852 0,
2853 btDevice,
2854 delay);
2855 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002856 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002857 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002858 break;
2859
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002860 case BluetoothProfile.A2DP_SINK:
2861 deviceList = proxy.getConnectedDevices();
2862 if (deviceList.size() > 0) {
2863 btDevice = deviceList.get(0);
2864 synchronized (mConnectedDevices) {
2865 int state = proxy.getConnectionState(btDevice);
2866 queueMsgUnderWakeLock(mAudioHandler,
2867 MSG_SET_A2DP_SRC_CONNECTION_STATE,
2868 state,
2869 0,
2870 btDevice,
2871 0 /* delay */);
2872 }
2873 }
2874 break;
2875
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002876 case BluetoothProfile.HEADSET:
2877 synchronized (mScoClients) {
2878 // Discard timeout message
2879 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
2880 mBluetoothHeadset = (BluetoothHeadset) proxy;
2881 deviceList = mBluetoothHeadset.getConnectedDevices();
2882 if (deviceList.size() > 0) {
2883 mBluetoothHeadsetDevice = deviceList.get(0);
2884 } else {
2885 mBluetoothHeadsetDevice = null;
2886 }
2887 // Refresh SCO audio state
2888 checkScoAudioState();
2889 // Continue pending action if any
2890 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
2891 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
2892 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2893 boolean status = false;
2894 if (mBluetoothHeadsetDevice != null) {
2895 switch (mScoAudioState) {
2896 case SCO_STATE_ACTIVATE_REQ:
2897 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07002898 if (mScoAudioMode == SCO_MODE_RAW) {
2899 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002900 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002901 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2902 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002903 } else if (mScoAudioMode == SCO_MODE_VR) {
2904 status = mBluetoothHeadset.startVoiceRecognition(
2905 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002906 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002907 break;
2908 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07002909 if (mScoAudioMode == SCO_MODE_RAW) {
2910 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002911 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002912 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2913 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002914 } else if (mScoAudioMode == SCO_MODE_VR) {
2915 status = mBluetoothHeadset.stopVoiceRecognition(
2916 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002917 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002918 break;
2919 case SCO_STATE_DEACTIVATE_EXT_REQ:
2920 status = mBluetoothHeadset.stopVoiceRecognition(
2921 mBluetoothHeadsetDevice);
2922 }
2923 }
2924 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002925 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002926 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07002927 }
2928 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002929 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002930 break;
2931
2932 default:
2933 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002934 }
2935 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002936 public void onServiceDisconnected(int profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002937 switch(profile) {
2938 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09002939 synchronized (mConnectedDevices) {
2940 synchronized (mA2dpAvrcpLock) {
2941 mA2dp = null;
John Du5a0cf7a2013-07-19 11:30:34 -07002942 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
2943 makeA2dpDeviceUnavailableNow(
2944 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
2945 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002946 }
2947 }
2948 break;
2949
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002950 case BluetoothProfile.A2DP_SINK:
2951 synchronized (mConnectedDevices) {
2952 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) {
2953 makeA2dpSrcUnavailable(
2954 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP));
2955 }
2956 }
2957 break;
2958
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002959 case BluetoothProfile.HEADSET:
2960 synchronized (mScoClients) {
2961 mBluetoothHeadset = null;
2962 }
2963 break;
2964
2965 default:
2966 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002967 }
2968 }
2969 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08002970
Eric Laurentc34dcc12012-09-10 13:51:52 -07002971 private void onCheckMusicActive() {
Eric Laurentd640bd32012-09-28 18:01:48 -07002972 synchronized (mSafeMediaVolumeState) {
2973 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002974 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
2975
2976 if ((device & mSafeMediaVolumeDevices) != 0) {
2977 sendMsg(mAudioHandler,
2978 MSG_CHECK_MUSIC_ACTIVE,
2979 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07002980 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07002981 0,
2982 null,
2983 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07002984 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07002985 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
2986 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002987 // Approximate cumulative active music time
2988 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
2989 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
2990 setSafeMediaVolumeEnabled(true);
2991 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07002992 }
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002993 saveMusicActiveMs();
Eric Laurentc34dcc12012-09-10 13:51:52 -07002994 }
2995 }
2996 }
2997 }
2998 }
2999
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003000 private void saveMusicActiveMs() {
3001 mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
3002 }
3003
Eric Laurentd640bd32012-09-28 18:01:48 -07003004 private void onConfigureSafeVolume(boolean force) {
3005 synchronized (mSafeMediaVolumeState) {
3006 int mcc = mContext.getResources().getConfiguration().mcc;
3007 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
3008 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
3009 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
John Spurlock35134602014-07-24 18:10:48 -04003010 boolean safeMediaVolumeEnabled =
3011 SystemProperties.getBoolean("audio.safemedia.force", false)
3012 || mContext.getResources().getBoolean(
3013 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08003014
3015 // The persisted state is either "disabled" or "active": this is the state applied
3016 // next time we boot and cannot be "inactive"
3017 int persistedState;
Eric Laurentd640bd32012-09-28 18:01:48 -07003018 if (safeMediaVolumeEnabled) {
Eric Laurent05274f32012-11-29 12:48:18 -08003019 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
3020 // The state can already be "inactive" here if the user has forced it before
3021 // the 30 seconds timeout for forced configuration. In this case we don't reset
3022 // it to "active".
3023 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003024 if (mMusicActiveMs == 0) {
3025 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
3026 enforceSafeMediaVolume();
3027 } else {
3028 // We have existing playback time recorded, already confirmed.
3029 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
3030 }
Eric Laurent05274f32012-11-29 12:48:18 -08003031 }
Eric Laurentd640bd32012-09-28 18:01:48 -07003032 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08003033 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07003034 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
3035 }
3036 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08003037 sendMsg(mAudioHandler,
3038 MSG_PERSIST_SAFE_VOLUME_STATE,
3039 SENDMSG_QUEUE,
3040 persistedState,
3041 0,
3042 null,
3043 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07003044 }
3045 }
3046 }
3047
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003048 ///////////////////////////////////////////////////////////////////////////
3049 // Internal methods
3050 ///////////////////////////////////////////////////////////////////////////
3051
3052 /**
3053 * Checks if the adjustment should change ringer mode instead of just
3054 * adjusting volume. If so, this will set the proper ringer mode and volume
3055 * indices on the stream states.
3056 */
RoboErik5452e252015-02-06 15:33:53 -08003057 private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003058 int result = FLAG_ADJUST_VOLUME;
John Spurlock661f2cf2014-11-17 10:29:10 -05003059 int ringerMode = getRingerModeInternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003060
Eric Laurentbffc3d12012-05-07 17:43:49 -07003061 switch (ringerMode) {
3062 case RINGER_MODE_NORMAL:
3063 if (direction == AudioManager.ADJUST_LOWER) {
3064 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07003065 // "step" is the delta in internal index units corresponding to a
3066 // change of 1 in UI index units.
3067 // Because of rounding when rescaling from one stream index range to its alias
3068 // index range, we cannot simply test oldIndex == step:
3069 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
3070 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003071 ringerMode = RINGER_MODE_VIBRATE;
3072 }
3073 } else {
Eric Laurent24482012012-05-10 09:41:17 -07003074 // (oldIndex < step) is equivalent to (old UI index == 0)
John Spurlock86005342014-05-23 11:58:00 -04003075 if ((oldIndex < step)
3076 && VOLUME_SETS_RINGER_MODE_SILENT
3077 && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003078 ringerMode = RINGER_MODE_SILENT;
3079 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07003080 }
RoboErik5452e252015-02-06 15:33:53 -08003081 } else if (direction == AudioManager.ADJUST_TOGGLE_MUTE
3082 || direction == AudioManager.ADJUST_MUTE) {
3083 if (mHasVibrator) {
3084 ringerMode = RINGER_MODE_VIBRATE;
3085 } else {
3086 ringerMode = RINGER_MODE_SILENT;
3087 }
3088 // Setting the ringer mode will toggle mute
3089 result &= ~FLAG_ADJUST_VOLUME;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003090 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003091 break;
3092 case RINGER_MODE_VIBRATE:
3093 if (!mHasVibrator) {
3094 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
3095 "but no vibrator is present");
3096 break;
3097 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003098 if ((direction == AudioManager.ADJUST_LOWER)) {
RoboErik5452e252015-02-06 15:33:53 -08003099 // This is the case we were muted with the volume turned up
3100 if (oldIndex >= 2 * step && isMuted) {
3101 ringerMode = RINGER_MODE_NORMAL;
3102 } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
John Spurlock795a5142014-12-08 14:09:35 -05003103 if (VOLUME_SETS_RINGER_MODE_SILENT) {
3104 ringerMode = RINGER_MODE_SILENT;
3105 } else {
3106 result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
3107 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003108 }
RoboErik5452e252015-02-06 15:33:53 -08003109 } else if (direction == AudioManager.ADJUST_RAISE
3110 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3111 || direction == AudioManager.ADJUST_UNMUTE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003112 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07003113 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003114 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003115 break;
3116 case RINGER_MODE_SILENT:
RoboErik5452e252015-02-06 15:33:53 -08003117 if (direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
3118 // This is the case we were muted with the volume turned up
3119 ringerMode = RINGER_MODE_NORMAL;
3120 } else if (direction == AudioManager.ADJUST_RAISE
3121 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3122 || direction == AudioManager.ADJUST_UNMUTE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003123 if (PREVENT_VOLUME_ADJUSTMENT_IF_SILENT) {
3124 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003125 } else {
RoboErik5452e252015-02-06 15:33:53 -08003126 if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003127 ringerMode = RINGER_MODE_VIBRATE;
3128 } else {
RoboErik5452e252015-02-06 15:33:53 -08003129 // If we don't have a vibrator or they were toggling mute
3130 // go straight back to normal.
John Spurlocka11b4af2014-06-01 11:52:23 -04003131 ringerMode = RINGER_MODE_NORMAL;
3132 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003133 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05003134 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003135 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003136 break;
3137 default:
3138 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
3139 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003140 }
3141
John Spurlock661f2cf2014-11-17 10:29:10 -05003142 setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003143
Eric Laurent25101b02011-02-02 09:33:30 -08003144 mPrevVolDirection = direction;
3145
John Spurlocka11b4af2014-06-01 11:52:23 -04003146 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003147 }
3148
John Spurlock3346a802014-05-20 16:25:37 -04003149 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003150 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07003151 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003152 }
3153
Eric Laurent5b4e6542010-03-19 20:02:21 -07003154 private boolean isStreamMutedByRingerMode(int streamType) {
3155 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
3156 }
3157
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003158 boolean updateRingerModeAffectedStreams() {
3159 int ringerModeAffectedStreams;
3160 // make sure settings for ringer mode are consistent with device type: non voice capable
3161 // devices (tablets) include media stream in silent mode whereas phones don't.
3162 ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
3163 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3164 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
3165 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
3166 UserHandle.USER_CURRENT);
3167
3168 // ringtone, notification and system streams are always affected by ringer mode
3169 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
3170 (1 << AudioSystem.STREAM_NOTIFICATION)|
3171 (1 << AudioSystem.STREAM_SYSTEM);
3172
Eric Laurent212532b2014-07-21 15:43:18 -07003173 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003174 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -07003175 ringerModeAffectedStreams = 0;
3176 break;
3177 default:
John Spurlock77e54d92014-08-11 12:16:24 -04003178 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
Eric Laurent212532b2014-07-21 15:43:18 -07003179 break;
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003180 }
Eric Laurent212532b2014-07-21 15:43:18 -07003181
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003182 synchronized (mCameraSoundForced) {
3183 if (mCameraSoundForced) {
3184 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3185 } else {
3186 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3187 }
3188 }
3189 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
3190 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
3191 } else {
3192 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
3193 }
3194
3195 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3196 Settings.System.putIntForUser(mContentResolver,
3197 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3198 ringerModeAffectedStreams,
3199 UserHandle.USER_CURRENT);
3200 mRingerModeAffectedStreams = ringerModeAffectedStreams;
3201 return true;
3202 }
3203 return false;
3204 }
3205
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05003206 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003207 public boolean isStreamAffectedByMute(int streamType) {
3208 return (mMuteAffectedStreams & (1 << streamType)) != 0;
3209 }
3210
3211 private void ensureValidDirection(int direction) {
RoboErik4197cb62015-01-21 15:45:32 -08003212 switch (direction) {
3213 case AudioManager.ADJUST_LOWER:
3214 case AudioManager.ADJUST_RAISE:
3215 case AudioManager.ADJUST_SAME:
3216 case AudioManager.ADJUST_MUTE:
3217 case AudioManager.ADJUST_UNMUTE:
3218 case AudioManager.ADJUST_TOGGLE_MUTE:
3219 break;
3220 default:
3221 throw new IllegalArgumentException("Bad direction " + direction);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003222 }
3223 }
3224
Lei Zhang6c798972012-03-02 11:40:12 -08003225 private void ensureValidSteps(int steps) {
3226 if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
3227 throw new IllegalArgumentException("Bad volume adjust steps " + steps);
3228 }
3229 }
3230
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003231 private void ensureValidStreamType(int streamType) {
3232 if (streamType < 0 || streamType >= mStreamStates.length) {
3233 throw new IllegalArgumentException("Bad stream type " + streamType);
3234 }
3235 }
3236
RoboErik4197cb62015-01-21 15:45:32 -08003237 private boolean isMuteAdjust(int adjust) {
3238 return adjust == AudioManager.ADJUST_MUTE || adjust == AudioManager.ADJUST_UNMUTE
3239 || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
3240 }
3241
Eric Laurent6d517662012-04-23 18:42:39 -07003242 private boolean isInCommunication() {
Nancy Chen0eb1e402014-08-21 22:52:29 -07003243 boolean IsInCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003244
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003245 TelecomManager telecomManager =
3246 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
Eric Laurent38edfda2014-12-18 17:38:04 -08003247
3248 final long ident = Binder.clearCallingIdentity();
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003249 IsInCall = telecomManager.isInCall();
Eric Laurent38edfda2014-12-18 17:38:04 -08003250 Binder.restoreCallingIdentity(ident);
Santos Cordon9eb45932014-06-27 12:28:43 -07003251
Nancy Chen0eb1e402014-08-21 22:52:29 -07003252 return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
Eric Laurent6d517662012-04-23 18:42:39 -07003253 }
Eric Laurent25101b02011-02-02 09:33:30 -08003254
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003255 /**
3256 * For code clarity for getActiveStreamType(int)
3257 * @param delay_ms max time since last STREAM_MUSIC activity to consider
3258 * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
3259 * in the last "delay_ms" ms.
3260 */
3261 private boolean isAfMusicActiveRecently(int delay_ms) {
3262 return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
3263 || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
3264 }
3265
Eric Laurent6d517662012-04-23 18:42:39 -07003266 private int getActiveStreamType(int suggestedStreamType) {
Eric Laurent212532b2014-07-21 15:43:18 -07003267 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003268 case AudioSystem.PLATFORM_VOICE:
Eric Laurent6d517662012-04-23 18:42:39 -07003269 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003270 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3271 == AudioSystem.FORCE_BT_SCO) {
3272 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
3273 return AudioSystem.STREAM_BLUETOOTH_SCO;
3274 } else {
3275 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
3276 return AudioSystem.STREAM_VOICE_CALL;
3277 }
Eric Laurent25101b02011-02-02 09:33:30 -08003278 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003279 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003280 if (DEBUG_VOL)
3281 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3282 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003283 } else {
3284 if (DEBUG_VOL)
3285 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
3286 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003287 }
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003288 } else if (isAfMusicActiveRecently(0)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003289 if (DEBUG_VOL)
3290 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3291 return AudioSystem.STREAM_MUSIC;
Eric Laurent25101b02011-02-02 09:33:30 -08003292 }
Eric Laurent212532b2014-07-21 15:43:18 -07003293 break;
John Spurlock61560172015-02-06 19:46:04 -05003294 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -07003295 if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
RoboErik2811dd32014-08-12 09:48:13 -07003296 // TV always defaults to STREAM_MUSIC
Eric Laurent212532b2014-07-21 15:43:18 -07003297 return AudioSystem.STREAM_MUSIC;
Eric Laurent212532b2014-07-21 15:43:18 -07003298 }
3299 break;
3300 default:
Eric Laurent6d517662012-04-23 18:42:39 -07003301 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003302 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3303 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003304 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08003305 return AudioSystem.STREAM_BLUETOOTH_SCO;
3306 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003307 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08003308 return AudioSystem.STREAM_VOICE_CALL;
3309 }
3310 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003311 StreamOverride.sDelayMs) ||
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003312 AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003313 StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003314 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08003315 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003316 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003317 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003318 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
3319 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003320 } else {
John Spurlockeb1d88d2014-07-19 14:49:19 -04003321 if (DEBUG_VOL) Log.v(TAG,
3322 "getActiveStreamType: using STREAM_NOTIFICATION as default");
3323 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003324 }
Joe Onoratoc7fcba42011-01-05 16:53:11 -08003325 }
Eric Laurent212532b2014-07-21 15:43:18 -07003326 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003327 }
Eric Laurent212532b2014-07-21 15:43:18 -07003328 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
3329 + suggestedStreamType);
3330 return suggestedStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003331 }
3332
John Spurlockbcc10872014-11-28 15:29:21 -05003333 private void broadcastRingerMode(String action, int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003334 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05003335 Intent broadcast = new Intent(action);
Glenn Kastenba195eb2011-12-13 09:30:40 -08003336 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003337 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
3338 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003339 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003340 }
3341
3342 private void broadcastVibrateSetting(int vibrateType) {
3343 // Send broadcast
3344 if (ActivityManagerNative.isSystemReady()) {
3345 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
3346 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
3347 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003348 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003349 }
3350 }
3351
3352 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003353 /**
3354 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
3355 * Note that the wake lock needs to be released after the message has been handled.
3356 */
3357 private void queueMsgUnderWakeLock(Handler handler, int msg,
3358 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003359 final long ident = Binder.clearCallingIdentity();
3360 // Always acquire the wake lock as AudioService because it is released by the
3361 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003362 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003363 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003364 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
3365 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003366
Eric Laurentafbb0472011-12-15 09:04:23 -08003367 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003368 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003369
3370 if (existingMsgPolicy == SENDMSG_REPLACE) {
3371 handler.removeMessages(msg);
3372 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
3373 return;
3374 }
Eric Laurentadbe8bf2014-11-03 18:26:32 -08003375 synchronized (mLastDeviceConnectMsgTime) {
3376 long time = SystemClock.uptimeMillis() + delay;
3377 handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
3378 if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
3379 msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
3380 msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
3381 mLastDeviceConnectMsgTime = time;
3382 }
3383 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003384 }
3385
3386 boolean checkAudioSettingsPermission(String method) {
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07003387 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003388 == PackageManager.PERMISSION_GRANTED) {
3389 return true;
3390 }
3391 String msg = "Audio Settings Permission Denial: " + method + " from pid="
3392 + Binder.getCallingPid()
3393 + ", uid=" + Binder.getCallingUid();
3394 Log.w(TAG, msg);
3395 return false;
3396 }
3397
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003398 private int getDeviceForStream(int stream) {
3399 int device = AudioSystem.getDevicesForStream(stream);
3400 if ((device & (device - 1)) != 0) {
3401 // Multiple device selection is either:
3402 // - speaker + one other device: give priority to speaker in this case.
3403 // - one A2DP device + another device: happens with duplicated output. In this case
3404 // retain the device on the A2DP output as the other must not correspond to an active
3405 // selection if not the speaker.
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003406 // - HDMI-CEC system audio mode only output: give priority to available item in order.
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003407 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
3408 device = AudioSystem.DEVICE_OUT_SPEAKER;
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003409 } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
3410 device = AudioSystem.DEVICE_OUT_HDMI_ARC;
3411 } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
3412 device = AudioSystem.DEVICE_OUT_SPDIF;
3413 } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
3414 device = AudioSystem.DEVICE_OUT_AUX_LINE;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003415 } else {
3416 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
3417 }
3418 }
3419 return device;
3420 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003421
Paul McLean10804eb2015-01-28 11:16:35 -08003422 /*
3423 * A class just for packaging up a set of connection parameters.
3424 */
3425 private class WiredDeviceConnectionState {
3426 public int mType;
3427 public int mState;
3428 public String mAddress;
3429 public String mName;
3430
3431 public WiredDeviceConnectionState(int type, int state, String address, String name) {
3432 mType = type;
3433 mState = state;
3434 mAddress = address;
3435 mName = name;
3436 }
3437 }
3438
3439 public void setWiredDeviceConnectionState(int type, int state, String address,
3440 String name) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003441 synchronized (mConnectedDevices) {
Paul McLean10804eb2015-01-28 11:16:35 -08003442 int delay = checkSendBecomingNoisyIntent(type, state);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003443 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003444 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Paul McLean10804eb2015-01-28 11:16:35 -08003445 0,
3446 0,
3447 new WiredDeviceConnectionState(type, state, address, name),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003448 delay);
3449 }
3450 }
3451
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003452 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003453 {
3454 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003455 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
3456 throw new IllegalArgumentException("invalid profile " + profile);
3457 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003458 synchronized (mConnectedDevices) {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003459 if (profile == BluetoothProfile.A2DP) {
3460 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3461 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
3462 } else {
3463 delay = 0;
3464 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003465 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003466 (profile == BluetoothProfile.A2DP ?
3467 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003468 state,
3469 0,
3470 device,
3471 delay);
3472 }
3473 return delay;
3474 }
3475
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003476 ///////////////////////////////////////////////////////////////////////////
3477 // Inner classes
3478 ///////////////////////////////////////////////////////////////////////////
3479
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003480 // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
3481 // 1 mScoclient OR mSafeMediaVolumeState
3482 // 2 mSetModeDeathHandlers
3483 // 3 mSettingsLock
3484 // 4 VolumeStreamState.class
3485 // 5 mCameraSoundForced
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003486 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003487 private final int mStreamType;
3488
RoboErik4197cb62015-01-21 15:45:32 -08003489 private boolean mIsMuted;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003490 private String mVolumeIndexSettingName;
Eric Laurenta553c252009-07-17 12:17:14 -07003491 private int mIndexMax;
John Spurlock2bb02ec2015-03-02 13:13:06 -05003492 private final SparseIntArray mIndexMap = new SparseIntArray(8);
John Spurlockf63860c2015-02-19 09:46:27 -05003493 private final Intent mVolumeChanged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003494
Eric Laurenta553c252009-07-17 12:17:14 -07003495 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003496
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003497 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003498
3499 mStreamType = streamType;
Jared Suttles59820132009-08-13 21:50:52 -05003500 mIndexMax = MAX_STREAM_VOLUME[streamType];
Eric Laurenta553c252009-07-17 12:17:14 -07003501 AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
3502 mIndexMax *= 10;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003503
Eric Laurent33902db2012-10-07 16:15:07 -07003504 readSettings();
John Spurlockf63860c2015-02-19 09:46:27 -05003505 mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
3506 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003507 }
3508
Eric Laurent42b041e2013-03-29 11:36:03 -07003509 public String getSettingNameForDevice(int device) {
3510 String name = mVolumeIndexSettingName;
Eric Laurent948d3272014-05-16 15:18:45 -07003511 String suffix = AudioSystem.getOutputDeviceName(device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003512 if (suffix.isEmpty()) {
3513 return name;
3514 }
3515 return name + "_" + suffix;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003516 }
3517
Eric Laurentfdbee862014-05-12 15:26:12 -07003518 public void readSettings() {
3519 synchronized (VolumeStreamState.class) {
Wally Yauda392902014-11-28 12:40:30 -08003520 // force maximum volume on all streams if fixed volume property
3521 // or master volume property is set
3522 if (mUseFixedVolume || mUseMasterVolume) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003523 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07003524 return;
3525 }
3526 // do not read system stream volume from settings: this stream is always aliased
3527 // to another stream type and its volume is never persisted. Values in settings can
3528 // only be stale values
3529 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3530 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
John Spurlock61560172015-02-06 19:46:04 -05003531 int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
Eric Laurentfdbee862014-05-12 15:26:12 -07003532 synchronized (mCameraSoundForced) {
3533 if (mCameraSoundForced) {
3534 index = mIndexMax;
3535 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003536 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003537 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003538 return;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003539 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003540
Eric Laurentfdbee862014-05-12 15:26:12 -07003541 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
3542
3543 for (int i = 0; remainingDevices != 0; i++) {
3544 int device = (1 << i);
3545 if ((device & remainingDevices) == 0) {
3546 continue;
3547 }
3548 remainingDevices &= ~device;
3549
3550 // retrieve current volume for device
3551 String name = getSettingNameForDevice(device);
3552 // if no volume stored for current stream and device, use default volume if default
3553 // device, continue otherwise
3554 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
John Spurlock61560172015-02-06 19:46:04 -05003555 AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
Eric Laurentfdbee862014-05-12 15:26:12 -07003556 int index = Settings.System.getIntForUser(
3557 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3558 if (index == -1) {
3559 continue;
3560 }
3561
John Spurlock2bb02ec2015-03-02 13:13:06 -05003562 mIndexMap.put(device, getValidIndex(10 * index));
Eric Laurentdd45d012012-10-08 09:04:34 -07003563 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003564 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003565 }
3566
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003567 // must be called while synchronized VolumeStreamState.class
3568 public void applyDeviceVolume_syncVSS(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003569 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003570 if (mIsMuted) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003571 index = 0;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003572 } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported)
3573 || ((device & mFullVolumeDevices) != 0)) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003574 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07003575 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07003576 index = (getIndex(device) + 5)/10;
3577 }
3578 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003579 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003580
Eric Laurentfdbee862014-05-12 15:26:12 -07003581 public void applyAllVolumes() {
3582 synchronized (VolumeStreamState.class) {
3583 // apply default volume first: by convention this will reset all
3584 // devices volumes in audio policy manager to the supplied value
3585 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003586 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003587 index = 0;
3588 } else {
3589 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3590 }
3591 AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3592 // then apply device specific volumes
John Spurlock2bb02ec2015-03-02 13:13:06 -05003593 for (int i = 0; i < mIndexMap.size(); i++) {
3594 int device = mIndexMap.keyAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07003595 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
RoboErik4197cb62015-01-21 15:45:32 -08003596 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003597 index = 0;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003598 } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3599 mAvrcpAbsVolSupported)
3600 || ((device & mFullVolumeDevices) != 0))
3601 {
Eric Laurentfdbee862014-05-12 15:26:12 -07003602 index = (mIndexMax + 5)/10;
3603 } else {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003604 index = (mIndexMap.valueAt(i) + 5)/10;
Eric Laurentfdbee862014-05-12 15:26:12 -07003605 }
3606 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07003607 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003608 }
3609 }
3610 }
3611
3612 public boolean adjustIndex(int deltaIndex, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003613 return setIndex(getIndex(device) + deltaIndex,
3614 device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003615 }
3616
Eric Laurentfdbee862014-05-12 15:26:12 -07003617 public boolean setIndex(int index, int device) {
John Spurlockf63860c2015-02-19 09:46:27 -05003618 boolean changed = false;
3619 int oldIndex;
Eric Laurentfdbee862014-05-12 15:26:12 -07003620 synchronized (VolumeStreamState.class) {
John Spurlockf63860c2015-02-19 09:46:27 -05003621 oldIndex = getIndex(device);
Eric Laurentfdbee862014-05-12 15:26:12 -07003622 index = getValidIndex(index);
3623 synchronized (mCameraSoundForced) {
3624 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3625 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07003626 }
3627 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003628 mIndexMap.put(device, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003629
John Spurlockf63860c2015-02-19 09:46:27 -05003630 changed = oldIndex != index;
3631 if (changed) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003632 // Apply change to all streams using this one as alias
3633 // if changing volume of current device, also change volume of current
3634 // device on aliased stream
3635 boolean currentDevice = (device == getDeviceForStream(mStreamType));
3636 int numStreamTypes = AudioSystem.getNumStreamTypes();
3637 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3638 if (streamType != mStreamType &&
3639 mStreamVolumeAlias[streamType] == mStreamType) {
3640 int scaledIndex = rescaleIndex(index, mStreamType, streamType);
3641 mStreamStates[streamType].setIndex(scaledIndex,
3642 device);
3643 if (currentDevice) {
3644 mStreamStates[streamType].setIndex(scaledIndex,
3645 getDeviceForStream(streamType));
3646 }
3647 }
3648 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003649 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003650 }
John Spurlockf63860c2015-02-19 09:46:27 -05003651 if (changed) {
3652 oldIndex = (oldIndex + 5) / 10;
3653 index = (index + 5) / 10;
3654 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
3655 mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
3656 sendBroadcastToAll(mVolumeChanged);
3657 }
3658 return changed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003659 }
3660
Eric Laurentfdbee862014-05-12 15:26:12 -07003661 public int getIndex(int device) {
3662 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003663 int index = mIndexMap.get(device, -1);
3664 if (index == -1) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003665 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
John Spurlock2bb02ec2015-03-02 13:13:06 -05003666 index = mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurentfdbee862014-05-12 15:26:12 -07003667 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003668 return index;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003669 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07003670 }
3671
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003672 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07003673 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003674 }
3675
Eric Laurentfdbee862014-05-12 15:26:12 -07003676 public void setAllIndexes(VolumeStreamState srcStream) {
3677 synchronized (VolumeStreamState.class) {
3678 int srcStreamType = srcStream.getStreamType();
3679 // apply default device volume from source stream to all devices first in case
3680 // some devices are present in this stream state but not in source stream state
3681 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003682 index = rescaleIndex(index, srcStreamType, mStreamType);
John Spurlock2bb02ec2015-03-02 13:13:06 -05003683 for (int i = 0; i < mIndexMap.size(); i++) {
3684 mIndexMap.put(mIndexMap.keyAt(i), index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003685 }
3686 // Now apply actual volume for devices in source stream state
John Spurlock2bb02ec2015-03-02 13:13:06 -05003687 SparseIntArray srcMap = srcStream.mIndexMap;
3688 for (int i = 0; i < srcMap.size(); i++) {
3689 int device = srcMap.keyAt(i);
3690 index = srcMap.valueAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07003691 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07003692
Eric Laurentfdbee862014-05-12 15:26:12 -07003693 setIndex(index, device);
3694 }
Eric Laurent6d517662012-04-23 18:42:39 -07003695 }
3696 }
3697
Eric Laurentfdbee862014-05-12 15:26:12 -07003698 public void setAllIndexesToMax() {
3699 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003700 for (int i = 0; i < mIndexMap.size(); i++) {
3701 mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07003702 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003703 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003704 }
3705
RoboErik4197cb62015-01-21 15:45:32 -08003706 public void mute(boolean state) {
John Spurlock22b9ee12015-02-18 22:51:44 -05003707 boolean changed = false;
Eric Laurentfdbee862014-05-12 15:26:12 -07003708 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08003709 if (state != mIsMuted) {
John Spurlock22b9ee12015-02-18 22:51:44 -05003710 changed = true;
RoboErik4197cb62015-01-21 15:45:32 -08003711 mIsMuted = state;
John Spurlock22b9ee12015-02-18 22:51:44 -05003712
RoboErik4197cb62015-01-21 15:45:32 -08003713 // Set the new mute volume. This propagates the values to
3714 // the audio system, otherwise the volume won't be changed
3715 // at the lower level.
3716 sendMsg(mAudioHandler,
3717 MSG_SET_ALL_VOLUMES,
3718 SENDMSG_QUEUE,
3719 0,
3720 0,
3721 this, 0);
Eric Laurentfdbee862014-05-12 15:26:12 -07003722 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003723 }
John Spurlock22b9ee12015-02-18 22:51:44 -05003724 if (changed) {
3725 // Stream mute changed, fire the intent.
3726 Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
3727 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
3728 intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
3729 sendBroadcastToAll(intent);
3730 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003731 }
3732
Eric Laurent6d517662012-04-23 18:42:39 -07003733 public int getStreamType() {
3734 return mStreamType;
3735 }
3736
Eric Laurent212532b2014-07-21 15:43:18 -07003737 public void checkFixedVolumeDevices() {
3738 synchronized (VolumeStreamState.class) {
3739 // ignore settings for fixed volume devices: volume should always be at max or 0
3740 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003741 for (int i = 0; i < mIndexMap.size(); i++) {
3742 int device = mIndexMap.keyAt(i);
3743 int index = mIndexMap.valueAt(i);
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003744 if (((device & mFullVolumeDevices) != 0)
3745 || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003746 mIndexMap.put(device, mIndexMax);
Eric Laurent212532b2014-07-21 15:43:18 -07003747 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003748 applyDeviceVolume_syncVSS(device);
Eric Laurent212532b2014-07-21 15:43:18 -07003749 }
3750 }
3751 }
3752 }
3753
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003754 private int getValidIndex(int index) {
3755 if (index < 0) {
3756 return 0;
Wally Yauda392902014-11-28 12:40:30 -08003757 } else if (mUseFixedVolume || mUseMasterVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07003758 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003759 }
3760
3761 return index;
3762 }
3763
Eric Laurentbffc3d12012-05-07 17:43:49 -07003764 private void dump(PrintWriter pw) {
RoboErik4197cb62015-01-21 15:45:32 -08003765 pw.print(" Muted: ");
3766 pw.println(mIsMuted);
John Spurlock2b29bc42014-08-26 16:40:35 -04003767 pw.print(" Max: ");
3768 pw.println((mIndexMax + 5) / 10);
Eric Laurentbffc3d12012-05-07 17:43:49 -07003769 pw.print(" Current: ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05003770 for (int i = 0; i < mIndexMap.size(); i++) {
3771 if (i > 0) {
3772 pw.print(", ");
3773 }
3774 final int device = mIndexMap.keyAt(i);
John Spurlock2b29bc42014-08-26 16:40:35 -04003775 pw.print(Integer.toHexString(device));
3776 final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
3777 : AudioSystem.getOutputDeviceName(device);
3778 if (!deviceName.isEmpty()) {
3779 pw.print(" (");
3780 pw.print(deviceName);
3781 pw.print(")");
3782 }
3783 pw.print(": ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05003784 final int index = (mIndexMap.valueAt(i) + 5) / 10;
John Spurlock2b29bc42014-08-26 16:40:35 -04003785 pw.print(index);
Eric Laurentbffc3d12012-05-07 17:43:49 -07003786 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003787 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003788 }
3789
3790 /** Thread that handles native AudioSystem control. */
3791 private class AudioSystemThread extends Thread {
3792 AudioSystemThread() {
3793 super("AudioService");
3794 }
3795
3796 @Override
3797 public void run() {
3798 // Set this thread up so the handler will work on it
3799 Looper.prepare();
3800
3801 synchronized(AudioService.this) {
3802 mAudioHandler = new AudioHandler();
3803
3804 // Notify that the handler has been created
3805 AudioService.this.notify();
3806 }
3807
3808 // Listen for volume change requests that are set by VolumePanel
3809 Looper.loop();
3810 }
3811 }
3812
3813 /** Handles internal volume messages in separate volume thread. */
3814 private class AudioHandler extends Handler {
3815
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003816 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003817
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003818 synchronized (VolumeStreamState.class) {
3819 // Apply volume
3820 streamState.applyDeviceVolume_syncVSS(device);
Eric Laurenta553c252009-07-17 12:17:14 -07003821
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003822 // Apply change to all streams using this one as alias
3823 int numStreamTypes = AudioSystem.getNumStreamTypes();
3824 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3825 if (streamType != streamState.mStreamType &&
3826 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
3827 // Make sure volume is also maxed out on A2DP device for aliased stream
3828 // that may have a different device selected
3829 int streamDevice = getDeviceForStream(streamType);
3830 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
3831 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
3832 mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
3833 }
3834 mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
Eric Laurentcd772d02013-10-30 18:31:07 -07003835 }
Eric Laurenta553c252009-07-17 12:17:14 -07003836 }
3837 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003838 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08003839 sendMsg(mAudioHandler,
3840 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08003841 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003842 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07003843 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08003844 streamState,
3845 PERSIST_DELAY);
3846
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003847 }
3848
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003849 private void setAllVolumes(VolumeStreamState streamState) {
3850
3851 // Apply volume
3852 streamState.applyAllVolumes();
3853
3854 // Apply change to all streams using this one as alias
3855 int numStreamTypes = AudioSystem.getNumStreamTypes();
3856 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3857 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07003858 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003859 mStreamStates[streamType].applyAllVolumes();
3860 }
3861 }
3862 }
3863
Eric Laurent42b041e2013-03-29 11:36:03 -07003864 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003865 if (mUseFixedVolume) {
3866 return;
3867 }
Eric Laurent212532b2014-07-21 15:43:18 -07003868 if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
3869 return;
3870 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003871 System.putIntForUser(mContentResolver,
3872 streamState.getSettingNameForDevice(device),
3873 (streamState.getIndex(device) + 5)/ 10,
3874 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003875 }
3876
Glenn Kastenba195eb2011-12-13 09:30:40 -08003877 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003878 if (mUseFixedVolume) {
3879 return;
3880 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07003881 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003882 }
3883
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003884 private boolean onLoadSoundEffects() {
3885 int status;
3886
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003887 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07003888 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003889 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
3890 return false;
3891 }
3892
3893 if (mSoundPool != null) {
3894 return true;
3895 }
3896
3897 loadTouchSoundAssets();
3898
Jean-Michel Trivi55a30c42014-07-20 17:56:11 -07003899 mSoundPool = new SoundPool.Builder()
3900 .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
3901 .setAudioAttributes(new AudioAttributes.Builder()
3902 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
3903 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
3904 .build())
3905 .build();
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003906 mSoundPoolCallBack = null;
3907 mSoundPoolListenerThread = new SoundPoolListenerThread();
3908 mSoundPoolListenerThread.start();
3909 int attempts = 3;
3910 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
3911 try {
3912 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07003913 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003914 } catch (InterruptedException e) {
3915 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
3916 }
3917 }
3918
3919 if (mSoundPoolCallBack == null) {
3920 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
3921 if (mSoundPoolLooper != null) {
3922 mSoundPoolLooper.quit();
3923 mSoundPoolLooper = null;
3924 }
3925 mSoundPoolListenerThread = null;
3926 mSoundPool.release();
3927 mSoundPool = null;
3928 return false;
3929 }
3930 /*
3931 * poolId table: The value -1 in this table indicates that corresponding
3932 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
3933 * Once loaded, the value in poolId is the sample ID and the same
3934 * sample can be reused for another effect using the same file.
3935 */
3936 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3937 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3938 poolId[fileIdx] = -1;
3939 }
3940 /*
3941 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
3942 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
3943 * this indicates we have a valid sample loaded for this effect.
3944 */
3945
3946 int numSamples = 0;
3947 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3948 // Do not load sample if this effect uses the MediaPlayer
3949 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
3950 continue;
3951 }
3952 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
3953 String filePath = Environment.getRootDirectory()
3954 + SOUND_EFFECTS_PATH
3955 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
3956 int sampleId = mSoundPool.load(filePath, 0);
3957 if (sampleId <= 0) {
3958 Log.w(TAG, "Soundpool could not load file: "+filePath);
3959 } else {
3960 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
3961 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
3962 numSamples++;
3963 }
3964 } else {
3965 SOUND_EFFECT_FILES_MAP[effect][1] =
3966 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
3967 }
3968 }
3969 // wait for all samples to be loaded
3970 if (numSamples > 0) {
3971 mSoundPoolCallBack.setSamples(poolId);
3972
3973 attempts = 3;
3974 status = 1;
3975 while ((status == 1) && (attempts-- > 0)) {
3976 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07003977 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003978 status = mSoundPoolCallBack.status();
3979 } catch (InterruptedException e) {
3980 Log.w(TAG, "Interrupted while waiting sound pool callback.");
3981 }
3982 }
3983 } else {
3984 status = -1;
3985 }
3986
3987 if (mSoundPoolLooper != null) {
3988 mSoundPoolLooper.quit();
3989 mSoundPoolLooper = null;
3990 }
3991 mSoundPoolListenerThread = null;
3992 if (status != 0) {
3993 Log.w(TAG,
3994 "onLoadSoundEffects(), Error "+status+ " while loading samples");
3995 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3996 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
3997 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3998 }
3999 }
4000
4001 mSoundPool.release();
4002 mSoundPool = null;
4003 }
4004 }
4005 return (status == 0);
4006 }
4007
4008 /**
4009 * Unloads samples from the sound pool.
4010 * This method can be called to free some memory when
4011 * sound effects are disabled.
4012 */
4013 private void onUnloadSoundEffects() {
4014 synchronized (mSoundEffectsLock) {
4015 if (mSoundPool == null) {
4016 return;
4017 }
4018
4019 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4020 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4021 poolId[fileIdx] = 0;
4022 }
4023
4024 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4025 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
4026 continue;
4027 }
4028 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
4029 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
4030 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4031 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
4032 }
4033 }
4034 mSoundPool.release();
4035 mSoundPool = null;
4036 }
4037 }
4038
4039 private void onPlaySoundEffect(int effectType, int volume) {
4040 synchronized (mSoundEffectsLock) {
4041
4042 onLoadSoundEffects();
4043
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004044 if (mSoundPool == null) {
4045 return;
4046 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004047 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08004048 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004049 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07004050 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004051 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07004052 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004053 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004054
4055 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004056 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
4057 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004058 } else {
4059 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004060 try {
Eric Laurente78fced2013-03-15 16:03:47 -07004061 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
4062 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004063 mediaPlayer.setDataSource(filePath);
4064 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
4065 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08004066 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004067 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
4068 public void onCompletion(MediaPlayer mp) {
4069 cleanupPlayer(mp);
4070 }
4071 });
4072 mediaPlayer.setOnErrorListener(new OnErrorListener() {
4073 public boolean onError(MediaPlayer mp, int what, int extra) {
4074 cleanupPlayer(mp);
4075 return true;
4076 }
4077 });
4078 mediaPlayer.start();
4079 } catch (IOException ex) {
4080 Log.w(TAG, "MediaPlayer IOException: "+ex);
4081 } catch (IllegalArgumentException ex) {
4082 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
4083 } catch (IllegalStateException ex) {
4084 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004085 }
4086 }
4087 }
4088 }
4089
4090 private void cleanupPlayer(MediaPlayer mp) {
4091 if (mp != null) {
4092 try {
4093 mp.stop();
4094 mp.release();
4095 } catch (IllegalStateException ex) {
4096 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
4097 }
4098 }
4099 }
4100
Eric Laurentfa640152011-03-12 15:59:51 -08004101 private void setForceUse(int usage, int config) {
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004102 synchronized (mConnectedDevices) {
4103 setForceUseInt_SyncDevices(usage, config);
4104 }
Eric Laurentfa640152011-03-12 15:59:51 -08004105 }
4106
Eric Laurent05274f32012-11-29 12:48:18 -08004107 private void onPersistSafeVolumeState(int state) {
4108 Settings.Global.putInt(mContentResolver,
4109 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
4110 state);
4111 }
4112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004113 @Override
4114 public void handleMessage(Message msg) {
Eric Laurentafbb0472011-12-15 09:04:23 -08004115 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004116
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004117 case MSG_SET_DEVICE_VOLUME:
4118 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
4119 break;
4120
4121 case MSG_SET_ALL_VOLUMES:
4122 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004123 break;
4124
4125 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07004126 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004127 break;
4128
Mike Lockwood5c55a052011-12-15 17:21:44 -05004129 case MSG_PERSIST_MASTER_VOLUME:
Eric Laurent83a017b2013-03-19 18:15:31 -07004130 if (mUseFixedVolume) {
4131 return;
4132 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004133 Settings.System.putFloatForUser(mContentResolver,
4134 Settings.System.VOLUME_MASTER,
RoboErik8a2cfc32014-05-16 11:19:38 -07004135 msg.arg1 / (float)1000.0,
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004136 UserHandle.USER_CURRENT);
Mike Lockwood5c55a052011-12-15 17:21:44 -05004137 break;
4138
Justin Koh57978ed2012-04-03 17:37:58 -07004139 case MSG_PERSIST_MASTER_VOLUME_MUTE:
Eric Laurent83a017b2013-03-19 18:15:31 -07004140 if (mUseFixedVolume) {
4141 return;
4142 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004143 Settings.System.putIntForUser(mContentResolver,
4144 Settings.System.VOLUME_MASTER_MUTE,
4145 msg.arg1,
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004146 msg.arg2);
Justin Koh57978ed2012-04-03 17:37:58 -07004147 break;
4148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004149 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08004150 // note that the value persisted is the current ringer mode, not the
4151 // value of ringer mode as of the time the request was made to persist
John Spurlock661f2cf2014-11-17 10:29:10 -05004152 persistRingerMode(getRingerModeInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004153 break;
4154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004155 case MSG_MEDIA_SERVER_DIED:
Eric Laurenteb4b8a22014-07-21 13:10:07 -07004156 if (!mSystemReady ||
4157 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Eric Laurent89e74ba2009-09-30 18:26:36 -07004158 Log.e(TAG, "Media server died.");
Eric Laurentafbb0472011-12-15 09:04:23 -08004159 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent89e74ba2009-09-30 18:26:36 -07004160 null, 500);
Eric Laurentdfb881f2013-07-18 14:41:39 -07004161 break;
Eric Laurent89e74ba2009-09-30 18:26:36 -07004162 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004163 Log.e(TAG, "Media server started.");
Eric Laurentdfb881f2013-07-18 14:41:39 -07004164
Eric Laurent3c652ca2010-06-21 20:46:26 -07004165 // indicate to audio HAL that we start the reconfiguration phase after a media
4166 // server crash
Eric Laurentdfb881f2013-07-18 14:41:39 -07004167 // Note that we only execute this when the media server
Eric Laurent3c652ca2010-06-21 20:46:26 -07004168 // process restarts after a crash, not the first time it is started.
4169 AudioSystem.setParameters("restarting=true");
4170
Glenn Kastenfd116ad2013-07-12 17:10:39 -07004171 readAndSetLowRamDevice();
4172
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004173 // Restore device connection states
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004174 synchronized (mConnectedDevices) {
4175 Set set = mConnectedDevices.entrySet();
4176 Iterator i = set.iterator();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004177 while (i.hasNext()) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004178 Map.Entry device = (Map.Entry)i.next();
4179 AudioSystem.setDeviceConnectionState(
4180 ((Integer)device.getKey()).intValue(),
4181 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004182 (String)device.getValue(),
4183 "unknown-device");
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004184 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004185 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004186 // Restore call state
4187 AudioSystem.setPhoneState(mMode);
4188
Eric Laurentd5603c12009-08-06 08:49:39 -07004189 // Restore forced usage for communcations and record
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004190 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
Eric Laurentd5603c12009-08-06 08:49:39 -07004191 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
Eric Laurentdd45d012012-10-08 09:04:34 -07004192 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
4193 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004194
Eric Laurenta553c252009-07-17 12:17:14 -07004195 // Restore stream volumes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004196 int numStreamTypes = AudioSystem.getNumStreamTypes();
4197 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004198 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004199 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004200
4201 streamState.applyAllVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004202 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004203
4204 // Restore ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05004205 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3c652ca2010-06-21 20:46:26 -07004206
Mike Lockwood90631542012-01-06 11:20:37 -05004207 // Restore master volume
4208 restoreMasterVolume();
4209
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004210 // Reset device orientation (if monitored for this device)
Eric Laurentd640bd32012-09-28 18:01:48 -07004211 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004212 setOrientationForAudioSystem();
4213 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004214 if (mMonitorRotation) {
4215 setRotationForAudioSystem();
4216 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004217
Eric Laurent78472112012-05-21 08:57:21 -07004218 synchronized (mBluetoothA2dpEnabledLock) {
4219 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
4220 mBluetoothA2dpEnabled ?
4221 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
4222 }
Eric Laurentbff5ca52012-11-02 16:48:26 -07004223
4224 synchronized (mSettingsLock) {
4225 AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
4226 mDockAudioMediaEnabled ?
4227 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
4228 }
Eric Laurent212532b2014-07-21 15:43:18 -07004229 if (mHdmiManager != null) {
4230 synchronized (mHdmiManager) {
4231 if (mHdmiTvClient != null) {
4232 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
4233 }
4234 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004235 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08004236
4237 synchronized (mAudioPolicies) {
4238 for(AudioPolicyProxy policy : mAudioPolicies.values()) {
4239 policy.connectMixes();
4240 }
4241 }
4242
Eric Laurent3c652ca2010-06-21 20:46:26 -07004243 // indicate the end of reconfiguration phase to audio HAL
4244 AudioSystem.setParameters("restarting=false");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004245 break;
4246
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004247 case MSG_UNLOAD_SOUND_EFFECTS:
4248 onUnloadSoundEffects();
4249 break;
4250
Eric Laurent117b7bb2011-01-16 17:07:27 -08004251 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004252 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
4253 // can take several dozens of milliseconds to complete
4254 boolean loaded = onLoadSoundEffects();
4255 if (msg.obj != null) {
4256 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
4257 synchronized (reply) {
4258 reply.mStatus = loaded ? 0 : -1;
4259 reply.notify();
4260 }
4261 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08004262 break;
4263
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004264 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004265 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004266 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004267
4268 case MSG_BTA2DP_DOCK_TIMEOUT:
4269 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004270 synchronized (mConnectedDevices) {
4271 makeA2dpDeviceUnavailableNow( (String) msg.obj );
4272 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004273 break;
Eric Laurentfa640152011-03-12 15:59:51 -08004274
4275 case MSG_SET_FORCE_USE:
Eric Laurentc390bed2012-07-03 12:24:05 -07004276 case MSG_SET_FORCE_BT_A2DP_USE:
Eric Laurentfa640152011-03-12 15:59:51 -08004277 setForceUse(msg.arg1, msg.arg2);
4278 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07004279
Eric Laurentdc03c612011-04-01 10:59:41 -07004280 case MSG_BT_HEADSET_CNCT_FAILED:
4281 resetBluetoothSco();
4282 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004283
4284 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
Paul McLean10804eb2015-01-28 11:16:35 -08004285 { WiredDeviceConnectionState connectState =
4286 (WiredDeviceConnectionState)msg.obj;
4287 onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
4288 connectState.mAddress, connectState.mName);
4289 mAudioEventWakeLock.release();
4290 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004291 break;
4292
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004293 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
4294 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
4295 mAudioEventWakeLock.release();
4296 break;
4297
4298 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
4299 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004300 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004301 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004302
4303 case MSG_REPORT_NEW_ROUTES: {
4304 int N = mRoutesObservers.beginBroadcast();
4305 if (N > 0) {
4306 AudioRoutesInfo routes;
4307 synchronized (mCurAudioRoutes) {
4308 routes = new AudioRoutesInfo(mCurAudioRoutes);
4309 }
4310 while (N > 0) {
4311 N--;
4312 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
4313 try {
4314 obs.dispatchAudioRoutesChanged(routes);
4315 } catch (RemoteException e) {
4316 }
4317 }
4318 }
4319 mRoutesObservers.finishBroadcast();
4320 break;
4321 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004322
Eric Laurentc34dcc12012-09-10 13:51:52 -07004323 case MSG_CHECK_MUSIC_ACTIVE:
4324 onCheckMusicActive();
4325 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004326
4327 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
4328 onSendBecomingNoisyIntent();
4329 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07004330
4331 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
4332 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
4333 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
4334 break;
Eric Laurent05274f32012-11-29 12:48:18 -08004335 case MSG_PERSIST_SAFE_VOLUME_STATE:
4336 onPersistSafeVolumeState(msg.arg1);
4337 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08004338
Eric Laurent2a57ca92013-03-07 17:29:27 -08004339 case MSG_BROADCAST_BT_CONNECTION_STATE:
4340 onBroadcastScoConnectionState(msg.arg1);
4341 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004342
4343 case MSG_SYSTEM_READY:
4344 onSystemReady();
4345 break;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004346
4347 case MSG_PERSIST_MUSIC_ACTIVE_MS:
4348 final int musicActiveMs = msg.arg1;
4349 Settings.Secure.putIntForUser(mContentResolver,
4350 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
4351 UserHandle.USER_CURRENT);
4352 break;
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004353 case MSG_PERSIST_MICROPHONE_MUTE:
4354 Settings.System.putIntForUser(mContentResolver,
4355 Settings.System.MICROPHONE_MUTE,
4356 msg.arg1,
4357 msg.arg2);
4358 break;
RoboErik5452e252015-02-06 15:33:53 -08004359 case MSG_UNMUTE_STREAM:
4360 onUnmuteStream(msg.arg1, msg.arg2);
4361 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004362 }
4363 }
4364 }
4365
Jason Parekhb1096152009-03-24 17:48:25 -07004366 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07004367
Jason Parekhb1096152009-03-24 17:48:25 -07004368 SettingsObserver() {
4369 super(new Handler());
4370 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4371 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004372 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4373 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07004374 }
4375
4376 @Override
4377 public void onChange(boolean selfChange) {
4378 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08004379 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
4380 // However there appear to be some missing locks around mRingerModeMutedStreams
4381 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
4382 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07004383 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004384 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07004385 /*
4386 * Ensure all stream types that should be affected by ringer mode
4387 * are in the proper state.
4388 */
John Spurlock661f2cf2014-11-17 10:29:10 -05004389 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurenta553c252009-07-17 12:17:14 -07004390 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004391 readDockAudioSettings(mContentResolver);
Eric Laurenta553c252009-07-17 12:17:14 -07004392 }
Jason Parekhb1096152009-03-24 17:48:25 -07004393 }
Jason Parekhb1096152009-03-24 17:48:25 -07004394 }
Eric Laurenta553c252009-07-17 12:17:14 -07004395
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004396 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004397 private void makeA2dpDeviceAvailable(String address) {
Eric Laurent78472112012-05-21 08:57:21 -07004398 // enable A2DP before notifying A2DP connection to avoid unecessary processing in
4399 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004400 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4401 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4402 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Eric Laurent78472112012-05-21 08:57:21 -07004403 setBluetoothA2dpOnInt(true);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004404 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4405 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004406 address,
4407 "a2dp-device");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004408 // Reset A2DP suspend state each time a new sink is connected
4409 AudioSystem.setParameters("A2dpSuspended=false");
4410 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
4411 address);
4412 }
4413
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004414 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004415 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07004416 }
4417
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004418 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004419 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004420 synchronized (mA2dpAvrcpLock) {
4421 mAvrcpAbsVolSupported = false;
4422 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004423 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4424 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004425 address,
4426 "a2dp-device");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004427 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
RoboErik5535ea82014-09-25 14:53:16 -07004428 synchronized (mCurAudioRoutes) {
4429 // Remove A2DP routes as well
John Spurlock61560172015-02-06 19:46:04 -05004430 if (mCurAudioRoutes.bluetoothName != null) {
4431 mCurAudioRoutes.bluetoothName = null;
RoboErik5535ea82014-09-25 14:53:16 -07004432 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4433 SENDMSG_NOOP, 0, 0, null, 0);
4434 }
4435 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004436 }
4437
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004438 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004439 private void makeA2dpDeviceUnavailableLater(String address) {
Eric Laurent3b591262010-04-20 07:01:00 -07004440 // prevent any activity on the A2DP audio output to avoid unwanted
4441 // reconnection of the sink.
4442 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004443 // the device will be made unavailable later, so consider it disconnected right away
4444 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
4445 // send the delayed message to make the device unavailable later
4446 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
4447 mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
4448
4449 }
4450
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004451 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004452 private void makeA2dpSrcAvailable(String address) {
4453 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
4454 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004455 address,
4456 "a2dp-device");
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004457 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
4458 address);
4459 }
4460
4461 // must be called synchronized on mConnectedDevices
4462 private void makeA2dpSrcUnavailable(String address) {
4463 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
4464 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004465 address,
4466 "a2dp-device");
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004467 mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
4468 }
4469
4470 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004471 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004472 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4473 }
4474
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004475 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004476 private boolean hasScheduledA2dpDockTimeout() {
4477 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4478 }
4479
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004480 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004481 {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004482 if (DEBUG_VOL) {
4483 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
4484 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004485 if (btDevice == null) {
4486 return;
4487 }
4488 String address = btDevice.getAddress();
4489 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4490 address = "";
4491 }
John Du5a0cf7a2013-07-19 11:30:34 -07004492
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004493 synchronized (mConnectedDevices) {
4494 boolean isConnected =
4495 (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
4496 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
4497
4498 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4499 if (btDevice.isBluetoothDock()) {
4500 if (state == BluetoothProfile.STATE_DISCONNECTED) {
4501 // introduction of a delay for transient disconnections of docks when
4502 // power is rapidly turned off/on, this message will be canceled if
4503 // we reconnect the dock under a preset delay
4504 makeA2dpDeviceUnavailableLater(address);
4505 // the next time isConnected is evaluated, it will be false for the dock
4506 }
4507 } else {
4508 makeA2dpDeviceUnavailableNow(address);
4509 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07004510 synchronized (mCurAudioRoutes) {
John Spurlock61560172015-02-06 19:46:04 -05004511 if (mCurAudioRoutes.bluetoothName != null) {
4512 mCurAudioRoutes.bluetoothName = null;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004513 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4514 SENDMSG_NOOP, 0, 0, null, 0);
4515 }
4516 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004517 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4518 if (btDevice.isBluetoothDock()) {
4519 // this could be a reconnection after a transient disconnection
4520 cancelA2dpDeviceTimeout();
4521 mDockAddress = address;
4522 } else {
4523 // this could be a connection of another A2DP device before the timeout of
4524 // a dock: cancel the dock timeout, and make the dock unavailable now
4525 if(hasScheduledA2dpDockTimeout()) {
4526 cancelA2dpDeviceTimeout();
4527 makeA2dpDeviceUnavailableNow(mDockAddress);
4528 }
4529 }
4530 makeA2dpDeviceAvailable(address);
Dianne Hackborn632ca412012-06-14 19:34:10 -07004531 synchronized (mCurAudioRoutes) {
4532 String name = btDevice.getAliasName();
John Spurlock61560172015-02-06 19:46:04 -05004533 if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
4534 mCurAudioRoutes.bluetoothName = name;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004535 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4536 SENDMSG_NOOP, 0, 0, null, 0);
4537 }
4538 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004539 }
4540 }
4541 }
4542
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004543 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
4544 {
4545 if (DEBUG_VOL) {
4546 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
4547 }
4548 if (btDevice == null) {
4549 return;
4550 }
4551 String address = btDevice.getAddress();
4552 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4553 address = "";
4554 }
4555
4556 synchronized (mConnectedDevices) {
4557 boolean isConnected =
4558 (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
4559 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));
4560
4561 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4562 makeA2dpSrcUnavailable(address);
4563 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4564 makeA2dpSrcAvailable(address);
4565 }
4566 }
4567 }
4568
John Du5a0cf7a2013-07-19 11:30:34 -07004569 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
4570 // address is not used for now, but may be used when multiple a2dp devices are supported
4571 synchronized (mA2dpAvrcpLock) {
4572 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004573 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07004574 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4575 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4576 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4577 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4578 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07004579 }
4580 }
4581
Paul McLean10804eb2015-01-28 11:16:35 -08004582 private boolean handleDeviceConnection(boolean connect, int device, String address, String deviceName) {
4583 Slog.i(TAG, "handleDeviceConnection(" + connect +
4584 " dev:" + Integer.toHexString(device) +
RoboErik5452e252015-02-06 15:33:53 -08004585 " address:" + address +
Paul McLean10804eb2015-01-28 11:16:35 -08004586 " name:" + deviceName + ")");
Eric Laurent59f48272012-04-05 19:42:21 -07004587 synchronized (mConnectedDevices) {
4588 boolean isConnected = (mConnectedDevices.containsKey(device) &&
Paul McLean10804eb2015-01-28 11:16:35 -08004589 (address.isEmpty() || mConnectedDevices.get(device).equals(address)));
Eric Laurent59f48272012-04-05 19:42:21 -07004590
Paul McLean10804eb2015-01-28 11:16:35 -08004591 if (isConnected && !connect) {
Eric Laurent59f48272012-04-05 19:42:21 -07004592 AudioSystem.setDeviceConnectionState(device,
4593 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004594 address, deviceName);
Eric Laurent59f48272012-04-05 19:42:21 -07004595 mConnectedDevices.remove(device);
4596 return true;
Paul McLean10804eb2015-01-28 11:16:35 -08004597 } else if (!isConnected && connect) {
Eric Laurent59f48272012-04-05 19:42:21 -07004598 AudioSystem.setDeviceConnectionState(device,
4599 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004600 address, deviceName);
4601 mConnectedDevices.put(new Integer(device), address);
Eric Laurent59f48272012-04-05 19:42:21 -07004602 return true;
4603 }
4604 }
4605 return false;
4606 }
4607
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004608 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4609 // sent if none of these devices is connected.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004610 // Access synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004611 int mBecomingNoisyIntentDevices =
4612 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07004613 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07004614 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004615 AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004616
4617 // must be called before removing the device from mConnectedDevices
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004618 // Called synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004619 private int checkSendBecomingNoisyIntent(int device, int state) {
4620 int delay = 0;
4621 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4622 int devices = 0;
4623 for (int dev : mConnectedDevices.keySet()) {
Eric Laurent27c30e42014-08-27 12:36:33 -07004624 if (((dev & AudioSystem.DEVICE_BIT_IN) == 0) &&
4625 ((dev & mBecomingNoisyIntentDevices) != 0)) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004626 devices |= dev;
4627 }
4628 }
4629 if (devices == device) {
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004630 sendMsg(mAudioHandler,
4631 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4632 SENDMSG_REPLACE,
4633 0,
4634 0,
4635 null,
4636 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004637 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004638 }
4639 }
4640
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004641 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
4642 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004643 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004644 synchronized (mLastDeviceConnectMsgTime) {
4645 long time = SystemClock.uptimeMillis();
4646 if (mLastDeviceConnectMsgTime > time) {
Matthew Xiec525cf72015-01-22 20:13:17 -08004647 delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004648 }
4649 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004650 }
4651 return delay;
4652 }
4653
Paul McLean10804eb2015-01-28 11:16:35 -08004654 private void sendDeviceConnectionIntent(int device, int state, String address, String deviceName)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004655 {
Paul McLean10804eb2015-01-28 11:16:35 -08004656 Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
4657 " state:0x" + Integer.toHexString(state) +
4658 " address:" + address +
4659 " name:" + deviceName + ");");
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004660 Intent intent = new Intent();
4661
Paul McLean10804eb2015-01-28 11:16:35 -08004662 intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
4663 intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
4664 intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
4665
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004666 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4667
Dianne Hackborn632ca412012-06-14 19:34:10 -07004668 int connType = 0;
4669
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004670 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004671 connType = AudioRoutesInfo.MAIN_HEADSET;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004672 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4673 intent.putExtra("microphone", 1);
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004674 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
4675 device == AudioSystem.DEVICE_OUT_LINE) {
4676 /*do apps care about line-out vs headphones?*/
Dianne Hackborn632ca412012-06-14 19:34:10 -07004677 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004678 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4679 intent.putExtra("microphone", 0);
Eric Laurent6fa42452015-01-09 15:09:40 -08004680 } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
4681 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004682 connType = AudioRoutesInfo.MAIN_HDMI;
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004683 configureHdmiPlugIntent(intent, state);
Paul McLean10804eb2015-01-28 11:16:35 -08004684 } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE) {
4685 connType = AudioRoutesInfo.MAIN_USB;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004686 }
4687
Dianne Hackborn632ca412012-06-14 19:34:10 -07004688 synchronized (mCurAudioRoutes) {
4689 if (connType != 0) {
John Spurlock61560172015-02-06 19:46:04 -05004690 int newConn = mCurAudioRoutes.mainType;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004691 if (state != 0) {
4692 newConn |= connType;
4693 } else {
4694 newConn &= ~connType;
4695 }
John Spurlock61560172015-02-06 19:46:04 -05004696 if (newConn != mCurAudioRoutes.mainType) {
4697 mCurAudioRoutes.mainType = newConn;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004698 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4699 SENDMSG_NOOP, 0, 0, null, 0);
4700 }
4701 }
4702 }
4703
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004704 final long ident = Binder.clearCallingIdentity();
4705 try {
4706 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
4707 } finally {
4708 Binder.restoreCallingIdentity(ident);
4709 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004710 }
4711
Paul McLean10804eb2015-01-28 11:16:35 -08004712 private void onSetWiredDeviceConnectionState(int device, int state, String address,
4713 String deviceName)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004714 {
Paul McLean10804eb2015-01-28 11:16:35 -08004715 Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
4716 + " state:" + Integer.toHexString(state)
4717 + " address:" + address
4718 + " deviceName:" + deviceName + ");");
4719
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004720 synchronized (mConnectedDevices) {
4721 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004722 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4723 (device == AudioSystem.DEVICE_OUT_LINE))) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004724 setBluetoothA2dpOnInt(true);
4725 }
Eric Laurentae4506e2014-05-29 16:04:32 -07004726 boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
4727 (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
4728 ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
Paul McLean10804eb2015-01-28 11:16:35 -08004729 handleDeviceConnection(state == 1, device, address, deviceName);
Eric Laurentf1a457d2012-09-20 16:27:23 -07004730 if (state != 0) {
4731 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004732 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4733 (device == AudioSystem.DEVICE_OUT_LINE)) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07004734 setBluetoothA2dpOnInt(false);
4735 }
4736 if ((device & mSafeMediaVolumeDevices) != 0) {
4737 sendMsg(mAudioHandler,
4738 MSG_CHECK_MUSIC_ACTIVE,
4739 SENDMSG_REPLACE,
4740 0,
4741 0,
4742 null,
4743 MUSIC_ACTIVE_POLL_PERIOD_MS);
4744 }
Eric Laurent212532b2014-07-21 15:43:18 -07004745 // Television devices without CEC service apply software volume on HDMI output
4746 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4747 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
4748 checkAllFixedVolumeDevices();
4749 if (mHdmiManager != null) {
4750 synchronized (mHdmiManager) {
4751 if (mHdmiPlaybackClient != null) {
4752 mHdmiCecSink = false;
4753 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
4754 }
4755 }
4756 }
4757 }
4758 } else {
4759 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4760 if (mHdmiManager != null) {
4761 synchronized (mHdmiManager) {
4762 mHdmiCecSink = false;
4763 }
4764 }
4765 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004766 }
Paul McLean10804eb2015-01-28 11:16:35 -08004767 if (!isUsb && device != AudioSystem.DEVICE_IN_WIRED_HEADSET) {
4768 sendDeviceConnectionIntent(device, state, address, deviceName);
Mike Lockwooddb454842012-09-18 11:16:57 -07004769 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004770 }
4771 }
4772
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004773 private void configureHdmiPlugIntent(Intent intent, int state) {
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004774 intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
4775 intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004776 if (state == 1) {
4777 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
4778 int[] portGeneration = new int[1];
4779 int status = AudioSystem.listAudioPorts(ports, portGeneration);
4780 if (status == AudioManager.SUCCESS) {
4781 for (AudioPort port : ports) {
4782 if (port instanceof AudioDevicePort) {
4783 final AudioDevicePort devicePort = (AudioDevicePort) port;
Eric Laurent6fa42452015-01-09 15:09:40 -08004784 if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
4785 devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004786 // format the list of supported encodings
4787 int[] formats = devicePort.formats();
4788 if (formats.length > 0) {
4789 ArrayList<Integer> encodingList = new ArrayList(1);
4790 for (int format : formats) {
4791 // a format in the list can be 0, skip it
4792 if (format != AudioFormat.ENCODING_INVALID) {
4793 encodingList.add(format);
4794 }
4795 }
4796 int[] encodingArray = new int[encodingList.size()];
4797 for (int i = 0 ; i < encodingArray.length ; i++) {
4798 encodingArray[i] = encodingList.get(i);
4799 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004800 intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004801 }
4802 // find the maximum supported number of channels
4803 int maxChannels = 0;
4804 for (int mask : devicePort.channelMasks()) {
4805 int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
4806 if (channelCount > maxChannels) {
4807 maxChannels = channelCount;
4808 }
4809 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004810 intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004811 }
4812 }
4813 }
4814 }
4815 }
4816 }
4817
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004818 /* cache of the address of the last dock the device was connected to */
4819 private String mDockAddress;
4820
Eric Laurenta553c252009-07-17 12:17:14 -07004821 /**
4822 * Receiver for misc intent broadcasts the Phone app cares about.
4823 */
4824 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4825 @Override
4826 public void onReceive(Context context, Intent intent) {
4827 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07004828 int outDevice;
4829 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07004830 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07004831
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004832 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4833 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4834 Intent.EXTRA_DOCK_STATE_UNDOCKED);
4835 int config;
4836 switch (dockState) {
4837 case Intent.EXTRA_DOCK_STATE_DESK:
4838 config = AudioSystem.FORCE_BT_DESK_DOCK;
4839 break;
4840 case Intent.EXTRA_DOCK_STATE_CAR:
4841 config = AudioSystem.FORCE_BT_CAR_DOCK;
4842 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004843 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08004844 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004845 break;
4846 case Intent.EXTRA_DOCK_STATE_HE_DESK:
4847 config = AudioSystem.FORCE_DIGITAL_DOCK;
4848 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004849 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4850 default:
4851 config = AudioSystem.FORCE_NONE;
4852 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08004853 // Low end docks have a menu to enable or disable audio
4854 // (see mDockAudioMediaEnabled)
4855 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
4856 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
4857 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
4858 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
4859 }
4860 mDockState = dockState;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004861 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
Eric Laurent59f48272012-04-05 19:42:21 -07004862 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004863 BluetoothProfile.STATE_DISCONNECTED);
Eric Laurentae4506e2014-05-29 16:04:32 -07004864 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
4865 inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
Nick Pellya56d1c72009-08-19 14:49:29 -07004866 String address = null;
Eric Laurentdca56b92011-09-02 14:20:56 -07004867
4868 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
4869 if (btDevice == null) {
4870 return;
4871 }
4872
4873 address = btDevice.getAddress();
4874 BluetoothClass btClass = btDevice.getBluetoothClass();
4875 if (btClass != null) {
4876 switch (btClass.getDeviceClass()) {
4877 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
4878 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
Eric Laurentae4506e2014-05-29 16:04:32 -07004879 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurentdca56b92011-09-02 14:20:56 -07004880 break;
4881 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
Eric Laurentae4506e2014-05-29 16:04:32 -07004882 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurentdca56b92011-09-02 14:20:56 -07004883 break;
Eric Laurentd5603c12009-08-06 08:49:39 -07004884 }
4885 }
4886
Eric Laurentdca56b92011-09-02 14:20:56 -07004887 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4888 address = "";
4889 }
Eric Laurentd5603c12009-08-06 08:49:39 -07004890
Eric Laurent59f48272012-04-05 19:42:21 -07004891 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
Paul McLean10804eb2015-01-28 11:16:35 -08004892 boolean success =
4893 handleDeviceConnection(connected, outDevice, address, "Bluetooth Headset") &&
4894 handleDeviceConnection(connected, inDevice, address, "Bluetooth Headset");
Eric Laurentae4506e2014-05-29 16:04:32 -07004895 if (success) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004896 synchronized (mScoClients) {
Eric Laurent59f48272012-04-05 19:42:21 -07004897 if (connected) {
4898 mBluetoothHeadsetDevice = btDevice;
4899 } else {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004900 mBluetoothHeadsetDevice = null;
4901 resetBluetoothSco();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004902 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004903 }
Eric Laurenta553c252009-07-17 12:17:14 -07004904 }
Paul McLeandf361462014-04-10 16:02:55 -07004905 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004906 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07004907 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004908 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004909 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07004910 // broadcast intent if the connection was initated by AudioService
4911 if (!mScoClients.isEmpty() &&
4912 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
4913 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
4914 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004915 broadcast = true;
4916 }
4917 switch (btState) {
4918 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004919 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07004920 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4921 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4922 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004923 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004924 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004925 break;
4926 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004927 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08004928 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07004929 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08004930 break;
4931 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07004932 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4933 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4934 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004935 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004936 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004937 default:
4938 // do not broadcast CONNECTING or invalid state
4939 broadcast = false;
4940 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004941 }
4942 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004943 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07004944 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07004945 //FIXME: this is to maintain compatibility with deprecated intent
4946 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08004947 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07004948 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004949 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08004950 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004951 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06004952 if (mMonitorRotation) {
4953 mOrientationListener.onOrientationChanged(0); //argument is ignored anyway
4954 mOrientationListener.enable();
4955 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004956 AudioSystem.setParameters("screen_state=on");
4957 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06004958 if (mMonitorRotation) {
4959 //reduce wakeups (save current) by only listening when display is on
4960 mOrientationListener.disable();
4961 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004962 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07004963 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004964 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004965 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004966 // attempt to stop music playback for background user
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004967 sendMsg(mAudioHandler,
4968 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4969 SENDMSG_REPLACE,
4970 0,
4971 0,
4972 null,
4973 0);
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004974 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004975 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004976
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004977 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004978 readAudioSettings(true /*userSwitch*/);
4979 // preserve STREAM_MUSIC volume from one user to the next.
4980 sendMsg(mAudioHandler,
4981 MSG_SET_ALL_VOLUMES,
4982 SENDMSG_QUEUE,
4983 0,
4984 0,
4985 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Eric Laurenta553c252009-07-17 12:17:14 -07004986 }
4987 }
Paul McLeanc837a452014-04-09 09:04:43 -07004988 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004989
4990 //==========================================================================================
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004991 // RemoteControlDisplay / RemoteControlClient / Remote info
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004992 //==========================================================================================
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004993 public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
4994 ComponentName listenerComp) {
4995 return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
4996 }
4997
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004998 public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004999 return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005000 }
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005001
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005002 public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005003 mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005004 }
5005
5006 public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005007 mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005008 }
5009
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07005010 public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
5011 boolean wantsSync) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005012 mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
5013 }
5014
John Spurlock3346a802014-05-20 16:25:37 -04005015 @Override
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005016 public void setRemoteStreamVolume(int index) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005017 enforceVolumeController("set the remote stream volume");
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005018 mMediaFocusControl.setRemoteStreamVolume(index);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005019 }
5020
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005021 //==========================================================================================
5022 // Audio Focus
5023 //==========================================================================================
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005024 public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005025 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005026 IAudioPolicyCallback pcb) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005027 // permission checks
5028 if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
John Spurlock61560172015-02-06 19:46:04 -05005029 if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005030 if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
5031 android.Manifest.permission.MODIFY_PHONE_STATE)) {
5032 Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
5033 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5034 }
5035 } else {
5036 // only a registered audio policy can be used to lock focus
5037 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005038 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
5039 Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005040 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5041 }
5042 }
5043 }
5044 }
5045
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005046 return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
5047 clientId, callingPackageName, flags);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005048 }
5049
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005050 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
5051 return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005052 }
5053
5054 public void unregisterAudioFocusClient(String clientId) {
5055 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005056 }
5057
Jean-Michel Trivi23805662013-07-31 14:19:18 -07005058 public int getCurrentAudioFocus() {
5059 return mMediaFocusControl.getCurrentAudioFocus();
5060 }
5061
John Spurlock5e783732015-02-19 10:28:59 -05005062 private boolean readCameraSoundForced() {
5063 return SystemProperties.getBoolean("audio.camerasound.force", false) ||
5064 mContext.getResources().getBoolean(
5065 com.android.internal.R.bool.config_camera_sound_forced);
5066 }
5067
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005068 //==========================================================================================
5069 // Device orientation
5070 //==========================================================================================
5071 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005072 * Handles device configuration changes that may map to a change in the orientation
5073 * or orientation.
5074 * Monitoring orientation and rotation is optional, and is defined by the definition and value
5075 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005076 */
5077 private void handleConfigurationChanged(Context context) {
5078 try {
5079 // reading new orientation "safely" (i.e. under try catch) in case anything
5080 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07005081 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005082 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07005083 if (mMonitorOrientation) {
5084 int newOrientation = config.orientation;
5085 if (newOrientation != mDeviceOrientation) {
5086 mDeviceOrientation = newOrientation;
5087 setOrientationForAudioSystem();
5088 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005089 }
Eric Laurentd640bd32012-09-28 18:01:48 -07005090 sendMsg(mAudioHandler,
5091 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
5092 SENDMSG_REPLACE,
5093 0,
5094 0,
5095 null,
5096 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07005097
John Spurlock5e783732015-02-19 10:28:59 -05005098 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -07005099 synchronized (mSettingsLock) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005100 boolean cameraSoundForcedChanged = false;
Eric Laurentdd45d012012-10-08 09:04:34 -07005101 synchronized (mCameraSoundForced) {
5102 if (cameraSoundForced != mCameraSoundForced) {
5103 mCameraSoundForced = cameraSoundForced;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005104 cameraSoundForcedChanged = true;
Eric Laurentdd45d012012-10-08 09:04:34 -07005105 }
5106 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005107 if (cameraSoundForcedChanged) {
5108 if (!isPlatformTelevision()) {
5109 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
5110 if (cameraSoundForced) {
5111 s.setAllIndexesToMax();
5112 mRingerModeAffectedStreams &=
5113 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5114 } else {
5115 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
5116 mRingerModeAffectedStreams |=
5117 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5118 }
5119 // take new state into account for streams muted by ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05005120 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005121 }
5122
5123 sendMsg(mAudioHandler,
5124 MSG_SET_FORCE_USE,
5125 SENDMSG_QUEUE,
5126 AudioSystem.FOR_SYSTEM,
5127 cameraSoundForced ?
5128 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
5129 null,
5130 0);
5131
5132 sendMsg(mAudioHandler,
5133 MSG_SET_ALL_VOLUMES,
5134 SENDMSG_QUEUE,
5135 0,
5136 0,
5137 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
5138 }
Eric Laurentdd45d012012-10-08 09:04:34 -07005139 }
John Spurlock3346a802014-05-20 16:25:37 -04005140 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005141 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005142 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005143 }
5144 }
5145
5146 private void setOrientationForAudioSystem() {
5147 switch (mDeviceOrientation) {
5148 case Configuration.ORIENTATION_LANDSCAPE:
5149 //Log.i(TAG, "orientation is landscape");
5150 AudioSystem.setParameters("orientation=landscape");
5151 break;
5152 case Configuration.ORIENTATION_PORTRAIT:
5153 //Log.i(TAG, "orientation is portrait");
5154 AudioSystem.setParameters("orientation=portrait");
5155 break;
5156 case Configuration.ORIENTATION_SQUARE:
5157 //Log.i(TAG, "orientation is square");
5158 AudioSystem.setParameters("orientation=square");
5159 break;
5160 case Configuration.ORIENTATION_UNDEFINED:
5161 //Log.i(TAG, "orientation is undefined");
5162 AudioSystem.setParameters("orientation=undefined");
5163 break;
5164 default:
5165 Log.e(TAG, "Unknown orientation");
5166 }
5167 }
5168
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005169 private void setRotationForAudioSystem() {
5170 switch (mDeviceRotation) {
5171 case Surface.ROTATION_0:
5172 AudioSystem.setParameters("rotation=0");
5173 break;
5174 case Surface.ROTATION_90:
5175 AudioSystem.setParameters("rotation=90");
5176 break;
5177 case Surface.ROTATION_180:
5178 AudioSystem.setParameters("rotation=180");
5179 break;
5180 case Surface.ROTATION_270:
5181 AudioSystem.setParameters("rotation=270");
5182 break;
5183 default:
5184 Log.e(TAG, "Unknown device rotation");
5185 }
5186 }
5187
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005188
Eric Laurent78472112012-05-21 08:57:21 -07005189 // Handles request to override default use of A2DP for media.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005190 // Must be called synchronized on mConnectedDevices
Eric Laurent78472112012-05-21 08:57:21 -07005191 public void setBluetoothA2dpOnInt(boolean on) {
5192 synchronized (mBluetoothA2dpEnabledLock) {
5193 mBluetoothA2dpEnabled = on;
Eric Laurentc390bed2012-07-03 12:24:05 -07005194 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005195 setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
Eric Laurentc390bed2012-07-03 12:24:05 -07005196 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
Eric Laurent78472112012-05-21 08:57:21 -07005197 }
5198 }
5199
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005200 // Must be called synchronized on mConnectedDevices
5201 private void setForceUseInt_SyncDevices(int usage, int config) {
5202 switch (usage) {
5203 case AudioSystem.FOR_MEDIA:
5204 if (config == AudioSystem.FORCE_NO_BT_A2DP) {
5205 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ALL_A2DP;
5206 } else { // config == AudioSystem.FORCE_NONE
5207 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
5208 }
5209 break;
5210 case AudioSystem.FOR_DOCK:
5211 if (config == AudioSystem.FORCE_ANALOG_DOCK) {
5212 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5213 } else { // config == AudioSystem.FORCE_NONE
5214 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5215 }
5216 break;
5217 default:
5218 // usage doesn't affect the broadcast of ACTION_AUDIO_BECOMING_NOISY
5219 }
5220 AudioSystem.setForceUse(usage, config);
5221 }
5222
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005223 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07005224 public void setRingtonePlayer(IRingtonePlayer player) {
5225 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5226 mRingtonePlayer = player;
5227 }
5228
5229 @Override
5230 public IRingtonePlayer getRingtonePlayer() {
5231 return mRingtonePlayer;
5232 }
5233
5234 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07005235 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5236 synchronized (mCurAudioRoutes) {
5237 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5238 mRoutesObservers.register(observer);
5239 return routes;
5240 }
5241 }
5242
Eric Laurentc34dcc12012-09-10 13:51:52 -07005243
5244 //==========================================================================================
5245 // Safe media volume management.
5246 // MUSIC stream volume level is limited when headphones are connected according to safety
5247 // regulation. When the user attempts to raise the volume above the limit, a warning is
5248 // displayed and the user has to acknowlegde before the volume is actually changed.
5249 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
5250 // property. Platforms with a different limit must set this property accordingly in their
5251 // overlay.
5252 //==========================================================================================
5253
Eric Laurentd640bd32012-09-28 18:01:48 -07005254 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
5255 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
5256 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
5257 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
5258 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
5259 // (when user opts out).
John Spurlock35134602014-07-24 18:10:48 -04005260 private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
5261 private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
5262 private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed
5263 private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
Eric Laurentd640bd32012-09-28 18:01:48 -07005264 private Integer mSafeMediaVolumeState;
5265
5266 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005267 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07005268 private int mSafeMediaVolumeIndex;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005269 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
5270 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
5271 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
5272 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
5273 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
5274 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
5275 private int mMusicActiveMs;
5276 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
5277 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07005278 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07005279
5280 private void setSafeMediaVolumeEnabled(boolean on) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005281 synchronized (mSafeMediaVolumeState) {
5282 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
5283 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
5284 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
5285 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
5286 enforceSafeMediaVolume();
5287 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
5288 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005289 mMusicActiveMs = 1; // nonzero = confirmed
5290 saveMusicActiveMs();
Eric Laurentd640bd32012-09-28 18:01:48 -07005291 sendMsg(mAudioHandler,
5292 MSG_CHECK_MUSIC_ACTIVE,
5293 SENDMSG_REPLACE,
5294 0,
5295 0,
5296 null,
5297 MUSIC_ACTIVE_POLL_PERIOD_MS);
5298 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005299 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005300 }
5301 }
5302
5303 private void enforceSafeMediaVolume() {
5304 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07005305 int devices = mSafeMediaVolumeDevices;
5306 int i = 0;
5307
5308 while (devices != 0) {
5309 int device = 1 << i++;
5310 if ((device & devices) == 0) {
5311 continue;
5312 }
Eric Laurent42b041e2013-03-29 11:36:03 -07005313 int index = streamState.getIndex(device);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005314 if (index > mSafeMediaVolumeIndex) {
Eric Laurent42b041e2013-03-29 11:36:03 -07005315 streamState.setIndex(mSafeMediaVolumeIndex, device);
5316 sendMsg(mAudioHandler,
5317 MSG_SET_DEVICE_VOLUME,
5318 SENDMSG_QUEUE,
5319 device,
5320 0,
5321 streamState,
5322 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005323 }
5324 devices &= ~device;
5325 }
5326 }
5327
5328 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005329 synchronized (mSafeMediaVolumeState) {
5330 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07005331 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
5332 ((device & mSafeMediaVolumeDevices) != 0) &&
5333 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005334 return false;
5335 }
5336 return true;
5337 }
5338 }
5339
John Spurlock3346a802014-05-20 16:25:37 -04005340 @Override
Eric Laurentc34dcc12012-09-10 13:51:52 -07005341 public void disableSafeMediaVolume() {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005342 enforceVolumeController("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07005343 synchronized (mSafeMediaVolumeState) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005344 setSafeMediaVolumeEnabled(false);
Eric Laurentfde16d52012-12-03 14:42:39 -08005345 if (mPendingVolumeCommand != null) {
5346 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
5347 mPendingVolumeCommand.mIndex,
5348 mPendingVolumeCommand.mFlags,
5349 mPendingVolumeCommand.mDevice);
5350 mPendingVolumeCommand = null;
5351 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005352 }
5353 }
5354
Jungshik Jang41d97462014-06-30 22:26:29 +09005355 //==========================================================================================
5356 // Hdmi Cec system audio mode.
5357 // If Hdmi Cec's system audio mode is on, audio service should notify volume change
5358 // to HdmiControlService so that audio recevier can handle volume change.
5359 //==========================================================================================
5360
Eric Laurent212532b2014-07-21 15:43:18 -07005361 private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
5362 public void onComplete(int status) {
5363 if (mHdmiManager != null) {
5364 synchronized (mHdmiManager) {
5365 mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
5366 // Television devices without CEC service apply software volume on HDMI output
5367 if (isPlatformTelevision() && !mHdmiCecSink) {
5368 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5369 }
5370 checkAllFixedVolumeDevices();
5371 }
5372 }
5373 }
5374 };
5375
Jungshik Jang41d97462014-06-30 22:26:29 +09005376 // If HDMI-CEC system audio is supported
5377 private boolean mHdmiSystemAudioSupported = false;
5378 // Set only when device is tv.
5379 private HdmiTvClient mHdmiTvClient;
Eric Laurent0b03f992014-11-18 18:08:02 -08005380 // true if the device has system feature PackageManager.FEATURE_LEANBACK.
Eric Laurent212532b2014-07-21 15:43:18 -07005381 // cached HdmiControlManager interface
5382 private HdmiControlManager mHdmiManager;
5383 // Set only when device is a set-top box.
5384 private HdmiPlaybackClient mHdmiPlaybackClient;
5385 // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5386 private boolean mHdmiCecSink;
5387
5388 private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
Jungshik Jang41d97462014-06-30 22:26:29 +09005389
5390 @Override
Jungshik Jang12307ca2014-07-15 19:27:56 +09005391 public int setHdmiSystemAudioSupported(boolean on) {
Eric Laurent212532b2014-07-21 15:43:18 -07005392 int device = AudioSystem.DEVICE_NONE;
5393 if (mHdmiManager != null) {
5394 synchronized (mHdmiManager) {
5395 if (mHdmiTvClient == null) {
5396 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5397 return device;
5398 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005399
Eric Laurent212532b2014-07-21 15:43:18 -07005400 synchronized (mHdmiTvClient) {
5401 if (mHdmiSystemAudioSupported != on) {
5402 mHdmiSystemAudioSupported = on;
5403 AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5404 on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5405 AudioSystem.FORCE_NONE);
5406 }
5407 device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
5408 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005409 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005410 }
Eric Laurent212532b2014-07-21 15:43:18 -07005411 return device;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005412 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005413
Terry Heoe7d6d972014-09-04 21:05:28 +09005414 @Override
5415 public boolean isHdmiSystemAudioSupported() {
5416 return mHdmiSystemAudioSupported;
5417 }
5418
Eric Laurentdd45d012012-10-08 09:04:34 -07005419 //==========================================================================================
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005420 // Accessibility: taking touch exploration into account for selecting the default
5421 // stream override timeout when adjusting volume
5422 //==========================================================================================
5423 private static class StreamOverride
5424 implements AccessibilityManager.TouchExplorationStateChangeListener {
5425
5426 // AudioService.getActiveStreamType() will return:
5427 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
5428 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
5429 // stopped
5430 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
5431 private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
5432
5433 static int sDelayMs;
5434
5435 static void init(Context ctxt) {
5436 AccessibilityManager accessibilityManager =
5437 (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
5438 updateDefaultStreamOverrideDelay(
5439 accessibilityManager.isTouchExplorationEnabled());
5440 accessibilityManager.addTouchExplorationStateChangeListener(
5441 new StreamOverride());
5442 }
5443
5444 @Override
5445 public void onTouchExplorationStateChanged(boolean enabled) {
5446 updateDefaultStreamOverrideDelay(enabled);
5447 }
5448
5449 private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
5450 if (touchExploreEnabled) {
5451 sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
5452 } else {
5453 sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
5454 }
5455 if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
5456 + " stream override delay is now " + sDelayMs + " ms");
5457 }
5458 }
5459
5460 //==========================================================================================
Eric Laurentdd45d012012-10-08 09:04:34 -07005461 // Camera shutter sound policy.
5462 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5463 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5464 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5465 //==========================================================================================
5466
5467 // cached value of com.android.internal.R.bool.config_camera_sound_forced
5468 private Boolean mCameraSoundForced;
5469
5470 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5471 public boolean isCameraSoundForced() {
5472 synchronized (mCameraSoundForced) {
5473 return mCameraSoundForced;
5474 }
5475 }
5476
5477 private static final String[] RINGER_MODE_NAMES = new String[] {
5478 "SILENT",
5479 "VIBRATE",
5480 "NORMAL"
5481 };
5482
5483 private void dumpRingerMode(PrintWriter pw) {
5484 pw.println("\nRinger mode: ");
John Spurlock661f2cf2014-11-17 10:29:10 -05005485 pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
5486 pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
Eric Laurentdd45d012012-10-08 09:04:34 -07005487 pw.print("- ringer mode affected streams = 0x");
5488 pw.println(Integer.toHexString(mRingerModeAffectedStreams));
5489 pw.print("- ringer mode muted streams = 0x");
5490 pw.println(Integer.toHexString(mRingerModeMutedStreams));
John Spurlock661f2cf2014-11-17 10:29:10 -05005491 pw.print("- delegate = "); pw.println(mRingerModeDelegate);
Eric Laurentdd45d012012-10-08 09:04:34 -07005492 }
5493
Dianne Hackborn632ca412012-06-14 19:34:10 -07005494 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005495 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07005496 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5497
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005498 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07005499 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07005500 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005501 pw.println("\nAudio routes:");
John Spurlock61560172015-02-06 19:46:04 -05005502 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
5503 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
John Spurlock35134602014-07-24 18:10:48 -04005504
5505 pw.println("\nOther state:");
John Spurlock3346a802014-05-20 16:25:37 -04005506 pw.print(" mVolumeController="); pw.println(mVolumeController);
John Spurlock35134602014-07-24 18:10:48 -04005507 pw.print(" mSafeMediaVolumeState=");
5508 pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
5509 pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
5510 pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
5511 pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005512 pw.print(" mMcc="); pw.println(mMcc);
John Spurlock5e783732015-02-19 10:28:59 -05005513 pw.print(" mCameraSoundForced="); pw.println(mCameraSoundForced);
John Spurlock661f2cf2014-11-17 10:29:10 -05005514 pw.print(" mHasVibrator="); pw.println(mHasVibrator);
John Spurlockcdb57ae2015-02-11 19:04:11 -05005515 pw.print(" mControllerService="); pw.println(mControllerService);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005516
5517 dumpAudioPolicies(pw);
John Spurlock35134602014-07-24 18:10:48 -04005518 }
5519
5520 private static String safeMediaVolumeStateToString(Integer state) {
5521 switch(state) {
5522 case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
5523 case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
5524 case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
5525 case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
5526 }
5527 return null;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005528 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07005529
5530 // Inform AudioFlinger of our device's low RAM attribute
5531 private static void readAndSetLowRamDevice()
5532 {
5533 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
5534 if (status != 0) {
5535 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
5536 }
5537 }
John Spurlock3346a802014-05-20 16:25:37 -04005538
John Spurlockcdb57ae2015-02-11 19:04:11 -05005539 private void enforceVolumeController(String action) {
5540 if (mControllerService.mUid != 0 && Binder.getCallingUid() == mControllerService.mUid) {
5541 return;
5542 }
John Spurlock3346a802014-05-20 16:25:37 -04005543 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
5544 "Only SystemUI can " + action);
5545 }
5546
5547 @Override
5548 public void setVolumeController(final IVolumeController controller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005549 enforceVolumeController("set the volume controller");
John Spurlock3346a802014-05-20 16:25:37 -04005550
5551 // return early if things are not actually changing
5552 if (mVolumeController.isSameBinder(controller)) {
5553 return;
5554 }
5555
5556 // dismiss the old volume controller
5557 mVolumeController.postDismiss();
5558 if (controller != null) {
5559 // we are about to register a new controller, listen for its death
5560 try {
5561 controller.asBinder().linkToDeath(new DeathRecipient() {
5562 @Override
5563 public void binderDied() {
5564 if (mVolumeController.isSameBinder(controller)) {
5565 Log.w(TAG, "Current remote volume controller died, unregistering");
5566 setVolumeController(null);
5567 }
5568 }
5569 }, 0);
5570 } catch (RemoteException e) {
5571 // noop
5572 }
5573 }
5574 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04005575 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
5576 }
5577
5578 @Override
5579 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005580 enforceVolumeController("notify about volume controller visibility");
John Spurlock33f4e042014-07-11 13:10:58 -04005581
5582 // return early if the controller is not current
5583 if (!mVolumeController.isSameBinder(controller)) {
5584 return;
5585 }
5586
5587 mVolumeController.setVisible(visible);
5588 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04005589 }
RoboErikd09bd0c2014-06-24 17:45:19 -07005590
5591 public static class VolumeController {
5592 private static final String TAG = "VolumeController";
5593
5594 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04005595 private boolean mVisible;
5596 private long mNextLongPress;
5597 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07005598
5599 public void setController(IVolumeController controller) {
5600 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04005601 mVisible = false;
5602 }
5603
5604 public void loadSettings(ContentResolver cr) {
5605 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
5606 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
5607 }
5608
RoboErik4197cb62015-01-21 15:45:32 -08005609 public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
5610 if (isMute) {
5611 return false;
5612 }
John Spurlock33f4e042014-07-11 13:10:58 -04005613 boolean suppress = false;
5614 if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
5615 final long now = SystemClock.uptimeMillis();
5616 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
5617 // ui will become visible
5618 if (mNextLongPress < now) {
5619 mNextLongPress = now + mLongPressTimeout;
5620 }
5621 suppress = true;
5622 } else if (mNextLongPress > 0) { // in a long-press
5623 if (now > mNextLongPress) {
5624 // long press triggered, no more suppression
5625 mNextLongPress = 0;
5626 } else {
5627 // keep suppressing until the long press triggers
5628 suppress = true;
5629 }
5630 }
5631 }
5632 return suppress;
5633 }
5634
5635 public void setVisible(boolean visible) {
5636 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07005637 }
5638
5639 public boolean isSameBinder(IVolumeController controller) {
5640 return Objects.equals(asBinder(), binder(controller));
5641 }
5642
5643 public IBinder asBinder() {
5644 return binder(mController);
5645 }
5646
5647 private static IBinder binder(IVolumeController controller) {
5648 return controller == null ? null : controller.asBinder();
5649 }
5650
5651 @Override
5652 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04005653 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07005654 }
5655
5656 public void postDisplaySafeVolumeWarning(int flags) {
5657 if (mController == null)
5658 return;
5659 try {
5660 mController.displaySafeVolumeWarning(flags);
5661 } catch (RemoteException e) {
5662 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
5663 }
5664 }
5665
5666 public void postVolumeChanged(int streamType, int flags) {
5667 if (mController == null)
5668 return;
5669 try {
5670 mController.volumeChanged(streamType, flags);
5671 } catch (RemoteException e) {
5672 Log.w(TAG, "Error calling volumeChanged", e);
5673 }
5674 }
5675
5676 public void postMasterVolumeChanged(int flags) {
5677 if (mController == null)
5678 return;
5679 try {
5680 mController.masterVolumeChanged(flags);
5681 } catch (RemoteException e) {
5682 Log.w(TAG, "Error calling masterVolumeChanged", e);
5683 }
5684 }
5685
5686 public void postMasterMuteChanged(int flags) {
5687 if (mController == null)
5688 return;
5689 try {
5690 mController.masterMuteChanged(flags);
5691 } catch (RemoteException e) {
5692 Log.w(TAG, "Error calling masterMuteChanged", e);
5693 }
5694 }
5695
5696 public void setLayoutDirection(int layoutDirection) {
5697 if (mController == null)
5698 return;
5699 try {
5700 mController.setLayoutDirection(layoutDirection);
5701 } catch (RemoteException e) {
5702 Log.w(TAG, "Error calling setLayoutDirection", e);
5703 }
5704 }
5705
5706 public void postDismiss() {
5707 if (mController == null)
5708 return;
5709 try {
5710 mController.dismiss();
5711 } catch (RemoteException e) {
5712 Log.w(TAG, "Error calling dismiss", e);
5713 }
5714 }
5715 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005716
RoboErik0dac35a2014-08-12 15:48:49 -07005717 /**
5718 * Interface for system components to get some extra functionality through
5719 * LocalServices.
5720 */
5721 final class AudioServiceInternal extends AudioManagerInternal {
John Spurlock661f2cf2014-11-17 10:29:10 -05005722 @Override
5723 public void setRingerModeDelegate(RingerModeDelegate delegate) {
5724 mRingerModeDelegate = delegate;
5725 if (mRingerModeDelegate != null) {
5726 setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
5727 }
5728 }
RoboErik272e1612014-09-05 11:39:29 -07005729
5730 @Override
5731 public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
5732 String callingPackage, int uid) {
5733 // direction and stream type swap here because the public
5734 // adjustSuggested has a different order than the other methods.
5735 adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage, uid);
5736 }
5737
RoboErik0dac35a2014-08-12 15:48:49 -07005738 @Override
5739 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
5740 String callingPackage, int uid) {
5741 adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
5742 }
5743
5744 @Override
5745 public void setStreamVolumeForUid(int streamType, int direction, int flags,
5746 String callingPackage, int uid) {
5747 setStreamVolume(streamType, direction, flags, callingPackage, uid);
5748 }
RoboErik519c7742014-11-18 10:59:09 -08005749
5750 @Override
5751 public void adjustMasterVolumeForUid(int steps, int flags, String callingPackage,
5752 int uid) {
5753 adjustMasterVolume(steps, flags, callingPackage, uid);
5754 }
John Spurlock661f2cf2014-11-17 10:29:10 -05005755
5756 @Override
5757 public int getRingerModeInternal() {
5758 return AudioService.this.getRingerModeInternal();
5759 }
5760
5761 @Override
5762 public void setRingerModeInternal(int ringerMode, String caller) {
5763 AudioService.this.setRingerModeInternal(ringerMode, caller);
5764 }
John Spurlockcdb57ae2015-02-11 19:04:11 -05005765
5766 @Override
5767 public int getVolumeControllerUid() {
5768 return mControllerService.mUid;
5769 }
RoboErik0dac35a2014-08-12 15:48:49 -07005770 }
5771
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005772 //==========================================================================================
5773 // Audio policy management
5774 //==========================================================================================
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005775 public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
5776 boolean hasFocusListener) {
5777 if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
5778 + " with config:" + policyConfig);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005779 String regId = null;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005780 // error handling
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005781 boolean hasPermissionForPolicy =
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005782 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005783 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5784 if (!hasPermissionForPolicy) {
5785 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
5786 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005787 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005788 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005789
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005790 synchronized (mAudioPolicies) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005791 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005792 if (mAudioPolicies.containsKey(pcb.asBinder())) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005793 Slog.e(TAG, "Cannot re-register policy");
5794 return null;
5795 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005796 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
5797 pcb.asBinder().linkToDeath(app, 0/*flags*/);
5798 regId = app.getRegistrationId();
5799 mAudioPolicies.put(pcb.asBinder(), app);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005800 } catch (RemoteException e) {
5801 // audio policy owner has already died!
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005802 Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005803 " binder death", e);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005804 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005805 }
5806 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005807 return regId;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005808 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005809
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005810 public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
5811 if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005812 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005813 AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005814 if (app == null) {
5815 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
5816 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005817 return;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005818 } else {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005819 pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005820 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005821 app.release();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005822 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005823 // TODO implement clearing mix attribute matching info in native audio policy
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005824 }
5825
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005826 public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
5827 if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
5828 + " policy " + pcb.asBinder());
5829 // error handling
5830 boolean hasPermissionForPolicy =
5831 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
5832 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5833 if (!hasPermissionForPolicy) {
5834 Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
5835 + Binder.getCallingPid() + " / uid "
5836 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
5837 return AudioManager.ERROR;
5838 }
5839
5840 synchronized (mAudioPolicies) {
5841 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
5842 Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
5843 return AudioManager.ERROR;
5844 }
5845 final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
5846 if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5847 // is there already one policy managing ducking?
5848 for(AudioPolicyProxy policy : mAudioPolicies.values()) {
5849 if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5850 Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
5851 return AudioManager.ERROR;
5852 }
5853 }
5854 }
5855 app.mFocusDuckBehavior = duckingBehavior;
5856 mMediaFocusControl.setDuckingInExtPolicyAvailable(
5857 duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
5858 }
5859 return AudioManager.SUCCESS;
5860 }
5861
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005862 private void dumpAudioPolicies(PrintWriter pw) {
5863 pw.println("\nAudio policies:");
5864 synchronized (mAudioPolicies) {
5865 for(AudioPolicyProxy policy : mAudioPolicies.values()) {
5866 pw.println(policy.toLogFriendlyString());
5867 }
5868 }
5869 }
5870
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005871 //======================
5872 // Audio policy proxy
5873 //======================
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005874 /**
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005875 * This internal class inherits from AudioPolicyConfig, each instance contains all the
5876 * mixes of an AudioPolicy and their configurations.
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005877 */
5878 public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005879 private static final String TAG = "AudioPolicyProxy";
5880 AudioPolicyConfig mConfig;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005881 IAudioPolicyCallback mPolicyToken;
5882 boolean mHasFocusListener;
5883 /**
5884 * Audio focus ducking behavior for an audio policy.
5885 * This variable reflects the value that was successfully set in
5886 * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
5887 * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
5888 * is handling ducking for audio focus.
5889 */
5890 int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
5891
5892 AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
5893 boolean hasFocusListener) {
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005894 super(config);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005895 setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005896 mPolicyToken = token;
5897 mHasFocusListener = hasFocusListener;
5898 if (mHasFocusListener) {
5899 mMediaFocusControl.addFocusFollower(mPolicyToken);
5900 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08005901 connectMixes();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005902 }
5903
5904 public void binderDied() {
5905 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005906 Log.i(TAG, "audio policy " + mPolicyToken + " died");
5907 release();
5908 mAudioPolicies.remove(mPolicyToken.asBinder());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005909 }
5910 }
5911
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005912 String getRegistrationId() {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005913 return getRegistration();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005914 }
5915
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005916 void release() {
5917 if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5918 mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
5919 }
5920 if (mHasFocusListener) {
5921 mMediaFocusControl.removeFocusFollower(mPolicyToken);
5922 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08005923 AudioSystem.registerPolicyMixes(mMixes, false);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005924 }
5925
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08005926 void connectMixes() {
5927 AudioSystem.registerPolicyMixes(mMixes, true);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005928 }
5929 };
5930
5931 private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
5932 new HashMap<IBinder, AudioPolicyProxy>();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005933 private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
John Spurlockcdb57ae2015-02-11 19:04:11 -05005934
5935 private class ControllerService extends ContentObserver {
5936 private int mUid;
5937 private ComponentName mComponent;
5938
5939 public ControllerService() {
5940 super(null);
5941 }
5942
5943 @Override
5944 public String toString() {
5945 return String.format("{mUid=%d,mComponent=%s}", mUid, mComponent);
5946 }
5947
5948 public void init() {
5949 onChange(true);
5950 mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
5951 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT), false, this);
5952 }
5953
5954 @Override
5955 public void onChange(boolean selfChange) {
5956 mUid = 0;
5957 mComponent = null;
5958 final String setting = Settings.Secure.getString(mContentResolver,
5959 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
5960 if (setting == null) return;
5961 try {
5962 mComponent = ComponentName.unflattenFromString(setting);
5963 if (mComponent == null) return;
5964 mUid = mContext.getPackageManager()
5965 .getApplicationInfo(mComponent.getPackageName(), 0).uid;
5966 } catch (Exception e) {
5967 Log.w(TAG, "Error loading controller service", e);
5968 }
5969 if (DEBUG_VOL) Log.d(TAG, "Reloaded controller service: " + this);
5970 }
5971 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005972}