blob: d82f86f7f678b2308c6b25579ea569271ec4a24b [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;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070098import android.view.KeyEvent;
RoboErik519c7742014-11-18 10:59:09 -080099import android.view.OrientationEventListener;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700100import android.view.Surface;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700101import android.view.WindowManager;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700102import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103
Eric Laurente78fced2013-03-15 16:03:47 -0700104import com.android.internal.util.XmlUtils;
RoboErik0dac35a2014-08-12 15:48:49 -0700105import com.android.server.LocalServices;
Eric Laurente78fced2013-03-15 16:03:47 -0700106
107import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800109import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110import java.io.IOException;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800111import java.io.PrintWriter;
Eric Laurente78fced2013-03-15 16:03:47 -0700112import java.lang.reflect.Field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113import java.util.ArrayList;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700114import java.util.HashMap;
115import java.util.Iterator;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -0700116import java.util.List;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700117import java.util.Map;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700118import java.util.NoSuchElementException;
RoboErikd09bd0c2014-06-24 17:45:19 -0700119import java.util.Objects;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700120import java.util.Set;
RoboErik519c7742014-11-18 10:59:09 -0800121import java.util.concurrent.ConcurrentHashMap;
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
Eric Laurentdd45d012012-10-08 09:04:34 -0700584 boolean cameraSoundForced = mContext.getResources().getBoolean(
585 com.android.internal.R.bool.config_camera_sound_forced);
586 mCameraSoundForced = new Boolean(cameraSoundForced);
587 sendMsg(mAudioHandler,
588 MSG_SET_FORCE_USE,
589 SENDMSG_QUEUE,
590 AudioSystem.FOR_SYSTEM,
591 cameraSoundForced ?
592 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
593 null,
594 0);
595
Eric Laurent05274f32012-11-29 12:48:18 -0800596 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
597 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
598 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
599 // The default safe volume index read here will be replaced by the actual value when
600 // the mcc is read by onConfigureSafeVolume()
601 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
602 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
603
Eric Laurent83a017b2013-03-19 18:15:31 -0700604 mUseFixedVolume = mContext.getResources().getBoolean(
605 com.android.internal.R.bool.config_useFixedVolume);
Wally Yauda392902014-11-28 12:40:30 -0800606 mUseMasterVolume = context.getResources().getBoolean(
607 com.android.internal.R.bool.config_useMasterVolume);
608 mMasterVolumeRamp = context.getResources().getIntArray(
609 com.android.internal.R.array.config_masterVolumeRamp);
Eric Laurent83a017b2013-03-19 18:15:31 -0700610
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700611 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
612 // array initialized by updateStreamVolumeAlias()
613 updateStreamVolumeAlias(false /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614 readPersistedSettings();
Eric Laurentc1d41662011-07-19 11:21:13 -0700615 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700616 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700617
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700618 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700619
620 // Call setRingerModeInt() to apply correct mute
621 // state on streams affected by ringer mode.
622 mRingerModeMutedStreams = 0;
John Spurlock661f2cf2014-11-17 10:29:10 -0500623 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3891c4c2010-04-20 09:40:57 -0700624
Eric Laurenta553c252009-07-17 12:17:14 -0700625 // Register for device connection intent broadcasts.
626 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700627 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700628 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
629 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700630 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
631 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700632 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Paul McLeanc837a452014-04-09 09:04:43 -0700633 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700634
Eric Laurentd640bd32012-09-28 18:01:48 -0700635 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700636 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700637 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
638 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700639 Log.v(TAG, "monitoring device orientation");
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700640 // initialize orientation in AudioSystem
641 setOrientationForAudioSystem();
642 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700643 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
644 if (mMonitorRotation) {
645 mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
646 .getDefaultDisplay().getRotation();
647 Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
Jon Eklund318f0fe2014-01-23 17:53:48 -0600648
649 mOrientationListener = new AudioOrientationEventListener(mContext);
650 mOrientationListener.enable();
651
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700652 // initialize rotation in AudioSystem
653 setRotationForAudioSystem();
654 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700655
Eric Laurenta553c252009-07-17 12:17:14 -0700656 context.registerReceiver(mReceiver, intentFilter);
Jared Suttles59820132009-08-13 21:50:52 -0500657
Mike Lockwood90631542012-01-06 11:20:37 -0500658 restoreMasterVolume();
Mike Lockwood97606472012-02-09 11:24:10 -0800659
RoboErik0dac35a2014-08-12 15:48:49 -0700660 LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800661 }
662
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700663 public void systemReady() {
664 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
665 0, 0, null, 0);
666 }
667
668 public void onSystemReady() {
669 mSystemReady = true;
670 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
671 0, 0, null, 0);
672
673 mKeyguardManager =
674 (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
675 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
676 resetBluetoothSco();
677 getBluetoothHeadset();
678 //FIXME: this is to maintain compatibility with deprecated intent
679 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
680 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
681 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
682 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
683 sendStickyBroadcastToAll(newIntent);
684
685 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
686 if (adapter != null) {
687 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
688 BluetoothProfile.A2DP);
689 }
690
Eric Laurent212532b2014-07-21 15:43:18 -0700691 mHdmiManager =
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900692 (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700693 if (mHdmiManager != null) {
694 synchronized (mHdmiManager) {
695 mHdmiTvClient = mHdmiManager.getTvClient();
Jungshik Jangc9ff9682014-09-15 17:41:06 +0900696 if (mHdmiTvClient != null) {
697 mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
698 }
Eric Laurent212532b2014-07-21 15:43:18 -0700699 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
700 mHdmiCecSink = false;
701 }
702 }
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900703
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700704 sendMsg(mAudioHandler,
705 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
706 SENDMSG_REPLACE,
707 0,
708 0,
709 null,
710 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700711
712 StreamOverride.init(mContext);
John Spurlockcdb57ae2015-02-11 19:04:11 -0500713 mControllerService.init();
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700714 }
715
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800716 private void createAudioSystemThread() {
717 mAudioSystemThread = new AudioSystemThread();
718 mAudioSystemThread.start();
719 waitForAudioHandlerCreation();
720 }
721
722 /** Waits for the volume handler to be created by the other thread. */
723 private void waitForAudioHandlerCreation() {
724 synchronized(this) {
725 while (mAudioHandler == null) {
726 try {
727 // Wait for mAudioHandler to be set by the other thread
728 wait();
729 } catch (InterruptedException e) {
730 Log.e(TAG, "Interrupted while waiting on volume handler.");
731 }
732 }
733 }
734 }
735
Eric Laurent24482012012-05-10 09:41:17 -0700736 private void checkAllAliasStreamVolumes() {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700737 synchronized (VolumeStreamState.class) {
738 int numStreamTypes = AudioSystem.getNumStreamTypes();
739 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
740 if (streamType != mStreamVolumeAlias[streamType]) {
741 mStreamStates[streamType].
Eric Laurent42b041e2013-03-29 11:36:03 -0700742 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700743 }
744 // apply stream volume
RoboErik4197cb62015-01-21 15:45:32 -0800745 if (!mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700746 mStreamStates[streamType].applyAllVolumes();
747 }
Eric Laurent24482012012-05-10 09:41:17 -0700748 }
749 }
750 }
751
Eric Laurent212532b2014-07-21 15:43:18 -0700752 private void checkAllFixedVolumeDevices()
753 {
754 int numStreamTypes = AudioSystem.getNumStreamTypes();
755 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
756 mStreamStates[streamType].checkFixedVolumeDevices();
757 }
758 }
759
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700760 private void checkAllFixedVolumeDevices(int streamType) {
761 mStreamStates[streamType].checkFixedVolumeDevices();
762 }
763
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 int numStreamTypes = AudioSystem.getNumStreamTypes();
766 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
767
768 for (int i = 0; i < numStreamTypes; i++) {
Eric Laurent6d517662012-04-23 18:42:39 -0700769 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -0700770 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771
Eric Laurent212532b2014-07-21 15:43:18 -0700772 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -0700773 checkAllAliasStreamVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774 }
775
Eric Laurentbffc3d12012-05-07 17:43:49 -0700776 private void dumpStreamStates(PrintWriter pw) {
777 pw.println("\nStream volumes (device: index)");
778 int numStreamTypes = AudioSystem.getNumStreamTypes();
779 for (int i = 0; i < numStreamTypes; i++) {
John Spurlock61560172015-02-06 19:46:04 -0500780 pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":");
Eric Laurentbffc3d12012-05-07 17:43:49 -0700781 mStreamStates[i].dump(pw);
782 pw.println("");
783 }
Eric Laurentdd45d012012-10-08 09:04:34 -0700784 pw.print("\n- mute affected streams = 0x");
785 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -0700786 }
787
Eric Laurent6d517662012-04-23 18:42:39 -0700788 private void updateStreamVolumeAlias(boolean updateVolumes) {
789 int dtmfStreamAlias;
Eric Laurent212532b2014-07-21 15:43:18 -0700790
791 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -0500792 case AudioSystem.PLATFORM_VOICE:
Eric Laurent212532b2014-07-21 15:43:18 -0700793 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
Eric Laurent6d517662012-04-23 18:42:39 -0700794 dtmfStreamAlias = AudioSystem.STREAM_RING;
Eric Laurent212532b2014-07-21 15:43:18 -0700795 break;
John Spurlock61560172015-02-06 19:46:04 -0500796 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -0700797 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
798 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
799 break;
800 default:
801 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
Eric Laurent6d517662012-04-23 18:42:39 -0700802 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
803 }
Eric Laurent212532b2014-07-21 15:43:18 -0700804
805 if (isPlatformTelevision()) {
806 mRingerModeAffectedStreams = 0;
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700807 } else {
Eric Laurent212532b2014-07-21 15:43:18 -0700808 if (isInCommunication()) {
809 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
810 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
811 } else {
812 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
813 }
Eric Laurent6d517662012-04-23 18:42:39 -0700814 }
Eric Laurent212532b2014-07-21 15:43:18 -0700815
Eric Laurent6d517662012-04-23 18:42:39 -0700816 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
817 if (updateVolumes) {
Eric Laurent42b041e2013-03-29 11:36:03 -0700818 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700819 // apply stream mute states according to new value of mRingerModeAffectedStreams
John Spurlock661f2cf2014-11-17 10:29:10 -0500820 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent6d517662012-04-23 18:42:39 -0700821 sendMsg(mAudioHandler,
822 MSG_SET_ALL_VOLUMES,
823 SENDMSG_QUEUE,
824 0,
825 0,
826 mStreamStates[AudioSystem.STREAM_DTMF], 0);
827 }
828 }
829
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700830 private void readDockAudioSettings(ContentResolver cr)
831 {
832 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -0700833 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700834
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700835 sendMsg(mAudioHandler,
836 MSG_SET_FORCE_USE,
837 SENDMSG_QUEUE,
838 AudioSystem.FOR_DOCK,
839 mDockAudioMediaEnabled ?
840 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
841 null,
842 0);
843 }
844
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845 private void readPersistedSettings() {
846 final ContentResolver cr = mContentResolver;
847
Eric Laurentbffc3d12012-05-07 17:43:49 -0700848 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700849 Settings.Global.getInt(
850 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -0700851 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -0700852 // sanity check in case the settings are restored from a device with incompatible
853 // ringer modes
John Spurlock97559372014-10-24 16:27:36 -0400854 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -0800855 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700856 }
857 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
858 ringerMode = AudioManager.RINGER_MODE_SILENT;
859 }
860 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700861 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -0800862 }
Eric Laurent212532b2014-07-21 15:43:18 -0700863 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -0700864 ringerMode = AudioManager.RINGER_MODE_NORMAL;
865 }
Glenn Kastenba195eb2011-12-13 09:30:40 -0800866 synchronized(mSettingsLock) {
867 mRingerMode = ringerMode;
John Spurlock661f2cf2014-11-17 10:29:10 -0500868 if (mRingerModeExternal == -1) {
869 mRingerModeExternal = mRingerMode;
870 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871
Eric Laurentdd45d012012-10-08 09:04:34 -0700872 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
873 // are still needed while setVibrateSetting() and getVibrateSetting() are being
874 // deprecated.
John Spurlock61560172015-02-06 19:46:04 -0500875 mVibrateSetting = AudioSystem.getValueForVibrateSetting(0,
Eric Laurentdd45d012012-10-08 09:04:34 -0700876 AudioManager.VIBRATE_TYPE_NOTIFICATION,
877 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
878 : AudioManager.VIBRATE_SETTING_OFF);
John Spurlock61560172015-02-06 19:46:04 -0500879 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting,
Eric Laurentdd45d012012-10-08 09:04:34 -0700880 AudioManager.VIBRATE_TYPE_RINGER,
881 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
882 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700884 updateRingerModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700885 readDockAudioSettings(cr);
Eric Laurent402f7f22011-02-04 12:30:32 -0800886 }
Eric Laurentc1d41662011-07-19 11:21:13 -0700887
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700888 mMuteAffectedStreams = System.getIntForUser(cr,
John Spurlock61560172015-02-06 19:46:04 -0500889 System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
John Spurlock24c05182015-02-05 12:30:36 -0500890 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800891
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700892 boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
893 0, UserHandle.USER_CURRENT) == 1;
Eric Laurent83a017b2013-03-19 18:15:31 -0700894 if (mUseFixedVolume) {
895 masterMute = false;
896 AudioSystem.setMasterVolume(1.0f);
897 }
Justin Koh57978ed2012-04-03 17:37:58 -0700898 AudioSystem.setMasterMute(masterMute);
899 broadcastMasterMuteStatus(masterMute);
900
Julia Reynoldsb53453f2014-08-22 11:42:43 -0400901 boolean microphoneMute =
902 System.getIntForUser(cr, System.MICROPHONE_MUTE, 0, UserHandle.USER_CURRENT) == 1;
903 AudioSystem.muteMicrophone(microphoneMute);
904
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800905 // Each stream will read its own persisted settings
906
John Spurlockbcc10872014-11-28 15:29:21 -0500907 // Broadcast the sticky intents
908 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
909 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800910
911 // Broadcast vibrate settings
912 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
913 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -0700914
John Spurlock33f4e042014-07-11 13:10:58 -0400915 // Load settings for the volume controller
916 mVolumeController.loadSettings(cr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800917 }
918
Eric Laurenta553c252009-07-17 12:17:14 -0700919 private int rescaleIndex(int index, int srcStream, int dstStream) {
920 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
921 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800922
Jon Eklund318f0fe2014-01-23 17:53:48 -0600923 private class AudioOrientationEventListener
924 extends OrientationEventListener {
925 public AudioOrientationEventListener(Context context) {
926 super(context);
927 }
928
929 @Override
930 public void onOrientationChanged(int orientation) {
931 //Even though we're responding to phone orientation events,
932 //use display rotation so audio stays in sync with video/dialogs
933 int newRotation = ((WindowManager) mContext.getSystemService(
934 Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
935 if (newRotation != mDeviceRotation) {
936 mDeviceRotation = newRotation;
937 setRotationForAudioSystem();
938 }
939 }
940 }
941
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 ///////////////////////////////////////////////////////////////////////////
943 // IPC methods
944 ///////////////////////////////////////////////////////////////////////////
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 /** @see AudioManager#adjustVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700946 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
947 String callingPackage) {
RoboErik272e1612014-09-05 11:39:29 -0700948 adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
949 Binder.getCallingUid());
950 }
951
952 private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
953 String callingPackage, int uid) {
John Spurlockae641c92014-06-30 18:11:40 -0400954 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType
955 + ", flags=" + flags);
Eric Laurent402f7f22011-02-04 12:30:32 -0800956 int streamType;
RoboErik4197cb62015-01-21 15:45:32 -0800957 boolean isMute = isMuteAdjust(direction);
Eric Laurent45c90ce2012-04-24 18:44:22 -0700958 if (mVolumeControlStream != -1) {
959 streamType = mVolumeControlStream;
Eric Laurent402f7f22011-02-04 12:30:32 -0800960 } else {
961 streamType = getActiveStreamType(suggestedStreamType);
962 }
John Spurlock33f4e042014-07-11 13:10:58 -0400963 final int resolvedStream = mStreamVolumeAlias[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964
RoboErik2811dd32014-08-12 09:48:13 -0700965 // Play sounds on STREAM_RING only.
966 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
John Spurlock33f4e042014-07-11 13:10:58 -0400967 resolvedStream != AudioSystem.STREAM_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 flags &= ~AudioManager.FLAG_PLAY_SOUND;
969 }
970
John Spurlock33f4e042014-07-11 13:10:58 -0400971 // For notifications/ring, show the ui before making any adjustments
RoboErik4197cb62015-01-21 15:45:32 -0800972 // Don't suppress mute/unmute requests
973 if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
John Spurlock33f4e042014-07-11 13:10:58 -0400974 direction = 0;
975 flags &= ~AudioManager.FLAG_PLAY_SOUND;
976 flags &= ~AudioManager.FLAG_VIBRATE;
977 if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
978 }
979
RoboErik272e1612014-09-05 11:39:29 -0700980 adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 }
982
983 /** @see AudioManager#adjustStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700984 public void adjustStreamVolume(int streamType, int direction, int flags,
985 String callingPackage) {
RoboErik0dac35a2014-08-12 15:48:49 -0700986 adjustStreamVolume(streamType, direction, flags, callingPackage, Binder.getCallingUid());
987 }
988
989 private void adjustStreamVolume(int streamType, int direction, int flags,
990 String callingPackage, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -0700991 if (mUseFixedVolume) {
992 return;
993 }
John Spurlockae641c92014-06-30 18:11:40 -0400994 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction
995 + ", flags="+flags);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700996
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 ensureValidDirection(direction);
998 ensureValidStreamType(streamType);
999
RoboErik4197cb62015-01-21 15:45:32 -08001000 boolean isMuteAdjust = isMuteAdjust(direction);
1001
John Spurlock3ce37252015-02-17 13:20:45 -05001002 if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
1003 return;
1004 }
1005
Eric Laurent96a33d12011-11-08 10:31:57 -08001006 // use stream type alias here so that streams with same alias have the same behavior,
1007 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
1008 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
Eric Laurent6d517662012-04-23 18:42:39 -07001009 int streamTypeAlias = mStreamVolumeAlias[streamType];
RoboErik4197cb62015-01-21 15:45:32 -08001010
Eric Laurentb024c302011-10-14 17:19:27 -07001011 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001012
1013 final int device = getDeviceForStream(streamTypeAlias);
Eric Laurent3ef75492012-11-28 12:12:23 -08001014
Eric Laurent42b041e2013-03-29 11:36:03 -07001015 int aliasIndex = streamState.getIndex(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001016 boolean adjustVolume = true;
Eric Laurent3ef75492012-11-28 12:12:23 -08001017 int step;
Eric Laurent24482012012-05-10 09:41:17 -07001018
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001019 // skip a2dp absolute volume control request when the device
1020 // is not an a2dp device
1021 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1022 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1023 return;
1024 }
1025
RoboErik0dac35a2014-08-12 15:48:49 -07001026 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
1027 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001028 return;
1029 }
1030
Eric Laurentfde16d52012-12-03 14:42:39 -08001031 // reset any pending volume command
1032 synchronized (mSafeMediaVolumeState) {
1033 mPendingVolumeCommand = null;
1034 }
1035
Eric Laurent3ef75492012-11-28 12:12:23 -08001036 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1037 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1038 ((device & mFixedVolumeDevices) != 0)) {
1039 flags |= AudioManager.FLAG_FIXED_VOLUME;
1040
1041 // Always toggle between max safe volume and 0 for fixed volume devices where safe
1042 // volume is enforced, and max and 0 for the others.
1043 // This is simulated by stepping by the full allowed volume range
1044 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1045 (device & mSafeMediaVolumeDevices) != 0) {
1046 step = mSafeMediaVolumeIndex;
1047 } else {
1048 step = streamState.getMaxIndex();
1049 }
1050 if (aliasIndex != 0) {
1051 aliasIndex = step;
1052 }
1053 } else {
1054 // convert one UI step (+/-1) into a number of internal units on the stream alias
1055 step = rescaleIndex(10, streamType, streamTypeAlias);
1056 }
1057
Eric Laurent42b041e2013-03-29 11:36:03 -07001058 // If either the client forces allowing ringer modes for this adjustment,
1059 // or the stream type is one that is affected by ringer modes
1060 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1061 (streamTypeAlias == getMasterStreamType())) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001062 int ringerMode = getRingerModeInternal();
Eric Laurent42b041e2013-03-29 11:36:03 -07001063 // do not vibrate if already in vibrate mode
1064 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
1065 flags &= ~AudioManager.FLAG_VIBRATE;
Eric Laurent3ef75492012-11-28 12:12:23 -08001066 }
RoboErik5452e252015-02-06 15:33:53 -08001067 // Check if the ringer mode handles this adjustment. If it does we don't
1068 // need to adjust the volume further.
1069 final int result = checkForRingerModeChange(aliasIndex, direction, step, streamState.mIsMuted);
John Spurlocka11b4af2014-06-01 11:52:23 -04001070 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
1071 // If suppressing a volume adjustment in silent mode, display the UI hint
1072 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
1073 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
1074 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001075 // If suppressing a volume down adjustment in vibrate mode, display the UI hint
1076 if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
1077 flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
1078 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001079 }
Eric Laurent3ef75492012-11-28 12:12:23 -08001080
Eric Laurent42b041e2013-03-29 11:36:03 -07001081 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001082
Eric Laurent42b041e2013-03-29 11:36:03 -07001083 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
RoboErik5452e252015-02-06 15:33:53 -08001084 mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001085
John Du5a0cf7a2013-07-19 11:30:34 -07001086 // Check if volume update should be send to AVRCP
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001087 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1088 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1089 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1090 synchronized (mA2dpAvrcpLock) {
1091 if (mA2dp != null && mAvrcpAbsVolSupported) {
1092 mA2dp.adjustAvrcpAbsoluteVolume(direction);
1093 }
John Du5a0cf7a2013-07-19 11:30:34 -07001094 }
1095 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001096
RoboErik4197cb62015-01-21 15:45:32 -08001097 if (isMuteAdjust) {
1098 boolean state;
1099 if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
1100 state = !streamState.mIsMuted;
1101 } else {
1102 state = direction == AudioManager.ADJUST_MUTE;
1103 }
1104 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1105 setSystemAudioMute(state);
1106 }
1107 for (int stream = 0; stream < mStreamStates.length; stream++) {
1108 if (streamTypeAlias == mStreamVolumeAlias[stream]) {
1109 mStreamStates[stream].mute(state);
RoboErik4197cb62015-01-21 15:45:32 -08001110 }
1111 }
1112 } else if ((direction == AudioManager.ADJUST_RAISE) &&
Eric Laurent42b041e2013-03-29 11:36:03 -07001113 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
RoboErik4197cb62015-01-21 15:45:32 -08001114 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -04001115 mVolumeController.postDisplaySafeVolumeWarning(flags);
RoboErik4197cb62015-01-21 15:45:32 -08001116 } else if (streamState.adjustIndex(direction * step, device) || streamState.mIsMuted) {
1117 // Post message to set system volume (it in turn will post a
1118 // message to persist).
1119 if (streamState.mIsMuted) {
1120 // Unmute the stream if it was previously muted
RoboErik5452e252015-02-06 15:33:53 -08001121 if (direction == AudioManager.ADJUST_RAISE) {
1122 // unmute immediately for volume up
1123 streamState.mute(false);
1124 } else if (direction == AudioManager.ADJUST_LOWER) {
1125 sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
1126 streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
1127 }
RoboErik4197cb62015-01-21 15:45:32 -08001128 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001129 sendMsg(mAudioHandler,
1130 MSG_SET_DEVICE_VOLUME,
1131 SENDMSG_QUEUE,
1132 device,
1133 0,
1134 streamState,
1135 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001136 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001137
RoboErik4197cb62015-01-21 15:45:32 -08001138 // Check if volume update should be sent to Hdmi system audio.
Jungshik Jang41d97462014-06-30 22:26:29 +09001139 int newIndex = mStreamStates[streamType].getIndex(device);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001140 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1141 setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
1142 }
Eric Laurent212532b2014-07-21 15:43:18 -07001143 if (mHdmiManager != null) {
1144 synchronized (mHdmiManager) {
Eric Laurent212532b2014-07-21 15:43:18 -07001145 // mHdmiCecSink true => mHdmiPlaybackClient != null
1146 if (mHdmiCecSink &&
1147 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1148 oldIndex != newIndex) {
1149 synchronized (mHdmiPlaybackClient) {
1150 int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
RoboErik4197cb62015-01-21 15:45:32 -08001151 KeyEvent.KEYCODE_VOLUME_UP;
Eric Laurent212532b2014-07-21 15:43:18 -07001152 mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1153 mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1154 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001155 }
1156 }
1157 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001158 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001159 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001160 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161 }
1162
RoboErik5452e252015-02-06 15:33:53 -08001163 // Called after a delay when volume down is pressed while muted
1164 private void onUnmuteStream(int stream, int flags) {
1165 VolumeStreamState streamState = mStreamStates[stream];
1166 streamState.mute(false);
1167
1168 final int device = getDeviceForStream(stream);
1169 final int index = mStreamStates[stream].getIndex(device);
1170 sendVolumeUpdate(stream, index, index, flags);
1171 }
1172
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001173 private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
1174 if (mHdmiManager == null
1175 || mHdmiTvClient == null
1176 || oldVolume == newVolume
1177 || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
1178
1179 // Sets the audio volume of AVR when we are in system audio mode. The new volume info
1180 // is tranformed to HDMI-CEC commands and passed through CEC bus.
1181 synchronized (mHdmiManager) {
1182 if (!mHdmiSystemAudioSupported) return;
1183 synchronized (mHdmiTvClient) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001184 final long token = Binder.clearCallingIdentity();
1185 try {
1186 mHdmiTvClient.setSystemAudioVolume(
1187 (oldVolume + 5) / 10, (newVolume + 5) / 10, maxVolume);
1188 } finally {
1189 Binder.restoreCallingIdentity(token);
1190 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001191 }
1192 }
1193 }
1194
Dianne Hackborn961cae92013-03-20 14:59:43 -07001195 /** @see AudioManager#adjustMasterVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001196 public void adjustMasterVolume(int steps, int flags, String callingPackage) {
RoboErik519c7742014-11-18 10:59:09 -08001197 adjustMasterVolume(steps, flags, callingPackage, Binder.getCallingUid());
1198 }
1199
1200 public void adjustMasterVolume(int steps, int flags, String callingPackage, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001201 if (mUseFixedVolume) {
1202 return;
1203 }
RoboErik4197cb62015-01-21 15:45:32 -08001204 if (isMuteAdjust(steps)) {
1205 setMasterMuteInternal(steps, flags, callingPackage, uid);
1206 return;
1207 }
Lei Zhang6c798972012-03-02 11:40:12 -08001208 ensureValidSteps(steps);
Mike Lockwood97606472012-02-09 11:24:10 -08001209 int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1210 int delta = 0;
Lei Zhang6c798972012-03-02 11:40:12 -08001211 int numSteps = Math.abs(steps);
1212 int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
1213 for (int i = 0; i < numSteps; ++i) {
1214 delta = findVolumeDelta(direction, volume);
1215 volume += delta;
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001216 }
RoboErik24b082f2012-02-24 14:21:16 -08001217
Lei Zhang6c798972012-03-02 11:40:12 -08001218 //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
RoboErik519c7742014-11-18 10:59:09 -08001219 setMasterVolume(volume, flags, callingPackage, uid);
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001220 }
1221
Eric Laurentfde16d52012-12-03 14:42:39 -08001222 // StreamVolumeCommand contains the information needed to defer the process of
1223 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1224 class StreamVolumeCommand {
1225 public final int mStreamType;
1226 public final int mIndex;
1227 public final int mFlags;
1228 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001229
Eric Laurentfde16d52012-12-03 14:42:39 -08001230 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1231 mStreamType = streamType;
1232 mIndex = index;
1233 mFlags = flags;
1234 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001235 }
John Spurlock35134602014-07-24 18:10:48 -04001236
1237 @Override
1238 public String toString() {
1239 return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1240 .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1241 .append(mDevice).append('}').toString();
1242 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001243 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001244
Eric Laurentfde16d52012-12-03 14:42:39 -08001245 private void onSetStreamVolume(int streamType, int index, int flags, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001246 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
Eric Laurent3ef75492012-11-28 12:12:23 -08001247 // setting volume on master stream type also controls silent mode
1248 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1249 (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
1250 int newRingerMode;
1251 if (index == 0) {
1252 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlock86005342014-05-23 11:58:00 -04001253 : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
1254 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001255 } else {
1256 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1257 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001258 setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/);
Eric Laurent3ef75492012-11-28 12:12:23 -08001259 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001260 }
1261
1262 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001263 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
RoboErik0dac35a2014-08-12 15:48:49 -07001264 setStreamVolume(streamType, index, flags, callingPackage, Binder.getCallingUid());
1265 }
1266
1267 private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
1268 int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001269 if (mUseFixedVolume) {
1270 return;
1271 }
1272
Eric Laurentfde16d52012-12-03 14:42:39 -08001273 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001274 int streamTypeAlias = mStreamVolumeAlias[streamType];
1275 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001276
1277 final int device = getDeviceForStream(streamType);
1278 int oldIndex;
1279
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001280 // skip a2dp absolute volume control request when the device
1281 // is not an a2dp device
1282 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1283 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1284 return;
1285 }
1286
RoboErik0dac35a2014-08-12 15:48:49 -07001287 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
1288 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001289 return;
1290 }
1291
Eric Laurentfde16d52012-12-03 14:42:39 -08001292 synchronized (mSafeMediaVolumeState) {
1293 // reset any pending volume command
1294 mPendingVolumeCommand = null;
1295
Eric Laurent42b041e2013-03-29 11:36:03 -07001296 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001297
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001298 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001299
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001300 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1301 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1302 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1303 synchronized (mA2dpAvrcpLock) {
1304 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001305 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001306 }
John Du5a0cf7a2013-07-19 11:30:34 -07001307 }
1308 }
1309
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001310 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1311 setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
Jungshik Jang41d97462014-06-30 22:26:29 +09001312 }
1313
Eric Laurentfde16d52012-12-03 14:42:39 -08001314 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001315 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001316 ((device & mFixedVolumeDevices) != 0)) {
1317 flags |= AudioManager.FLAG_FIXED_VOLUME;
1318
1319 // volume is either 0 or max allowed for fixed volume devices
1320 if (index != 0) {
1321 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1322 (device & mSafeMediaVolumeDevices) != 0) {
1323 index = mSafeMediaVolumeIndex;
1324 } else {
1325 index = streamState.getMaxIndex();
1326 }
1327 }
1328 }
1329
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001330 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001331 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001332 mPendingVolumeCommand = new StreamVolumeCommand(
1333 streamType, index, flags, device);
1334 } else {
1335 onSetStreamVolume(streamType, index, flags, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07001336 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001337 }
1338 }
Eric Laurent25101b02011-02-02 09:33:30 -08001339 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001340 }
1341
Eric Laurent45c90ce2012-04-24 18:44:22 -07001342 /** @see AudioManager#forceVolumeControlStream(int) */
1343 public void forceVolumeControlStream(int streamType, IBinder cb) {
1344 synchronized(mForceControlStreamLock) {
1345 mVolumeControlStream = streamType;
1346 if (mVolumeControlStream == -1) {
1347 if (mForceControlStreamClient != null) {
1348 mForceControlStreamClient.release();
1349 mForceControlStreamClient = null;
1350 }
1351 } else {
1352 mForceControlStreamClient = new ForceControlStreamClient(cb);
1353 }
1354 }
1355 }
1356
1357 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1358 private IBinder mCb; // To be notified of client's death
1359
1360 ForceControlStreamClient(IBinder cb) {
1361 if (cb != null) {
1362 try {
1363 cb.linkToDeath(this, 0);
1364 } catch (RemoteException e) {
1365 // Client has died!
1366 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1367 cb = null;
1368 }
1369 }
1370 mCb = cb;
1371 }
1372
1373 public void binderDied() {
1374 synchronized(mForceControlStreamLock) {
1375 Log.w(TAG, "SCO client died");
1376 if (mForceControlStreamClient != this) {
1377 Log.w(TAG, "unregistered control stream client died");
1378 } else {
1379 mForceControlStreamClient = null;
1380 mVolumeControlStream = -1;
1381 }
1382 }
1383 }
1384
1385 public void release() {
1386 if (mCb != null) {
1387 mCb.unlinkToDeath(this, 0);
1388 mCb = null;
1389 }
1390 }
1391 }
1392
Lei Zhang6c798972012-03-02 11:40:12 -08001393 private int findVolumeDelta(int direction, int volume) {
1394 int delta = 0;
1395 if (direction == AudioManager.ADJUST_RAISE) {
1396 if (volume == MAX_MASTER_VOLUME) {
1397 return 0;
1398 }
1399 // This is the default value if we make it to the end
1400 delta = mMasterVolumeRamp[1];
1401 // If we're raising the volume move down the ramp array until we
1402 // find the volume we're above and use that groups delta.
1403 for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
1404 if (volume >= mMasterVolumeRamp[i - 1]) {
1405 delta = mMasterVolumeRamp[i];
1406 break;
1407 }
1408 }
1409 } else if (direction == AudioManager.ADJUST_LOWER){
1410 if (volume == 0) {
1411 return 0;
1412 }
1413 int length = mMasterVolumeRamp.length;
1414 // This is the default value if we make it to the end
1415 delta = -mMasterVolumeRamp[length - 1];
1416 // If we're lowering the volume move up the ramp array until we
1417 // find the volume we're below and use the group below it's delta
1418 for (int i = 2; i < length; i += 2) {
1419 if (volume <= mMasterVolumeRamp[i]) {
1420 delta = -mMasterVolumeRamp[i - 1];
1421 break;
1422 }
1423 }
1424 }
1425 return delta;
1426 }
1427
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001428 private void sendBroadcastToAll(Intent intent) {
Christopher Tate267603f2015-01-20 14:21:21 -08001429 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001430 final long ident = Binder.clearCallingIdentity();
1431 try {
1432 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1433 } finally {
1434 Binder.restoreCallingIdentity(ident);
1435 }
1436 }
1437
1438 private void sendStickyBroadcastToAll(Intent intent) {
1439 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);
Eric Laurent25101b02011-02-02 09:33:30 -08001457
Eric Laurent4bbcc652012-09-24 14:26:30 -07001458 if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
1459 oldIndex = (oldIndex + 5) / 10;
1460 index = (index + 5) / 10;
1461 Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
1462 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
1463 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
1464 intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
1465 sendBroadcastToAll(intent);
1466 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001467 }
1468
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001469 // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
1470 // receives volume notification from Audio Receiver.
1471 private int updateFlagsForSystemAudio(int flags) {
1472 if (mHdmiTvClient != null) {
1473 synchronized (mHdmiTvClient) {
1474 if (mHdmiSystemAudioSupported &&
1475 ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
1476 flags &= ~AudioManager.FLAG_SHOW_UI;
1477 }
1478 }
1479 }
1480 return flags;
1481 }
1482
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001483 // UI update and Broadcast Intent
1484 private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001485 mVolumeController.postMasterVolumeChanged(updateFlagsForSystemAudio(flags));
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001486
1487 Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
1488 intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
1489 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001490 sendBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001491 }
1492
1493 // UI update and Broadcast Intent
1494 private void sendMasterMuteUpdate(boolean muted, int flags) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001495 mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
Justin Koh57978ed2012-04-03 17:37:58 -07001496 broadcastMasterMuteStatus(muted);
1497 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001498
Justin Koh57978ed2012-04-03 17:37:58 -07001499 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001500 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1501 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001502 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1503 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001504 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001505 }
1506
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001507 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001508 * Sets the stream state's index, and posts a message to set system volume.
1509 * This will not call out to the UI. Assumes a valid stream type.
1510 *
1511 * @param streamType Type of the stream
1512 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001513 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001514 * @param force If true, set the volume even if the desired volume is same
1515 * as the current volume.
1516 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001517 private void setStreamVolumeInt(int streamType,
1518 int index,
1519 int device,
Eric Laurent42b041e2013-03-29 11:36:03 -07001520 boolean force) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001521 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07001522
Eric Laurent42b041e2013-03-29 11:36:03 -07001523 if (streamState.setIndex(index, device) || force) {
1524 // Post message to set system volume (it in turn will post a message
1525 // to persist).
1526 sendMsg(mAudioHandler,
1527 MSG_SET_DEVICE_VOLUME,
1528 SENDMSG_QUEUE,
1529 device,
1530 0,
1531 streamState,
1532 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001533 }
1534 }
1535
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001536 private void setSystemAudioMute(boolean state) {
1537 if (mHdmiManager == null || mHdmiTvClient == null) return;
1538 synchronized (mHdmiManager) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001539 if (!mHdmiSystemAudioSupported) return;
1540 synchronized (mHdmiTvClient) {
1541 final long token = Binder.clearCallingIdentity();
1542 try {
1543 mHdmiTvClient.setSystemAudioMute(state);
1544 } finally {
1545 Binder.restoreCallingIdentity(token);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001546 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001547 }
1548 }
1549 }
1550
Eric Laurent25101b02011-02-02 09:33:30 -08001551 /** get stream mute state. */
1552 public boolean isStreamMute(int streamType) {
RoboErik7c82ced2014-12-04 17:39:08 -08001553 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1554 streamType = getActiveStreamType(streamType);
1555 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001556 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08001557 return mStreamStates[streamType].mIsMuted;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001558 }
Eric Laurent25101b02011-02-02 09:33:30 -08001559 }
1560
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07001561 private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
1562 private IBinder mICallback; // To be notified of client's death
1563
1564 RmtSbmxFullVolDeathHandler(IBinder cb) {
1565 mICallback = cb;
1566 try {
1567 cb.linkToDeath(this, 0/*flags*/);
1568 } catch (RemoteException e) {
1569 Log.e(TAG, "can't link to death", e);
1570 }
1571 }
1572
1573 boolean isHandlerFor(IBinder cb) {
1574 return mICallback.equals(cb);
1575 }
1576
1577 void forget() {
1578 try {
1579 mICallback.unlinkToDeath(this, 0/*flags*/);
1580 } catch (NoSuchElementException e) {
1581 Log.e(TAG, "error unlinking to death", e);
1582 }
1583 }
1584
1585 public void binderDied() {
1586 Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
1587 forceRemoteSubmixFullVolume(false, mICallback);
1588 }
1589 }
1590
1591 /**
1592 * call must be synchronized on mRmtSbmxFullVolDeathHandlers
1593 * @return true if there is a registered death handler, false otherwise */
1594 private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1595 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1596 while (it.hasNext()) {
1597 final RmtSbmxFullVolDeathHandler handler = it.next();
1598 if (handler.isHandlerFor(cb)) {
1599 handler.forget();
1600 mRmtSbmxFullVolDeathHandlers.remove(handler);
1601 return true;
1602 }
1603 }
1604 return false;
1605 }
1606
1607 /** call synchronized on mRmtSbmxFullVolDeathHandlers */
1608 private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1609 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1610 while (it.hasNext()) {
1611 if (it.next().isHandlerFor(cb)) {
1612 return true;
1613 }
1614 }
1615 return false;
1616 }
1617
1618 private int mRmtSbmxFullVolRefCount = 0;
1619 private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
1620 new ArrayList<RmtSbmxFullVolDeathHandler>();
1621
1622 public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
1623 if (cb == null) {
1624 return;
1625 }
1626 if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
1627 android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
1628 Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
1629 return;
1630 }
1631 synchronized(mRmtSbmxFullVolDeathHandlers) {
1632 boolean applyRequired = false;
1633 if (startForcing) {
1634 if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
1635 mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
1636 if (mRmtSbmxFullVolRefCount == 0) {
1637 mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1638 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1639 applyRequired = true;
1640 }
1641 mRmtSbmxFullVolRefCount++;
1642 }
1643 } else {
1644 if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
1645 mRmtSbmxFullVolRefCount--;
1646 if (mRmtSbmxFullVolRefCount == 0) {
1647 mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1648 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1649 applyRequired = true;
1650 }
1651 }
1652 }
1653 if (applyRequired) {
1654 // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
1655 checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
1656 mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
1657 }
1658 }
1659 }
1660
RoboErik4197cb62015-01-21 15:45:32 -08001661 private void setMasterMuteInternal(int adjust, int flags, String callingPackage, int uid) {
RoboErik7c82ced2014-12-04 17:39:08 -08001662 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
1663 != AppOpsManager.MODE_ALLOWED) {
Julia Reynolds4a21b252014-06-04 11:11:43 -04001664 return;
1665 }
RoboErik4197cb62015-01-21 15:45:32 -08001666 boolean state;
1667 if (adjust == AudioManager.ADJUST_TOGGLE_MUTE) {
1668 state = !AudioSystem.getMasterMute();
1669 } else {
1670 state = adjust == AudioManager.ADJUST_MUTE;
1671 }
Jason Simmons1ce5b262012-02-02 13:00:17 -08001672 if (state != AudioSystem.getMasterMute()) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001673 setSystemAudioMute(state);
Jason Simmons1ce5b262012-02-02 13:00:17 -08001674 AudioSystem.setMasterMute(state);
Justin Koh57978ed2012-04-03 17:37:58 -07001675 // Post a persist master volume msg
Justin Koh75cf9e12012-04-04 15:27:37 -07001676 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001677 : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
Justin Koh0273af52012-04-04 18:29:50 -07001678 sendMasterMuteUpdate(state, flags);
RoboErik7c82ced2014-12-04 17:39:08 -08001679
1680 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1681 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, state);
1682 sendBroadcastToAll(intent);
Jason Simmons1ce5b262012-02-02 13:00:17 -08001683 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08001684 }
1685
1686 /** get master mute state. */
1687 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08001688 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001689 }
1690
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07001691 protected static int getMaxStreamVolume(int streamType) {
1692 return MAX_STREAM_VOLUME[streamType];
1693 }
1694
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001695 /** @see AudioManager#getStreamVolume(int) */
1696 public int getStreamVolume(int streamType) {
1697 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001698 int device = getDeviceForStream(streamType);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001699 synchronized (VolumeStreamState.class) {
1700 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001701
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001702 // by convention getStreamVolume() returns 0 when a stream is muted.
RoboErik4197cb62015-01-21 15:45:32 -08001703 if (mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001704 index = 0;
1705 }
1706 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
1707 (device & mFixedVolumeDevices) != 0) {
1708 index = mStreamStates[streamType].getMaxIndex();
1709 }
1710 return (index + 5) / 10;
Eric Laurent42b041e2013-03-29 11:36:03 -07001711 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001712 }
1713
RoboErik519c7742014-11-18 10:59:09 -08001714 @Override
Mike Lockwood47676902011-11-08 10:31:21 -08001715 public int getMasterVolume() {
Mike Lockwoodce952c82011-11-14 10:47:42 -08001716 if (isMasterMute()) return 0;
1717 return getLastAudibleMasterVolume();
Mike Lockwood8dc1dab2011-10-27 09:52:41 -04001718 }
1719
RoboErik519c7742014-11-18 10:59:09 -08001720 @Override
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001721 public void setMasterVolume(int volume, int flags, String callingPackage) {
RoboErik519c7742014-11-18 10:59:09 -08001722 setMasterVolume(volume, flags, callingPackage, Binder.getCallingUid());
1723 }
1724
1725 public void setMasterVolume(int volume, int flags, String callingPackage, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001726 if (mUseFixedVolume) {
1727 return;
1728 }
1729
RoboErik519c7742014-11-18 10:59:09 -08001730 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
1731 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001732 return;
1733 }
1734
Mike Lockwood97606472012-02-09 11:24:10 -08001735 if (volume < 0) {
1736 volume = 0;
1737 } else if (volume > MAX_MASTER_VOLUME) {
1738 volume = MAX_MASTER_VOLUME;
1739 }
Mike Lockwood5c55a052011-12-15 17:21:44 -05001740 doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
1741 }
1742
1743 private void doSetMasterVolume(float volume, int flags) {
1744 // don't allow changing master volume when muted
1745 if (!AudioSystem.getMasterMute()) {
1746 int oldVolume = getMasterVolume();
1747 AudioSystem.setMasterVolume(volume);
1748
1749 int newVolume = getMasterVolume();
1750 if (newVolume != oldVolume) {
1751 // Post a persist master volume msg
1752 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
1753 Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001754 setSystemAudioVolume(oldVolume, newVolume, getMasterMaxVolume(), flags);
Mike Lockwood5c55a052011-12-15 17:21:44 -05001755 }
Justin Koh3caba512012-04-02 15:32:18 -07001756 // Send the volume update regardless whether there was a change.
1757 sendMasterVolumeUpdate(flags, oldVolume, newVolume);
Mike Lockwood5c55a052011-12-15 17:21:44 -05001758 }
Mike Lockwood8dc1dab2011-10-27 09:52:41 -04001759 }
1760
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001761 /** @see AudioManager#getStreamMaxVolume(int) */
1762 public int getStreamMaxVolume(int streamType) {
1763 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07001764 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001765 }
1766
Mike Lockwood47676902011-11-08 10:31:21 -08001767 public int getMasterMaxVolume() {
1768 return MAX_MASTER_VOLUME;
1769 }
Eric Laurent25101b02011-02-02 09:33:30 -08001770
1771 /** Get last audible volume before stream was muted. */
1772 public int getLastAudibleStreamVolume(int streamType) {
1773 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001774 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001775 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08001776 }
1777
Mike Lockwoodce952c82011-11-14 10:47:42 -08001778 /** Get last audible master volume before it was muted. */
1779 public int getLastAudibleMasterVolume() {
1780 return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1781 }
1782
Dianne Hackborn961cae92013-03-20 14:59:43 -07001783 /** @see AudioManager#getMasterStreamType() */
Eric Laurent6d517662012-04-23 18:42:39 -07001784 public int getMasterStreamType() {
John Spurlock4f0f1202014-08-05 13:28:33 -04001785 return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
Eric Laurent6d517662012-04-23 18:42:39 -07001786 }
1787
Emily Bernier22c921a2014-05-28 11:01:32 -04001788 /** @see AudioManager#setMicrophoneMute(boolean) */
1789 public void setMicrophoneMute(boolean on, String callingPackage) {
1790 if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(),
1791 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1792 return;
1793 }
Jean-Michel Trivi4a4fea02014-08-29 18:14:09 -07001794 if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
1795 return;
1796 }
Emily Bernier22c921a2014-05-28 11:01:32 -04001797
1798 AudioSystem.muteMicrophone(on);
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001799 // Post a persist microphone msg.
1800 sendMsg(mAudioHandler, MSG_PERSIST_MICROPHONE_MUTE, SENDMSG_REPLACE, on ? 1
1801 : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
Emily Bernier22c921a2014-05-28 11:01:32 -04001802 }
1803
John Spurlock661f2cf2014-11-17 10:29:10 -05001804 @Override
1805 public int getRingerModeExternal() {
1806 synchronized(mSettingsLock) {
1807 return mRingerModeExternal;
1808 }
1809 }
1810
1811 @Override
1812 public int getRingerModeInternal() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001813 synchronized(mSettingsLock) {
1814 return mRingerMode;
1815 }
1816 }
1817
1818 private void ensureValidRingerMode(int ringerMode) {
John Spurlock97559372014-10-24 16:27:36 -04001819 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001820 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1821 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001822 }
1823
John Spurlock97559372014-10-24 16:27:36 -04001824 /** @see AudioManager#isValidRingerMode(int) */
1825 public boolean isValidRingerMode(int ringerMode) {
1826 return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
1827 }
1828
John Spurlock661f2cf2014-11-17 10:29:10 -05001829 public void setRingerModeExternal(int ringerMode, String caller) {
John Spurlockaf88a192014-12-23 16:14:44 -05001830 setRingerMode(ringerMode, caller, true /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05001831 }
1832
1833 public void setRingerModeInternal(int ringerMode, String caller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05001834 enforceVolumeController("setRingerModeInternal");
John Spurlockaf88a192014-12-23 16:14:44 -05001835 setRingerMode(ringerMode, caller, false /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05001836 }
1837
1838 private void setRingerMode(int ringerMode, String caller, boolean external) {
Eric Laurent212532b2014-07-21 15:43:18 -07001839 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001840 return;
1841 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001842 if (caller == null || caller.length() == 0) {
1843 throw new IllegalArgumentException("Bad caller: " + caller);
1844 }
John Spurlock97559372014-10-24 16:27:36 -04001845 ensureValidRingerMode(ringerMode);
Eric Laurent24482012012-05-10 09:41:17 -07001846 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1847 ringerMode = AudioManager.RINGER_MODE_SILENT;
1848 }
John Spurlockaf88a192014-12-23 16:14:44 -05001849 final long identity = Binder.clearCallingIdentity();
1850 try {
1851 synchronized (mSettingsLock) {
1852 final int ringerModeInternal = getRingerModeInternal();
1853 final int ringerModeExternal = getRingerModeExternal();
1854 if (external) {
1855 setRingerModeExt(ringerMode);
1856 if (mRingerModeDelegate != null) {
1857 ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
1858 ringerMode, caller, ringerModeInternal);
1859 }
1860 if (ringerMode != ringerModeInternal) {
1861 setRingerModeInt(ringerMode, true /*persist*/);
1862 }
1863 } else /*internal*/ {
1864 if (ringerMode != ringerModeInternal) {
1865 setRingerModeInt(ringerMode, true /*persist*/);
1866 }
1867 if (mRingerModeDelegate != null) {
1868 ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
1869 ringerMode, caller, ringerModeExternal);
1870 }
1871 setRingerModeExt(ringerMode);
John Spurlock57627792014-12-11 11:29:54 -05001872 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001873 }
John Spurlockaf88a192014-12-23 16:14:44 -05001874 } finally {
1875 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876 }
1877 }
1878
John Spurlock661f2cf2014-11-17 10:29:10 -05001879 private void setRingerModeExt(int ringerMode) {
1880 synchronized(mSettingsLock) {
1881 if (ringerMode == mRingerModeExternal) return;
1882 mRingerModeExternal = ringerMode;
John Spurlocke5b42d92014-10-15 12:03:48 -04001883 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001884 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05001885 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
John Spurlocke5b42d92014-10-15 12:03:48 -04001886 }
1887
Eric Laurent4050c932009-07-08 02:52:14 -07001888 private void setRingerModeInt(int ringerMode, boolean persist) {
John Spurlockbcc10872014-11-28 15:29:21 -05001889 final boolean change;
Glenn Kastenba195eb2011-12-13 09:30:40 -08001890 synchronized(mSettingsLock) {
John Spurlockbcc10872014-11-28 15:29:21 -05001891 change = mRingerMode != ringerMode;
Glenn Kastenba195eb2011-12-13 09:30:40 -08001892 mRingerMode = ringerMode;
1893 }
Jason Parekhb1096152009-03-24 17:48:25 -07001894
Eric Laurent5b4e6542010-03-19 20:02:21 -07001895 // Mute stream if not previously muted by ringer mode and ringer mode
1896 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
1897 // Unmute stream if previously muted by ringer mode and ringer mode
1898 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07001899 int numStreamTypes = AudioSystem.getNumStreamTypes();
John Spurlock661f2cf2014-11-17 10:29:10 -05001900 final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE
1901 || ringerMode == AudioManager.RINGER_MODE_SILENT;
Eric Laurent5b4e6542010-03-19 20:02:21 -07001902 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001903 final boolean isMuted = isStreamMutedByRingerMode(streamType);
1904 final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
1905 if (isMuted == shouldMute) continue;
1906 if (!shouldMute) {
1907 // unmute
1908 // ring and notifications volume should never be 0 when not silenced
1909 // on voice capable devices or devices that support vibration
1910 if ((isPlatformVoice() || mHasVibrator) &&
1911 mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
1912 synchronized (VolumeStreamState.class) {
1913 Set set = mStreamStates[streamType].mIndex.entrySet();
1914 Iterator i = set.iterator();
1915 while (i.hasNext()) {
1916 Map.Entry entry = (Map.Entry)i.next();
1917 if ((Integer)entry.getValue() == 0) {
1918 entry.setValue(10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001919 }
1920 }
Eric Laurent9e0d25f2015-02-12 17:28:53 -08001921 // Persist volume for stream ring when it is changed here
1922 final int device = getDeviceForStream(streamType);
1923 sendMsg(mAudioHandler,
1924 MSG_PERSIST_VOLUME,
1925 SENDMSG_QUEUE,
1926 device,
1927 0,
1928 mStreamStates[streamType],
1929 PERSIST_DELAY);
Eric Laurentb024c302011-10-14 17:19:27 -07001930 }
Eric Laurent9bcf4012009-06-12 06:09:28 -07001931 }
RoboErik4197cb62015-01-21 15:45:32 -08001932 mStreamStates[streamType].mute(false);
John Spurlock661f2cf2014-11-17 10:29:10 -05001933 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent5b4e6542010-03-19 20:02:21 -07001934 } else {
John Spurlock661f2cf2014-11-17 10:29:10 -05001935 // mute
RoboErik4197cb62015-01-21 15:45:32 -08001936 mStreamStates[streamType].mute(true);
John Spurlock661f2cf2014-11-17 10:29:10 -05001937 mRingerModeMutedStreams |= (1 << streamType);
Jason Parekhb1096152009-03-24 17:48:25 -07001938 }
1939 }
Eric Laurenta553c252009-07-17 12:17:14 -07001940
Jason Parekhb1096152009-03-24 17:48:25 -07001941 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07001942 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08001943 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07001944 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
1945 }
John Spurlockbcc10872014-11-28 15:29:21 -05001946 if (change) {
1947 // Send sticky broadcast
1948 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
1949 }
Jason Parekhb1096152009-03-24 17:48:25 -07001950 }
1951
Mike Lockwood90631542012-01-06 11:20:37 -05001952 private void restoreMasterVolume() {
Eric Laurent83a017b2013-03-19 18:15:31 -07001953 if (mUseFixedVolume) {
1954 AudioSystem.setMasterVolume(1.0f);
1955 return;
1956 }
Mike Lockwood90631542012-01-06 11:20:37 -05001957 if (mUseMasterVolume) {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001958 float volume = Settings.System.getFloatForUser(mContentResolver,
1959 Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
Mike Lockwood90631542012-01-06 11:20:37 -05001960 if (volume >= 0.0f) {
1961 AudioSystem.setMasterVolume(volume);
1962 }
1963 }
1964 }
1965
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001966 /** @see AudioManager#shouldVibrate(int) */
1967 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001968 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001969
1970 switch (getVibrateSetting(vibrateType)) {
1971
1972 case AudioManager.VIBRATE_SETTING_ON:
John Spurlock57627792014-12-11 11:29:54 -05001973 return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001974
1975 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
John Spurlock57627792014-12-11 11:29:54 -05001976 return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001977
1978 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04001979 // return false, even for incoming calls
1980 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001981
1982 default:
1983 return false;
1984 }
1985 }
1986
1987 /** @see AudioManager#getVibrateSetting(int) */
1988 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001989 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001990 return (mVibrateSetting >> (vibrateType * 2)) & 3;
1991 }
1992
1993 /** @see AudioManager#setVibrateSetting(int, int) */
1994 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
1995
Eric Laurentbffc3d12012-05-07 17:43:49 -07001996 if (!mHasVibrator) return;
1997
John Spurlock61560172015-02-06 19:46:04 -05001998 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
1999 vibrateSetting);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002000
2001 // Broadcast change
2002 broadcastVibrateSetting(vibrateType);
2003
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002004 }
2005
Eric Laurent9272b4b2010-01-23 17:12:59 -08002006 private class SetModeDeathHandler implements IBinder.DeathRecipient {
2007 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002008 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002009 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
2010
Eric Laurent9f103de2011-09-08 15:04:23 -07002011 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08002012 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07002013 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002014 }
2015
2016 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07002017 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002018 synchronized(mSetModeDeathHandlers) {
2019 Log.w(TAG, "setMode() client died");
2020 int index = mSetModeDeathHandlers.indexOf(this);
2021 if (index < 0) {
2022 Log.w(TAG, "unregistered setMode() client died");
2023 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07002024 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
Eric Laurent9272b4b2010-01-23 17:12:59 -08002025 }
2026 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002027 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2028 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002029 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07002030 final long ident = Binder.clearCallingIdentity();
2031 disconnectBluetoothSco(newModeOwnerPid);
2032 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07002033 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08002034 }
2035
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002036 public int getPid() {
2037 return mPid;
2038 }
2039
Eric Laurent9272b4b2010-01-23 17:12:59 -08002040 public void setMode(int mode) {
2041 mMode = mode;
2042 }
2043
2044 public int getMode() {
2045 return mMode;
2046 }
2047
2048 public IBinder getBinder() {
2049 return mCb;
2050 }
2051 }
2052
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002053 /** @see AudioManager#setMode(int) */
Eric Laurent9272b4b2010-01-23 17:12:59 -08002054 public void setMode(int mode, IBinder cb) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002055 if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ")"); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002056 if (!checkAudioSettingsPermission("setMode()")) {
2057 return;
2058 }
Eric Laurenta553c252009-07-17 12:17:14 -07002059
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07002060 if ( (mode == AudioSystem.MODE_IN_CALL) &&
2061 (mContext.checkCallingOrSelfPermission(
2062 android.Manifest.permission.MODIFY_PHONE_STATE)
2063 != PackageManager.PERMISSION_GRANTED)) {
2064 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
2065 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
2066 return;
2067 }
2068
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08002069 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07002070 return;
2071 }
2072
Eric Laurentd7454be2011-09-14 08:45:58 -07002073 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002074 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07002075 if (mode == AudioSystem.MODE_CURRENT) {
2076 mode = mMode;
2077 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002078 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
Eric Laurent9f103de2011-09-08 15:04:23 -07002079 }
2080 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2081 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002082 if (newModeOwnerPid != 0) {
2083 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07002084 }
2085 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002086
Eric Laurent9f103de2011-09-08 15:04:23 -07002087 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07002088 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07002089 // any mode other than NORMAL.
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07002090 private int setModeInt(int mode, IBinder cb, int pid) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002091 if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ")"); }
Eric Laurentd7454be2011-09-14 08:45:58 -07002092 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002093 if (cb == null) {
2094 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07002095 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07002096 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002097
Eric Laurent9f103de2011-09-08 15:04:23 -07002098 SetModeDeathHandler hdlr = null;
2099 Iterator iter = mSetModeDeathHandlers.iterator();
2100 while (iter.hasNext()) {
2101 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
2102 if (h.getPid() == pid) {
2103 hdlr = h;
2104 // Remove from client list so that it is re-inserted at top of list
2105 iter.remove();
2106 hdlr.getBinder().unlinkToDeath(hdlr, 0);
2107 break;
2108 }
2109 }
2110 int status = AudioSystem.AUDIO_STATUS_OK;
2111 do {
2112 if (mode == AudioSystem.MODE_NORMAL) {
2113 // get new mode from client at top the list if any
2114 if (!mSetModeDeathHandlers.isEmpty()) {
2115 hdlr = mSetModeDeathHandlers.get(0);
2116 cb = hdlr.getBinder();
2117 mode = hdlr.getMode();
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002118 if (DEBUG_MODE) {
2119 Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
2120 + hdlr.mPid);
2121 }
Eric Laurentb9c9d262009-05-06 08:13:20 -07002122 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002123 } else {
2124 if (hdlr == null) {
2125 hdlr = new SetModeDeathHandler(cb, pid);
2126 }
2127 // Register for client death notification
2128 try {
2129 cb.linkToDeath(hdlr, 0);
2130 } catch (RemoteException e) {
2131 // Client has died!
2132 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
2133 }
2134
2135 // Last client to call setMode() is always at top of client list
2136 // as required by SetModeDeathHandler.binderDied()
2137 mSetModeDeathHandlers.add(0, hdlr);
2138 hdlr.setMode(mode);
2139 }
2140
2141 if (mode != mMode) {
2142 status = AudioSystem.setPhoneState(mode);
2143 if (status == AudioSystem.AUDIO_STATUS_OK) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002144 if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002145 mMode = mode;
2146 } else {
2147 if (hdlr != null) {
2148 mSetModeDeathHandlers.remove(hdlr);
2149 cb.unlinkToDeath(hdlr, 0);
2150 }
2151 // force reading new top of mSetModeDeathHandlers stack
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002152 if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002153 mode = AudioSystem.MODE_NORMAL;
2154 }
2155 } else {
2156 status = AudioSystem.AUDIO_STATUS_OK;
2157 }
2158 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
2159
2160 if (status == AudioSystem.AUDIO_STATUS_OK) {
2161 if (mode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002162 if (mSetModeDeathHandlers.isEmpty()) {
2163 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
2164 } else {
2165 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2166 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002167 }
2168 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002169 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07002170 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
2171 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
Eric Laurent6d517662012-04-23 18:42:39 -07002172
2173 updateStreamVolumeAlias(true /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002174 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002175 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002176 }
2177
2178 /** @see AudioManager#getMode() */
2179 public int getMode() {
2180 return mMode;
2181 }
2182
Eric Laurente78fced2013-03-15 16:03:47 -07002183 //==========================================================================================
2184 // Sound Effects
2185 //==========================================================================================
2186
2187 private static final String TAG_AUDIO_ASSETS = "audio_assets";
2188 private static final String ATTR_VERSION = "version";
2189 private static final String TAG_GROUP = "group";
2190 private static final String ATTR_GROUP_NAME = "name";
2191 private static final String TAG_ASSET = "asset";
2192 private static final String ATTR_ASSET_ID = "id";
2193 private static final String ATTR_ASSET_FILE = "file";
2194
2195 private static final String ASSET_FILE_VERSION = "1.0";
2196 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
2197
Glenn Kasten167d1a22013-07-23 16:24:41 -07002198 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002199
2200 class LoadSoundEffectReply {
2201 public int mStatus = 1;
2202 };
2203
Eric Laurente78fced2013-03-15 16:03:47 -07002204 private void loadTouchSoundAssetDefaults() {
2205 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
2206 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
2207 SOUND_EFFECT_FILES_MAP[i][0] = 0;
2208 SOUND_EFFECT_FILES_MAP[i][1] = -1;
2209 }
2210 }
2211
2212 private void loadTouchSoundAssets() {
2213 XmlResourceParser parser = null;
2214
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002215 // only load assets once.
2216 if (!SOUND_EFFECT_FILES.isEmpty()) {
2217 return;
2218 }
2219
Eric Laurente78fced2013-03-15 16:03:47 -07002220 loadTouchSoundAssetDefaults();
2221
2222 try {
2223 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
2224
2225 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
2226 String version = parser.getAttributeValue(null, ATTR_VERSION);
2227 boolean inTouchSoundsGroup = false;
2228
2229 if (ASSET_FILE_VERSION.equals(version)) {
2230 while (true) {
2231 XmlUtils.nextElement(parser);
2232 String element = parser.getName();
2233 if (element == null) {
2234 break;
2235 }
2236 if (element.equals(TAG_GROUP)) {
2237 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
2238 if (GROUP_TOUCH_SOUNDS.equals(name)) {
2239 inTouchSoundsGroup = true;
2240 break;
2241 }
2242 }
2243 }
2244 while (inTouchSoundsGroup) {
2245 XmlUtils.nextElement(parser);
2246 String element = parser.getName();
2247 if (element == null) {
2248 break;
2249 }
2250 if (element.equals(TAG_ASSET)) {
2251 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
2252 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
2253 int fx;
2254
2255 try {
2256 Field field = AudioManager.class.getField(id);
2257 fx = field.getInt(null);
2258 } catch (Exception e) {
2259 Log.w(TAG, "Invalid touch sound ID: "+id);
2260 continue;
2261 }
2262
2263 int i = SOUND_EFFECT_FILES.indexOf(file);
2264 if (i == -1) {
2265 i = SOUND_EFFECT_FILES.size();
2266 SOUND_EFFECT_FILES.add(file);
2267 }
2268 SOUND_EFFECT_FILES_MAP[fx][0] = i;
2269 } else {
2270 break;
2271 }
2272 }
2273 }
2274 } catch (Resources.NotFoundException e) {
2275 Log.w(TAG, "audio assets file not found", e);
2276 } catch (XmlPullParserException e) {
2277 Log.w(TAG, "XML parser exception reading touch sound assets", e);
2278 } catch (IOException e) {
2279 Log.w(TAG, "I/O exception reading touch sound assets", e);
2280 } finally {
2281 if (parser != null) {
2282 parser.close();
2283 }
2284 }
2285 }
2286
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002287 /** @see AudioManager#playSoundEffect(int) */
2288 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002289 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002290 }
2291
2292 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002293 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07002294 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
2295 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
2296 return;
2297 }
2298
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002299 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002300 effectType, (int) (volume * 1000), null, 0);
2301 }
2302
2303 /**
2304 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08002305 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002306 */
2307 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002308 int attempts = 3;
2309 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08002310
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002311 synchronized (reply) {
2312 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
2313 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08002314 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07002315 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002316 } catch (InterruptedException e) {
2317 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08002318 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002319 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002320 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002321 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002322 }
2323
2324 /**
2325 * Unloads samples from the sound pool.
2326 * This method can be called to free some memory when
2327 * sound effects are disabled.
2328 */
2329 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002330 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002331 }
2332
Eric Laurenta60e2122010-12-28 16:49:07 -08002333 class SoundPoolListenerThread extends Thread {
2334 public SoundPoolListenerThread() {
2335 super("SoundPoolListenerThread");
2336 }
2337
2338 @Override
2339 public void run() {
2340
2341 Looper.prepare();
2342 mSoundPoolLooper = Looper.myLooper();
2343
2344 synchronized (mSoundEffectsLock) {
2345 if (mSoundPool != null) {
2346 mSoundPoolCallBack = new SoundPoolCallback();
2347 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2348 }
2349 mSoundEffectsLock.notify();
2350 }
2351 Looper.loop();
2352 }
2353 }
2354
2355 private final class SoundPoolCallback implements
2356 android.media.SoundPool.OnLoadCompleteListener {
2357
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002358 int mStatus = 1; // 1 means neither error nor last sample loaded yet
2359 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08002360
2361 public int status() {
2362 return mStatus;
2363 }
2364
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002365 public void setSamples(int[] samples) {
2366 for (int i = 0; i < samples.length; i++) {
2367 // do not wait ack for samples rejected upfront by SoundPool
2368 if (samples[i] > 0) {
2369 mSamples.add(samples[i]);
2370 }
2371 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002372 }
2373
2374 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2375 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002376 int i = mSamples.indexOf(sampleId);
2377 if (i >= 0) {
2378 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08002379 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002380 if ((status != 0) || mSamples. isEmpty()) {
2381 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08002382 mSoundEffectsLock.notify();
2383 }
2384 }
2385 }
2386 }
2387
Eric Laurent4050c932009-07-08 02:52:14 -07002388 /** @see AudioManager#reloadAudioSettings() */
2389 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002390 readAudioSettings(false /*userSwitch*/);
2391 }
2392
2393 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07002394 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2395 readPersistedSettings();
2396
2397 // restore volume settings
2398 int numStreamTypes = AudioSystem.getNumStreamTypes();
2399 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2400 VolumeStreamState streamState = mStreamStates[streamType];
2401
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002402 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2403 continue;
2404 }
2405
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002406 streamState.readSettings();
2407 synchronized (VolumeStreamState.class) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002408 // unmute stream that was muted but is not affect by mute anymore
RoboErik4197cb62015-01-21 15:45:32 -08002409 if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07002410 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
RoboErik4197cb62015-01-21 15:45:32 -08002411 streamState.mIsMuted = false;
Eric Laurent4050c932009-07-08 02:52:14 -07002412 }
Eric Laurent4050c932009-07-08 02:52:14 -07002413 }
2414 }
2415
Eric Laurent33902db2012-10-07 16:15:07 -07002416 // apply new ringer mode before checking volume for alias streams so that streams
2417 // muted by ringer mode have the correct volume
John Spurlock661f2cf2014-11-17 10:29:10 -05002418 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent33902db2012-10-07 16:15:07 -07002419
Eric Laurent212532b2014-07-21 15:43:18 -07002420 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07002421 checkAllAliasStreamVolumes();
2422
Eric Laurentd640bd32012-09-28 18:01:48 -07002423 synchronized (mSafeMediaVolumeState) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002424 mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2425 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2426 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
Eric Laurentd640bd32012-09-28 18:01:48 -07002427 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07002428 enforceSafeMediaVolume();
2429 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07002430 }
Eric Laurent4050c932009-07-08 02:52:14 -07002431 }
2432
Dianne Hackborn961cae92013-03-20 14:59:43 -07002433 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002434 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002435 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2436 return;
2437 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002438
2439 if (on) {
2440 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2441 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2442 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
2443 }
2444 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2445 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2446 mForcedUseForComm = AudioSystem.FORCE_NONE;
2447 }
Eric Laurentfa640152011-03-12 15:59:51 -08002448
Eric Laurentafbb0472011-12-15 09:04:23 -08002449 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002450 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002451 }
2452
2453 /** @see AudioManager#isSpeakerphoneOn() */
2454 public boolean isSpeakerphoneOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002455 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002456 }
2457
Dianne Hackborn961cae92013-03-20 14:59:43 -07002458 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002459 public void setBluetoothScoOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002460 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2461 return;
2462 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002463
2464 if (on) {
2465 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2466 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2467 mForcedUseForComm = AudioSystem.FORCE_NONE;
2468 }
Eric Laurentfa640152011-03-12 15:59:51 -08002469
Eric Laurentafbb0472011-12-15 09:04:23 -08002470 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002471 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08002472 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002473 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002474 }
2475
2476 /** @see AudioManager#isBluetoothScoOn() */
2477 public boolean isBluetoothScoOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002478 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002479 }
2480
Dianne Hackborn961cae92013-03-20 14:59:43 -07002481 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07002482 public void setBluetoothA2dpOn(boolean on) {
Eric Laurentc390bed2012-07-03 12:24:05 -07002483 synchronized (mBluetoothA2dpEnabledLock) {
2484 mBluetoothA2dpEnabled = on;
2485 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2486 AudioSystem.FOR_MEDIA,
2487 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2488 null, 0);
2489 }
Eric Laurent78472112012-05-21 08:57:21 -07002490 }
2491
2492 /** @see AudioManager#isBluetoothA2dpOn() */
2493 public boolean isBluetoothA2dpOn() {
2494 synchronized (mBluetoothA2dpEnabledLock) {
2495 return mBluetoothA2dpEnabled;
2496 }
2497 }
2498
Eric Laurent3def1ee2010-03-17 23:26:26 -07002499 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07002500 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
2501 int scoAudioMode =
2502 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
Liejun Taof4e51d82014-07-16 11:18:29 -07002503 SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
Eric Laurent83900752014-05-15 15:14:22 -07002504 startBluetoothScoInt(cb, scoAudioMode);
2505 }
2506
2507 /** @see AudioManager#startBluetoothScoVirtualCall() */
2508 public void startBluetoothScoVirtualCall(IBinder cb) {
2509 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
2510 }
2511
2512 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07002513 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002514 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002515 return;
2516 }
Eric Laurent854938a2011-02-22 12:05:20 -08002517 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002518 // The calling identity must be cleared before calling ScoClient.incCount().
2519 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2520 // and this must be done on behalf of system server to make sure permissions are granted.
2521 // The caller identity must be cleared after getScoClient() because it is needed if a new
2522 // client is created.
2523 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07002524 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08002525 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002526 }
2527
2528 /** @see AudioManager#stopBluetoothSco() */
2529 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07002530 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002531 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002532 return;
2533 }
Eric Laurent854938a2011-02-22 12:05:20 -08002534 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002535 // The calling identity must be cleared before calling ScoClient.decCount().
2536 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2537 // and this must be done on behalf of system server to make sure permissions are granted.
2538 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08002539 if (client != null) {
2540 client.decCount();
2541 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08002542 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002543 }
2544
Eric Laurent78472112012-05-21 08:57:21 -07002545
Eric Laurent3def1ee2010-03-17 23:26:26 -07002546 private class ScoClient implements IBinder.DeathRecipient {
2547 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002548 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002549 private int mStartcount; // number of SCO connections started by this client
2550
2551 ScoClient(IBinder cb) {
2552 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002553 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002554 mStartcount = 0;
2555 }
2556
2557 public void binderDied() {
2558 synchronized(mScoClients) {
2559 Log.w(TAG, "SCO client died");
2560 int index = mScoClients.indexOf(this);
2561 if (index < 0) {
2562 Log.w(TAG, "unregistered SCO client died");
2563 } else {
2564 clearCount(true);
2565 mScoClients.remove(this);
2566 }
2567 }
2568 }
2569
Eric Laurent83900752014-05-15 15:14:22 -07002570 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002571 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07002572 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002573 if (mStartcount == 0) {
2574 try {
2575 mCb.linkToDeath(this, 0);
2576 } catch (RemoteException e) {
2577 // client has already died!
2578 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
2579 }
2580 }
2581 mStartcount++;
2582 }
2583 }
2584
2585 public void decCount() {
2586 synchronized(mScoClients) {
2587 if (mStartcount == 0) {
2588 Log.w(TAG, "ScoClient.decCount() already 0");
2589 } else {
2590 mStartcount--;
2591 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002592 try {
2593 mCb.unlinkToDeath(this, 0);
2594 } catch (NoSuchElementException e) {
2595 Log.w(TAG, "decCount() going to 0 but not registered to binder");
2596 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002597 }
Eric Laurentc18c9132013-04-12 17:24:56 -07002598 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002599 }
2600 }
2601 }
2602
2603 public void clearCount(boolean stopSco) {
2604 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002605 if (mStartcount != 0) {
2606 try {
2607 mCb.unlinkToDeath(this, 0);
2608 } catch (NoSuchElementException e) {
2609 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2610 }
2611 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002612 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002613 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002614 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002615 }
2616 }
2617 }
2618
2619 public int getCount() {
2620 return mStartcount;
2621 }
2622
2623 public IBinder getBinder() {
2624 return mCb;
2625 }
2626
Eric Laurentd7454be2011-09-14 08:45:58 -07002627 public int getPid() {
2628 return mCreatorPid;
2629 }
2630
Eric Laurent3def1ee2010-03-17 23:26:26 -07002631 public int totalCount() {
2632 synchronized(mScoClients) {
2633 int count = 0;
2634 int size = mScoClients.size();
2635 for (int i = 0; i < size; i++) {
2636 count += mScoClients.get(i).getCount();
2637 }
2638 return count;
2639 }
2640 }
2641
Eric Laurent83900752014-05-15 15:14:22 -07002642 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08002643 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07002644 if (totalCount() == 0) {
2645 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2646 // Make sure that the state transitions to CONNECTING even if we cannot initiate
2647 // the connection.
2648 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2649 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002650 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07002651 synchronized(mSetModeDeathHandlers) {
2652 if ((mSetModeDeathHandlers.isEmpty() ||
2653 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2654 (mScoAudioState == SCO_STATE_INACTIVE ||
2655 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2656 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07002657 mScoAudioMode = scoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -07002658 if (scoAudioMode == SCO_MODE_UNDEFINED) {
Andre Eisenbach570cc532014-10-28 17:03:18 -07002659 if (mBluetoothHeadsetDevice != null) {
2660 mScoAudioMode = new Integer(Settings.Global.getInt(
2661 mContentResolver,
2662 "bluetooth_sco_channel_"+
2663 mBluetoothHeadsetDevice.getAddress(),
2664 SCO_MODE_VIRTUAL_CALL));
2665 if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2666 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2667 }
2668 } else {
2669 mScoAudioMode = SCO_MODE_RAW;
Liejun Taof4e51d82014-07-16 11:18:29 -07002670 }
2671 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002672 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002673 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002674 if (mScoAudioMode == SCO_MODE_RAW) {
2675 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002676 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002677 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2678 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002679 } else if (mScoAudioMode == SCO_MODE_VR) {
2680 status = mBluetoothHeadset.startVoiceRecognition(
2681 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002682 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002683
Eric Laurentc18c9132013-04-12 17:24:56 -07002684 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07002685 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2686 } else {
2687 broadcastScoConnectionState(
2688 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2689 }
2690 } else if (getBluetoothHeadset()) {
2691 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07002692 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002693 } else {
2694 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2695 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002696 }
2697 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07002698 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002699 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002700 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002701 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002702 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2703 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2704 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07002705 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002706 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002707 if (mScoAudioMode == SCO_MODE_RAW) {
2708 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002709 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002710 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2711 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002712 } else if (mScoAudioMode == SCO_MODE_VR) {
2713 status = mBluetoothHeadset.stopVoiceRecognition(
2714 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002715 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002716
Eric Laurentc18c9132013-04-12 17:24:56 -07002717 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002718 mScoAudioState = SCO_STATE_INACTIVE;
2719 broadcastScoConnectionState(
2720 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2721 }
2722 } else if (getBluetoothHeadset()) {
2723 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2724 }
2725 } else {
2726 mScoAudioState = SCO_STATE_INACTIVE;
2727 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2728 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002729 }
2730 }
2731 }
2732 }
2733
Eric Laurent62ef7672010-11-24 10:58:32 -08002734 private void checkScoAudioState() {
2735 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002736 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08002737 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2738 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2739 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2740 }
2741 }
2742
Eric Laurent854938a2011-02-22 12:05:20 -08002743 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002744 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002745 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002746 int size = mScoClients.size();
2747 for (int i = 0; i < size; i++) {
2748 client = mScoClients.get(i);
2749 if (client.getBinder() == cb)
2750 return client;
2751 }
Eric Laurent854938a2011-02-22 12:05:20 -08002752 if (create) {
2753 client = new ScoClient(cb);
2754 mScoClients.add(client);
2755 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002756 return client;
2757 }
2758 }
2759
Eric Laurentd7454be2011-09-14 08:45:58 -07002760 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002761 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002762 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002763 int size = mScoClients.size();
2764 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08002765 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07002766 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08002767 cl.clearCount(stopSco);
2768 } else {
2769 savedClient = cl;
2770 }
2771 }
2772 mScoClients.clear();
2773 if (savedClient != null) {
2774 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002775 }
2776 }
2777 }
2778
Eric Laurentdc03c612011-04-01 10:59:41 -07002779 private boolean getBluetoothHeadset() {
2780 boolean result = false;
2781 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2782 if (adapter != null) {
2783 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2784 BluetoothProfile.HEADSET);
2785 }
2786 // If we could not get a bluetooth headset proxy, send a failure message
2787 // without delay to reset the SCO audio state and clear SCO clients.
2788 // If we could get a proxy, send a delayed failure message that will reset our state
2789 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08002790 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002791 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2792 return result;
2793 }
2794
Eric Laurentd7454be2011-09-14 08:45:58 -07002795 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002796 synchronized(mScoClients) {
2797 checkScoAudioState();
2798 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2799 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2800 if (mBluetoothHeadsetDevice != null) {
2801 if (mBluetoothHeadset != null) {
2802 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07002803 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002804 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002805 SENDMSG_REPLACE, 0, 0, null, 0);
2806 }
2807 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2808 getBluetoothHeadset()) {
2809 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2810 }
2811 }
2812 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07002813 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07002814 }
2815 }
2816 }
2817
2818 private void resetBluetoothSco() {
2819 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002820 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07002821 mScoAudioState = SCO_STATE_INACTIVE;
2822 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2823 }
2824 }
2825
2826 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08002827 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
2828 SENDMSG_QUEUE, state, 0, null, 0);
2829 }
2830
2831 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002832 if (state != mScoConnectionState) {
2833 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2834 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2835 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2836 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002837 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07002838 mScoConnectionState = state;
2839 }
2840 }
2841
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002842 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
2843 new BluetoothProfile.ServiceListener() {
2844 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002845 BluetoothDevice btDevice;
2846 List<BluetoothDevice> deviceList;
2847 switch(profile) {
2848 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09002849 synchronized (mConnectedDevices) {
2850 synchronized (mA2dpAvrcpLock) {
2851 mA2dp = (BluetoothA2dp) proxy;
2852 deviceList = mA2dp.getConnectedDevices();
2853 if (deviceList.size() > 0) {
2854 btDevice = deviceList.get(0);
John Du5a0cf7a2013-07-19 11:30:34 -07002855 int state = mA2dp.getConnectionState(btDevice);
2856 int delay = checkSendBecomingNoisyIntent(
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002857 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2858 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
John Du5a0cf7a2013-07-19 11:30:34 -07002859 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002860 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07002861 state,
2862 0,
2863 btDevice,
2864 delay);
2865 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002866 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002867 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002868 break;
2869
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002870 case BluetoothProfile.A2DP_SINK:
2871 deviceList = proxy.getConnectedDevices();
2872 if (deviceList.size() > 0) {
2873 btDevice = deviceList.get(0);
2874 synchronized (mConnectedDevices) {
2875 int state = proxy.getConnectionState(btDevice);
2876 queueMsgUnderWakeLock(mAudioHandler,
2877 MSG_SET_A2DP_SRC_CONNECTION_STATE,
2878 state,
2879 0,
2880 btDevice,
2881 0 /* delay */);
2882 }
2883 }
2884 break;
2885
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002886 case BluetoothProfile.HEADSET:
2887 synchronized (mScoClients) {
2888 // Discard timeout message
2889 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
2890 mBluetoothHeadset = (BluetoothHeadset) proxy;
2891 deviceList = mBluetoothHeadset.getConnectedDevices();
2892 if (deviceList.size() > 0) {
2893 mBluetoothHeadsetDevice = deviceList.get(0);
2894 } else {
2895 mBluetoothHeadsetDevice = null;
2896 }
2897 // Refresh SCO audio state
2898 checkScoAudioState();
2899 // Continue pending action if any
2900 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
2901 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
2902 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2903 boolean status = false;
2904 if (mBluetoothHeadsetDevice != null) {
2905 switch (mScoAudioState) {
2906 case SCO_STATE_ACTIVATE_REQ:
2907 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07002908 if (mScoAudioMode == SCO_MODE_RAW) {
2909 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002910 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002911 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2912 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002913 } else if (mScoAudioMode == SCO_MODE_VR) {
2914 status = mBluetoothHeadset.startVoiceRecognition(
2915 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002916 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002917 break;
2918 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07002919 if (mScoAudioMode == SCO_MODE_RAW) {
2920 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002921 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002922 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2923 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002924 } else if (mScoAudioMode == SCO_MODE_VR) {
2925 status = mBluetoothHeadset.stopVoiceRecognition(
2926 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002927 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002928 break;
2929 case SCO_STATE_DEACTIVATE_EXT_REQ:
2930 status = mBluetoothHeadset.stopVoiceRecognition(
2931 mBluetoothHeadsetDevice);
2932 }
2933 }
2934 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002935 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002936 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07002937 }
2938 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002939 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002940 break;
2941
2942 default:
2943 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002944 }
2945 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002946 public void onServiceDisconnected(int profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002947 switch(profile) {
2948 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09002949 synchronized (mConnectedDevices) {
2950 synchronized (mA2dpAvrcpLock) {
2951 mA2dp = null;
John Du5a0cf7a2013-07-19 11:30:34 -07002952 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
2953 makeA2dpDeviceUnavailableNow(
2954 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
2955 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002956 }
2957 }
2958 break;
2959
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002960 case BluetoothProfile.A2DP_SINK:
2961 synchronized (mConnectedDevices) {
2962 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) {
2963 makeA2dpSrcUnavailable(
2964 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP));
2965 }
2966 }
2967 break;
2968
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002969 case BluetoothProfile.HEADSET:
2970 synchronized (mScoClients) {
2971 mBluetoothHeadset = null;
2972 }
2973 break;
2974
2975 default:
2976 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002977 }
2978 }
2979 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08002980
Eric Laurentc34dcc12012-09-10 13:51:52 -07002981 private void onCheckMusicActive() {
Eric Laurentd640bd32012-09-28 18:01:48 -07002982 synchronized (mSafeMediaVolumeState) {
2983 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002984 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
2985
2986 if ((device & mSafeMediaVolumeDevices) != 0) {
2987 sendMsg(mAudioHandler,
2988 MSG_CHECK_MUSIC_ACTIVE,
2989 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07002990 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07002991 0,
2992 null,
2993 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07002994 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07002995 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
2996 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002997 // Approximate cumulative active music time
2998 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
2999 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
3000 setSafeMediaVolumeEnabled(true);
3001 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07003002 }
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003003 saveMusicActiveMs();
Eric Laurentc34dcc12012-09-10 13:51:52 -07003004 }
3005 }
3006 }
3007 }
3008 }
3009
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003010 private void saveMusicActiveMs() {
3011 mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
3012 }
3013
Eric Laurentd640bd32012-09-28 18:01:48 -07003014 private void onConfigureSafeVolume(boolean force) {
3015 synchronized (mSafeMediaVolumeState) {
3016 int mcc = mContext.getResources().getConfiguration().mcc;
3017 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
3018 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
3019 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
John Spurlock35134602014-07-24 18:10:48 -04003020 boolean safeMediaVolumeEnabled =
3021 SystemProperties.getBoolean("audio.safemedia.force", false)
3022 || mContext.getResources().getBoolean(
3023 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08003024
3025 // The persisted state is either "disabled" or "active": this is the state applied
3026 // next time we boot and cannot be "inactive"
3027 int persistedState;
Eric Laurentd640bd32012-09-28 18:01:48 -07003028 if (safeMediaVolumeEnabled) {
Eric Laurent05274f32012-11-29 12:48:18 -08003029 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
3030 // The state can already be "inactive" here if the user has forced it before
3031 // the 30 seconds timeout for forced configuration. In this case we don't reset
3032 // it to "active".
3033 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003034 if (mMusicActiveMs == 0) {
3035 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
3036 enforceSafeMediaVolume();
3037 } else {
3038 // We have existing playback time recorded, already confirmed.
3039 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
3040 }
Eric Laurent05274f32012-11-29 12:48:18 -08003041 }
Eric Laurentd640bd32012-09-28 18:01:48 -07003042 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08003043 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07003044 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
3045 }
3046 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08003047 sendMsg(mAudioHandler,
3048 MSG_PERSIST_SAFE_VOLUME_STATE,
3049 SENDMSG_QUEUE,
3050 persistedState,
3051 0,
3052 null,
3053 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07003054 }
3055 }
3056 }
3057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003058 ///////////////////////////////////////////////////////////////////////////
3059 // Internal methods
3060 ///////////////////////////////////////////////////////////////////////////
3061
3062 /**
3063 * Checks if the adjustment should change ringer mode instead of just
3064 * adjusting volume. If so, this will set the proper ringer mode and volume
3065 * indices on the stream states.
3066 */
RoboErik5452e252015-02-06 15:33:53 -08003067 private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003068 int result = FLAG_ADJUST_VOLUME;
John Spurlock661f2cf2014-11-17 10:29:10 -05003069 int ringerMode = getRingerModeInternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003070
Eric Laurentbffc3d12012-05-07 17:43:49 -07003071 switch (ringerMode) {
3072 case RINGER_MODE_NORMAL:
3073 if (direction == AudioManager.ADJUST_LOWER) {
3074 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07003075 // "step" is the delta in internal index units corresponding to a
3076 // change of 1 in UI index units.
3077 // Because of rounding when rescaling from one stream index range to its alias
3078 // index range, we cannot simply test oldIndex == step:
3079 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
3080 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003081 ringerMode = RINGER_MODE_VIBRATE;
3082 }
3083 } else {
Eric Laurent24482012012-05-10 09:41:17 -07003084 // (oldIndex < step) is equivalent to (old UI index == 0)
John Spurlock86005342014-05-23 11:58:00 -04003085 if ((oldIndex < step)
3086 && VOLUME_SETS_RINGER_MODE_SILENT
3087 && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003088 ringerMode = RINGER_MODE_SILENT;
3089 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07003090 }
RoboErik5452e252015-02-06 15:33:53 -08003091 } else if (direction == AudioManager.ADJUST_TOGGLE_MUTE
3092 || direction == AudioManager.ADJUST_MUTE) {
3093 if (mHasVibrator) {
3094 ringerMode = RINGER_MODE_VIBRATE;
3095 } else {
3096 ringerMode = RINGER_MODE_SILENT;
3097 }
3098 // Setting the ringer mode will toggle mute
3099 result &= ~FLAG_ADJUST_VOLUME;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003100 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003101 break;
3102 case RINGER_MODE_VIBRATE:
3103 if (!mHasVibrator) {
3104 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
3105 "but no vibrator is present");
3106 break;
3107 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003108 if ((direction == AudioManager.ADJUST_LOWER)) {
RoboErik5452e252015-02-06 15:33:53 -08003109 // This is the case we were muted with the volume turned up
3110 if (oldIndex >= 2 * step && isMuted) {
3111 ringerMode = RINGER_MODE_NORMAL;
3112 } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
John Spurlock795a5142014-12-08 14:09:35 -05003113 if (VOLUME_SETS_RINGER_MODE_SILENT) {
3114 ringerMode = RINGER_MODE_SILENT;
3115 } else {
3116 result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
3117 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003118 }
RoboErik5452e252015-02-06 15:33:53 -08003119 } else if (direction == AudioManager.ADJUST_RAISE
3120 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3121 || direction == AudioManager.ADJUST_UNMUTE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003122 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07003123 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003124 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003125 break;
3126 case RINGER_MODE_SILENT:
RoboErik5452e252015-02-06 15:33:53 -08003127 if (direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
3128 // This is the case we were muted with the volume turned up
3129 ringerMode = RINGER_MODE_NORMAL;
3130 } else if (direction == AudioManager.ADJUST_RAISE
3131 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3132 || direction == AudioManager.ADJUST_UNMUTE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003133 if (PREVENT_VOLUME_ADJUSTMENT_IF_SILENT) {
3134 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003135 } else {
RoboErik5452e252015-02-06 15:33:53 -08003136 if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003137 ringerMode = RINGER_MODE_VIBRATE;
3138 } else {
RoboErik5452e252015-02-06 15:33:53 -08003139 // If we don't have a vibrator or they were toggling mute
3140 // go straight back to normal.
John Spurlocka11b4af2014-06-01 11:52:23 -04003141 ringerMode = RINGER_MODE_NORMAL;
3142 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003143 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05003144 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003145 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003146 break;
3147 default:
3148 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
3149 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003150 }
3151
John Spurlock661f2cf2014-11-17 10:29:10 -05003152 setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003153
Eric Laurent25101b02011-02-02 09:33:30 -08003154 mPrevVolDirection = direction;
3155
John Spurlocka11b4af2014-06-01 11:52:23 -04003156 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003157 }
3158
John Spurlock3346a802014-05-20 16:25:37 -04003159 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003160 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07003161 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003162 }
3163
Eric Laurent5b4e6542010-03-19 20:02:21 -07003164 private boolean isStreamMutedByRingerMode(int streamType) {
3165 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
3166 }
3167
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003168 boolean updateRingerModeAffectedStreams() {
3169 int ringerModeAffectedStreams;
3170 // make sure settings for ringer mode are consistent with device type: non voice capable
3171 // devices (tablets) include media stream in silent mode whereas phones don't.
3172 ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
3173 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3174 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
3175 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
3176 UserHandle.USER_CURRENT);
3177
3178 // ringtone, notification and system streams are always affected by ringer mode
3179 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
3180 (1 << AudioSystem.STREAM_NOTIFICATION)|
3181 (1 << AudioSystem.STREAM_SYSTEM);
3182
Eric Laurent212532b2014-07-21 15:43:18 -07003183 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003184 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -07003185 ringerModeAffectedStreams = 0;
3186 break;
3187 default:
John Spurlock77e54d92014-08-11 12:16:24 -04003188 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
Eric Laurent212532b2014-07-21 15:43:18 -07003189 break;
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003190 }
Eric Laurent212532b2014-07-21 15:43:18 -07003191
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003192 synchronized (mCameraSoundForced) {
3193 if (mCameraSoundForced) {
3194 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3195 } else {
3196 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3197 }
3198 }
3199 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
3200 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
3201 } else {
3202 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
3203 }
3204
3205 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3206 Settings.System.putIntForUser(mContentResolver,
3207 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3208 ringerModeAffectedStreams,
3209 UserHandle.USER_CURRENT);
3210 mRingerModeAffectedStreams = ringerModeAffectedStreams;
3211 return true;
3212 }
3213 return false;
3214 }
3215
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05003216 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003217 public boolean isStreamAffectedByMute(int streamType) {
3218 return (mMuteAffectedStreams & (1 << streamType)) != 0;
3219 }
3220
3221 private void ensureValidDirection(int direction) {
RoboErik4197cb62015-01-21 15:45:32 -08003222 switch (direction) {
3223 case AudioManager.ADJUST_LOWER:
3224 case AudioManager.ADJUST_RAISE:
3225 case AudioManager.ADJUST_SAME:
3226 case AudioManager.ADJUST_MUTE:
3227 case AudioManager.ADJUST_UNMUTE:
3228 case AudioManager.ADJUST_TOGGLE_MUTE:
3229 break;
3230 default:
3231 throw new IllegalArgumentException("Bad direction " + direction);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003232 }
3233 }
3234
Lei Zhang6c798972012-03-02 11:40:12 -08003235 private void ensureValidSteps(int steps) {
3236 if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
3237 throw new IllegalArgumentException("Bad volume adjust steps " + steps);
3238 }
3239 }
3240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003241 private void ensureValidStreamType(int streamType) {
3242 if (streamType < 0 || streamType >= mStreamStates.length) {
3243 throw new IllegalArgumentException("Bad stream type " + streamType);
3244 }
3245 }
3246
RoboErik4197cb62015-01-21 15:45:32 -08003247 private boolean isMuteAdjust(int adjust) {
3248 return adjust == AudioManager.ADJUST_MUTE || adjust == AudioManager.ADJUST_UNMUTE
3249 || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
3250 }
3251
Eric Laurent6d517662012-04-23 18:42:39 -07003252 private boolean isInCommunication() {
Nancy Chen0eb1e402014-08-21 22:52:29 -07003253 boolean IsInCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003254
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003255 TelecomManager telecomManager =
3256 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
Eric Laurent38edfda2014-12-18 17:38:04 -08003257
3258 final long ident = Binder.clearCallingIdentity();
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003259 IsInCall = telecomManager.isInCall();
Eric Laurent38edfda2014-12-18 17:38:04 -08003260 Binder.restoreCallingIdentity(ident);
Santos Cordon9eb45932014-06-27 12:28:43 -07003261
Nancy Chen0eb1e402014-08-21 22:52:29 -07003262 return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
Eric Laurent6d517662012-04-23 18:42:39 -07003263 }
Eric Laurent25101b02011-02-02 09:33:30 -08003264
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003265 /**
3266 * For code clarity for getActiveStreamType(int)
3267 * @param delay_ms max time since last STREAM_MUSIC activity to consider
3268 * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
3269 * in the last "delay_ms" ms.
3270 */
3271 private boolean isAfMusicActiveRecently(int delay_ms) {
3272 return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
3273 || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
3274 }
3275
Eric Laurent6d517662012-04-23 18:42:39 -07003276 private int getActiveStreamType(int suggestedStreamType) {
Eric Laurent212532b2014-07-21 15:43:18 -07003277 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003278 case AudioSystem.PLATFORM_VOICE:
Eric Laurent6d517662012-04-23 18:42:39 -07003279 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003280 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3281 == AudioSystem.FORCE_BT_SCO) {
3282 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
3283 return AudioSystem.STREAM_BLUETOOTH_SCO;
3284 } else {
3285 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
3286 return AudioSystem.STREAM_VOICE_CALL;
3287 }
Eric Laurent25101b02011-02-02 09:33:30 -08003288 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003289 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003290 if (DEBUG_VOL)
3291 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3292 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003293 } else {
3294 if (DEBUG_VOL)
3295 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
3296 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003297 }
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003298 } else if (isAfMusicActiveRecently(0)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003299 if (DEBUG_VOL)
3300 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3301 return AudioSystem.STREAM_MUSIC;
Eric Laurent25101b02011-02-02 09:33:30 -08003302 }
Eric Laurent212532b2014-07-21 15:43:18 -07003303 break;
John Spurlock61560172015-02-06 19:46:04 -05003304 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -07003305 if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
RoboErik2811dd32014-08-12 09:48:13 -07003306 // TV always defaults to STREAM_MUSIC
Eric Laurent212532b2014-07-21 15:43:18 -07003307 return AudioSystem.STREAM_MUSIC;
Eric Laurent212532b2014-07-21 15:43:18 -07003308 }
3309 break;
3310 default:
Eric Laurent6d517662012-04-23 18:42:39 -07003311 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003312 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3313 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003314 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08003315 return AudioSystem.STREAM_BLUETOOTH_SCO;
3316 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003317 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08003318 return AudioSystem.STREAM_VOICE_CALL;
3319 }
3320 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003321 StreamOverride.sDelayMs) ||
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003322 AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003323 StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003324 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08003325 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003326 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003327 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003328 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
3329 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003330 } else {
John Spurlockeb1d88d2014-07-19 14:49:19 -04003331 if (DEBUG_VOL) Log.v(TAG,
3332 "getActiveStreamType: using STREAM_NOTIFICATION as default");
3333 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003334 }
Joe Onoratoc7fcba42011-01-05 16:53:11 -08003335 }
Eric Laurent212532b2014-07-21 15:43:18 -07003336 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003337 }
Eric Laurent212532b2014-07-21 15:43:18 -07003338 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
3339 + suggestedStreamType);
3340 return suggestedStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003341 }
3342
John Spurlockbcc10872014-11-28 15:29:21 -05003343 private void broadcastRingerMode(String action, int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003344 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05003345 Intent broadcast = new Intent(action);
Glenn Kastenba195eb2011-12-13 09:30:40 -08003346 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003347 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
3348 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003349 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003350 }
3351
3352 private void broadcastVibrateSetting(int vibrateType) {
3353 // Send broadcast
3354 if (ActivityManagerNative.isSystemReady()) {
3355 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
3356 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
3357 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003358 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003359 }
3360 }
3361
3362 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003363 /**
3364 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
3365 * Note that the wake lock needs to be released after the message has been handled.
3366 */
3367 private void queueMsgUnderWakeLock(Handler handler, int msg,
3368 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003369 final long ident = Binder.clearCallingIdentity();
3370 // Always acquire the wake lock as AudioService because it is released by the
3371 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003372 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003373 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003374 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
3375 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003376
Eric Laurentafbb0472011-12-15 09:04:23 -08003377 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003378 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003379
3380 if (existingMsgPolicy == SENDMSG_REPLACE) {
3381 handler.removeMessages(msg);
3382 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
3383 return;
3384 }
Eric Laurentadbe8bf2014-11-03 18:26:32 -08003385 synchronized (mLastDeviceConnectMsgTime) {
3386 long time = SystemClock.uptimeMillis() + delay;
3387 handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
3388 if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
3389 msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
3390 msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
3391 mLastDeviceConnectMsgTime = time;
3392 }
3393 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003394 }
3395
3396 boolean checkAudioSettingsPermission(String method) {
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07003397 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003398 == PackageManager.PERMISSION_GRANTED) {
3399 return true;
3400 }
3401 String msg = "Audio Settings Permission Denial: " + method + " from pid="
3402 + Binder.getCallingPid()
3403 + ", uid=" + Binder.getCallingUid();
3404 Log.w(TAG, msg);
3405 return false;
3406 }
3407
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003408 private int getDeviceForStream(int stream) {
3409 int device = AudioSystem.getDevicesForStream(stream);
3410 if ((device & (device - 1)) != 0) {
3411 // Multiple device selection is either:
3412 // - speaker + one other device: give priority to speaker in this case.
3413 // - one A2DP device + another device: happens with duplicated output. In this case
3414 // retain the device on the A2DP output as the other must not correspond to an active
3415 // selection if not the speaker.
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003416 // - HDMI-CEC system audio mode only output: give priority to available item in order.
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003417 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
3418 device = AudioSystem.DEVICE_OUT_SPEAKER;
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003419 } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
3420 device = AudioSystem.DEVICE_OUT_HDMI_ARC;
3421 } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
3422 device = AudioSystem.DEVICE_OUT_SPDIF;
3423 } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
3424 device = AudioSystem.DEVICE_OUT_AUX_LINE;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003425 } else {
3426 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
3427 }
3428 }
3429 return device;
3430 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003431
Paul McLean10804eb2015-01-28 11:16:35 -08003432 /*
3433 * A class just for packaging up a set of connection parameters.
3434 */
3435 private class WiredDeviceConnectionState {
3436 public int mType;
3437 public int mState;
3438 public String mAddress;
3439 public String mName;
3440
3441 public WiredDeviceConnectionState(int type, int state, String address, String name) {
3442 mType = type;
3443 mState = state;
3444 mAddress = address;
3445 mName = name;
3446 }
3447 }
3448
3449 public void setWiredDeviceConnectionState(int type, int state, String address,
3450 String name) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003451 synchronized (mConnectedDevices) {
Paul McLean10804eb2015-01-28 11:16:35 -08003452 int delay = checkSendBecomingNoisyIntent(type, state);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003453 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003454 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Paul McLean10804eb2015-01-28 11:16:35 -08003455 0,
3456 0,
3457 new WiredDeviceConnectionState(type, state, address, name),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003458 delay);
3459 }
3460 }
3461
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003462 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003463 {
3464 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003465 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
3466 throw new IllegalArgumentException("invalid profile " + profile);
3467 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003468 synchronized (mConnectedDevices) {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003469 if (profile == BluetoothProfile.A2DP) {
3470 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3471 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
3472 } else {
3473 delay = 0;
3474 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003475 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003476 (profile == BluetoothProfile.A2DP ?
3477 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003478 state,
3479 0,
3480 device,
3481 delay);
3482 }
3483 return delay;
3484 }
3485
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003486 ///////////////////////////////////////////////////////////////////////////
3487 // Inner classes
3488 ///////////////////////////////////////////////////////////////////////////
3489
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003490 // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
3491 // 1 mScoclient OR mSafeMediaVolumeState
3492 // 2 mSetModeDeathHandlers
3493 // 3 mSettingsLock
3494 // 4 VolumeStreamState.class
3495 // 5 mCameraSoundForced
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003496 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003497 private final int mStreamType;
3498
RoboErik4197cb62015-01-21 15:45:32 -08003499 private boolean mIsMuted;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003500 private String mVolumeIndexSettingName;
Eric Laurenta553c252009-07-17 12:17:14 -07003501 private int mIndexMax;
Eric Laurent3172d5e2012-05-09 11:38:16 -07003502 private final ConcurrentHashMap<Integer, Integer> mIndex =
3503 new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003504
Eric Laurenta553c252009-07-17 12:17:14 -07003505 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003506
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003507 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003508
3509 mStreamType = streamType;
Jared Suttles59820132009-08-13 21:50:52 -05003510 mIndexMax = MAX_STREAM_VOLUME[streamType];
Eric Laurenta553c252009-07-17 12:17:14 -07003511 AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
3512 mIndexMax *= 10;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003513
Eric Laurent33902db2012-10-07 16:15:07 -07003514 readSettings();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003515 }
3516
Eric Laurent42b041e2013-03-29 11:36:03 -07003517 public String getSettingNameForDevice(int device) {
3518 String name = mVolumeIndexSettingName;
Eric Laurent948d3272014-05-16 15:18:45 -07003519 String suffix = AudioSystem.getOutputDeviceName(device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003520 if (suffix.isEmpty()) {
3521 return name;
3522 }
3523 return name + "_" + suffix;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003524 }
3525
Eric Laurentfdbee862014-05-12 15:26:12 -07003526 public void readSettings() {
3527 synchronized (VolumeStreamState.class) {
Wally Yauda392902014-11-28 12:40:30 -08003528 // force maximum volume on all streams if fixed volume property
3529 // or master volume property is set
3530 if (mUseFixedVolume || mUseMasterVolume) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003531 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
3532 return;
3533 }
3534 // do not read system stream volume from settings: this stream is always aliased
3535 // to another stream type and its volume is never persisted. Values in settings can
3536 // only be stale values
3537 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3538 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
John Spurlock61560172015-02-06 19:46:04 -05003539 int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
Eric Laurentfdbee862014-05-12 15:26:12 -07003540 synchronized (mCameraSoundForced) {
3541 if (mCameraSoundForced) {
3542 index = mIndexMax;
3543 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003544 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003545 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
3546 return;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003547 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003548
Eric Laurentfdbee862014-05-12 15:26:12 -07003549 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
3550
3551 for (int i = 0; remainingDevices != 0; i++) {
3552 int device = (1 << i);
3553 if ((device & remainingDevices) == 0) {
3554 continue;
3555 }
3556 remainingDevices &= ~device;
3557
3558 // retrieve current volume for device
3559 String name = getSettingNameForDevice(device);
3560 // if no volume stored for current stream and device, use default volume if default
3561 // device, continue otherwise
3562 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
John Spurlock61560172015-02-06 19:46:04 -05003563 AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
Eric Laurentfdbee862014-05-12 15:26:12 -07003564 int index = Settings.System.getIntForUser(
3565 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3566 if (index == -1) {
3567 continue;
3568 }
3569
Eric Laurent212532b2014-07-21 15:43:18 -07003570 mIndex.put(device, getValidIndex(10 * index));
Eric Laurentdd45d012012-10-08 09:04:34 -07003571 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003572 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003573 }
3574
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003575 // must be called while synchronized VolumeStreamState.class
3576 public void applyDeviceVolume_syncVSS(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003577 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003578 if (mIsMuted) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003579 index = 0;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003580 } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported)
3581 || ((device & mFullVolumeDevices) != 0)) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003582 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07003583 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07003584 index = (getIndex(device) + 5)/10;
3585 }
3586 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003587 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003588
Eric Laurentfdbee862014-05-12 15:26:12 -07003589 public void applyAllVolumes() {
3590 synchronized (VolumeStreamState.class) {
3591 // apply default volume first: by convention this will reset all
3592 // devices volumes in audio policy manager to the supplied value
3593 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003594 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003595 index = 0;
3596 } else {
3597 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3598 }
3599 AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3600 // then apply device specific volumes
3601 Set set = mIndex.entrySet();
3602 Iterator i = set.iterator();
3603 while (i.hasNext()) {
3604 Map.Entry entry = (Map.Entry)i.next();
3605 int device = ((Integer)entry.getKey()).intValue();
3606 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
RoboErik4197cb62015-01-21 15:45:32 -08003607 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003608 index = 0;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003609 } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3610 mAvrcpAbsVolSupported)
3611 || ((device & mFullVolumeDevices) != 0))
3612 {
Eric Laurentfdbee862014-05-12 15:26:12 -07003613 index = (mIndexMax + 5)/10;
3614 } else {
3615 index = ((Integer)entry.getValue() + 5)/10;
3616 }
3617 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07003618 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003619 }
3620 }
3621 }
3622
3623 public boolean adjustIndex(int deltaIndex, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003624 return setIndex(getIndex(device) + deltaIndex,
3625 device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003626 }
3627
Eric Laurentfdbee862014-05-12 15:26:12 -07003628 public boolean setIndex(int index, int device) {
3629 synchronized (VolumeStreamState.class) {
3630 int oldIndex = getIndex(device);
3631 index = getValidIndex(index);
3632 synchronized (mCameraSoundForced) {
3633 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3634 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07003635 }
3636 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003637 mIndex.put(device, index);
3638
3639 if (oldIndex != index) {
3640 // Apply change to all streams using this one as alias
3641 // if changing volume of current device, also change volume of current
3642 // device on aliased stream
3643 boolean currentDevice = (device == getDeviceForStream(mStreamType));
3644 int numStreamTypes = AudioSystem.getNumStreamTypes();
3645 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3646 if (streamType != mStreamType &&
3647 mStreamVolumeAlias[streamType] == mStreamType) {
3648 int scaledIndex = rescaleIndex(index, mStreamType, streamType);
3649 mStreamStates[streamType].setIndex(scaledIndex,
3650 device);
3651 if (currentDevice) {
3652 mStreamStates[streamType].setIndex(scaledIndex,
3653 getDeviceForStream(streamType));
3654 }
3655 }
3656 }
3657 return true;
3658 } else {
3659 return false;
3660 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003661 }
3662 }
3663
Eric Laurentfdbee862014-05-12 15:26:12 -07003664 public int getIndex(int device) {
3665 synchronized (VolumeStreamState.class) {
3666 Integer index = mIndex.get(device);
3667 if (index == null) {
3668 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
3669 index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
3670 }
3671 return index.intValue();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003672 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07003673 }
3674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003675 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07003676 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003677 }
3678
Eric Laurentfdbee862014-05-12 15:26:12 -07003679 public void setAllIndexes(VolumeStreamState srcStream) {
3680 synchronized (VolumeStreamState.class) {
3681 int srcStreamType = srcStream.getStreamType();
3682 // apply default device volume from source stream to all devices first in case
3683 // some devices are present in this stream state but not in source stream state
3684 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003685 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurentfdbee862014-05-12 15:26:12 -07003686 Set set = mIndex.entrySet();
3687 Iterator i = set.iterator();
3688 while (i.hasNext()) {
3689 Map.Entry entry = (Map.Entry)i.next();
3690 entry.setValue(index);
3691 }
3692 // Now apply actual volume for devices in source stream state
3693 set = srcStream.mIndex.entrySet();
3694 i = set.iterator();
3695 while (i.hasNext()) {
3696 Map.Entry entry = (Map.Entry)i.next();
3697 int device = ((Integer)entry.getKey()).intValue();
3698 index = ((Integer)entry.getValue()).intValue();
3699 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07003700
Eric Laurentfdbee862014-05-12 15:26:12 -07003701 setIndex(index, device);
3702 }
Eric Laurent6d517662012-04-23 18:42:39 -07003703 }
3704 }
3705
Eric Laurentfdbee862014-05-12 15:26:12 -07003706 public void setAllIndexesToMax() {
3707 synchronized (VolumeStreamState.class) {
3708 Set set = mIndex.entrySet();
3709 Iterator i = set.iterator();
3710 while (i.hasNext()) {
3711 Map.Entry entry = (Map.Entry)i.next();
3712 entry.setValue(mIndexMax);
3713 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003714 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003715 }
3716
RoboErik4197cb62015-01-21 15:45:32 -08003717 public void mute(boolean state) {
John Spurlock22b9ee12015-02-18 22:51:44 -05003718 boolean changed = false;
Eric Laurentfdbee862014-05-12 15:26:12 -07003719 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08003720 if (state != mIsMuted) {
John Spurlock22b9ee12015-02-18 22:51:44 -05003721 changed = true;
RoboErik4197cb62015-01-21 15:45:32 -08003722 mIsMuted = state;
John Spurlock22b9ee12015-02-18 22:51:44 -05003723
RoboErik4197cb62015-01-21 15:45:32 -08003724 // Set the new mute volume. This propagates the values to
3725 // the audio system, otherwise the volume won't be changed
3726 // at the lower level.
3727 sendMsg(mAudioHandler,
3728 MSG_SET_ALL_VOLUMES,
3729 SENDMSG_QUEUE,
3730 0,
3731 0,
3732 this, 0);
Eric Laurentfdbee862014-05-12 15:26:12 -07003733 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003734 }
John Spurlock22b9ee12015-02-18 22:51:44 -05003735 if (changed) {
3736 // Stream mute changed, fire the intent.
3737 Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
3738 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
3739 intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
3740 sendBroadcastToAll(intent);
3741 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003742 }
3743
Eric Laurent6d517662012-04-23 18:42:39 -07003744 public int getStreamType() {
3745 return mStreamType;
3746 }
3747
Eric Laurent212532b2014-07-21 15:43:18 -07003748 public void checkFixedVolumeDevices() {
3749 synchronized (VolumeStreamState.class) {
3750 // ignore settings for fixed volume devices: volume should always be at max or 0
3751 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
3752 Set set = mIndex.entrySet();
3753 Iterator i = set.iterator();
3754 while (i.hasNext()) {
3755 Map.Entry entry = (Map.Entry)i.next();
3756 int device = ((Integer)entry.getKey()).intValue();
3757 int index = ((Integer)entry.getValue()).intValue();
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003758 if (((device & mFullVolumeDevices) != 0)
3759 || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
Eric Laurent212532b2014-07-21 15:43:18 -07003760 entry.setValue(mIndexMax);
3761 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003762 applyDeviceVolume_syncVSS(device);
Eric Laurent212532b2014-07-21 15:43:18 -07003763 }
3764 }
3765 }
3766 }
3767
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003768 private int getValidIndex(int index) {
3769 if (index < 0) {
3770 return 0;
Wally Yauda392902014-11-28 12:40:30 -08003771 } else if (mUseFixedVolume || mUseMasterVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07003772 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003773 }
3774
3775 return index;
3776 }
3777
Eric Laurentbffc3d12012-05-07 17:43:49 -07003778 private void dump(PrintWriter pw) {
RoboErik4197cb62015-01-21 15:45:32 -08003779 pw.print(" Muted: ");
3780 pw.println(mIsMuted);
John Spurlock2b29bc42014-08-26 16:40:35 -04003781 pw.print(" Max: ");
3782 pw.println((mIndexMax + 5) / 10);
Eric Laurentbffc3d12012-05-07 17:43:49 -07003783 pw.print(" Current: ");
3784 Set set = mIndex.entrySet();
3785 Iterator i = set.iterator();
3786 while (i.hasNext()) {
3787 Map.Entry entry = (Map.Entry)i.next();
John Spurlock2b29bc42014-08-26 16:40:35 -04003788 final int device = (Integer) entry.getKey();
3789 pw.print(Integer.toHexString(device));
3790 final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
3791 : AudioSystem.getOutputDeviceName(device);
3792 if (!deviceName.isEmpty()) {
3793 pw.print(" (");
3794 pw.print(deviceName);
3795 pw.print(")");
3796 }
3797 pw.print(": ");
3798 final int index = (((Integer) entry.getValue()) + 5) / 10;
3799 pw.print(index);
3800 if (i.hasNext()) {
3801 pw.print(", ");
3802 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003803 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003804 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003805 }
3806
3807 /** Thread that handles native AudioSystem control. */
3808 private class AudioSystemThread extends Thread {
3809 AudioSystemThread() {
3810 super("AudioService");
3811 }
3812
3813 @Override
3814 public void run() {
3815 // Set this thread up so the handler will work on it
3816 Looper.prepare();
3817
3818 synchronized(AudioService.this) {
3819 mAudioHandler = new AudioHandler();
3820
3821 // Notify that the handler has been created
3822 AudioService.this.notify();
3823 }
3824
3825 // Listen for volume change requests that are set by VolumePanel
3826 Looper.loop();
3827 }
3828 }
3829
3830 /** Handles internal volume messages in separate volume thread. */
3831 private class AudioHandler extends Handler {
3832
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003833 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003834
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003835 synchronized (VolumeStreamState.class) {
3836 // Apply volume
3837 streamState.applyDeviceVolume_syncVSS(device);
Eric Laurenta553c252009-07-17 12:17:14 -07003838
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003839 // Apply change to all streams using this one as alias
3840 int numStreamTypes = AudioSystem.getNumStreamTypes();
3841 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3842 if (streamType != streamState.mStreamType &&
3843 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
3844 // Make sure volume is also maxed out on A2DP device for aliased stream
3845 // that may have a different device selected
3846 int streamDevice = getDeviceForStream(streamType);
3847 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
3848 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
3849 mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
3850 }
3851 mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
Eric Laurentcd772d02013-10-30 18:31:07 -07003852 }
Eric Laurenta553c252009-07-17 12:17:14 -07003853 }
3854 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003855 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08003856 sendMsg(mAudioHandler,
3857 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08003858 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003859 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07003860 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08003861 streamState,
3862 PERSIST_DELAY);
3863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003864 }
3865
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003866 private void setAllVolumes(VolumeStreamState streamState) {
3867
3868 // Apply volume
3869 streamState.applyAllVolumes();
3870
3871 // Apply change to all streams using this one as alias
3872 int numStreamTypes = AudioSystem.getNumStreamTypes();
3873 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3874 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07003875 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003876 mStreamStates[streamType].applyAllVolumes();
3877 }
3878 }
3879 }
3880
Eric Laurent42b041e2013-03-29 11:36:03 -07003881 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003882 if (mUseFixedVolume) {
3883 return;
3884 }
Eric Laurent212532b2014-07-21 15:43:18 -07003885 if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
3886 return;
3887 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003888 System.putIntForUser(mContentResolver,
3889 streamState.getSettingNameForDevice(device),
3890 (streamState.getIndex(device) + 5)/ 10,
3891 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003892 }
3893
Glenn Kastenba195eb2011-12-13 09:30:40 -08003894 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003895 if (mUseFixedVolume) {
3896 return;
3897 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07003898 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003899 }
3900
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003901 private boolean onLoadSoundEffects() {
3902 int status;
3903
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003904 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07003905 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003906 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
3907 return false;
3908 }
3909
3910 if (mSoundPool != null) {
3911 return true;
3912 }
3913
3914 loadTouchSoundAssets();
3915
Jean-Michel Trivi55a30c42014-07-20 17:56:11 -07003916 mSoundPool = new SoundPool.Builder()
3917 .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
3918 .setAudioAttributes(new AudioAttributes.Builder()
3919 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
3920 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
3921 .build())
3922 .build();
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003923 mSoundPoolCallBack = null;
3924 mSoundPoolListenerThread = new SoundPoolListenerThread();
3925 mSoundPoolListenerThread.start();
3926 int attempts = 3;
3927 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
3928 try {
3929 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07003930 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003931 } catch (InterruptedException e) {
3932 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
3933 }
3934 }
3935
3936 if (mSoundPoolCallBack == null) {
3937 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
3938 if (mSoundPoolLooper != null) {
3939 mSoundPoolLooper.quit();
3940 mSoundPoolLooper = null;
3941 }
3942 mSoundPoolListenerThread = null;
3943 mSoundPool.release();
3944 mSoundPool = null;
3945 return false;
3946 }
3947 /*
3948 * poolId table: The value -1 in this table indicates that corresponding
3949 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
3950 * Once loaded, the value in poolId is the sample ID and the same
3951 * sample can be reused for another effect using the same file.
3952 */
3953 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3954 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3955 poolId[fileIdx] = -1;
3956 }
3957 /*
3958 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
3959 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
3960 * this indicates we have a valid sample loaded for this effect.
3961 */
3962
3963 int numSamples = 0;
3964 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3965 // Do not load sample if this effect uses the MediaPlayer
3966 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
3967 continue;
3968 }
3969 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
3970 String filePath = Environment.getRootDirectory()
3971 + SOUND_EFFECTS_PATH
3972 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
3973 int sampleId = mSoundPool.load(filePath, 0);
3974 if (sampleId <= 0) {
3975 Log.w(TAG, "Soundpool could not load file: "+filePath);
3976 } else {
3977 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
3978 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
3979 numSamples++;
3980 }
3981 } else {
3982 SOUND_EFFECT_FILES_MAP[effect][1] =
3983 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
3984 }
3985 }
3986 // wait for all samples to be loaded
3987 if (numSamples > 0) {
3988 mSoundPoolCallBack.setSamples(poolId);
3989
3990 attempts = 3;
3991 status = 1;
3992 while ((status == 1) && (attempts-- > 0)) {
3993 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07003994 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003995 status = mSoundPoolCallBack.status();
3996 } catch (InterruptedException e) {
3997 Log.w(TAG, "Interrupted while waiting sound pool callback.");
3998 }
3999 }
4000 } else {
4001 status = -1;
4002 }
4003
4004 if (mSoundPoolLooper != null) {
4005 mSoundPoolLooper.quit();
4006 mSoundPoolLooper = null;
4007 }
4008 mSoundPoolListenerThread = null;
4009 if (status != 0) {
4010 Log.w(TAG,
4011 "onLoadSoundEffects(), Error "+status+ " while loading samples");
4012 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4013 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
4014 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4015 }
4016 }
4017
4018 mSoundPool.release();
4019 mSoundPool = null;
4020 }
4021 }
4022 return (status == 0);
4023 }
4024
4025 /**
4026 * Unloads samples from the sound pool.
4027 * This method can be called to free some memory when
4028 * sound effects are disabled.
4029 */
4030 private void onUnloadSoundEffects() {
4031 synchronized (mSoundEffectsLock) {
4032 if (mSoundPool == null) {
4033 return;
4034 }
4035
4036 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4037 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4038 poolId[fileIdx] = 0;
4039 }
4040
4041 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4042 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
4043 continue;
4044 }
4045 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
4046 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
4047 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4048 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
4049 }
4050 }
4051 mSoundPool.release();
4052 mSoundPool = null;
4053 }
4054 }
4055
4056 private void onPlaySoundEffect(int effectType, int volume) {
4057 synchronized (mSoundEffectsLock) {
4058
4059 onLoadSoundEffects();
4060
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004061 if (mSoundPool == null) {
4062 return;
4063 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004064 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08004065 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004066 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07004067 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004068 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07004069 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004070 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004071
4072 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004073 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
4074 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004075 } else {
4076 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004077 try {
Eric Laurente78fced2013-03-15 16:03:47 -07004078 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
4079 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004080 mediaPlayer.setDataSource(filePath);
4081 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
4082 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08004083 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004084 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
4085 public void onCompletion(MediaPlayer mp) {
4086 cleanupPlayer(mp);
4087 }
4088 });
4089 mediaPlayer.setOnErrorListener(new OnErrorListener() {
4090 public boolean onError(MediaPlayer mp, int what, int extra) {
4091 cleanupPlayer(mp);
4092 return true;
4093 }
4094 });
4095 mediaPlayer.start();
4096 } catch (IOException ex) {
4097 Log.w(TAG, "MediaPlayer IOException: "+ex);
4098 } catch (IllegalArgumentException ex) {
4099 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
4100 } catch (IllegalStateException ex) {
4101 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004102 }
4103 }
4104 }
4105 }
4106
4107 private void cleanupPlayer(MediaPlayer mp) {
4108 if (mp != null) {
4109 try {
4110 mp.stop();
4111 mp.release();
4112 } catch (IllegalStateException ex) {
4113 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
4114 }
4115 }
4116 }
4117
Eric Laurentfa640152011-03-12 15:59:51 -08004118 private void setForceUse(int usage, int config) {
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004119 synchronized (mConnectedDevices) {
4120 setForceUseInt_SyncDevices(usage, config);
4121 }
Eric Laurentfa640152011-03-12 15:59:51 -08004122 }
4123
Eric Laurent05274f32012-11-29 12:48:18 -08004124 private void onPersistSafeVolumeState(int state) {
4125 Settings.Global.putInt(mContentResolver,
4126 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
4127 state);
4128 }
4129
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004130 @Override
4131 public void handleMessage(Message msg) {
Eric Laurentafbb0472011-12-15 09:04:23 -08004132 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004133
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004134 case MSG_SET_DEVICE_VOLUME:
4135 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
4136 break;
4137
4138 case MSG_SET_ALL_VOLUMES:
4139 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004140 break;
4141
4142 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07004143 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004144 break;
4145
Mike Lockwood5c55a052011-12-15 17:21:44 -05004146 case MSG_PERSIST_MASTER_VOLUME:
Eric Laurent83a017b2013-03-19 18:15:31 -07004147 if (mUseFixedVolume) {
4148 return;
4149 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004150 Settings.System.putFloatForUser(mContentResolver,
4151 Settings.System.VOLUME_MASTER,
RoboErik8a2cfc32014-05-16 11:19:38 -07004152 msg.arg1 / (float)1000.0,
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004153 UserHandle.USER_CURRENT);
Mike Lockwood5c55a052011-12-15 17:21:44 -05004154 break;
4155
Justin Koh57978ed2012-04-03 17:37:58 -07004156 case MSG_PERSIST_MASTER_VOLUME_MUTE:
Eric Laurent83a017b2013-03-19 18:15:31 -07004157 if (mUseFixedVolume) {
4158 return;
4159 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004160 Settings.System.putIntForUser(mContentResolver,
4161 Settings.System.VOLUME_MASTER_MUTE,
4162 msg.arg1,
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004163 msg.arg2);
Justin Koh57978ed2012-04-03 17:37:58 -07004164 break;
4165
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004166 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08004167 // note that the value persisted is the current ringer mode, not the
4168 // value of ringer mode as of the time the request was made to persist
John Spurlock661f2cf2014-11-17 10:29:10 -05004169 persistRingerMode(getRingerModeInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004170 break;
4171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004172 case MSG_MEDIA_SERVER_DIED:
Eric Laurenteb4b8a22014-07-21 13:10:07 -07004173 if (!mSystemReady ||
4174 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Eric Laurent89e74ba2009-09-30 18:26:36 -07004175 Log.e(TAG, "Media server died.");
Eric Laurentafbb0472011-12-15 09:04:23 -08004176 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent89e74ba2009-09-30 18:26:36 -07004177 null, 500);
Eric Laurentdfb881f2013-07-18 14:41:39 -07004178 break;
Eric Laurent89e74ba2009-09-30 18:26:36 -07004179 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004180 Log.e(TAG, "Media server started.");
Eric Laurentdfb881f2013-07-18 14:41:39 -07004181
Eric Laurent3c652ca2010-06-21 20:46:26 -07004182 // indicate to audio HAL that we start the reconfiguration phase after a media
4183 // server crash
Eric Laurentdfb881f2013-07-18 14:41:39 -07004184 // Note that we only execute this when the media server
Eric Laurent3c652ca2010-06-21 20:46:26 -07004185 // process restarts after a crash, not the first time it is started.
4186 AudioSystem.setParameters("restarting=true");
4187
Glenn Kastenfd116ad2013-07-12 17:10:39 -07004188 readAndSetLowRamDevice();
4189
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004190 // Restore device connection states
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004191 synchronized (mConnectedDevices) {
4192 Set set = mConnectedDevices.entrySet();
4193 Iterator i = set.iterator();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004194 while (i.hasNext()) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004195 Map.Entry device = (Map.Entry)i.next();
4196 AudioSystem.setDeviceConnectionState(
4197 ((Integer)device.getKey()).intValue(),
4198 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004199 (String)device.getValue(),
4200 "unknown-device");
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004201 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004202 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004203 // Restore call state
4204 AudioSystem.setPhoneState(mMode);
4205
Eric Laurentd5603c12009-08-06 08:49:39 -07004206 // Restore forced usage for communcations and record
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004207 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
Eric Laurentd5603c12009-08-06 08:49:39 -07004208 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
Eric Laurentdd45d012012-10-08 09:04:34 -07004209 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
4210 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004211
Eric Laurenta553c252009-07-17 12:17:14 -07004212 // Restore stream volumes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004213 int numStreamTypes = AudioSystem.getNumStreamTypes();
4214 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004215 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004216 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004217
4218 streamState.applyAllVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004219 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004220
4221 // Restore ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05004222 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3c652ca2010-06-21 20:46:26 -07004223
Mike Lockwood90631542012-01-06 11:20:37 -05004224 // Restore master volume
4225 restoreMasterVolume();
4226
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004227 // Reset device orientation (if monitored for this device)
Eric Laurentd640bd32012-09-28 18:01:48 -07004228 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004229 setOrientationForAudioSystem();
4230 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004231 if (mMonitorRotation) {
4232 setRotationForAudioSystem();
4233 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004234
Eric Laurent78472112012-05-21 08:57:21 -07004235 synchronized (mBluetoothA2dpEnabledLock) {
4236 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
4237 mBluetoothA2dpEnabled ?
4238 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
4239 }
Eric Laurentbff5ca52012-11-02 16:48:26 -07004240
4241 synchronized (mSettingsLock) {
4242 AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
4243 mDockAudioMediaEnabled ?
4244 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
4245 }
Eric Laurent212532b2014-07-21 15:43:18 -07004246 if (mHdmiManager != null) {
4247 synchronized (mHdmiManager) {
4248 if (mHdmiTvClient != null) {
4249 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
4250 }
4251 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004252 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08004253
4254 synchronized (mAudioPolicies) {
4255 for(AudioPolicyProxy policy : mAudioPolicies.values()) {
4256 policy.connectMixes();
4257 }
4258 }
4259
Eric Laurent3c652ca2010-06-21 20:46:26 -07004260 // indicate the end of reconfiguration phase to audio HAL
4261 AudioSystem.setParameters("restarting=false");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004262 break;
4263
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004264 case MSG_UNLOAD_SOUND_EFFECTS:
4265 onUnloadSoundEffects();
4266 break;
4267
Eric Laurent117b7bb2011-01-16 17:07:27 -08004268 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004269 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
4270 // can take several dozens of milliseconds to complete
4271 boolean loaded = onLoadSoundEffects();
4272 if (msg.obj != null) {
4273 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
4274 synchronized (reply) {
4275 reply.mStatus = loaded ? 0 : -1;
4276 reply.notify();
4277 }
4278 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08004279 break;
4280
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004281 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004282 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004283 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004284
4285 case MSG_BTA2DP_DOCK_TIMEOUT:
4286 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004287 synchronized (mConnectedDevices) {
4288 makeA2dpDeviceUnavailableNow( (String) msg.obj );
4289 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004290 break;
Eric Laurentfa640152011-03-12 15:59:51 -08004291
4292 case MSG_SET_FORCE_USE:
Eric Laurentc390bed2012-07-03 12:24:05 -07004293 case MSG_SET_FORCE_BT_A2DP_USE:
Eric Laurentfa640152011-03-12 15:59:51 -08004294 setForceUse(msg.arg1, msg.arg2);
4295 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07004296
Eric Laurentdc03c612011-04-01 10:59:41 -07004297 case MSG_BT_HEADSET_CNCT_FAILED:
4298 resetBluetoothSco();
4299 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004300
4301 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
Paul McLean10804eb2015-01-28 11:16:35 -08004302 { WiredDeviceConnectionState connectState =
4303 (WiredDeviceConnectionState)msg.obj;
4304 onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
4305 connectState.mAddress, connectState.mName);
4306 mAudioEventWakeLock.release();
4307 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004308 break;
4309
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004310 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
4311 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
4312 mAudioEventWakeLock.release();
4313 break;
4314
4315 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
4316 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004317 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004318 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004319
4320 case MSG_REPORT_NEW_ROUTES: {
4321 int N = mRoutesObservers.beginBroadcast();
4322 if (N > 0) {
4323 AudioRoutesInfo routes;
4324 synchronized (mCurAudioRoutes) {
4325 routes = new AudioRoutesInfo(mCurAudioRoutes);
4326 }
4327 while (N > 0) {
4328 N--;
4329 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
4330 try {
4331 obs.dispatchAudioRoutesChanged(routes);
4332 } catch (RemoteException e) {
4333 }
4334 }
4335 }
4336 mRoutesObservers.finishBroadcast();
4337 break;
4338 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004339
Eric Laurentc34dcc12012-09-10 13:51:52 -07004340 case MSG_CHECK_MUSIC_ACTIVE:
4341 onCheckMusicActive();
4342 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004343
4344 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
4345 onSendBecomingNoisyIntent();
4346 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07004347
4348 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
4349 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
4350 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
4351 break;
Eric Laurent05274f32012-11-29 12:48:18 -08004352 case MSG_PERSIST_SAFE_VOLUME_STATE:
4353 onPersistSafeVolumeState(msg.arg1);
4354 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08004355
Eric Laurent2a57ca92013-03-07 17:29:27 -08004356 case MSG_BROADCAST_BT_CONNECTION_STATE:
4357 onBroadcastScoConnectionState(msg.arg1);
4358 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004359
4360 case MSG_SYSTEM_READY:
4361 onSystemReady();
4362 break;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004363
4364 case MSG_PERSIST_MUSIC_ACTIVE_MS:
4365 final int musicActiveMs = msg.arg1;
4366 Settings.Secure.putIntForUser(mContentResolver,
4367 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
4368 UserHandle.USER_CURRENT);
4369 break;
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004370 case MSG_PERSIST_MICROPHONE_MUTE:
4371 Settings.System.putIntForUser(mContentResolver,
4372 Settings.System.MICROPHONE_MUTE,
4373 msg.arg1,
4374 msg.arg2);
4375 break;
RoboErik5452e252015-02-06 15:33:53 -08004376 case MSG_UNMUTE_STREAM:
4377 onUnmuteStream(msg.arg1, msg.arg2);
4378 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004379 }
4380 }
4381 }
4382
Jason Parekhb1096152009-03-24 17:48:25 -07004383 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07004384
Jason Parekhb1096152009-03-24 17:48:25 -07004385 SettingsObserver() {
4386 super(new Handler());
4387 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4388 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004389 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4390 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07004391 }
4392
4393 @Override
4394 public void onChange(boolean selfChange) {
4395 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08004396 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
4397 // However there appear to be some missing locks around mRingerModeMutedStreams
4398 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
4399 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07004400 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004401 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07004402 /*
4403 * Ensure all stream types that should be affected by ringer mode
4404 * are in the proper state.
4405 */
John Spurlock661f2cf2014-11-17 10:29:10 -05004406 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurenta553c252009-07-17 12:17:14 -07004407 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004408 readDockAudioSettings(mContentResolver);
Eric Laurenta553c252009-07-17 12:17:14 -07004409 }
Jason Parekhb1096152009-03-24 17:48:25 -07004410 }
Jason Parekhb1096152009-03-24 17:48:25 -07004411 }
Eric Laurenta553c252009-07-17 12:17:14 -07004412
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004413 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004414 private void makeA2dpDeviceAvailable(String address) {
Eric Laurent78472112012-05-21 08:57:21 -07004415 // enable A2DP before notifying A2DP connection to avoid unecessary processing in
4416 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004417 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4418 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4419 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Eric Laurent78472112012-05-21 08:57:21 -07004420 setBluetoothA2dpOnInt(true);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004421 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4422 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004423 address,
4424 "a2dp-device");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004425 // Reset A2DP suspend state each time a new sink is connected
4426 AudioSystem.setParameters("A2dpSuspended=false");
4427 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
4428 address);
4429 }
4430
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004431 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004432 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07004433 }
4434
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004435 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004436 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004437 synchronized (mA2dpAvrcpLock) {
4438 mAvrcpAbsVolSupported = false;
4439 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004440 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4441 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004442 address,
4443 "a2dp-device");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004444 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
RoboErik5535ea82014-09-25 14:53:16 -07004445 synchronized (mCurAudioRoutes) {
4446 // Remove A2DP routes as well
John Spurlock61560172015-02-06 19:46:04 -05004447 if (mCurAudioRoutes.bluetoothName != null) {
4448 mCurAudioRoutes.bluetoothName = null;
RoboErik5535ea82014-09-25 14:53:16 -07004449 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4450 SENDMSG_NOOP, 0, 0, null, 0);
4451 }
4452 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004453 }
4454
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004455 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004456 private void makeA2dpDeviceUnavailableLater(String address) {
Eric Laurent3b591262010-04-20 07:01:00 -07004457 // prevent any activity on the A2DP audio output to avoid unwanted
4458 // reconnection of the sink.
4459 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004460 // the device will be made unavailable later, so consider it disconnected right away
4461 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
4462 // send the delayed message to make the device unavailable later
4463 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
4464 mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
4465
4466 }
4467
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004468 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004469 private void makeA2dpSrcAvailable(String address) {
4470 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
4471 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004472 address,
4473 "a2dp-device");
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004474 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
4475 address);
4476 }
4477
4478 // must be called synchronized on mConnectedDevices
4479 private void makeA2dpSrcUnavailable(String address) {
4480 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
4481 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004482 address,
4483 "a2dp-device");
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004484 mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
4485 }
4486
4487 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004488 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004489 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4490 }
4491
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004492 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004493 private boolean hasScheduledA2dpDockTimeout() {
4494 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4495 }
4496
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004497 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004498 {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004499 if (DEBUG_VOL) {
4500 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
4501 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004502 if (btDevice == null) {
4503 return;
4504 }
4505 String address = btDevice.getAddress();
4506 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4507 address = "";
4508 }
John Du5a0cf7a2013-07-19 11:30:34 -07004509
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004510 synchronized (mConnectedDevices) {
4511 boolean isConnected =
4512 (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
4513 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
4514
4515 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4516 if (btDevice.isBluetoothDock()) {
4517 if (state == BluetoothProfile.STATE_DISCONNECTED) {
4518 // introduction of a delay for transient disconnections of docks when
4519 // power is rapidly turned off/on, this message will be canceled if
4520 // we reconnect the dock under a preset delay
4521 makeA2dpDeviceUnavailableLater(address);
4522 // the next time isConnected is evaluated, it will be false for the dock
4523 }
4524 } else {
4525 makeA2dpDeviceUnavailableNow(address);
4526 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07004527 synchronized (mCurAudioRoutes) {
John Spurlock61560172015-02-06 19:46:04 -05004528 if (mCurAudioRoutes.bluetoothName != null) {
4529 mCurAudioRoutes.bluetoothName = null;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004530 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4531 SENDMSG_NOOP, 0, 0, null, 0);
4532 }
4533 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004534 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4535 if (btDevice.isBluetoothDock()) {
4536 // this could be a reconnection after a transient disconnection
4537 cancelA2dpDeviceTimeout();
4538 mDockAddress = address;
4539 } else {
4540 // this could be a connection of another A2DP device before the timeout of
4541 // a dock: cancel the dock timeout, and make the dock unavailable now
4542 if(hasScheduledA2dpDockTimeout()) {
4543 cancelA2dpDeviceTimeout();
4544 makeA2dpDeviceUnavailableNow(mDockAddress);
4545 }
4546 }
4547 makeA2dpDeviceAvailable(address);
Dianne Hackborn632ca412012-06-14 19:34:10 -07004548 synchronized (mCurAudioRoutes) {
4549 String name = btDevice.getAliasName();
John Spurlock61560172015-02-06 19:46:04 -05004550 if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
4551 mCurAudioRoutes.bluetoothName = name;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004552 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4553 SENDMSG_NOOP, 0, 0, null, 0);
4554 }
4555 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004556 }
4557 }
4558 }
4559
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004560 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
4561 {
4562 if (DEBUG_VOL) {
4563 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
4564 }
4565 if (btDevice == null) {
4566 return;
4567 }
4568 String address = btDevice.getAddress();
4569 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4570 address = "";
4571 }
4572
4573 synchronized (mConnectedDevices) {
4574 boolean isConnected =
4575 (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
4576 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));
4577
4578 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4579 makeA2dpSrcUnavailable(address);
4580 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4581 makeA2dpSrcAvailable(address);
4582 }
4583 }
4584 }
4585
John Du5a0cf7a2013-07-19 11:30:34 -07004586 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
4587 // address is not used for now, but may be used when multiple a2dp devices are supported
4588 synchronized (mA2dpAvrcpLock) {
4589 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004590 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07004591 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4592 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4593 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4594 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4595 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07004596 }
4597 }
4598
Paul McLean10804eb2015-01-28 11:16:35 -08004599 private boolean handleDeviceConnection(boolean connect, int device, String address, String deviceName) {
4600 Slog.i(TAG, "handleDeviceConnection(" + connect +
4601 " dev:" + Integer.toHexString(device) +
RoboErik5452e252015-02-06 15:33:53 -08004602 " address:" + address +
Paul McLean10804eb2015-01-28 11:16:35 -08004603 " name:" + deviceName + ")");
Eric Laurent59f48272012-04-05 19:42:21 -07004604 synchronized (mConnectedDevices) {
4605 boolean isConnected = (mConnectedDevices.containsKey(device) &&
Paul McLean10804eb2015-01-28 11:16:35 -08004606 (address.isEmpty() || mConnectedDevices.get(device).equals(address)));
Eric Laurent59f48272012-04-05 19:42:21 -07004607
Paul McLean10804eb2015-01-28 11:16:35 -08004608 if (isConnected && !connect) {
Eric Laurent59f48272012-04-05 19:42:21 -07004609 AudioSystem.setDeviceConnectionState(device,
4610 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004611 address, deviceName);
Eric Laurent59f48272012-04-05 19:42:21 -07004612 mConnectedDevices.remove(device);
4613 return true;
Paul McLean10804eb2015-01-28 11:16:35 -08004614 } else if (!isConnected && connect) {
Eric Laurent59f48272012-04-05 19:42:21 -07004615 AudioSystem.setDeviceConnectionState(device,
4616 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004617 address, deviceName);
4618 mConnectedDevices.put(new Integer(device), address);
Eric Laurent59f48272012-04-05 19:42:21 -07004619 return true;
4620 }
4621 }
4622 return false;
4623 }
4624
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004625 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4626 // sent if none of these devices is connected.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004627 // Access synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004628 int mBecomingNoisyIntentDevices =
4629 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07004630 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07004631 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004632 AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004633
4634 // must be called before removing the device from mConnectedDevices
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004635 // Called synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004636 private int checkSendBecomingNoisyIntent(int device, int state) {
4637 int delay = 0;
4638 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4639 int devices = 0;
4640 for (int dev : mConnectedDevices.keySet()) {
Eric Laurent27c30e42014-08-27 12:36:33 -07004641 if (((dev & AudioSystem.DEVICE_BIT_IN) == 0) &&
4642 ((dev & mBecomingNoisyIntentDevices) != 0)) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004643 devices |= dev;
4644 }
4645 }
4646 if (devices == device) {
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004647 sendMsg(mAudioHandler,
4648 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4649 SENDMSG_REPLACE,
4650 0,
4651 0,
4652 null,
4653 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004654 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004655 }
4656 }
4657
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004658 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
4659 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004660 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004661 synchronized (mLastDeviceConnectMsgTime) {
4662 long time = SystemClock.uptimeMillis();
4663 if (mLastDeviceConnectMsgTime > time) {
Matthew Xiec525cf72015-01-22 20:13:17 -08004664 delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004665 }
4666 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004667 }
4668 return delay;
4669 }
4670
Paul McLean10804eb2015-01-28 11:16:35 -08004671 private void sendDeviceConnectionIntent(int device, int state, String address, String deviceName)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004672 {
Paul McLean10804eb2015-01-28 11:16:35 -08004673 Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
4674 " state:0x" + Integer.toHexString(state) +
4675 " address:" + address +
4676 " name:" + deviceName + ");");
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004677 Intent intent = new Intent();
4678
Paul McLean10804eb2015-01-28 11:16:35 -08004679 intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
4680 intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
4681 intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
4682
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004683 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4684
Dianne Hackborn632ca412012-06-14 19:34:10 -07004685 int connType = 0;
4686
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004687 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004688 connType = AudioRoutesInfo.MAIN_HEADSET;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004689 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4690 intent.putExtra("microphone", 1);
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004691 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
4692 device == AudioSystem.DEVICE_OUT_LINE) {
4693 /*do apps care about line-out vs headphones?*/
Dianne Hackborn632ca412012-06-14 19:34:10 -07004694 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004695 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4696 intent.putExtra("microphone", 0);
Eric Laurent6fa42452015-01-09 15:09:40 -08004697 } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
4698 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004699 connType = AudioRoutesInfo.MAIN_HDMI;
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004700 configureHdmiPlugIntent(intent, state);
Paul McLean10804eb2015-01-28 11:16:35 -08004701 } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE) {
4702 connType = AudioRoutesInfo.MAIN_USB;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004703 }
4704
Dianne Hackborn632ca412012-06-14 19:34:10 -07004705 synchronized (mCurAudioRoutes) {
4706 if (connType != 0) {
John Spurlock61560172015-02-06 19:46:04 -05004707 int newConn = mCurAudioRoutes.mainType;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004708 if (state != 0) {
4709 newConn |= connType;
4710 } else {
4711 newConn &= ~connType;
4712 }
John Spurlock61560172015-02-06 19:46:04 -05004713 if (newConn != mCurAudioRoutes.mainType) {
4714 mCurAudioRoutes.mainType = newConn;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004715 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4716 SENDMSG_NOOP, 0, 0, null, 0);
4717 }
4718 }
4719 }
4720
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004721 final long ident = Binder.clearCallingIdentity();
4722 try {
4723 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
4724 } finally {
4725 Binder.restoreCallingIdentity(ident);
4726 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004727 }
4728
Paul McLean10804eb2015-01-28 11:16:35 -08004729 private void onSetWiredDeviceConnectionState(int device, int state, String address,
4730 String deviceName)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004731 {
Paul McLean10804eb2015-01-28 11:16:35 -08004732 Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
4733 + " state:" + Integer.toHexString(state)
4734 + " address:" + address
4735 + " deviceName:" + deviceName + ");");
4736
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004737 synchronized (mConnectedDevices) {
4738 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004739 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4740 (device == AudioSystem.DEVICE_OUT_LINE))) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004741 setBluetoothA2dpOnInt(true);
4742 }
Eric Laurentae4506e2014-05-29 16:04:32 -07004743 boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
4744 (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
4745 ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
Paul McLean10804eb2015-01-28 11:16:35 -08004746 handleDeviceConnection(state == 1, device, address, deviceName);
Eric Laurentf1a457d2012-09-20 16:27:23 -07004747 if (state != 0) {
4748 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004749 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4750 (device == AudioSystem.DEVICE_OUT_LINE)) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07004751 setBluetoothA2dpOnInt(false);
4752 }
4753 if ((device & mSafeMediaVolumeDevices) != 0) {
4754 sendMsg(mAudioHandler,
4755 MSG_CHECK_MUSIC_ACTIVE,
4756 SENDMSG_REPLACE,
4757 0,
4758 0,
4759 null,
4760 MUSIC_ACTIVE_POLL_PERIOD_MS);
4761 }
Eric Laurent212532b2014-07-21 15:43:18 -07004762 // Television devices without CEC service apply software volume on HDMI output
4763 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4764 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
4765 checkAllFixedVolumeDevices();
4766 if (mHdmiManager != null) {
4767 synchronized (mHdmiManager) {
4768 if (mHdmiPlaybackClient != null) {
4769 mHdmiCecSink = false;
4770 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
4771 }
4772 }
4773 }
4774 }
4775 } else {
4776 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4777 if (mHdmiManager != null) {
4778 synchronized (mHdmiManager) {
4779 mHdmiCecSink = false;
4780 }
4781 }
4782 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004783 }
Paul McLean10804eb2015-01-28 11:16:35 -08004784 if (!isUsb && device != AudioSystem.DEVICE_IN_WIRED_HEADSET) {
4785 sendDeviceConnectionIntent(device, state, address, deviceName);
Mike Lockwooddb454842012-09-18 11:16:57 -07004786 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004787 }
4788 }
4789
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004790 private void configureHdmiPlugIntent(Intent intent, int state) {
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004791 intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
4792 intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004793 if (state == 1) {
4794 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
4795 int[] portGeneration = new int[1];
4796 int status = AudioSystem.listAudioPorts(ports, portGeneration);
4797 if (status == AudioManager.SUCCESS) {
4798 for (AudioPort port : ports) {
4799 if (port instanceof AudioDevicePort) {
4800 final AudioDevicePort devicePort = (AudioDevicePort) port;
Eric Laurent6fa42452015-01-09 15:09:40 -08004801 if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
4802 devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004803 // format the list of supported encodings
4804 int[] formats = devicePort.formats();
4805 if (formats.length > 0) {
4806 ArrayList<Integer> encodingList = new ArrayList(1);
4807 for (int format : formats) {
4808 // a format in the list can be 0, skip it
4809 if (format != AudioFormat.ENCODING_INVALID) {
4810 encodingList.add(format);
4811 }
4812 }
4813 int[] encodingArray = new int[encodingList.size()];
4814 for (int i = 0 ; i < encodingArray.length ; i++) {
4815 encodingArray[i] = encodingList.get(i);
4816 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004817 intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004818 }
4819 // find the maximum supported number of channels
4820 int maxChannels = 0;
4821 for (int mask : devicePort.channelMasks()) {
4822 int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
4823 if (channelCount > maxChannels) {
4824 maxChannels = channelCount;
4825 }
4826 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004827 intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004828 }
4829 }
4830 }
4831 }
4832 }
4833 }
4834
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004835 /* cache of the address of the last dock the device was connected to */
4836 private String mDockAddress;
4837
Eric Laurenta553c252009-07-17 12:17:14 -07004838 /**
4839 * Receiver for misc intent broadcasts the Phone app cares about.
4840 */
4841 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4842 @Override
4843 public void onReceive(Context context, Intent intent) {
4844 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07004845 int outDevice;
4846 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07004847 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07004848
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004849 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4850 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4851 Intent.EXTRA_DOCK_STATE_UNDOCKED);
4852 int config;
4853 switch (dockState) {
4854 case Intent.EXTRA_DOCK_STATE_DESK:
4855 config = AudioSystem.FORCE_BT_DESK_DOCK;
4856 break;
4857 case Intent.EXTRA_DOCK_STATE_CAR:
4858 config = AudioSystem.FORCE_BT_CAR_DOCK;
4859 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004860 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08004861 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004862 break;
4863 case Intent.EXTRA_DOCK_STATE_HE_DESK:
4864 config = AudioSystem.FORCE_DIGITAL_DOCK;
4865 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004866 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4867 default:
4868 config = AudioSystem.FORCE_NONE;
4869 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08004870 // Low end docks have a menu to enable or disable audio
4871 // (see mDockAudioMediaEnabled)
4872 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
4873 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
4874 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
4875 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
4876 }
4877 mDockState = dockState;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004878 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
Eric Laurent59f48272012-04-05 19:42:21 -07004879 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004880 BluetoothProfile.STATE_DISCONNECTED);
Eric Laurentae4506e2014-05-29 16:04:32 -07004881 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
4882 inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
Nick Pellya56d1c72009-08-19 14:49:29 -07004883 String address = null;
Eric Laurentdca56b92011-09-02 14:20:56 -07004884
4885 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
4886 if (btDevice == null) {
4887 return;
4888 }
4889
4890 address = btDevice.getAddress();
4891 BluetoothClass btClass = btDevice.getBluetoothClass();
4892 if (btClass != null) {
4893 switch (btClass.getDeviceClass()) {
4894 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
4895 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
Eric Laurentae4506e2014-05-29 16:04:32 -07004896 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurentdca56b92011-09-02 14:20:56 -07004897 break;
4898 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
Eric Laurentae4506e2014-05-29 16:04:32 -07004899 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurentdca56b92011-09-02 14:20:56 -07004900 break;
Eric Laurentd5603c12009-08-06 08:49:39 -07004901 }
4902 }
4903
Eric Laurentdca56b92011-09-02 14:20:56 -07004904 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4905 address = "";
4906 }
Eric Laurentd5603c12009-08-06 08:49:39 -07004907
Eric Laurent59f48272012-04-05 19:42:21 -07004908 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
Paul McLean10804eb2015-01-28 11:16:35 -08004909 boolean success =
4910 handleDeviceConnection(connected, outDevice, address, "Bluetooth Headset") &&
4911 handleDeviceConnection(connected, inDevice, address, "Bluetooth Headset");
Eric Laurentae4506e2014-05-29 16:04:32 -07004912 if (success) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004913 synchronized (mScoClients) {
Eric Laurent59f48272012-04-05 19:42:21 -07004914 if (connected) {
4915 mBluetoothHeadsetDevice = btDevice;
4916 } else {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004917 mBluetoothHeadsetDevice = null;
4918 resetBluetoothSco();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004919 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004920 }
Eric Laurenta553c252009-07-17 12:17:14 -07004921 }
Paul McLeandf361462014-04-10 16:02:55 -07004922 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004923 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07004924 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004925 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004926 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07004927 // broadcast intent if the connection was initated by AudioService
4928 if (!mScoClients.isEmpty() &&
4929 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
4930 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
4931 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004932 broadcast = true;
4933 }
4934 switch (btState) {
4935 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004936 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07004937 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4938 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4939 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004940 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004941 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004942 break;
4943 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004944 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08004945 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07004946 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08004947 break;
4948 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07004949 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4950 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4951 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004952 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004953 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004954 default:
4955 // do not broadcast CONNECTING or invalid state
4956 broadcast = false;
4957 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004958 }
4959 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004960 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07004961 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07004962 //FIXME: this is to maintain compatibility with deprecated intent
4963 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08004964 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07004965 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004966 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08004967 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004968 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06004969 if (mMonitorRotation) {
4970 mOrientationListener.onOrientationChanged(0); //argument is ignored anyway
4971 mOrientationListener.enable();
4972 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004973 AudioSystem.setParameters("screen_state=on");
4974 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06004975 if (mMonitorRotation) {
4976 //reduce wakeups (save current) by only listening when display is on
4977 mOrientationListener.disable();
4978 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004979 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07004980 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004981 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004982 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004983 // attempt to stop music playback for background user
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004984 sendMsg(mAudioHandler,
4985 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4986 SENDMSG_REPLACE,
4987 0,
4988 0,
4989 null,
4990 0);
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004991 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004992 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004993
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004994 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004995 readAudioSettings(true /*userSwitch*/);
4996 // preserve STREAM_MUSIC volume from one user to the next.
4997 sendMsg(mAudioHandler,
4998 MSG_SET_ALL_VOLUMES,
4999 SENDMSG_QUEUE,
5000 0,
5001 0,
5002 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Eric Laurenta553c252009-07-17 12:17:14 -07005003 }
5004 }
Paul McLeanc837a452014-04-09 09:04:43 -07005005 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005006
5007 //==========================================================================================
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005008 // RemoteControlDisplay / RemoteControlClient / Remote info
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005009 //==========================================================================================
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07005010 public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
5011 ComponentName listenerComp) {
5012 return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
5013 }
5014
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005015 public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07005016 return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005017 }
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005018
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005019 public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005020 mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005021 }
5022
5023 public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005024 mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005025 }
5026
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07005027 public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
5028 boolean wantsSync) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005029 mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
5030 }
5031
John Spurlock3346a802014-05-20 16:25:37 -04005032 @Override
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005033 public void setRemoteStreamVolume(int index) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005034 enforceVolumeController("set the remote stream volume");
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005035 mMediaFocusControl.setRemoteStreamVolume(index);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005036 }
5037
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005038 //==========================================================================================
5039 // Audio Focus
5040 //==========================================================================================
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005041 public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005042 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005043 IAudioPolicyCallback pcb) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005044 // permission checks
5045 if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
John Spurlock61560172015-02-06 19:46:04 -05005046 if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005047 if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
5048 android.Manifest.permission.MODIFY_PHONE_STATE)) {
5049 Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
5050 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5051 }
5052 } else {
5053 // only a registered audio policy can be used to lock focus
5054 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005055 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
5056 Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005057 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5058 }
5059 }
5060 }
5061 }
5062
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005063 return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
5064 clientId, callingPackageName, flags);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005065 }
5066
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005067 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
5068 return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005069 }
5070
5071 public void unregisterAudioFocusClient(String clientId) {
5072 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005073 }
5074
Jean-Michel Trivi23805662013-07-31 14:19:18 -07005075 public int getCurrentAudioFocus() {
5076 return mMediaFocusControl.getCurrentAudioFocus();
5077 }
5078
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005079 //==========================================================================================
5080 // Device orientation
5081 //==========================================================================================
5082 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005083 * Handles device configuration changes that may map to a change in the orientation
5084 * or orientation.
5085 * Monitoring orientation and rotation is optional, and is defined by the definition and value
5086 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005087 */
5088 private void handleConfigurationChanged(Context context) {
5089 try {
5090 // reading new orientation "safely" (i.e. under try catch) in case anything
5091 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07005092 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005093 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07005094 if (mMonitorOrientation) {
5095 int newOrientation = config.orientation;
5096 if (newOrientation != mDeviceOrientation) {
5097 mDeviceOrientation = newOrientation;
5098 setOrientationForAudioSystem();
5099 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005100 }
Eric Laurentd640bd32012-09-28 18:01:48 -07005101 sendMsg(mAudioHandler,
5102 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
5103 SENDMSG_REPLACE,
5104 0,
5105 0,
5106 null,
5107 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07005108
5109 boolean cameraSoundForced = mContext.getResources().getBoolean(
5110 com.android.internal.R.bool.config_camera_sound_forced);
5111 synchronized (mSettingsLock) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005112 boolean cameraSoundForcedChanged = false;
Eric Laurentdd45d012012-10-08 09:04:34 -07005113 synchronized (mCameraSoundForced) {
5114 if (cameraSoundForced != mCameraSoundForced) {
5115 mCameraSoundForced = cameraSoundForced;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005116 cameraSoundForcedChanged = true;
Eric Laurentdd45d012012-10-08 09:04:34 -07005117 }
5118 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005119 if (cameraSoundForcedChanged) {
5120 if (!isPlatformTelevision()) {
5121 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
5122 if (cameraSoundForced) {
5123 s.setAllIndexesToMax();
5124 mRingerModeAffectedStreams &=
5125 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5126 } else {
5127 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
5128 mRingerModeAffectedStreams |=
5129 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5130 }
5131 // take new state into account for streams muted by ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05005132 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005133 }
5134
5135 sendMsg(mAudioHandler,
5136 MSG_SET_FORCE_USE,
5137 SENDMSG_QUEUE,
5138 AudioSystem.FOR_SYSTEM,
5139 cameraSoundForced ?
5140 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
5141 null,
5142 0);
5143
5144 sendMsg(mAudioHandler,
5145 MSG_SET_ALL_VOLUMES,
5146 SENDMSG_QUEUE,
5147 0,
5148 0,
5149 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
5150 }
Eric Laurentdd45d012012-10-08 09:04:34 -07005151 }
John Spurlock3346a802014-05-20 16:25:37 -04005152 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005153 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005154 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005155 }
5156 }
5157
5158 private void setOrientationForAudioSystem() {
5159 switch (mDeviceOrientation) {
5160 case Configuration.ORIENTATION_LANDSCAPE:
5161 //Log.i(TAG, "orientation is landscape");
5162 AudioSystem.setParameters("orientation=landscape");
5163 break;
5164 case Configuration.ORIENTATION_PORTRAIT:
5165 //Log.i(TAG, "orientation is portrait");
5166 AudioSystem.setParameters("orientation=portrait");
5167 break;
5168 case Configuration.ORIENTATION_SQUARE:
5169 //Log.i(TAG, "orientation is square");
5170 AudioSystem.setParameters("orientation=square");
5171 break;
5172 case Configuration.ORIENTATION_UNDEFINED:
5173 //Log.i(TAG, "orientation is undefined");
5174 AudioSystem.setParameters("orientation=undefined");
5175 break;
5176 default:
5177 Log.e(TAG, "Unknown orientation");
5178 }
5179 }
5180
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005181 private void setRotationForAudioSystem() {
5182 switch (mDeviceRotation) {
5183 case Surface.ROTATION_0:
5184 AudioSystem.setParameters("rotation=0");
5185 break;
5186 case Surface.ROTATION_90:
5187 AudioSystem.setParameters("rotation=90");
5188 break;
5189 case Surface.ROTATION_180:
5190 AudioSystem.setParameters("rotation=180");
5191 break;
5192 case Surface.ROTATION_270:
5193 AudioSystem.setParameters("rotation=270");
5194 break;
5195 default:
5196 Log.e(TAG, "Unknown device rotation");
5197 }
5198 }
5199
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005200
Eric Laurent78472112012-05-21 08:57:21 -07005201 // Handles request to override default use of A2DP for media.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005202 // Must be called synchronized on mConnectedDevices
Eric Laurent78472112012-05-21 08:57:21 -07005203 public void setBluetoothA2dpOnInt(boolean on) {
5204 synchronized (mBluetoothA2dpEnabledLock) {
5205 mBluetoothA2dpEnabled = on;
Eric Laurentc390bed2012-07-03 12:24:05 -07005206 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005207 setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
Eric Laurentc390bed2012-07-03 12:24:05 -07005208 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
Eric Laurent78472112012-05-21 08:57:21 -07005209 }
5210 }
5211
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005212 // Must be called synchronized on mConnectedDevices
5213 private void setForceUseInt_SyncDevices(int usage, int config) {
5214 switch (usage) {
5215 case AudioSystem.FOR_MEDIA:
5216 if (config == AudioSystem.FORCE_NO_BT_A2DP) {
5217 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ALL_A2DP;
5218 } else { // config == AudioSystem.FORCE_NONE
5219 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
5220 }
5221 break;
5222 case AudioSystem.FOR_DOCK:
5223 if (config == AudioSystem.FORCE_ANALOG_DOCK) {
5224 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5225 } else { // config == AudioSystem.FORCE_NONE
5226 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5227 }
5228 break;
5229 default:
5230 // usage doesn't affect the broadcast of ACTION_AUDIO_BECOMING_NOISY
5231 }
5232 AudioSystem.setForceUse(usage, config);
5233 }
5234
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005235 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07005236 public void setRingtonePlayer(IRingtonePlayer player) {
5237 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5238 mRingtonePlayer = player;
5239 }
5240
5241 @Override
5242 public IRingtonePlayer getRingtonePlayer() {
5243 return mRingtonePlayer;
5244 }
5245
5246 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07005247 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5248 synchronized (mCurAudioRoutes) {
5249 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5250 mRoutesObservers.register(observer);
5251 return routes;
5252 }
5253 }
5254
Eric Laurentc34dcc12012-09-10 13:51:52 -07005255
5256 //==========================================================================================
5257 // Safe media volume management.
5258 // MUSIC stream volume level is limited when headphones are connected according to safety
5259 // regulation. When the user attempts to raise the volume above the limit, a warning is
5260 // displayed and the user has to acknowlegde before the volume is actually changed.
5261 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
5262 // property. Platforms with a different limit must set this property accordingly in their
5263 // overlay.
5264 //==========================================================================================
5265
Eric Laurentd640bd32012-09-28 18:01:48 -07005266 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
5267 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
5268 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
5269 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
5270 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
5271 // (when user opts out).
John Spurlock35134602014-07-24 18:10:48 -04005272 private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
5273 private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
5274 private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed
5275 private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
Eric Laurentd640bd32012-09-28 18:01:48 -07005276 private Integer mSafeMediaVolumeState;
5277
5278 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005279 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07005280 private int mSafeMediaVolumeIndex;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005281 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
5282 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
5283 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
5284 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
5285 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
5286 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
5287 private int mMusicActiveMs;
5288 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
5289 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07005290 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07005291
5292 private void setSafeMediaVolumeEnabled(boolean on) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005293 synchronized (mSafeMediaVolumeState) {
5294 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
5295 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
5296 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
5297 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
5298 enforceSafeMediaVolume();
5299 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
5300 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005301 mMusicActiveMs = 1; // nonzero = confirmed
5302 saveMusicActiveMs();
Eric Laurentd640bd32012-09-28 18:01:48 -07005303 sendMsg(mAudioHandler,
5304 MSG_CHECK_MUSIC_ACTIVE,
5305 SENDMSG_REPLACE,
5306 0,
5307 0,
5308 null,
5309 MUSIC_ACTIVE_POLL_PERIOD_MS);
5310 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005311 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005312 }
5313 }
5314
5315 private void enforceSafeMediaVolume() {
5316 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07005317 int devices = mSafeMediaVolumeDevices;
5318 int i = 0;
5319
5320 while (devices != 0) {
5321 int device = 1 << i++;
5322 if ((device & devices) == 0) {
5323 continue;
5324 }
Eric Laurent42b041e2013-03-29 11:36:03 -07005325 int index = streamState.getIndex(device);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005326 if (index > mSafeMediaVolumeIndex) {
Eric Laurent42b041e2013-03-29 11:36:03 -07005327 streamState.setIndex(mSafeMediaVolumeIndex, device);
5328 sendMsg(mAudioHandler,
5329 MSG_SET_DEVICE_VOLUME,
5330 SENDMSG_QUEUE,
5331 device,
5332 0,
5333 streamState,
5334 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005335 }
5336 devices &= ~device;
5337 }
5338 }
5339
5340 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005341 synchronized (mSafeMediaVolumeState) {
5342 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07005343 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
5344 ((device & mSafeMediaVolumeDevices) != 0) &&
5345 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005346 return false;
5347 }
5348 return true;
5349 }
5350 }
5351
John Spurlock3346a802014-05-20 16:25:37 -04005352 @Override
Eric Laurentc34dcc12012-09-10 13:51:52 -07005353 public void disableSafeMediaVolume() {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005354 enforceVolumeController("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07005355 synchronized (mSafeMediaVolumeState) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005356 setSafeMediaVolumeEnabled(false);
Eric Laurentfde16d52012-12-03 14:42:39 -08005357 if (mPendingVolumeCommand != null) {
5358 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
5359 mPendingVolumeCommand.mIndex,
5360 mPendingVolumeCommand.mFlags,
5361 mPendingVolumeCommand.mDevice);
5362 mPendingVolumeCommand = null;
5363 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005364 }
5365 }
5366
Jungshik Jang41d97462014-06-30 22:26:29 +09005367 //==========================================================================================
5368 // Hdmi Cec system audio mode.
5369 // If Hdmi Cec's system audio mode is on, audio service should notify volume change
5370 // to HdmiControlService so that audio recevier can handle volume change.
5371 //==========================================================================================
5372
Eric Laurent212532b2014-07-21 15:43:18 -07005373 private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
5374 public void onComplete(int status) {
5375 if (mHdmiManager != null) {
5376 synchronized (mHdmiManager) {
5377 mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
5378 // Television devices without CEC service apply software volume on HDMI output
5379 if (isPlatformTelevision() && !mHdmiCecSink) {
5380 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5381 }
5382 checkAllFixedVolumeDevices();
5383 }
5384 }
5385 }
5386 };
5387
Jungshik Jang41d97462014-06-30 22:26:29 +09005388 // If HDMI-CEC system audio is supported
5389 private boolean mHdmiSystemAudioSupported = false;
5390 // Set only when device is tv.
5391 private HdmiTvClient mHdmiTvClient;
Eric Laurent0b03f992014-11-18 18:08:02 -08005392 // true if the device has system feature PackageManager.FEATURE_LEANBACK.
Eric Laurent212532b2014-07-21 15:43:18 -07005393 // cached HdmiControlManager interface
5394 private HdmiControlManager mHdmiManager;
5395 // Set only when device is a set-top box.
5396 private HdmiPlaybackClient mHdmiPlaybackClient;
5397 // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5398 private boolean mHdmiCecSink;
5399
5400 private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
Jungshik Jang41d97462014-06-30 22:26:29 +09005401
5402 @Override
Jungshik Jang12307ca2014-07-15 19:27:56 +09005403 public int setHdmiSystemAudioSupported(boolean on) {
Eric Laurent212532b2014-07-21 15:43:18 -07005404 int device = AudioSystem.DEVICE_NONE;
5405 if (mHdmiManager != null) {
5406 synchronized (mHdmiManager) {
5407 if (mHdmiTvClient == null) {
5408 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5409 return device;
5410 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005411
Eric Laurent212532b2014-07-21 15:43:18 -07005412 synchronized (mHdmiTvClient) {
5413 if (mHdmiSystemAudioSupported != on) {
5414 mHdmiSystemAudioSupported = on;
5415 AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5416 on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5417 AudioSystem.FORCE_NONE);
5418 }
5419 device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
5420 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005421 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005422 }
Eric Laurent212532b2014-07-21 15:43:18 -07005423 return device;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005424 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005425
Terry Heoe7d6d972014-09-04 21:05:28 +09005426 @Override
5427 public boolean isHdmiSystemAudioSupported() {
5428 return mHdmiSystemAudioSupported;
5429 }
5430
Eric Laurentdd45d012012-10-08 09:04:34 -07005431 //==========================================================================================
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005432 // Accessibility: taking touch exploration into account for selecting the default
5433 // stream override timeout when adjusting volume
5434 //==========================================================================================
5435 private static class StreamOverride
5436 implements AccessibilityManager.TouchExplorationStateChangeListener {
5437
5438 // AudioService.getActiveStreamType() will return:
5439 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
5440 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
5441 // stopped
5442 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
5443 private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
5444
5445 static int sDelayMs;
5446
5447 static void init(Context ctxt) {
5448 AccessibilityManager accessibilityManager =
5449 (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
5450 updateDefaultStreamOverrideDelay(
5451 accessibilityManager.isTouchExplorationEnabled());
5452 accessibilityManager.addTouchExplorationStateChangeListener(
5453 new StreamOverride());
5454 }
5455
5456 @Override
5457 public void onTouchExplorationStateChanged(boolean enabled) {
5458 updateDefaultStreamOverrideDelay(enabled);
5459 }
5460
5461 private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
5462 if (touchExploreEnabled) {
5463 sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
5464 } else {
5465 sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
5466 }
5467 if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
5468 + " stream override delay is now " + sDelayMs + " ms");
5469 }
5470 }
5471
5472 //==========================================================================================
Eric Laurentdd45d012012-10-08 09:04:34 -07005473 // Camera shutter sound policy.
5474 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5475 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5476 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5477 //==========================================================================================
5478
5479 // cached value of com.android.internal.R.bool.config_camera_sound_forced
5480 private Boolean mCameraSoundForced;
5481
5482 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5483 public boolean isCameraSoundForced() {
5484 synchronized (mCameraSoundForced) {
5485 return mCameraSoundForced;
5486 }
5487 }
5488
5489 private static final String[] RINGER_MODE_NAMES = new String[] {
5490 "SILENT",
5491 "VIBRATE",
5492 "NORMAL"
5493 };
5494
5495 private void dumpRingerMode(PrintWriter pw) {
5496 pw.println("\nRinger mode: ");
John Spurlock661f2cf2014-11-17 10:29:10 -05005497 pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
5498 pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
Eric Laurentdd45d012012-10-08 09:04:34 -07005499 pw.print("- ringer mode affected streams = 0x");
5500 pw.println(Integer.toHexString(mRingerModeAffectedStreams));
5501 pw.print("- ringer mode muted streams = 0x");
5502 pw.println(Integer.toHexString(mRingerModeMutedStreams));
John Spurlock661f2cf2014-11-17 10:29:10 -05005503 pw.print("- delegate = "); pw.println(mRingerModeDelegate);
Eric Laurentdd45d012012-10-08 09:04:34 -07005504 }
5505
Dianne Hackborn632ca412012-06-14 19:34:10 -07005506 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005507 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07005508 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5509
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005510 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07005511 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07005512 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005513 pw.println("\nAudio routes:");
John Spurlock61560172015-02-06 19:46:04 -05005514 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
5515 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
John Spurlock35134602014-07-24 18:10:48 -04005516
5517 pw.println("\nOther state:");
John Spurlock3346a802014-05-20 16:25:37 -04005518 pw.print(" mVolumeController="); pw.println(mVolumeController);
John Spurlock35134602014-07-24 18:10:48 -04005519 pw.print(" mSafeMediaVolumeState=");
5520 pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
5521 pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
5522 pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
5523 pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005524 pw.print(" mMcc="); pw.println(mMcc);
John Spurlock661f2cf2014-11-17 10:29:10 -05005525 pw.print(" mHasVibrator="); pw.println(mHasVibrator);
John Spurlockcdb57ae2015-02-11 19:04:11 -05005526 pw.print(" mControllerService="); pw.println(mControllerService);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005527
5528 dumpAudioPolicies(pw);
John Spurlock35134602014-07-24 18:10:48 -04005529 }
5530
5531 private static String safeMediaVolumeStateToString(Integer state) {
5532 switch(state) {
5533 case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
5534 case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
5535 case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
5536 case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
5537 }
5538 return null;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005539 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07005540
5541 // Inform AudioFlinger of our device's low RAM attribute
5542 private static void readAndSetLowRamDevice()
5543 {
5544 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
5545 if (status != 0) {
5546 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
5547 }
5548 }
John Spurlock3346a802014-05-20 16:25:37 -04005549
John Spurlockcdb57ae2015-02-11 19:04:11 -05005550 private void enforceVolumeController(String action) {
5551 if (mControllerService.mUid != 0 && Binder.getCallingUid() == mControllerService.mUid) {
5552 return;
5553 }
John Spurlock3346a802014-05-20 16:25:37 -04005554 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
5555 "Only SystemUI can " + action);
5556 }
5557
5558 @Override
5559 public void setVolumeController(final IVolumeController controller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005560 enforceVolumeController("set the volume controller");
John Spurlock3346a802014-05-20 16:25:37 -04005561
5562 // return early if things are not actually changing
5563 if (mVolumeController.isSameBinder(controller)) {
5564 return;
5565 }
5566
5567 // dismiss the old volume controller
5568 mVolumeController.postDismiss();
5569 if (controller != null) {
5570 // we are about to register a new controller, listen for its death
5571 try {
5572 controller.asBinder().linkToDeath(new DeathRecipient() {
5573 @Override
5574 public void binderDied() {
5575 if (mVolumeController.isSameBinder(controller)) {
5576 Log.w(TAG, "Current remote volume controller died, unregistering");
5577 setVolumeController(null);
5578 }
5579 }
5580 }, 0);
5581 } catch (RemoteException e) {
5582 // noop
5583 }
5584 }
5585 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04005586 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
5587 }
5588
5589 @Override
5590 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005591 enforceVolumeController("notify about volume controller visibility");
John Spurlock33f4e042014-07-11 13:10:58 -04005592
5593 // return early if the controller is not current
5594 if (!mVolumeController.isSameBinder(controller)) {
5595 return;
5596 }
5597
5598 mVolumeController.setVisible(visible);
5599 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04005600 }
RoboErikd09bd0c2014-06-24 17:45:19 -07005601
5602 public static class VolumeController {
5603 private static final String TAG = "VolumeController";
5604
5605 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04005606 private boolean mVisible;
5607 private long mNextLongPress;
5608 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07005609
5610 public void setController(IVolumeController controller) {
5611 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04005612 mVisible = false;
5613 }
5614
5615 public void loadSettings(ContentResolver cr) {
5616 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
5617 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
5618 }
5619
RoboErik4197cb62015-01-21 15:45:32 -08005620 public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
5621 if (isMute) {
5622 return false;
5623 }
John Spurlock33f4e042014-07-11 13:10:58 -04005624 boolean suppress = false;
5625 if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
5626 final long now = SystemClock.uptimeMillis();
5627 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
5628 // ui will become visible
5629 if (mNextLongPress < now) {
5630 mNextLongPress = now + mLongPressTimeout;
5631 }
5632 suppress = true;
5633 } else if (mNextLongPress > 0) { // in a long-press
5634 if (now > mNextLongPress) {
5635 // long press triggered, no more suppression
5636 mNextLongPress = 0;
5637 } else {
5638 // keep suppressing until the long press triggers
5639 suppress = true;
5640 }
5641 }
5642 }
5643 return suppress;
5644 }
5645
5646 public void setVisible(boolean visible) {
5647 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07005648 }
5649
5650 public boolean isSameBinder(IVolumeController controller) {
5651 return Objects.equals(asBinder(), binder(controller));
5652 }
5653
5654 public IBinder asBinder() {
5655 return binder(mController);
5656 }
5657
5658 private static IBinder binder(IVolumeController controller) {
5659 return controller == null ? null : controller.asBinder();
5660 }
5661
5662 @Override
5663 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04005664 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07005665 }
5666
5667 public void postDisplaySafeVolumeWarning(int flags) {
5668 if (mController == null)
5669 return;
5670 try {
5671 mController.displaySafeVolumeWarning(flags);
5672 } catch (RemoteException e) {
5673 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
5674 }
5675 }
5676
5677 public void postVolumeChanged(int streamType, int flags) {
5678 if (mController == null)
5679 return;
5680 try {
5681 mController.volumeChanged(streamType, flags);
5682 } catch (RemoteException e) {
5683 Log.w(TAG, "Error calling volumeChanged", e);
5684 }
5685 }
5686
5687 public void postMasterVolumeChanged(int flags) {
5688 if (mController == null)
5689 return;
5690 try {
5691 mController.masterVolumeChanged(flags);
5692 } catch (RemoteException e) {
5693 Log.w(TAG, "Error calling masterVolumeChanged", e);
5694 }
5695 }
5696
5697 public void postMasterMuteChanged(int flags) {
5698 if (mController == null)
5699 return;
5700 try {
5701 mController.masterMuteChanged(flags);
5702 } catch (RemoteException e) {
5703 Log.w(TAG, "Error calling masterMuteChanged", e);
5704 }
5705 }
5706
5707 public void setLayoutDirection(int layoutDirection) {
5708 if (mController == null)
5709 return;
5710 try {
5711 mController.setLayoutDirection(layoutDirection);
5712 } catch (RemoteException e) {
5713 Log.w(TAG, "Error calling setLayoutDirection", e);
5714 }
5715 }
5716
5717 public void postDismiss() {
5718 if (mController == null)
5719 return;
5720 try {
5721 mController.dismiss();
5722 } catch (RemoteException e) {
5723 Log.w(TAG, "Error calling dismiss", e);
5724 }
5725 }
5726 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005727
RoboErik0dac35a2014-08-12 15:48:49 -07005728 /**
5729 * Interface for system components to get some extra functionality through
5730 * LocalServices.
5731 */
5732 final class AudioServiceInternal extends AudioManagerInternal {
John Spurlock661f2cf2014-11-17 10:29:10 -05005733 @Override
5734 public void setRingerModeDelegate(RingerModeDelegate delegate) {
5735 mRingerModeDelegate = delegate;
5736 if (mRingerModeDelegate != null) {
5737 setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
5738 }
5739 }
RoboErik272e1612014-09-05 11:39:29 -07005740
5741 @Override
5742 public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
5743 String callingPackage, int uid) {
5744 // direction and stream type swap here because the public
5745 // adjustSuggested has a different order than the other methods.
5746 adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage, uid);
5747 }
5748
RoboErik0dac35a2014-08-12 15:48:49 -07005749 @Override
5750 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
5751 String callingPackage, int uid) {
5752 adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
5753 }
5754
5755 @Override
5756 public void setStreamVolumeForUid(int streamType, int direction, int flags,
5757 String callingPackage, int uid) {
5758 setStreamVolume(streamType, direction, flags, callingPackage, uid);
5759 }
RoboErik519c7742014-11-18 10:59:09 -08005760
5761 @Override
5762 public void adjustMasterVolumeForUid(int steps, int flags, String callingPackage,
5763 int uid) {
5764 adjustMasterVolume(steps, flags, callingPackage, uid);
5765 }
John Spurlock661f2cf2014-11-17 10:29:10 -05005766
5767 @Override
5768 public int getRingerModeInternal() {
5769 return AudioService.this.getRingerModeInternal();
5770 }
5771
5772 @Override
5773 public void setRingerModeInternal(int ringerMode, String caller) {
5774 AudioService.this.setRingerModeInternal(ringerMode, caller);
5775 }
John Spurlockcdb57ae2015-02-11 19:04:11 -05005776
5777 @Override
5778 public int getVolumeControllerUid() {
5779 return mControllerService.mUid;
5780 }
RoboErik0dac35a2014-08-12 15:48:49 -07005781 }
5782
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005783 //==========================================================================================
5784 // Audio policy management
5785 //==========================================================================================
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005786 public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
5787 boolean hasFocusListener) {
5788 if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
5789 + " with config:" + policyConfig);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005790 String regId = null;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005791 // error handling
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005792 boolean hasPermissionForPolicy =
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005793 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005794 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5795 if (!hasPermissionForPolicy) {
5796 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
5797 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005798 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005799 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005800
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005801 synchronized (mAudioPolicies) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005802 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005803 if (mAudioPolicies.containsKey(pcb.asBinder())) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005804 Slog.e(TAG, "Cannot re-register policy");
5805 return null;
5806 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005807 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
5808 pcb.asBinder().linkToDeath(app, 0/*flags*/);
5809 regId = app.getRegistrationId();
5810 mAudioPolicies.put(pcb.asBinder(), app);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005811 } catch (RemoteException e) {
5812 // audio policy owner has already died!
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005813 Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005814 " binder death", e);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005815 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005816 }
5817 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005818 return regId;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005819 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005820
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005821 public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
5822 if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005823 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005824 AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005825 if (app == null) {
5826 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
5827 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005828 return;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005829 } else {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005830 pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005831 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005832 app.release();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005833 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005834 // TODO implement clearing mix attribute matching info in native audio policy
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005835 }
5836
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005837 public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
5838 if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
5839 + " policy " + pcb.asBinder());
5840 // error handling
5841 boolean hasPermissionForPolicy =
5842 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
5843 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5844 if (!hasPermissionForPolicy) {
5845 Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
5846 + Binder.getCallingPid() + " / uid "
5847 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
5848 return AudioManager.ERROR;
5849 }
5850
5851 synchronized (mAudioPolicies) {
5852 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
5853 Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
5854 return AudioManager.ERROR;
5855 }
5856 final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
5857 if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5858 // is there already one policy managing ducking?
5859 for(AudioPolicyProxy policy : mAudioPolicies.values()) {
5860 if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5861 Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
5862 return AudioManager.ERROR;
5863 }
5864 }
5865 }
5866 app.mFocusDuckBehavior = duckingBehavior;
5867 mMediaFocusControl.setDuckingInExtPolicyAvailable(
5868 duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
5869 }
5870 return AudioManager.SUCCESS;
5871 }
5872
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005873 private void dumpAudioPolicies(PrintWriter pw) {
5874 pw.println("\nAudio policies:");
5875 synchronized (mAudioPolicies) {
5876 for(AudioPolicyProxy policy : mAudioPolicies.values()) {
5877 pw.println(policy.toLogFriendlyString());
5878 }
5879 }
5880 }
5881
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005882 //======================
5883 // Audio policy proxy
5884 //======================
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005885 /**
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005886 * This internal class inherits from AudioPolicyConfig, each instance contains all the
5887 * mixes of an AudioPolicy and their configurations.
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005888 */
5889 public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005890 private static final String TAG = "AudioPolicyProxy";
5891 AudioPolicyConfig mConfig;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005892 IAudioPolicyCallback mPolicyToken;
5893 boolean mHasFocusListener;
5894 /**
5895 * Audio focus ducking behavior for an audio policy.
5896 * This variable reflects the value that was successfully set in
5897 * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
5898 * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
5899 * is handling ducking for audio focus.
5900 */
5901 int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
5902
5903 AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
5904 boolean hasFocusListener) {
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005905 super(config);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005906 setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005907 mPolicyToken = token;
5908 mHasFocusListener = hasFocusListener;
5909 if (mHasFocusListener) {
5910 mMediaFocusControl.addFocusFollower(mPolicyToken);
5911 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08005912 connectMixes();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005913 }
5914
5915 public void binderDied() {
5916 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005917 Log.i(TAG, "audio policy " + mPolicyToken + " died");
5918 release();
5919 mAudioPolicies.remove(mPolicyToken.asBinder());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005920 }
5921 }
5922
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005923 String getRegistrationId() {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005924 return getRegistration();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005925 }
5926
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005927 void release() {
5928 if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5929 mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
5930 }
5931 if (mHasFocusListener) {
5932 mMediaFocusControl.removeFocusFollower(mPolicyToken);
5933 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08005934 AudioSystem.registerPolicyMixes(mMixes, false);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005935 }
5936
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08005937 void connectMixes() {
5938 AudioSystem.registerPolicyMixes(mMixes, true);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005939 }
5940 };
5941
5942 private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
5943 new HashMap<IBinder, AudioPolicyProxy>();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005944 private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
John Spurlockcdb57ae2015-02-11 19:04:11 -05005945
5946 private class ControllerService extends ContentObserver {
5947 private int mUid;
5948 private ComponentName mComponent;
5949
5950 public ControllerService() {
5951 super(null);
5952 }
5953
5954 @Override
5955 public String toString() {
5956 return String.format("{mUid=%d,mComponent=%s}", mUid, mComponent);
5957 }
5958
5959 public void init() {
5960 onChange(true);
5961 mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
5962 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT), false, this);
5963 }
5964
5965 @Override
5966 public void onChange(boolean selfChange) {
5967 mUid = 0;
5968 mComponent = null;
5969 final String setting = Settings.Secure.getString(mContentResolver,
5970 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
5971 if (setting == null) return;
5972 try {
5973 mComponent = ComponentName.unflattenFromString(setting);
5974 if (mComponent == null) return;
5975 mUid = mContext.getPackageManager()
5976 .getApplicationInfo(mComponent.getPackageName(), 0).uid;
5977 } catch (Exception e) {
5978 Log.w(TAG, "Error loading controller service", e);
5979 }
5980 if (DEBUG_VOL) Log.d(TAG, "Reloaded controller service: " + this);
5981 }
5982 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005983}