blob: 4ea62ecd0ae69ffa6e09e8ad2201b0e5dfc66507 [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);
1110
1111 Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
1112 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, stream);
1113 intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
1114 sendBroadcastToAll(intent);
1115 }
1116 }
1117 } else if ((direction == AudioManager.ADJUST_RAISE) &&
Eric Laurent42b041e2013-03-29 11:36:03 -07001118 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
RoboErik4197cb62015-01-21 15:45:32 -08001119 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -04001120 mVolumeController.postDisplaySafeVolumeWarning(flags);
RoboErik4197cb62015-01-21 15:45:32 -08001121 } else if (streamState.adjustIndex(direction * step, device) || streamState.mIsMuted) {
1122 // Post message to set system volume (it in turn will post a
1123 // message to persist).
1124 if (streamState.mIsMuted) {
1125 // Unmute the stream if it was previously muted
RoboErik5452e252015-02-06 15:33:53 -08001126 if (direction == AudioManager.ADJUST_RAISE) {
1127 // unmute immediately for volume up
1128 streamState.mute(false);
1129 } else if (direction == AudioManager.ADJUST_LOWER) {
1130 sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
1131 streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
1132 }
RoboErik4197cb62015-01-21 15:45:32 -08001133 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001134 sendMsg(mAudioHandler,
1135 MSG_SET_DEVICE_VOLUME,
1136 SENDMSG_QUEUE,
1137 device,
1138 0,
1139 streamState,
1140 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001141 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001142
RoboErik4197cb62015-01-21 15:45:32 -08001143 // Check if volume update should be sent to Hdmi system audio.
Jungshik Jang41d97462014-06-30 22:26:29 +09001144 int newIndex = mStreamStates[streamType].getIndex(device);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001145 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1146 setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
1147 }
Eric Laurent212532b2014-07-21 15:43:18 -07001148 if (mHdmiManager != null) {
1149 synchronized (mHdmiManager) {
Eric Laurent212532b2014-07-21 15:43:18 -07001150 // mHdmiCecSink true => mHdmiPlaybackClient != null
1151 if (mHdmiCecSink &&
1152 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1153 oldIndex != newIndex) {
1154 synchronized (mHdmiPlaybackClient) {
1155 int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
RoboErik4197cb62015-01-21 15:45:32 -08001156 KeyEvent.KEYCODE_VOLUME_UP;
Eric Laurent212532b2014-07-21 15:43:18 -07001157 mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1158 mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1159 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001160 }
1161 }
1162 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001163 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001164 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001165 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001166 }
1167
RoboErik5452e252015-02-06 15:33:53 -08001168 // Called after a delay when volume down is pressed while muted
1169 private void onUnmuteStream(int stream, int flags) {
1170 VolumeStreamState streamState = mStreamStates[stream];
1171 streamState.mute(false);
1172
1173 final int device = getDeviceForStream(stream);
1174 final int index = mStreamStates[stream].getIndex(device);
1175 sendVolumeUpdate(stream, index, index, flags);
1176 }
1177
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001178 private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
1179 if (mHdmiManager == null
1180 || mHdmiTvClient == null
1181 || oldVolume == newVolume
1182 || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
1183
1184 // Sets the audio volume of AVR when we are in system audio mode. The new volume info
1185 // is tranformed to HDMI-CEC commands and passed through CEC bus.
1186 synchronized (mHdmiManager) {
1187 if (!mHdmiSystemAudioSupported) return;
1188 synchronized (mHdmiTvClient) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001189 final long token = Binder.clearCallingIdentity();
1190 try {
1191 mHdmiTvClient.setSystemAudioVolume(
1192 (oldVolume + 5) / 10, (newVolume + 5) / 10, maxVolume);
1193 } finally {
1194 Binder.restoreCallingIdentity(token);
1195 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001196 }
1197 }
1198 }
1199
Dianne Hackborn961cae92013-03-20 14:59:43 -07001200 /** @see AudioManager#adjustMasterVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001201 public void adjustMasterVolume(int steps, int flags, String callingPackage) {
RoboErik519c7742014-11-18 10:59:09 -08001202 adjustMasterVolume(steps, flags, callingPackage, Binder.getCallingUid());
1203 }
1204
1205 public void adjustMasterVolume(int steps, int flags, String callingPackage, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001206 if (mUseFixedVolume) {
1207 return;
1208 }
RoboErik4197cb62015-01-21 15:45:32 -08001209 if (isMuteAdjust(steps)) {
1210 setMasterMuteInternal(steps, flags, callingPackage, uid);
1211 return;
1212 }
Lei Zhang6c798972012-03-02 11:40:12 -08001213 ensureValidSteps(steps);
Mike Lockwood97606472012-02-09 11:24:10 -08001214 int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1215 int delta = 0;
Lei Zhang6c798972012-03-02 11:40:12 -08001216 int numSteps = Math.abs(steps);
1217 int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
1218 for (int i = 0; i < numSteps; ++i) {
1219 delta = findVolumeDelta(direction, volume);
1220 volume += delta;
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001221 }
RoboErik24b082f2012-02-24 14:21:16 -08001222
Lei Zhang6c798972012-03-02 11:40:12 -08001223 //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
RoboErik519c7742014-11-18 10:59:09 -08001224 setMasterVolume(volume, flags, callingPackage, uid);
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001225 }
1226
Eric Laurentfde16d52012-12-03 14:42:39 -08001227 // StreamVolumeCommand contains the information needed to defer the process of
1228 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1229 class StreamVolumeCommand {
1230 public final int mStreamType;
1231 public final int mIndex;
1232 public final int mFlags;
1233 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001234
Eric Laurentfde16d52012-12-03 14:42:39 -08001235 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1236 mStreamType = streamType;
1237 mIndex = index;
1238 mFlags = flags;
1239 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001240 }
John Spurlock35134602014-07-24 18:10:48 -04001241
1242 @Override
1243 public String toString() {
1244 return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1245 .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1246 .append(mDevice).append('}').toString();
1247 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001248 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001249
Eric Laurentfde16d52012-12-03 14:42:39 -08001250 private void onSetStreamVolume(int streamType, int index, int flags, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001251 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
Eric Laurent3ef75492012-11-28 12:12:23 -08001252 // setting volume on master stream type also controls silent mode
1253 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
1254 (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
1255 int newRingerMode;
1256 if (index == 0) {
1257 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlock86005342014-05-23 11:58:00 -04001258 : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
1259 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001260 } else {
1261 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1262 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001263 setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/);
Eric Laurent3ef75492012-11-28 12:12:23 -08001264 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001265 }
1266
1267 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001268 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
RoboErik0dac35a2014-08-12 15:48:49 -07001269 setStreamVolume(streamType, index, flags, callingPackage, Binder.getCallingUid());
1270 }
1271
1272 private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
1273 int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001274 if (mUseFixedVolume) {
1275 return;
1276 }
1277
Eric Laurentfde16d52012-12-03 14:42:39 -08001278 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001279 int streamTypeAlias = mStreamVolumeAlias[streamType];
1280 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001281
1282 final int device = getDeviceForStream(streamType);
1283 int oldIndex;
1284
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001285 // skip a2dp absolute volume control request when the device
1286 // is not an a2dp device
1287 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1288 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1289 return;
1290 }
1291
RoboErik0dac35a2014-08-12 15:48:49 -07001292 if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
1293 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001294 return;
1295 }
1296
Eric Laurentfde16d52012-12-03 14:42:39 -08001297 synchronized (mSafeMediaVolumeState) {
1298 // reset any pending volume command
1299 mPendingVolumeCommand = null;
1300
Eric Laurent42b041e2013-03-29 11:36:03 -07001301 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001302
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001303 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001304
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001305 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1306 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1307 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1308 synchronized (mA2dpAvrcpLock) {
1309 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001310 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001311 }
John Du5a0cf7a2013-07-19 11:30:34 -07001312 }
1313 }
1314
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001315 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1316 setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
Jungshik Jang41d97462014-06-30 22:26:29 +09001317 }
1318
Eric Laurentfde16d52012-12-03 14:42:39 -08001319 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001320 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001321 ((device & mFixedVolumeDevices) != 0)) {
1322 flags |= AudioManager.FLAG_FIXED_VOLUME;
1323
1324 // volume is either 0 or max allowed for fixed volume devices
1325 if (index != 0) {
1326 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1327 (device & mSafeMediaVolumeDevices) != 0) {
1328 index = mSafeMediaVolumeIndex;
1329 } else {
1330 index = streamState.getMaxIndex();
1331 }
1332 }
1333 }
1334
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001335 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001336 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001337 mPendingVolumeCommand = new StreamVolumeCommand(
1338 streamType, index, flags, device);
1339 } else {
1340 onSetStreamVolume(streamType, index, flags, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07001341 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001342 }
1343 }
Eric Laurent25101b02011-02-02 09:33:30 -08001344 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001345 }
1346
Eric Laurent45c90ce2012-04-24 18:44:22 -07001347 /** @see AudioManager#forceVolumeControlStream(int) */
1348 public void forceVolumeControlStream(int streamType, IBinder cb) {
1349 synchronized(mForceControlStreamLock) {
1350 mVolumeControlStream = streamType;
1351 if (mVolumeControlStream == -1) {
1352 if (mForceControlStreamClient != null) {
1353 mForceControlStreamClient.release();
1354 mForceControlStreamClient = null;
1355 }
1356 } else {
1357 mForceControlStreamClient = new ForceControlStreamClient(cb);
1358 }
1359 }
1360 }
1361
1362 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1363 private IBinder mCb; // To be notified of client's death
1364
1365 ForceControlStreamClient(IBinder cb) {
1366 if (cb != null) {
1367 try {
1368 cb.linkToDeath(this, 0);
1369 } catch (RemoteException e) {
1370 // Client has died!
1371 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1372 cb = null;
1373 }
1374 }
1375 mCb = cb;
1376 }
1377
1378 public void binderDied() {
1379 synchronized(mForceControlStreamLock) {
1380 Log.w(TAG, "SCO client died");
1381 if (mForceControlStreamClient != this) {
1382 Log.w(TAG, "unregistered control stream client died");
1383 } else {
1384 mForceControlStreamClient = null;
1385 mVolumeControlStream = -1;
1386 }
1387 }
1388 }
1389
1390 public void release() {
1391 if (mCb != null) {
1392 mCb.unlinkToDeath(this, 0);
1393 mCb = null;
1394 }
1395 }
1396 }
1397
Lei Zhang6c798972012-03-02 11:40:12 -08001398 private int findVolumeDelta(int direction, int volume) {
1399 int delta = 0;
1400 if (direction == AudioManager.ADJUST_RAISE) {
1401 if (volume == MAX_MASTER_VOLUME) {
1402 return 0;
1403 }
1404 // This is the default value if we make it to the end
1405 delta = mMasterVolumeRamp[1];
1406 // If we're raising the volume move down the ramp array until we
1407 // find the volume we're above and use that groups delta.
1408 for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
1409 if (volume >= mMasterVolumeRamp[i - 1]) {
1410 delta = mMasterVolumeRamp[i];
1411 break;
1412 }
1413 }
1414 } else if (direction == AudioManager.ADJUST_LOWER){
1415 if (volume == 0) {
1416 return 0;
1417 }
1418 int length = mMasterVolumeRamp.length;
1419 // This is the default value if we make it to the end
1420 delta = -mMasterVolumeRamp[length - 1];
1421 // If we're lowering the volume move up the ramp array until we
1422 // find the volume we're below and use the group below it's delta
1423 for (int i = 2; i < length; i += 2) {
1424 if (volume <= mMasterVolumeRamp[i]) {
1425 delta = -mMasterVolumeRamp[i - 1];
1426 break;
1427 }
1428 }
1429 }
1430 return delta;
1431 }
1432
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001433 private void sendBroadcastToAll(Intent intent) {
Christopher Tate267603f2015-01-20 14:21:21 -08001434 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001435 final long ident = Binder.clearCallingIdentity();
1436 try {
1437 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1438 } finally {
1439 Binder.restoreCallingIdentity(ident);
1440 }
1441 }
1442
1443 private void sendStickyBroadcastToAll(Intent intent) {
1444 final long ident = Binder.clearCallingIdentity();
1445 try {
1446 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1447 } finally {
1448 Binder.restoreCallingIdentity(ident);
1449 }
1450 }
1451
Eric Laurent25101b02011-02-02 09:33:30 -08001452 // UI update and Broadcast Intent
1453 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
Eric Laurent212532b2014-07-21 15:43:18 -07001454 if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) {
Eric Laurent25101b02011-02-02 09:33:30 -08001455 streamType = AudioSystem.STREAM_NOTIFICATION;
1456 }
1457
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001458 if (streamType == AudioSystem.STREAM_MUSIC) {
1459 flags = updateFlagsForSystemAudio(flags);
Jungshik Jang1a6be6e2014-09-16 11:04:54 +09001460 }
John Spurlock3346a802014-05-20 16:25:37 -04001461 mVolumeController.postVolumeChanged(streamType, flags);
Eric Laurent25101b02011-02-02 09:33:30 -08001462
Eric Laurent4bbcc652012-09-24 14:26:30 -07001463 if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
1464 oldIndex = (oldIndex + 5) / 10;
1465 index = (index + 5) / 10;
1466 Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
1467 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
1468 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
1469 intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
1470 sendBroadcastToAll(intent);
1471 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472 }
1473
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001474 // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
1475 // receives volume notification from Audio Receiver.
1476 private int updateFlagsForSystemAudio(int flags) {
1477 if (mHdmiTvClient != null) {
1478 synchronized (mHdmiTvClient) {
1479 if (mHdmiSystemAudioSupported &&
1480 ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
1481 flags &= ~AudioManager.FLAG_SHOW_UI;
1482 }
1483 }
1484 }
1485 return flags;
1486 }
1487
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001488 // UI update and Broadcast Intent
1489 private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001490 mVolumeController.postMasterVolumeChanged(updateFlagsForSystemAudio(flags));
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001491
1492 Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
1493 intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
1494 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001495 sendBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001496 }
1497
1498 // UI update and Broadcast Intent
1499 private void sendMasterMuteUpdate(boolean muted, int flags) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001500 mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
Justin Koh57978ed2012-04-03 17:37:58 -07001501 broadcastMasterMuteStatus(muted);
1502 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001503
Justin Koh57978ed2012-04-03 17:37:58 -07001504 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001505 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1506 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001507 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1508 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001509 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001510 }
1511
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001512 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001513 * Sets the stream state's index, and posts a message to set system volume.
1514 * This will not call out to the UI. Assumes a valid stream type.
1515 *
1516 * @param streamType Type of the stream
1517 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001518 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001519 * @param force If true, set the volume even if the desired volume is same
1520 * as the current volume.
1521 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001522 private void setStreamVolumeInt(int streamType,
1523 int index,
1524 int device,
Eric Laurent42b041e2013-03-29 11:36:03 -07001525 boolean force) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001526 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07001527
Eric Laurent42b041e2013-03-29 11:36:03 -07001528 if (streamState.setIndex(index, device) || force) {
1529 // Post message to set system volume (it in turn will post a message
1530 // to persist).
1531 sendMsg(mAudioHandler,
1532 MSG_SET_DEVICE_VOLUME,
1533 SENDMSG_QUEUE,
1534 device,
1535 0,
1536 streamState,
1537 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001538 }
1539 }
1540
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001541 private void setSystemAudioMute(boolean state) {
1542 if (mHdmiManager == null || mHdmiTvClient == null) return;
1543 synchronized (mHdmiManager) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001544 if (!mHdmiSystemAudioSupported) return;
1545 synchronized (mHdmiTvClient) {
1546 final long token = Binder.clearCallingIdentity();
1547 try {
1548 mHdmiTvClient.setSystemAudioMute(state);
1549 } finally {
1550 Binder.restoreCallingIdentity(token);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001551 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001552 }
1553 }
1554 }
1555
Eric Laurent25101b02011-02-02 09:33:30 -08001556 /** get stream mute state. */
1557 public boolean isStreamMute(int streamType) {
RoboErik7c82ced2014-12-04 17:39:08 -08001558 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1559 streamType = getActiveStreamType(streamType);
1560 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001561 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08001562 return mStreamStates[streamType].mIsMuted;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001563 }
Eric Laurent25101b02011-02-02 09:33:30 -08001564 }
1565
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07001566 private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
1567 private IBinder mICallback; // To be notified of client's death
1568
1569 RmtSbmxFullVolDeathHandler(IBinder cb) {
1570 mICallback = cb;
1571 try {
1572 cb.linkToDeath(this, 0/*flags*/);
1573 } catch (RemoteException e) {
1574 Log.e(TAG, "can't link to death", e);
1575 }
1576 }
1577
1578 boolean isHandlerFor(IBinder cb) {
1579 return mICallback.equals(cb);
1580 }
1581
1582 void forget() {
1583 try {
1584 mICallback.unlinkToDeath(this, 0/*flags*/);
1585 } catch (NoSuchElementException e) {
1586 Log.e(TAG, "error unlinking to death", e);
1587 }
1588 }
1589
1590 public void binderDied() {
1591 Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
1592 forceRemoteSubmixFullVolume(false, mICallback);
1593 }
1594 }
1595
1596 /**
1597 * call must be synchronized on mRmtSbmxFullVolDeathHandlers
1598 * @return true if there is a registered death handler, false otherwise */
1599 private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1600 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1601 while (it.hasNext()) {
1602 final RmtSbmxFullVolDeathHandler handler = it.next();
1603 if (handler.isHandlerFor(cb)) {
1604 handler.forget();
1605 mRmtSbmxFullVolDeathHandlers.remove(handler);
1606 return true;
1607 }
1608 }
1609 return false;
1610 }
1611
1612 /** call synchronized on mRmtSbmxFullVolDeathHandlers */
1613 private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1614 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1615 while (it.hasNext()) {
1616 if (it.next().isHandlerFor(cb)) {
1617 return true;
1618 }
1619 }
1620 return false;
1621 }
1622
1623 private int mRmtSbmxFullVolRefCount = 0;
1624 private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
1625 new ArrayList<RmtSbmxFullVolDeathHandler>();
1626
1627 public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
1628 if (cb == null) {
1629 return;
1630 }
1631 if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
1632 android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
1633 Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
1634 return;
1635 }
1636 synchronized(mRmtSbmxFullVolDeathHandlers) {
1637 boolean applyRequired = false;
1638 if (startForcing) {
1639 if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
1640 mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
1641 if (mRmtSbmxFullVolRefCount == 0) {
1642 mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1643 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1644 applyRequired = true;
1645 }
1646 mRmtSbmxFullVolRefCount++;
1647 }
1648 } else {
1649 if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
1650 mRmtSbmxFullVolRefCount--;
1651 if (mRmtSbmxFullVolRefCount == 0) {
1652 mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1653 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1654 applyRequired = true;
1655 }
1656 }
1657 }
1658 if (applyRequired) {
1659 // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
1660 checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
1661 mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
1662 }
1663 }
1664 }
1665
RoboErik4197cb62015-01-21 15:45:32 -08001666 private void setMasterMuteInternal(int adjust, int flags, String callingPackage, int uid) {
RoboErik7c82ced2014-12-04 17:39:08 -08001667 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
1668 != AppOpsManager.MODE_ALLOWED) {
Julia Reynolds4a21b252014-06-04 11:11:43 -04001669 return;
1670 }
RoboErik4197cb62015-01-21 15:45:32 -08001671 boolean state;
1672 if (adjust == AudioManager.ADJUST_TOGGLE_MUTE) {
1673 state = !AudioSystem.getMasterMute();
1674 } else {
1675 state = adjust == AudioManager.ADJUST_MUTE;
1676 }
Jason Simmons1ce5b262012-02-02 13:00:17 -08001677 if (state != AudioSystem.getMasterMute()) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001678 setSystemAudioMute(state);
Jason Simmons1ce5b262012-02-02 13:00:17 -08001679 AudioSystem.setMasterMute(state);
Justin Koh57978ed2012-04-03 17:37:58 -07001680 // Post a persist master volume msg
Justin Koh75cf9e12012-04-04 15:27:37 -07001681 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001682 : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
Justin Koh0273af52012-04-04 18:29:50 -07001683 sendMasterMuteUpdate(state, flags);
RoboErik7c82ced2014-12-04 17:39:08 -08001684
1685 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1686 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, state);
1687 sendBroadcastToAll(intent);
Jason Simmons1ce5b262012-02-02 13:00:17 -08001688 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08001689 }
1690
1691 /** get master mute state. */
1692 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08001693 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001694 }
1695
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07001696 protected static int getMaxStreamVolume(int streamType) {
1697 return MAX_STREAM_VOLUME[streamType];
1698 }
1699
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001700 /** @see AudioManager#getStreamVolume(int) */
1701 public int getStreamVolume(int streamType) {
1702 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001703 int device = getDeviceForStream(streamType);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001704 synchronized (VolumeStreamState.class) {
1705 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001706
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001707 // by convention getStreamVolume() returns 0 when a stream is muted.
RoboErik4197cb62015-01-21 15:45:32 -08001708 if (mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001709 index = 0;
1710 }
1711 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
1712 (device & mFixedVolumeDevices) != 0) {
1713 index = mStreamStates[streamType].getMaxIndex();
1714 }
1715 return (index + 5) / 10;
Eric Laurent42b041e2013-03-29 11:36:03 -07001716 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 }
1718
RoboErik519c7742014-11-18 10:59:09 -08001719 @Override
Mike Lockwood47676902011-11-08 10:31:21 -08001720 public int getMasterVolume() {
Mike Lockwoodce952c82011-11-14 10:47:42 -08001721 if (isMasterMute()) return 0;
1722 return getLastAudibleMasterVolume();
Mike Lockwood8dc1dab2011-10-27 09:52:41 -04001723 }
1724
RoboErik519c7742014-11-18 10:59:09 -08001725 @Override
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001726 public void setMasterVolume(int volume, int flags, String callingPackage) {
RoboErik519c7742014-11-18 10:59:09 -08001727 setMasterVolume(volume, flags, callingPackage, Binder.getCallingUid());
1728 }
1729
1730 public void setMasterVolume(int volume, int flags, String callingPackage, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001731 if (mUseFixedVolume) {
1732 return;
1733 }
1734
RoboErik519c7742014-11-18 10:59:09 -08001735 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
1736 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001737 return;
1738 }
1739
Mike Lockwood97606472012-02-09 11:24:10 -08001740 if (volume < 0) {
1741 volume = 0;
1742 } else if (volume > MAX_MASTER_VOLUME) {
1743 volume = MAX_MASTER_VOLUME;
1744 }
Mike Lockwood5c55a052011-12-15 17:21:44 -05001745 doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
1746 }
1747
1748 private void doSetMasterVolume(float volume, int flags) {
1749 // don't allow changing master volume when muted
1750 if (!AudioSystem.getMasterMute()) {
1751 int oldVolume = getMasterVolume();
1752 AudioSystem.setMasterVolume(volume);
1753
1754 int newVolume = getMasterVolume();
1755 if (newVolume != oldVolume) {
1756 // Post a persist master volume msg
1757 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
1758 Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001759 setSystemAudioVolume(oldVolume, newVolume, getMasterMaxVolume(), flags);
Mike Lockwood5c55a052011-12-15 17:21:44 -05001760 }
Justin Koh3caba512012-04-02 15:32:18 -07001761 // Send the volume update regardless whether there was a change.
1762 sendMasterVolumeUpdate(flags, oldVolume, newVolume);
Mike Lockwood5c55a052011-12-15 17:21:44 -05001763 }
Mike Lockwood8dc1dab2011-10-27 09:52:41 -04001764 }
1765
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001766 /** @see AudioManager#getStreamMaxVolume(int) */
1767 public int getStreamMaxVolume(int streamType) {
1768 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07001769 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001770 }
1771
Mike Lockwood47676902011-11-08 10:31:21 -08001772 public int getMasterMaxVolume() {
1773 return MAX_MASTER_VOLUME;
1774 }
Eric Laurent25101b02011-02-02 09:33:30 -08001775
1776 /** Get last audible volume before stream was muted. */
1777 public int getLastAudibleStreamVolume(int streamType) {
1778 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001779 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001780 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08001781 }
1782
Mike Lockwoodce952c82011-11-14 10:47:42 -08001783 /** Get last audible master volume before it was muted. */
1784 public int getLastAudibleMasterVolume() {
1785 return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1786 }
1787
Dianne Hackborn961cae92013-03-20 14:59:43 -07001788 /** @see AudioManager#getMasterStreamType() */
Eric Laurent6d517662012-04-23 18:42:39 -07001789 public int getMasterStreamType() {
John Spurlock4f0f1202014-08-05 13:28:33 -04001790 return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
Eric Laurent6d517662012-04-23 18:42:39 -07001791 }
1792
Emily Bernier22c921a2014-05-28 11:01:32 -04001793 /** @see AudioManager#setMicrophoneMute(boolean) */
1794 public void setMicrophoneMute(boolean on, String callingPackage) {
1795 if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(),
1796 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1797 return;
1798 }
Jean-Michel Trivi4a4fea02014-08-29 18:14:09 -07001799 if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
1800 return;
1801 }
Emily Bernier22c921a2014-05-28 11:01:32 -04001802
1803 AudioSystem.muteMicrophone(on);
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001804 // Post a persist microphone msg.
1805 sendMsg(mAudioHandler, MSG_PERSIST_MICROPHONE_MUTE, SENDMSG_REPLACE, on ? 1
1806 : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
Emily Bernier22c921a2014-05-28 11:01:32 -04001807 }
1808
John Spurlock661f2cf2014-11-17 10:29:10 -05001809 @Override
1810 public int getRingerModeExternal() {
1811 synchronized(mSettingsLock) {
1812 return mRingerModeExternal;
1813 }
1814 }
1815
1816 @Override
1817 public int getRingerModeInternal() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001818 synchronized(mSettingsLock) {
1819 return mRingerMode;
1820 }
1821 }
1822
1823 private void ensureValidRingerMode(int ringerMode) {
John Spurlock97559372014-10-24 16:27:36 -04001824 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001825 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1826 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001827 }
1828
John Spurlock97559372014-10-24 16:27:36 -04001829 /** @see AudioManager#isValidRingerMode(int) */
1830 public boolean isValidRingerMode(int ringerMode) {
1831 return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
1832 }
1833
John Spurlock661f2cf2014-11-17 10:29:10 -05001834 public void setRingerModeExternal(int ringerMode, String caller) {
John Spurlockaf88a192014-12-23 16:14:44 -05001835 setRingerMode(ringerMode, caller, true /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05001836 }
1837
1838 public void setRingerModeInternal(int ringerMode, String caller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05001839 enforceVolumeController("setRingerModeInternal");
John Spurlockaf88a192014-12-23 16:14:44 -05001840 setRingerMode(ringerMode, caller, false /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05001841 }
1842
1843 private void setRingerMode(int ringerMode, String caller, boolean external) {
Eric Laurent212532b2014-07-21 15:43:18 -07001844 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001845 return;
1846 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001847 if (caller == null || caller.length() == 0) {
1848 throw new IllegalArgumentException("Bad caller: " + caller);
1849 }
John Spurlock97559372014-10-24 16:27:36 -04001850 ensureValidRingerMode(ringerMode);
Eric Laurent24482012012-05-10 09:41:17 -07001851 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1852 ringerMode = AudioManager.RINGER_MODE_SILENT;
1853 }
John Spurlockaf88a192014-12-23 16:14:44 -05001854 final long identity = Binder.clearCallingIdentity();
1855 try {
1856 synchronized (mSettingsLock) {
1857 final int ringerModeInternal = getRingerModeInternal();
1858 final int ringerModeExternal = getRingerModeExternal();
1859 if (external) {
1860 setRingerModeExt(ringerMode);
1861 if (mRingerModeDelegate != null) {
1862 ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
1863 ringerMode, caller, ringerModeInternal);
1864 }
1865 if (ringerMode != ringerModeInternal) {
1866 setRingerModeInt(ringerMode, true /*persist*/);
1867 }
1868 } else /*internal*/ {
1869 if (ringerMode != ringerModeInternal) {
1870 setRingerModeInt(ringerMode, true /*persist*/);
1871 }
1872 if (mRingerModeDelegate != null) {
1873 ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
1874 ringerMode, caller, ringerModeExternal);
1875 }
1876 setRingerModeExt(ringerMode);
John Spurlock57627792014-12-11 11:29:54 -05001877 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001878 }
John Spurlockaf88a192014-12-23 16:14:44 -05001879 } finally {
1880 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001881 }
1882 }
1883
John Spurlock661f2cf2014-11-17 10:29:10 -05001884 private void setRingerModeExt(int ringerMode) {
1885 synchronized(mSettingsLock) {
1886 if (ringerMode == mRingerModeExternal) return;
1887 mRingerModeExternal = ringerMode;
John Spurlocke5b42d92014-10-15 12:03:48 -04001888 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001889 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05001890 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
John Spurlocke5b42d92014-10-15 12:03:48 -04001891 }
1892
Eric Laurent4050c932009-07-08 02:52:14 -07001893 private void setRingerModeInt(int ringerMode, boolean persist) {
John Spurlockbcc10872014-11-28 15:29:21 -05001894 final boolean change;
Glenn Kastenba195eb2011-12-13 09:30:40 -08001895 synchronized(mSettingsLock) {
John Spurlockbcc10872014-11-28 15:29:21 -05001896 change = mRingerMode != ringerMode;
Glenn Kastenba195eb2011-12-13 09:30:40 -08001897 mRingerMode = ringerMode;
1898 }
Jason Parekhb1096152009-03-24 17:48:25 -07001899
Eric Laurent5b4e6542010-03-19 20:02:21 -07001900 // Mute stream if not previously muted by ringer mode and ringer mode
1901 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
1902 // Unmute stream if previously muted by ringer mode and ringer mode
1903 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07001904 int numStreamTypes = AudioSystem.getNumStreamTypes();
John Spurlock661f2cf2014-11-17 10:29:10 -05001905 final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE
1906 || ringerMode == AudioManager.RINGER_MODE_SILENT;
Eric Laurent5b4e6542010-03-19 20:02:21 -07001907 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001908 final boolean isMuted = isStreamMutedByRingerMode(streamType);
1909 final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
1910 if (isMuted == shouldMute) continue;
1911 if (!shouldMute) {
1912 // unmute
1913 // ring and notifications volume should never be 0 when not silenced
1914 // on voice capable devices or devices that support vibration
1915 if ((isPlatformVoice() || mHasVibrator) &&
1916 mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
1917 synchronized (VolumeStreamState.class) {
1918 Set set = mStreamStates[streamType].mIndex.entrySet();
1919 Iterator i = set.iterator();
1920 while (i.hasNext()) {
1921 Map.Entry entry = (Map.Entry)i.next();
1922 if ((Integer)entry.getValue() == 0) {
1923 entry.setValue(10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001924 }
1925 }
Eric Laurent9e0d25f2015-02-12 17:28:53 -08001926 // Persist volume for stream ring when it is changed here
1927 final int device = getDeviceForStream(streamType);
1928 sendMsg(mAudioHandler,
1929 MSG_PERSIST_VOLUME,
1930 SENDMSG_QUEUE,
1931 device,
1932 0,
1933 mStreamStates[streamType],
1934 PERSIST_DELAY);
Eric Laurentb024c302011-10-14 17:19:27 -07001935 }
Eric Laurent9bcf4012009-06-12 06:09:28 -07001936 }
RoboErik4197cb62015-01-21 15:45:32 -08001937 mStreamStates[streamType].mute(false);
John Spurlock661f2cf2014-11-17 10:29:10 -05001938 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent5b4e6542010-03-19 20:02:21 -07001939 } else {
John Spurlock661f2cf2014-11-17 10:29:10 -05001940 // mute
RoboErik4197cb62015-01-21 15:45:32 -08001941 mStreamStates[streamType].mute(true);
John Spurlock661f2cf2014-11-17 10:29:10 -05001942 mRingerModeMutedStreams |= (1 << streamType);
Jason Parekhb1096152009-03-24 17:48:25 -07001943 }
1944 }
Eric Laurenta553c252009-07-17 12:17:14 -07001945
Jason Parekhb1096152009-03-24 17:48:25 -07001946 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07001947 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08001948 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07001949 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
1950 }
John Spurlockbcc10872014-11-28 15:29:21 -05001951 if (change) {
1952 // Send sticky broadcast
1953 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
1954 }
Jason Parekhb1096152009-03-24 17:48:25 -07001955 }
1956
Mike Lockwood90631542012-01-06 11:20:37 -05001957 private void restoreMasterVolume() {
Eric Laurent83a017b2013-03-19 18:15:31 -07001958 if (mUseFixedVolume) {
1959 AudioSystem.setMasterVolume(1.0f);
1960 return;
1961 }
Mike Lockwood90631542012-01-06 11:20:37 -05001962 if (mUseMasterVolume) {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07001963 float volume = Settings.System.getFloatForUser(mContentResolver,
1964 Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
Mike Lockwood90631542012-01-06 11:20:37 -05001965 if (volume >= 0.0f) {
1966 AudioSystem.setMasterVolume(volume);
1967 }
1968 }
1969 }
1970
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001971 /** @see AudioManager#shouldVibrate(int) */
1972 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001973 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001974
1975 switch (getVibrateSetting(vibrateType)) {
1976
1977 case AudioManager.VIBRATE_SETTING_ON:
John Spurlock57627792014-12-11 11:29:54 -05001978 return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001979
1980 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
John Spurlock57627792014-12-11 11:29:54 -05001981 return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001982
1983 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04001984 // return false, even for incoming calls
1985 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001986
1987 default:
1988 return false;
1989 }
1990 }
1991
1992 /** @see AudioManager#getVibrateSetting(int) */
1993 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001994 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001995 return (mVibrateSetting >> (vibrateType * 2)) & 3;
1996 }
1997
1998 /** @see AudioManager#setVibrateSetting(int, int) */
1999 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
2000
Eric Laurentbffc3d12012-05-07 17:43:49 -07002001 if (!mHasVibrator) return;
2002
John Spurlock61560172015-02-06 19:46:04 -05002003 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
2004 vibrateSetting);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002005
2006 // Broadcast change
2007 broadcastVibrateSetting(vibrateType);
2008
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002009 }
2010
Eric Laurent9272b4b2010-01-23 17:12:59 -08002011 private class SetModeDeathHandler implements IBinder.DeathRecipient {
2012 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002013 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002014 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
2015
Eric Laurent9f103de2011-09-08 15:04:23 -07002016 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08002017 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07002018 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002019 }
2020
2021 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07002022 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08002023 synchronized(mSetModeDeathHandlers) {
2024 Log.w(TAG, "setMode() client died");
2025 int index = mSetModeDeathHandlers.indexOf(this);
2026 if (index < 0) {
2027 Log.w(TAG, "unregistered setMode() client died");
2028 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07002029 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
Eric Laurent9272b4b2010-01-23 17:12:59 -08002030 }
2031 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002032 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2033 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002034 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07002035 final long ident = Binder.clearCallingIdentity();
2036 disconnectBluetoothSco(newModeOwnerPid);
2037 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07002038 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08002039 }
2040
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002041 public int getPid() {
2042 return mPid;
2043 }
2044
Eric Laurent9272b4b2010-01-23 17:12:59 -08002045 public void setMode(int mode) {
2046 mMode = mode;
2047 }
2048
2049 public int getMode() {
2050 return mMode;
2051 }
2052
2053 public IBinder getBinder() {
2054 return mCb;
2055 }
2056 }
2057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002058 /** @see AudioManager#setMode(int) */
Eric Laurent9272b4b2010-01-23 17:12:59 -08002059 public void setMode(int mode, IBinder cb) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002060 if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ")"); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002061 if (!checkAudioSettingsPermission("setMode()")) {
2062 return;
2063 }
Eric Laurenta553c252009-07-17 12:17:14 -07002064
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07002065 if ( (mode == AudioSystem.MODE_IN_CALL) &&
2066 (mContext.checkCallingOrSelfPermission(
2067 android.Manifest.permission.MODIFY_PHONE_STATE)
2068 != PackageManager.PERMISSION_GRANTED)) {
2069 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
2070 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
2071 return;
2072 }
2073
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08002074 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07002075 return;
2076 }
2077
Eric Laurentd7454be2011-09-14 08:45:58 -07002078 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002079 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07002080 if (mode == AudioSystem.MODE_CURRENT) {
2081 mode = mMode;
2082 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002083 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
Eric Laurent9f103de2011-09-08 15:04:23 -07002084 }
2085 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
2086 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07002087 if (newModeOwnerPid != 0) {
2088 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07002089 }
2090 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002091
Eric Laurent9f103de2011-09-08 15:04:23 -07002092 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07002093 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07002094 // any mode other than NORMAL.
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07002095 private int setModeInt(int mode, IBinder cb, int pid) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002096 if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ")"); }
Eric Laurentd7454be2011-09-14 08:45:58 -07002097 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07002098 if (cb == null) {
2099 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07002100 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07002101 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08002102
Eric Laurent9f103de2011-09-08 15:04:23 -07002103 SetModeDeathHandler hdlr = null;
2104 Iterator iter = mSetModeDeathHandlers.iterator();
2105 while (iter.hasNext()) {
2106 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
2107 if (h.getPid() == pid) {
2108 hdlr = h;
2109 // Remove from client list so that it is re-inserted at top of list
2110 iter.remove();
2111 hdlr.getBinder().unlinkToDeath(hdlr, 0);
2112 break;
2113 }
2114 }
2115 int status = AudioSystem.AUDIO_STATUS_OK;
2116 do {
2117 if (mode == AudioSystem.MODE_NORMAL) {
2118 // get new mode from client at top the list if any
2119 if (!mSetModeDeathHandlers.isEmpty()) {
2120 hdlr = mSetModeDeathHandlers.get(0);
2121 cb = hdlr.getBinder();
2122 mode = hdlr.getMode();
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002123 if (DEBUG_MODE) {
2124 Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
2125 + hdlr.mPid);
2126 }
Eric Laurentb9c9d262009-05-06 08:13:20 -07002127 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002128 } else {
2129 if (hdlr == null) {
2130 hdlr = new SetModeDeathHandler(cb, pid);
2131 }
2132 // Register for client death notification
2133 try {
2134 cb.linkToDeath(hdlr, 0);
2135 } catch (RemoteException e) {
2136 // Client has died!
2137 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
2138 }
2139
2140 // Last client to call setMode() is always at top of client list
2141 // as required by SetModeDeathHandler.binderDied()
2142 mSetModeDeathHandlers.add(0, hdlr);
2143 hdlr.setMode(mode);
2144 }
2145
2146 if (mode != mMode) {
2147 status = AudioSystem.setPhoneState(mode);
2148 if (status == AudioSystem.AUDIO_STATUS_OK) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002149 if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002150 mMode = mode;
2151 } else {
2152 if (hdlr != null) {
2153 mSetModeDeathHandlers.remove(hdlr);
2154 cb.unlinkToDeath(hdlr, 0);
2155 }
2156 // force reading new top of mSetModeDeathHandlers stack
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002157 if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002158 mode = AudioSystem.MODE_NORMAL;
2159 }
2160 } else {
2161 status = AudioSystem.AUDIO_STATUS_OK;
2162 }
2163 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
2164
2165 if (status == AudioSystem.AUDIO_STATUS_OK) {
2166 if (mode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002167 if (mSetModeDeathHandlers.isEmpty()) {
2168 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
2169 } else {
2170 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2171 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002172 }
2173 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002174 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07002175 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
2176 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
Eric Laurent6d517662012-04-23 18:42:39 -07002177
2178 updateStreamVolumeAlias(true /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002179 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002180 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002181 }
2182
2183 /** @see AudioManager#getMode() */
2184 public int getMode() {
2185 return mMode;
2186 }
2187
Eric Laurente78fced2013-03-15 16:03:47 -07002188 //==========================================================================================
2189 // Sound Effects
2190 //==========================================================================================
2191
2192 private static final String TAG_AUDIO_ASSETS = "audio_assets";
2193 private static final String ATTR_VERSION = "version";
2194 private static final String TAG_GROUP = "group";
2195 private static final String ATTR_GROUP_NAME = "name";
2196 private static final String TAG_ASSET = "asset";
2197 private static final String ATTR_ASSET_ID = "id";
2198 private static final String ATTR_ASSET_FILE = "file";
2199
2200 private static final String ASSET_FILE_VERSION = "1.0";
2201 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
2202
Glenn Kasten167d1a22013-07-23 16:24:41 -07002203 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002204
2205 class LoadSoundEffectReply {
2206 public int mStatus = 1;
2207 };
2208
Eric Laurente78fced2013-03-15 16:03:47 -07002209 private void loadTouchSoundAssetDefaults() {
2210 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
2211 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
2212 SOUND_EFFECT_FILES_MAP[i][0] = 0;
2213 SOUND_EFFECT_FILES_MAP[i][1] = -1;
2214 }
2215 }
2216
2217 private void loadTouchSoundAssets() {
2218 XmlResourceParser parser = null;
2219
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002220 // only load assets once.
2221 if (!SOUND_EFFECT_FILES.isEmpty()) {
2222 return;
2223 }
2224
Eric Laurente78fced2013-03-15 16:03:47 -07002225 loadTouchSoundAssetDefaults();
2226
2227 try {
2228 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
2229
2230 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
2231 String version = parser.getAttributeValue(null, ATTR_VERSION);
2232 boolean inTouchSoundsGroup = false;
2233
2234 if (ASSET_FILE_VERSION.equals(version)) {
2235 while (true) {
2236 XmlUtils.nextElement(parser);
2237 String element = parser.getName();
2238 if (element == null) {
2239 break;
2240 }
2241 if (element.equals(TAG_GROUP)) {
2242 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
2243 if (GROUP_TOUCH_SOUNDS.equals(name)) {
2244 inTouchSoundsGroup = true;
2245 break;
2246 }
2247 }
2248 }
2249 while (inTouchSoundsGroup) {
2250 XmlUtils.nextElement(parser);
2251 String element = parser.getName();
2252 if (element == null) {
2253 break;
2254 }
2255 if (element.equals(TAG_ASSET)) {
2256 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
2257 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
2258 int fx;
2259
2260 try {
2261 Field field = AudioManager.class.getField(id);
2262 fx = field.getInt(null);
2263 } catch (Exception e) {
2264 Log.w(TAG, "Invalid touch sound ID: "+id);
2265 continue;
2266 }
2267
2268 int i = SOUND_EFFECT_FILES.indexOf(file);
2269 if (i == -1) {
2270 i = SOUND_EFFECT_FILES.size();
2271 SOUND_EFFECT_FILES.add(file);
2272 }
2273 SOUND_EFFECT_FILES_MAP[fx][0] = i;
2274 } else {
2275 break;
2276 }
2277 }
2278 }
2279 } catch (Resources.NotFoundException e) {
2280 Log.w(TAG, "audio assets file not found", e);
2281 } catch (XmlPullParserException e) {
2282 Log.w(TAG, "XML parser exception reading touch sound assets", e);
2283 } catch (IOException e) {
2284 Log.w(TAG, "I/O exception reading touch sound assets", e);
2285 } finally {
2286 if (parser != null) {
2287 parser.close();
2288 }
2289 }
2290 }
2291
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002292 /** @see AudioManager#playSoundEffect(int) */
2293 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002294 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002295 }
2296
2297 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002298 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07002299 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
2300 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
2301 return;
2302 }
2303
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002304 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002305 effectType, (int) (volume * 1000), null, 0);
2306 }
2307
2308 /**
2309 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08002310 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002311 */
2312 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002313 int attempts = 3;
2314 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08002315
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002316 synchronized (reply) {
2317 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
2318 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08002319 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07002320 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002321 } catch (InterruptedException e) {
2322 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08002323 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002324 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002325 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002326 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002327 }
2328
2329 /**
2330 * Unloads samples from the sound pool.
2331 * This method can be called to free some memory when
2332 * sound effects are disabled.
2333 */
2334 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002335 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002336 }
2337
Eric Laurenta60e2122010-12-28 16:49:07 -08002338 class SoundPoolListenerThread extends Thread {
2339 public SoundPoolListenerThread() {
2340 super("SoundPoolListenerThread");
2341 }
2342
2343 @Override
2344 public void run() {
2345
2346 Looper.prepare();
2347 mSoundPoolLooper = Looper.myLooper();
2348
2349 synchronized (mSoundEffectsLock) {
2350 if (mSoundPool != null) {
2351 mSoundPoolCallBack = new SoundPoolCallback();
2352 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2353 }
2354 mSoundEffectsLock.notify();
2355 }
2356 Looper.loop();
2357 }
2358 }
2359
2360 private final class SoundPoolCallback implements
2361 android.media.SoundPool.OnLoadCompleteListener {
2362
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002363 int mStatus = 1; // 1 means neither error nor last sample loaded yet
2364 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08002365
2366 public int status() {
2367 return mStatus;
2368 }
2369
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002370 public void setSamples(int[] samples) {
2371 for (int i = 0; i < samples.length; i++) {
2372 // do not wait ack for samples rejected upfront by SoundPool
2373 if (samples[i] > 0) {
2374 mSamples.add(samples[i]);
2375 }
2376 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002377 }
2378
2379 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2380 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002381 int i = mSamples.indexOf(sampleId);
2382 if (i >= 0) {
2383 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08002384 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002385 if ((status != 0) || mSamples. isEmpty()) {
2386 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08002387 mSoundEffectsLock.notify();
2388 }
2389 }
2390 }
2391 }
2392
Eric Laurent4050c932009-07-08 02:52:14 -07002393 /** @see AudioManager#reloadAudioSettings() */
2394 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002395 readAudioSettings(false /*userSwitch*/);
2396 }
2397
2398 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07002399 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2400 readPersistedSettings();
2401
2402 // restore volume settings
2403 int numStreamTypes = AudioSystem.getNumStreamTypes();
2404 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2405 VolumeStreamState streamState = mStreamStates[streamType];
2406
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002407 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2408 continue;
2409 }
2410
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002411 streamState.readSettings();
2412 synchronized (VolumeStreamState.class) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002413 // unmute stream that was muted but is not affect by mute anymore
RoboErik4197cb62015-01-21 15:45:32 -08002414 if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07002415 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
RoboErik4197cb62015-01-21 15:45:32 -08002416 streamState.mIsMuted = false;
Eric Laurent4050c932009-07-08 02:52:14 -07002417 }
Eric Laurent4050c932009-07-08 02:52:14 -07002418 }
2419 }
2420
Eric Laurent33902db2012-10-07 16:15:07 -07002421 // apply new ringer mode before checking volume for alias streams so that streams
2422 // muted by ringer mode have the correct volume
John Spurlock661f2cf2014-11-17 10:29:10 -05002423 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent33902db2012-10-07 16:15:07 -07002424
Eric Laurent212532b2014-07-21 15:43:18 -07002425 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07002426 checkAllAliasStreamVolumes();
2427
Eric Laurentd640bd32012-09-28 18:01:48 -07002428 synchronized (mSafeMediaVolumeState) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002429 mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2430 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2431 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
Eric Laurentd640bd32012-09-28 18:01:48 -07002432 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07002433 enforceSafeMediaVolume();
2434 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07002435 }
Eric Laurent4050c932009-07-08 02:52:14 -07002436 }
2437
Dianne Hackborn961cae92013-03-20 14:59:43 -07002438 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002439 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002440 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2441 return;
2442 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002443
2444 if (on) {
2445 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2446 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2447 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
2448 }
2449 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2450 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2451 mForcedUseForComm = AudioSystem.FORCE_NONE;
2452 }
Eric Laurentfa640152011-03-12 15:59:51 -08002453
Eric Laurentafbb0472011-12-15 09:04:23 -08002454 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002455 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002456 }
2457
2458 /** @see AudioManager#isSpeakerphoneOn() */
2459 public boolean isSpeakerphoneOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002460 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002461 }
2462
Dianne Hackborn961cae92013-03-20 14:59:43 -07002463 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002464 public void setBluetoothScoOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002465 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2466 return;
2467 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002468
2469 if (on) {
2470 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2471 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2472 mForcedUseForComm = AudioSystem.FORCE_NONE;
2473 }
Eric Laurentfa640152011-03-12 15:59:51 -08002474
Eric Laurentafbb0472011-12-15 09:04:23 -08002475 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002476 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08002477 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002478 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002479 }
2480
2481 /** @see AudioManager#isBluetoothScoOn() */
2482 public boolean isBluetoothScoOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002483 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002484 }
2485
Dianne Hackborn961cae92013-03-20 14:59:43 -07002486 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07002487 public void setBluetoothA2dpOn(boolean on) {
Eric Laurentc390bed2012-07-03 12:24:05 -07002488 synchronized (mBluetoothA2dpEnabledLock) {
2489 mBluetoothA2dpEnabled = on;
2490 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2491 AudioSystem.FOR_MEDIA,
2492 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2493 null, 0);
2494 }
Eric Laurent78472112012-05-21 08:57:21 -07002495 }
2496
2497 /** @see AudioManager#isBluetoothA2dpOn() */
2498 public boolean isBluetoothA2dpOn() {
2499 synchronized (mBluetoothA2dpEnabledLock) {
2500 return mBluetoothA2dpEnabled;
2501 }
2502 }
2503
Eric Laurent3def1ee2010-03-17 23:26:26 -07002504 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07002505 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
2506 int scoAudioMode =
2507 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
Liejun Taof4e51d82014-07-16 11:18:29 -07002508 SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
Eric Laurent83900752014-05-15 15:14:22 -07002509 startBluetoothScoInt(cb, scoAudioMode);
2510 }
2511
2512 /** @see AudioManager#startBluetoothScoVirtualCall() */
2513 public void startBluetoothScoVirtualCall(IBinder cb) {
2514 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
2515 }
2516
2517 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07002518 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002519 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002520 return;
2521 }
Eric Laurent854938a2011-02-22 12:05:20 -08002522 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002523 // The calling identity must be cleared before calling ScoClient.incCount().
2524 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2525 // and this must be done on behalf of system server to make sure permissions are granted.
2526 // The caller identity must be cleared after getScoClient() because it is needed if a new
2527 // client is created.
2528 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07002529 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08002530 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002531 }
2532
2533 /** @see AudioManager#stopBluetoothSco() */
2534 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07002535 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002536 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002537 return;
2538 }
Eric Laurent854938a2011-02-22 12:05:20 -08002539 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002540 // The calling identity must be cleared before calling ScoClient.decCount().
2541 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2542 // and this must be done on behalf of system server to make sure permissions are granted.
2543 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08002544 if (client != null) {
2545 client.decCount();
2546 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08002547 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002548 }
2549
Eric Laurent78472112012-05-21 08:57:21 -07002550
Eric Laurent3def1ee2010-03-17 23:26:26 -07002551 private class ScoClient implements IBinder.DeathRecipient {
2552 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002553 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002554 private int mStartcount; // number of SCO connections started by this client
2555
2556 ScoClient(IBinder cb) {
2557 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002558 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002559 mStartcount = 0;
2560 }
2561
2562 public void binderDied() {
2563 synchronized(mScoClients) {
2564 Log.w(TAG, "SCO client died");
2565 int index = mScoClients.indexOf(this);
2566 if (index < 0) {
2567 Log.w(TAG, "unregistered SCO client died");
2568 } else {
2569 clearCount(true);
2570 mScoClients.remove(this);
2571 }
2572 }
2573 }
2574
Eric Laurent83900752014-05-15 15:14:22 -07002575 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002576 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07002577 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002578 if (mStartcount == 0) {
2579 try {
2580 mCb.linkToDeath(this, 0);
2581 } catch (RemoteException e) {
2582 // client has already died!
2583 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
2584 }
2585 }
2586 mStartcount++;
2587 }
2588 }
2589
2590 public void decCount() {
2591 synchronized(mScoClients) {
2592 if (mStartcount == 0) {
2593 Log.w(TAG, "ScoClient.decCount() already 0");
2594 } else {
2595 mStartcount--;
2596 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002597 try {
2598 mCb.unlinkToDeath(this, 0);
2599 } catch (NoSuchElementException e) {
2600 Log.w(TAG, "decCount() going to 0 but not registered to binder");
2601 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002602 }
Eric Laurentc18c9132013-04-12 17:24:56 -07002603 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002604 }
2605 }
2606 }
2607
2608 public void clearCount(boolean stopSco) {
2609 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002610 if (mStartcount != 0) {
2611 try {
2612 mCb.unlinkToDeath(this, 0);
2613 } catch (NoSuchElementException e) {
2614 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2615 }
2616 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002617 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002618 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002619 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002620 }
2621 }
2622 }
2623
2624 public int getCount() {
2625 return mStartcount;
2626 }
2627
2628 public IBinder getBinder() {
2629 return mCb;
2630 }
2631
Eric Laurentd7454be2011-09-14 08:45:58 -07002632 public int getPid() {
2633 return mCreatorPid;
2634 }
2635
Eric Laurent3def1ee2010-03-17 23:26:26 -07002636 public int totalCount() {
2637 synchronized(mScoClients) {
2638 int count = 0;
2639 int size = mScoClients.size();
2640 for (int i = 0; i < size; i++) {
2641 count += mScoClients.get(i).getCount();
2642 }
2643 return count;
2644 }
2645 }
2646
Eric Laurent83900752014-05-15 15:14:22 -07002647 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08002648 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07002649 if (totalCount() == 0) {
2650 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2651 // Make sure that the state transitions to CONNECTING even if we cannot initiate
2652 // the connection.
2653 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2654 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002655 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07002656 synchronized(mSetModeDeathHandlers) {
2657 if ((mSetModeDeathHandlers.isEmpty() ||
2658 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2659 (mScoAudioState == SCO_STATE_INACTIVE ||
2660 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2661 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07002662 mScoAudioMode = scoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -07002663 if (scoAudioMode == SCO_MODE_UNDEFINED) {
Andre Eisenbach570cc532014-10-28 17:03:18 -07002664 if (mBluetoothHeadsetDevice != null) {
2665 mScoAudioMode = new Integer(Settings.Global.getInt(
2666 mContentResolver,
2667 "bluetooth_sco_channel_"+
2668 mBluetoothHeadsetDevice.getAddress(),
2669 SCO_MODE_VIRTUAL_CALL));
2670 if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2671 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2672 }
2673 } else {
2674 mScoAudioMode = SCO_MODE_RAW;
Liejun Taof4e51d82014-07-16 11:18:29 -07002675 }
2676 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002677 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002678 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002679 if (mScoAudioMode == SCO_MODE_RAW) {
2680 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002681 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002682 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2683 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002684 } else if (mScoAudioMode == SCO_MODE_VR) {
2685 status = mBluetoothHeadset.startVoiceRecognition(
2686 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002687 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002688
Eric Laurentc18c9132013-04-12 17:24:56 -07002689 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07002690 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2691 } else {
2692 broadcastScoConnectionState(
2693 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2694 }
2695 } else if (getBluetoothHeadset()) {
2696 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07002697 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002698 } else {
2699 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2700 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002701 }
2702 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07002703 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002704 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002705 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002706 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002707 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2708 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2709 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07002710 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002711 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002712 if (mScoAudioMode == SCO_MODE_RAW) {
2713 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002714 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002715 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2716 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002717 } else if (mScoAudioMode == SCO_MODE_VR) {
2718 status = mBluetoothHeadset.stopVoiceRecognition(
2719 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002720 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002721
Eric Laurentc18c9132013-04-12 17:24:56 -07002722 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002723 mScoAudioState = SCO_STATE_INACTIVE;
2724 broadcastScoConnectionState(
2725 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2726 }
2727 } else if (getBluetoothHeadset()) {
2728 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2729 }
2730 } else {
2731 mScoAudioState = SCO_STATE_INACTIVE;
2732 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2733 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002734 }
2735 }
2736 }
2737 }
2738
Eric Laurent62ef7672010-11-24 10:58:32 -08002739 private void checkScoAudioState() {
2740 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002741 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08002742 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2743 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2744 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2745 }
2746 }
2747
Eric Laurent854938a2011-02-22 12:05:20 -08002748 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002749 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002750 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002751 int size = mScoClients.size();
2752 for (int i = 0; i < size; i++) {
2753 client = mScoClients.get(i);
2754 if (client.getBinder() == cb)
2755 return client;
2756 }
Eric Laurent854938a2011-02-22 12:05:20 -08002757 if (create) {
2758 client = new ScoClient(cb);
2759 mScoClients.add(client);
2760 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002761 return client;
2762 }
2763 }
2764
Eric Laurentd7454be2011-09-14 08:45:58 -07002765 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002766 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002767 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002768 int size = mScoClients.size();
2769 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08002770 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07002771 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08002772 cl.clearCount(stopSco);
2773 } else {
2774 savedClient = cl;
2775 }
2776 }
2777 mScoClients.clear();
2778 if (savedClient != null) {
2779 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002780 }
2781 }
2782 }
2783
Eric Laurentdc03c612011-04-01 10:59:41 -07002784 private boolean getBluetoothHeadset() {
2785 boolean result = false;
2786 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2787 if (adapter != null) {
2788 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2789 BluetoothProfile.HEADSET);
2790 }
2791 // If we could not get a bluetooth headset proxy, send a failure message
2792 // without delay to reset the SCO audio state and clear SCO clients.
2793 // If we could get a proxy, send a delayed failure message that will reset our state
2794 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08002795 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002796 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2797 return result;
2798 }
2799
Eric Laurentd7454be2011-09-14 08:45:58 -07002800 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002801 synchronized(mScoClients) {
2802 checkScoAudioState();
2803 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2804 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2805 if (mBluetoothHeadsetDevice != null) {
2806 if (mBluetoothHeadset != null) {
2807 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07002808 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002809 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002810 SENDMSG_REPLACE, 0, 0, null, 0);
2811 }
2812 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2813 getBluetoothHeadset()) {
2814 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2815 }
2816 }
2817 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07002818 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07002819 }
2820 }
2821 }
2822
2823 private void resetBluetoothSco() {
2824 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002825 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07002826 mScoAudioState = SCO_STATE_INACTIVE;
2827 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2828 }
2829 }
2830
2831 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08002832 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
2833 SENDMSG_QUEUE, state, 0, null, 0);
2834 }
2835
2836 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002837 if (state != mScoConnectionState) {
2838 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2839 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2840 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2841 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002842 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07002843 mScoConnectionState = state;
2844 }
2845 }
2846
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002847 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
2848 new BluetoothProfile.ServiceListener() {
2849 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002850 BluetoothDevice btDevice;
2851 List<BluetoothDevice> deviceList;
2852 switch(profile) {
2853 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09002854 synchronized (mConnectedDevices) {
2855 synchronized (mA2dpAvrcpLock) {
2856 mA2dp = (BluetoothA2dp) proxy;
2857 deviceList = mA2dp.getConnectedDevices();
2858 if (deviceList.size() > 0) {
2859 btDevice = deviceList.get(0);
John Du5a0cf7a2013-07-19 11:30:34 -07002860 int state = mA2dp.getConnectionState(btDevice);
2861 int delay = checkSendBecomingNoisyIntent(
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002862 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2863 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
John Du5a0cf7a2013-07-19 11:30:34 -07002864 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002865 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07002866 state,
2867 0,
2868 btDevice,
2869 delay);
2870 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002871 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002872 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002873 break;
2874
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002875 case BluetoothProfile.A2DP_SINK:
2876 deviceList = proxy.getConnectedDevices();
2877 if (deviceList.size() > 0) {
2878 btDevice = deviceList.get(0);
2879 synchronized (mConnectedDevices) {
2880 int state = proxy.getConnectionState(btDevice);
2881 queueMsgUnderWakeLock(mAudioHandler,
2882 MSG_SET_A2DP_SRC_CONNECTION_STATE,
2883 state,
2884 0,
2885 btDevice,
2886 0 /* delay */);
2887 }
2888 }
2889 break;
2890
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002891 case BluetoothProfile.HEADSET:
2892 synchronized (mScoClients) {
2893 // Discard timeout message
2894 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
2895 mBluetoothHeadset = (BluetoothHeadset) proxy;
2896 deviceList = mBluetoothHeadset.getConnectedDevices();
2897 if (deviceList.size() > 0) {
2898 mBluetoothHeadsetDevice = deviceList.get(0);
2899 } else {
2900 mBluetoothHeadsetDevice = null;
2901 }
2902 // Refresh SCO audio state
2903 checkScoAudioState();
2904 // Continue pending action if any
2905 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
2906 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
2907 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2908 boolean status = false;
2909 if (mBluetoothHeadsetDevice != null) {
2910 switch (mScoAudioState) {
2911 case SCO_STATE_ACTIVATE_REQ:
2912 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07002913 if (mScoAudioMode == SCO_MODE_RAW) {
2914 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002915 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002916 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2917 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002918 } else if (mScoAudioMode == SCO_MODE_VR) {
2919 status = mBluetoothHeadset.startVoiceRecognition(
2920 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002921 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002922 break;
2923 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07002924 if (mScoAudioMode == SCO_MODE_RAW) {
2925 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002926 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002927 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2928 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002929 } else if (mScoAudioMode == SCO_MODE_VR) {
2930 status = mBluetoothHeadset.stopVoiceRecognition(
2931 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002932 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002933 break;
2934 case SCO_STATE_DEACTIVATE_EXT_REQ:
2935 status = mBluetoothHeadset.stopVoiceRecognition(
2936 mBluetoothHeadsetDevice);
2937 }
2938 }
2939 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002940 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002941 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07002942 }
2943 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002944 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002945 break;
2946
2947 default:
2948 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002949 }
2950 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002951 public void onServiceDisconnected(int profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002952 switch(profile) {
2953 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09002954 synchronized (mConnectedDevices) {
2955 synchronized (mA2dpAvrcpLock) {
2956 mA2dp = null;
John Du5a0cf7a2013-07-19 11:30:34 -07002957 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
2958 makeA2dpDeviceUnavailableNow(
2959 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
2960 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002961 }
2962 }
2963 break;
2964
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002965 case BluetoothProfile.A2DP_SINK:
2966 synchronized (mConnectedDevices) {
2967 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) {
2968 makeA2dpSrcUnavailable(
2969 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP));
2970 }
2971 }
2972 break;
2973
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002974 case BluetoothProfile.HEADSET:
2975 synchronized (mScoClients) {
2976 mBluetoothHeadset = null;
2977 }
2978 break;
2979
2980 default:
2981 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002982 }
2983 }
2984 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08002985
Eric Laurentc34dcc12012-09-10 13:51:52 -07002986 private void onCheckMusicActive() {
Eric Laurentd640bd32012-09-28 18:01:48 -07002987 synchronized (mSafeMediaVolumeState) {
2988 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002989 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
2990
2991 if ((device & mSafeMediaVolumeDevices) != 0) {
2992 sendMsg(mAudioHandler,
2993 MSG_CHECK_MUSIC_ACTIVE,
2994 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07002995 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07002996 0,
2997 null,
2998 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07002999 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07003000 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
3001 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07003002 // Approximate cumulative active music time
3003 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
3004 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
3005 setSafeMediaVolumeEnabled(true);
3006 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07003007 }
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003008 saveMusicActiveMs();
Eric Laurentc34dcc12012-09-10 13:51:52 -07003009 }
3010 }
3011 }
3012 }
3013 }
3014
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003015 private void saveMusicActiveMs() {
3016 mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
3017 }
3018
Eric Laurentd640bd32012-09-28 18:01:48 -07003019 private void onConfigureSafeVolume(boolean force) {
3020 synchronized (mSafeMediaVolumeState) {
3021 int mcc = mContext.getResources().getConfiguration().mcc;
3022 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
3023 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
3024 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
John Spurlock35134602014-07-24 18:10:48 -04003025 boolean safeMediaVolumeEnabled =
3026 SystemProperties.getBoolean("audio.safemedia.force", false)
3027 || mContext.getResources().getBoolean(
3028 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08003029
3030 // The persisted state is either "disabled" or "active": this is the state applied
3031 // next time we boot and cannot be "inactive"
3032 int persistedState;
Eric Laurentd640bd32012-09-28 18:01:48 -07003033 if (safeMediaVolumeEnabled) {
Eric Laurent05274f32012-11-29 12:48:18 -08003034 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
3035 // The state can already be "inactive" here if the user has forced it before
3036 // the 30 seconds timeout for forced configuration. In this case we don't reset
3037 // it to "active".
3038 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04003039 if (mMusicActiveMs == 0) {
3040 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
3041 enforceSafeMediaVolume();
3042 } else {
3043 // We have existing playback time recorded, already confirmed.
3044 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
3045 }
Eric Laurent05274f32012-11-29 12:48:18 -08003046 }
Eric Laurentd640bd32012-09-28 18:01:48 -07003047 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08003048 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07003049 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
3050 }
3051 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08003052 sendMsg(mAudioHandler,
3053 MSG_PERSIST_SAFE_VOLUME_STATE,
3054 SENDMSG_QUEUE,
3055 persistedState,
3056 0,
3057 null,
3058 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07003059 }
3060 }
3061 }
3062
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003063 ///////////////////////////////////////////////////////////////////////////
3064 // Internal methods
3065 ///////////////////////////////////////////////////////////////////////////
3066
3067 /**
3068 * Checks if the adjustment should change ringer mode instead of just
3069 * adjusting volume. If so, this will set the proper ringer mode and volume
3070 * indices on the stream states.
3071 */
RoboErik5452e252015-02-06 15:33:53 -08003072 private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003073 int result = FLAG_ADJUST_VOLUME;
John Spurlock661f2cf2014-11-17 10:29:10 -05003074 int ringerMode = getRingerModeInternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003075
Eric Laurentbffc3d12012-05-07 17:43:49 -07003076 switch (ringerMode) {
3077 case RINGER_MODE_NORMAL:
3078 if (direction == AudioManager.ADJUST_LOWER) {
3079 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07003080 // "step" is the delta in internal index units corresponding to a
3081 // change of 1 in UI index units.
3082 // Because of rounding when rescaling from one stream index range to its alias
3083 // index range, we cannot simply test oldIndex == step:
3084 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
3085 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003086 ringerMode = RINGER_MODE_VIBRATE;
3087 }
3088 } else {
Eric Laurent24482012012-05-10 09:41:17 -07003089 // (oldIndex < step) is equivalent to (old UI index == 0)
John Spurlock86005342014-05-23 11:58:00 -04003090 if ((oldIndex < step)
3091 && VOLUME_SETS_RINGER_MODE_SILENT
3092 && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003093 ringerMode = RINGER_MODE_SILENT;
3094 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07003095 }
RoboErik5452e252015-02-06 15:33:53 -08003096 } else if (direction == AudioManager.ADJUST_TOGGLE_MUTE
3097 || direction == AudioManager.ADJUST_MUTE) {
3098 if (mHasVibrator) {
3099 ringerMode = RINGER_MODE_VIBRATE;
3100 } else {
3101 ringerMode = RINGER_MODE_SILENT;
3102 }
3103 // Setting the ringer mode will toggle mute
3104 result &= ~FLAG_ADJUST_VOLUME;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003105 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003106 break;
3107 case RINGER_MODE_VIBRATE:
3108 if (!mHasVibrator) {
3109 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
3110 "but no vibrator is present");
3111 break;
3112 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003113 if ((direction == AudioManager.ADJUST_LOWER)) {
RoboErik5452e252015-02-06 15:33:53 -08003114 // This is the case we were muted with the volume turned up
3115 if (oldIndex >= 2 * step && isMuted) {
3116 ringerMode = RINGER_MODE_NORMAL;
3117 } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
John Spurlock795a5142014-12-08 14:09:35 -05003118 if (VOLUME_SETS_RINGER_MODE_SILENT) {
3119 ringerMode = RINGER_MODE_SILENT;
3120 } else {
3121 result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
3122 }
Amith Yamasanic696a532011-10-28 17:02:37 -07003123 }
RoboErik5452e252015-02-06 15:33:53 -08003124 } else if (direction == AudioManager.ADJUST_RAISE
3125 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3126 || direction == AudioManager.ADJUST_UNMUTE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07003127 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07003128 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003129 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003130 break;
3131 case RINGER_MODE_SILENT:
RoboErik5452e252015-02-06 15:33:53 -08003132 if (direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
3133 // This is the case we were muted with the volume turned up
3134 ringerMode = RINGER_MODE_NORMAL;
3135 } else if (direction == AudioManager.ADJUST_RAISE
3136 || direction == AudioManager.ADJUST_TOGGLE_MUTE
3137 || direction == AudioManager.ADJUST_UNMUTE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003138 if (PREVENT_VOLUME_ADJUSTMENT_IF_SILENT) {
3139 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003140 } else {
RoboErik5452e252015-02-06 15:33:53 -08003141 if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04003142 ringerMode = RINGER_MODE_VIBRATE;
3143 } else {
RoboErik5452e252015-02-06 15:33:53 -08003144 // If we don't have a vibrator or they were toggling mute
3145 // go straight back to normal.
John Spurlocka11b4af2014-06-01 11:52:23 -04003146 ringerMode = RINGER_MODE_NORMAL;
3147 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003148 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05003149 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003150 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003151 break;
3152 default:
3153 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
3154 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003155 }
3156
John Spurlock661f2cf2014-11-17 10:29:10 -05003157 setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003158
Eric Laurent25101b02011-02-02 09:33:30 -08003159 mPrevVolDirection = direction;
3160
John Spurlocka11b4af2014-06-01 11:52:23 -04003161 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003162 }
3163
John Spurlock3346a802014-05-20 16:25:37 -04003164 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003165 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07003166 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003167 }
3168
Eric Laurent5b4e6542010-03-19 20:02:21 -07003169 private boolean isStreamMutedByRingerMode(int streamType) {
3170 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
3171 }
3172
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003173 boolean updateRingerModeAffectedStreams() {
3174 int ringerModeAffectedStreams;
3175 // make sure settings for ringer mode are consistent with device type: non voice capable
3176 // devices (tablets) include media stream in silent mode whereas phones don't.
3177 ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
3178 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3179 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
3180 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
3181 UserHandle.USER_CURRENT);
3182
3183 // ringtone, notification and system streams are always affected by ringer mode
3184 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
3185 (1 << AudioSystem.STREAM_NOTIFICATION)|
3186 (1 << AudioSystem.STREAM_SYSTEM);
3187
Eric Laurent212532b2014-07-21 15:43:18 -07003188 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003189 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -07003190 ringerModeAffectedStreams = 0;
3191 break;
3192 default:
John Spurlock77e54d92014-08-11 12:16:24 -04003193 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
Eric Laurent212532b2014-07-21 15:43:18 -07003194 break;
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003195 }
Eric Laurent212532b2014-07-21 15:43:18 -07003196
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003197 synchronized (mCameraSoundForced) {
3198 if (mCameraSoundForced) {
3199 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3200 } else {
3201 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3202 }
3203 }
3204 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
3205 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
3206 } else {
3207 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
3208 }
3209
3210 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3211 Settings.System.putIntForUser(mContentResolver,
3212 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3213 ringerModeAffectedStreams,
3214 UserHandle.USER_CURRENT);
3215 mRingerModeAffectedStreams = ringerModeAffectedStreams;
3216 return true;
3217 }
3218 return false;
3219 }
3220
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05003221 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003222 public boolean isStreamAffectedByMute(int streamType) {
3223 return (mMuteAffectedStreams & (1 << streamType)) != 0;
3224 }
3225
3226 private void ensureValidDirection(int direction) {
RoboErik4197cb62015-01-21 15:45:32 -08003227 switch (direction) {
3228 case AudioManager.ADJUST_LOWER:
3229 case AudioManager.ADJUST_RAISE:
3230 case AudioManager.ADJUST_SAME:
3231 case AudioManager.ADJUST_MUTE:
3232 case AudioManager.ADJUST_UNMUTE:
3233 case AudioManager.ADJUST_TOGGLE_MUTE:
3234 break;
3235 default:
3236 throw new IllegalArgumentException("Bad direction " + direction);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003237 }
3238 }
3239
Lei Zhang6c798972012-03-02 11:40:12 -08003240 private void ensureValidSteps(int steps) {
3241 if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
3242 throw new IllegalArgumentException("Bad volume adjust steps " + steps);
3243 }
3244 }
3245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003246 private void ensureValidStreamType(int streamType) {
3247 if (streamType < 0 || streamType >= mStreamStates.length) {
3248 throw new IllegalArgumentException("Bad stream type " + streamType);
3249 }
3250 }
3251
RoboErik4197cb62015-01-21 15:45:32 -08003252 private boolean isMuteAdjust(int adjust) {
3253 return adjust == AudioManager.ADJUST_MUTE || adjust == AudioManager.ADJUST_UNMUTE
3254 || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
3255 }
3256
Eric Laurent6d517662012-04-23 18:42:39 -07003257 private boolean isInCommunication() {
Nancy Chen0eb1e402014-08-21 22:52:29 -07003258 boolean IsInCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003259
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003260 TelecomManager telecomManager =
3261 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
Eric Laurent38edfda2014-12-18 17:38:04 -08003262
3263 final long ident = Binder.clearCallingIdentity();
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003264 IsInCall = telecomManager.isInCall();
Eric Laurent38edfda2014-12-18 17:38:04 -08003265 Binder.restoreCallingIdentity(ident);
Santos Cordon9eb45932014-06-27 12:28:43 -07003266
Nancy Chen0eb1e402014-08-21 22:52:29 -07003267 return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
Eric Laurent6d517662012-04-23 18:42:39 -07003268 }
Eric Laurent25101b02011-02-02 09:33:30 -08003269
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003270 /**
3271 * For code clarity for getActiveStreamType(int)
3272 * @param delay_ms max time since last STREAM_MUSIC activity to consider
3273 * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
3274 * in the last "delay_ms" ms.
3275 */
3276 private boolean isAfMusicActiveRecently(int delay_ms) {
3277 return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
3278 || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
3279 }
3280
Eric Laurent6d517662012-04-23 18:42:39 -07003281 private int getActiveStreamType(int suggestedStreamType) {
Eric Laurent212532b2014-07-21 15:43:18 -07003282 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003283 case AudioSystem.PLATFORM_VOICE:
Eric Laurent6d517662012-04-23 18:42:39 -07003284 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003285 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3286 == AudioSystem.FORCE_BT_SCO) {
3287 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
3288 return AudioSystem.STREAM_BLUETOOTH_SCO;
3289 } else {
3290 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
3291 return AudioSystem.STREAM_VOICE_CALL;
3292 }
Eric Laurent25101b02011-02-02 09:33:30 -08003293 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003294 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003295 if (DEBUG_VOL)
3296 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3297 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003298 } else {
3299 if (DEBUG_VOL)
3300 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
3301 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003302 }
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003303 } else if (isAfMusicActiveRecently(0)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003304 if (DEBUG_VOL)
3305 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3306 return AudioSystem.STREAM_MUSIC;
Eric Laurent25101b02011-02-02 09:33:30 -08003307 }
Eric Laurent212532b2014-07-21 15:43:18 -07003308 break;
John Spurlock61560172015-02-06 19:46:04 -05003309 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -07003310 if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
RoboErik2811dd32014-08-12 09:48:13 -07003311 // TV always defaults to STREAM_MUSIC
Eric Laurent212532b2014-07-21 15:43:18 -07003312 return AudioSystem.STREAM_MUSIC;
Eric Laurent212532b2014-07-21 15:43:18 -07003313 }
3314 break;
3315 default:
Eric Laurent6d517662012-04-23 18:42:39 -07003316 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003317 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3318 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003319 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08003320 return AudioSystem.STREAM_BLUETOOTH_SCO;
3321 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003322 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08003323 return AudioSystem.STREAM_VOICE_CALL;
3324 }
3325 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003326 StreamOverride.sDelayMs) ||
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003327 AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003328 StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003329 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08003330 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003331 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003332 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003333 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
3334 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003335 } else {
John Spurlockeb1d88d2014-07-19 14:49:19 -04003336 if (DEBUG_VOL) Log.v(TAG,
3337 "getActiveStreamType: using STREAM_NOTIFICATION as default");
3338 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003339 }
Joe Onoratoc7fcba42011-01-05 16:53:11 -08003340 }
Eric Laurent212532b2014-07-21 15:43:18 -07003341 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003342 }
Eric Laurent212532b2014-07-21 15:43:18 -07003343 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
3344 + suggestedStreamType);
3345 return suggestedStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003346 }
3347
John Spurlockbcc10872014-11-28 15:29:21 -05003348 private void broadcastRingerMode(String action, int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003349 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05003350 Intent broadcast = new Intent(action);
Glenn Kastenba195eb2011-12-13 09:30:40 -08003351 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003352 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
3353 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003354 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003355 }
3356
3357 private void broadcastVibrateSetting(int vibrateType) {
3358 // Send broadcast
3359 if (ActivityManagerNative.isSystemReady()) {
3360 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
3361 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
3362 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003363 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003364 }
3365 }
3366
3367 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003368 /**
3369 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
3370 * Note that the wake lock needs to be released after the message has been handled.
3371 */
3372 private void queueMsgUnderWakeLock(Handler handler, int msg,
3373 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003374 final long ident = Binder.clearCallingIdentity();
3375 // Always acquire the wake lock as AudioService because it is released by the
3376 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003377 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003378 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003379 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
3380 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003381
Eric Laurentafbb0472011-12-15 09:04:23 -08003382 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003383 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003384
3385 if (existingMsgPolicy == SENDMSG_REPLACE) {
3386 handler.removeMessages(msg);
3387 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
3388 return;
3389 }
Eric Laurentadbe8bf2014-11-03 18:26:32 -08003390 synchronized (mLastDeviceConnectMsgTime) {
3391 long time = SystemClock.uptimeMillis() + delay;
3392 handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
3393 if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
3394 msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
3395 msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
3396 mLastDeviceConnectMsgTime = time;
3397 }
3398 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003399 }
3400
3401 boolean checkAudioSettingsPermission(String method) {
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07003402 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003403 == PackageManager.PERMISSION_GRANTED) {
3404 return true;
3405 }
3406 String msg = "Audio Settings Permission Denial: " + method + " from pid="
3407 + Binder.getCallingPid()
3408 + ", uid=" + Binder.getCallingUid();
3409 Log.w(TAG, msg);
3410 return false;
3411 }
3412
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003413 private int getDeviceForStream(int stream) {
3414 int device = AudioSystem.getDevicesForStream(stream);
3415 if ((device & (device - 1)) != 0) {
3416 // Multiple device selection is either:
3417 // - speaker + one other device: give priority to speaker in this case.
3418 // - one A2DP device + another device: happens with duplicated output. In this case
3419 // retain the device on the A2DP output as the other must not correspond to an active
3420 // selection if not the speaker.
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003421 // - HDMI-CEC system audio mode only output: give priority to available item in order.
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003422 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
3423 device = AudioSystem.DEVICE_OUT_SPEAKER;
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003424 } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
3425 device = AudioSystem.DEVICE_OUT_HDMI_ARC;
3426 } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
3427 device = AudioSystem.DEVICE_OUT_SPDIF;
3428 } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
3429 device = AudioSystem.DEVICE_OUT_AUX_LINE;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003430 } else {
3431 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
3432 }
3433 }
3434 return device;
3435 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003436
Paul McLean10804eb2015-01-28 11:16:35 -08003437 /*
3438 * A class just for packaging up a set of connection parameters.
3439 */
3440 private class WiredDeviceConnectionState {
3441 public int mType;
3442 public int mState;
3443 public String mAddress;
3444 public String mName;
3445
3446 public WiredDeviceConnectionState(int type, int state, String address, String name) {
3447 mType = type;
3448 mState = state;
3449 mAddress = address;
3450 mName = name;
3451 }
3452 }
3453
3454 public void setWiredDeviceConnectionState(int type, int state, String address,
3455 String name) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003456 synchronized (mConnectedDevices) {
Paul McLean10804eb2015-01-28 11:16:35 -08003457 int delay = checkSendBecomingNoisyIntent(type, state);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003458 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003459 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Paul McLean10804eb2015-01-28 11:16:35 -08003460 0,
3461 0,
3462 new WiredDeviceConnectionState(type, state, address, name),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003463 delay);
3464 }
3465 }
3466
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003467 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003468 {
3469 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003470 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
3471 throw new IllegalArgumentException("invalid profile " + profile);
3472 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003473 synchronized (mConnectedDevices) {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003474 if (profile == BluetoothProfile.A2DP) {
3475 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3476 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
3477 } else {
3478 delay = 0;
3479 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003480 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003481 (profile == BluetoothProfile.A2DP ?
3482 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003483 state,
3484 0,
3485 device,
3486 delay);
3487 }
3488 return delay;
3489 }
3490
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003491 ///////////////////////////////////////////////////////////////////////////
3492 // Inner classes
3493 ///////////////////////////////////////////////////////////////////////////
3494
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003495 // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
3496 // 1 mScoclient OR mSafeMediaVolumeState
3497 // 2 mSetModeDeathHandlers
3498 // 3 mSettingsLock
3499 // 4 VolumeStreamState.class
3500 // 5 mCameraSoundForced
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003501 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003502 private final int mStreamType;
3503
RoboErik4197cb62015-01-21 15:45:32 -08003504 private boolean mIsMuted;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003505 private String mVolumeIndexSettingName;
Eric Laurenta553c252009-07-17 12:17:14 -07003506 private int mIndexMax;
Eric Laurent3172d5e2012-05-09 11:38:16 -07003507 private final ConcurrentHashMap<Integer, Integer> mIndex =
3508 new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003509
Eric Laurenta553c252009-07-17 12:17:14 -07003510 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003511
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003512 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003513
3514 mStreamType = streamType;
Jared Suttles59820132009-08-13 21:50:52 -05003515 mIndexMax = MAX_STREAM_VOLUME[streamType];
Eric Laurenta553c252009-07-17 12:17:14 -07003516 AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
3517 mIndexMax *= 10;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003518
Eric Laurent33902db2012-10-07 16:15:07 -07003519 readSettings();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003520 }
3521
Eric Laurent42b041e2013-03-29 11:36:03 -07003522 public String getSettingNameForDevice(int device) {
3523 String name = mVolumeIndexSettingName;
Eric Laurent948d3272014-05-16 15:18:45 -07003524 String suffix = AudioSystem.getOutputDeviceName(device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003525 if (suffix.isEmpty()) {
3526 return name;
3527 }
3528 return name + "_" + suffix;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003529 }
3530
Eric Laurentfdbee862014-05-12 15:26:12 -07003531 public void readSettings() {
3532 synchronized (VolumeStreamState.class) {
Wally Yauda392902014-11-28 12:40:30 -08003533 // force maximum volume on all streams if fixed volume property
3534 // or master volume property is set
3535 if (mUseFixedVolume || mUseMasterVolume) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003536 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
3537 return;
3538 }
3539 // do not read system stream volume from settings: this stream is always aliased
3540 // to another stream type and its volume is never persisted. Values in settings can
3541 // only be stale values
3542 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3543 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
John Spurlock61560172015-02-06 19:46:04 -05003544 int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
Eric Laurentfdbee862014-05-12 15:26:12 -07003545 synchronized (mCameraSoundForced) {
3546 if (mCameraSoundForced) {
3547 index = mIndexMax;
3548 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003549 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003550 mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
3551 return;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003552 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003553
Eric Laurentfdbee862014-05-12 15:26:12 -07003554 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
3555
3556 for (int i = 0; remainingDevices != 0; i++) {
3557 int device = (1 << i);
3558 if ((device & remainingDevices) == 0) {
3559 continue;
3560 }
3561 remainingDevices &= ~device;
3562
3563 // retrieve current volume for device
3564 String name = getSettingNameForDevice(device);
3565 // if no volume stored for current stream and device, use default volume if default
3566 // device, continue otherwise
3567 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
John Spurlock61560172015-02-06 19:46:04 -05003568 AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
Eric Laurentfdbee862014-05-12 15:26:12 -07003569 int index = Settings.System.getIntForUser(
3570 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3571 if (index == -1) {
3572 continue;
3573 }
3574
Eric Laurent212532b2014-07-21 15:43:18 -07003575 mIndex.put(device, getValidIndex(10 * index));
Eric Laurentdd45d012012-10-08 09:04:34 -07003576 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003577 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003578 }
3579
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003580 // must be called while synchronized VolumeStreamState.class
3581 public void applyDeviceVolume_syncVSS(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003582 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003583 if (mIsMuted) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003584 index = 0;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003585 } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported)
3586 || ((device & mFullVolumeDevices) != 0)) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003587 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07003588 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07003589 index = (getIndex(device) + 5)/10;
3590 }
3591 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003592 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003593
Eric Laurentfdbee862014-05-12 15:26:12 -07003594 public void applyAllVolumes() {
3595 synchronized (VolumeStreamState.class) {
3596 // apply default volume first: by convention this will reset all
3597 // devices volumes in audio policy manager to the supplied value
3598 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003599 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003600 index = 0;
3601 } else {
3602 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3603 }
3604 AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3605 // then apply device specific volumes
3606 Set set = mIndex.entrySet();
3607 Iterator i = set.iterator();
3608 while (i.hasNext()) {
3609 Map.Entry entry = (Map.Entry)i.next();
3610 int device = ((Integer)entry.getKey()).intValue();
3611 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
RoboErik4197cb62015-01-21 15:45:32 -08003612 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003613 index = 0;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003614 } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3615 mAvrcpAbsVolSupported)
3616 || ((device & mFullVolumeDevices) != 0))
3617 {
Eric Laurentfdbee862014-05-12 15:26:12 -07003618 index = (mIndexMax + 5)/10;
3619 } else {
3620 index = ((Integer)entry.getValue() + 5)/10;
3621 }
3622 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07003623 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003624 }
3625 }
3626 }
3627
3628 public boolean adjustIndex(int deltaIndex, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003629 return setIndex(getIndex(device) + deltaIndex,
3630 device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003631 }
3632
Eric Laurentfdbee862014-05-12 15:26:12 -07003633 public boolean setIndex(int index, int device) {
3634 synchronized (VolumeStreamState.class) {
3635 int oldIndex = getIndex(device);
3636 index = getValidIndex(index);
3637 synchronized (mCameraSoundForced) {
3638 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3639 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07003640 }
3641 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003642 mIndex.put(device, index);
3643
3644 if (oldIndex != index) {
3645 // Apply change to all streams using this one as alias
3646 // if changing volume of current device, also change volume of current
3647 // device on aliased stream
3648 boolean currentDevice = (device == getDeviceForStream(mStreamType));
3649 int numStreamTypes = AudioSystem.getNumStreamTypes();
3650 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3651 if (streamType != mStreamType &&
3652 mStreamVolumeAlias[streamType] == mStreamType) {
3653 int scaledIndex = rescaleIndex(index, mStreamType, streamType);
3654 mStreamStates[streamType].setIndex(scaledIndex,
3655 device);
3656 if (currentDevice) {
3657 mStreamStates[streamType].setIndex(scaledIndex,
3658 getDeviceForStream(streamType));
3659 }
3660 }
3661 }
3662 return true;
3663 } else {
3664 return false;
3665 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003666 }
3667 }
3668
Eric Laurentfdbee862014-05-12 15:26:12 -07003669 public int getIndex(int device) {
3670 synchronized (VolumeStreamState.class) {
3671 Integer index = mIndex.get(device);
3672 if (index == null) {
3673 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
3674 index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
3675 }
3676 return index.intValue();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003677 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07003678 }
3679
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003680 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07003681 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003682 }
3683
Eric Laurentfdbee862014-05-12 15:26:12 -07003684 public void setAllIndexes(VolumeStreamState srcStream) {
3685 synchronized (VolumeStreamState.class) {
3686 int srcStreamType = srcStream.getStreamType();
3687 // apply default device volume from source stream to all devices first in case
3688 // some devices are present in this stream state but not in source stream state
3689 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003690 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurentfdbee862014-05-12 15:26:12 -07003691 Set set = mIndex.entrySet();
3692 Iterator i = set.iterator();
3693 while (i.hasNext()) {
3694 Map.Entry entry = (Map.Entry)i.next();
3695 entry.setValue(index);
3696 }
3697 // Now apply actual volume for devices in source stream state
3698 set = srcStream.mIndex.entrySet();
3699 i = set.iterator();
3700 while (i.hasNext()) {
3701 Map.Entry entry = (Map.Entry)i.next();
3702 int device = ((Integer)entry.getKey()).intValue();
3703 index = ((Integer)entry.getValue()).intValue();
3704 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07003705
Eric Laurentfdbee862014-05-12 15:26:12 -07003706 setIndex(index, device);
3707 }
Eric Laurent6d517662012-04-23 18:42:39 -07003708 }
3709 }
3710
Eric Laurentfdbee862014-05-12 15:26:12 -07003711 public void setAllIndexesToMax() {
3712 synchronized (VolumeStreamState.class) {
3713 Set set = mIndex.entrySet();
3714 Iterator i = set.iterator();
3715 while (i.hasNext()) {
3716 Map.Entry entry = (Map.Entry)i.next();
3717 entry.setValue(mIndexMax);
3718 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003719 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003720 }
3721
RoboErik4197cb62015-01-21 15:45:32 -08003722 public void mute(boolean state) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003723 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08003724 if (state != mIsMuted) {
3725 mIsMuted = state;
3726 // Set the new mute volume. This propagates the values to
3727 // the audio system, otherwise the volume won't be changed
3728 // at the lower level.
3729 sendMsg(mAudioHandler,
3730 MSG_SET_ALL_VOLUMES,
3731 SENDMSG_QUEUE,
3732 0,
3733 0,
3734 this, 0);
Eric Laurentfdbee862014-05-12 15:26:12 -07003735 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003736 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003737 }
3738
Eric Laurent6d517662012-04-23 18:42:39 -07003739 public int getStreamType() {
3740 return mStreamType;
3741 }
3742
Eric Laurent212532b2014-07-21 15:43:18 -07003743 public void checkFixedVolumeDevices() {
3744 synchronized (VolumeStreamState.class) {
3745 // ignore settings for fixed volume devices: volume should always be at max or 0
3746 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
3747 Set set = mIndex.entrySet();
3748 Iterator i = set.iterator();
3749 while (i.hasNext()) {
3750 Map.Entry entry = (Map.Entry)i.next();
3751 int device = ((Integer)entry.getKey()).intValue();
3752 int index = ((Integer)entry.getValue()).intValue();
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003753 if (((device & mFullVolumeDevices) != 0)
3754 || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
Eric Laurent212532b2014-07-21 15:43:18 -07003755 entry.setValue(mIndexMax);
3756 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003757 applyDeviceVolume_syncVSS(device);
Eric Laurent212532b2014-07-21 15:43:18 -07003758 }
3759 }
3760 }
3761 }
3762
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003763 private int getValidIndex(int index) {
3764 if (index < 0) {
3765 return 0;
Wally Yauda392902014-11-28 12:40:30 -08003766 } else if (mUseFixedVolume || mUseMasterVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07003767 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003768 }
3769
3770 return index;
3771 }
3772
Eric Laurentbffc3d12012-05-07 17:43:49 -07003773 private void dump(PrintWriter pw) {
RoboErik4197cb62015-01-21 15:45:32 -08003774 pw.print(" Muted: ");
3775 pw.println(mIsMuted);
John Spurlock2b29bc42014-08-26 16:40:35 -04003776 pw.print(" Max: ");
3777 pw.println((mIndexMax + 5) / 10);
Eric Laurentbffc3d12012-05-07 17:43:49 -07003778 pw.print(" Current: ");
3779 Set set = mIndex.entrySet();
3780 Iterator i = set.iterator();
3781 while (i.hasNext()) {
3782 Map.Entry entry = (Map.Entry)i.next();
John Spurlock2b29bc42014-08-26 16:40:35 -04003783 final int device = (Integer) entry.getKey();
3784 pw.print(Integer.toHexString(device));
3785 final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
3786 : AudioSystem.getOutputDeviceName(device);
3787 if (!deviceName.isEmpty()) {
3788 pw.print(" (");
3789 pw.print(deviceName);
3790 pw.print(")");
3791 }
3792 pw.print(": ");
3793 final int index = (((Integer) entry.getValue()) + 5) / 10;
3794 pw.print(index);
3795 if (i.hasNext()) {
3796 pw.print(", ");
3797 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003798 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003799 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003800 }
3801
3802 /** Thread that handles native AudioSystem control. */
3803 private class AudioSystemThread extends Thread {
3804 AudioSystemThread() {
3805 super("AudioService");
3806 }
3807
3808 @Override
3809 public void run() {
3810 // Set this thread up so the handler will work on it
3811 Looper.prepare();
3812
3813 synchronized(AudioService.this) {
3814 mAudioHandler = new AudioHandler();
3815
3816 // Notify that the handler has been created
3817 AudioService.this.notify();
3818 }
3819
3820 // Listen for volume change requests that are set by VolumePanel
3821 Looper.loop();
3822 }
3823 }
3824
3825 /** Handles internal volume messages in separate volume thread. */
3826 private class AudioHandler extends Handler {
3827
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003828 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003829
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003830 synchronized (VolumeStreamState.class) {
3831 // Apply volume
3832 streamState.applyDeviceVolume_syncVSS(device);
Eric Laurenta553c252009-07-17 12:17:14 -07003833
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003834 // Apply change to all streams using this one as alias
3835 int numStreamTypes = AudioSystem.getNumStreamTypes();
3836 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3837 if (streamType != streamState.mStreamType &&
3838 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
3839 // Make sure volume is also maxed out on A2DP device for aliased stream
3840 // that may have a different device selected
3841 int streamDevice = getDeviceForStream(streamType);
3842 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
3843 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
3844 mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
3845 }
3846 mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
Eric Laurentcd772d02013-10-30 18:31:07 -07003847 }
Eric Laurenta553c252009-07-17 12:17:14 -07003848 }
3849 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003850 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08003851 sendMsg(mAudioHandler,
3852 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08003853 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003854 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07003855 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08003856 streamState,
3857 PERSIST_DELAY);
3858
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003859 }
3860
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003861 private void setAllVolumes(VolumeStreamState streamState) {
3862
3863 // Apply volume
3864 streamState.applyAllVolumes();
3865
3866 // Apply change to all streams using this one as alias
3867 int numStreamTypes = AudioSystem.getNumStreamTypes();
3868 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3869 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07003870 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003871 mStreamStates[streamType].applyAllVolumes();
3872 }
3873 }
3874 }
3875
Eric Laurent42b041e2013-03-29 11:36:03 -07003876 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003877 if (mUseFixedVolume) {
3878 return;
3879 }
Eric Laurent212532b2014-07-21 15:43:18 -07003880 if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
3881 return;
3882 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003883 System.putIntForUser(mContentResolver,
3884 streamState.getSettingNameForDevice(device),
3885 (streamState.getIndex(device) + 5)/ 10,
3886 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003887 }
3888
Glenn Kastenba195eb2011-12-13 09:30:40 -08003889 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003890 if (mUseFixedVolume) {
3891 return;
3892 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07003893 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003894 }
3895
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003896 private boolean onLoadSoundEffects() {
3897 int status;
3898
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003899 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07003900 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003901 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
3902 return false;
3903 }
3904
3905 if (mSoundPool != null) {
3906 return true;
3907 }
3908
3909 loadTouchSoundAssets();
3910
Jean-Michel Trivi55a30c42014-07-20 17:56:11 -07003911 mSoundPool = new SoundPool.Builder()
3912 .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
3913 .setAudioAttributes(new AudioAttributes.Builder()
3914 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
3915 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
3916 .build())
3917 .build();
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003918 mSoundPoolCallBack = null;
3919 mSoundPoolListenerThread = new SoundPoolListenerThread();
3920 mSoundPoolListenerThread.start();
3921 int attempts = 3;
3922 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
3923 try {
3924 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07003925 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003926 } catch (InterruptedException e) {
3927 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
3928 }
3929 }
3930
3931 if (mSoundPoolCallBack == null) {
3932 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
3933 if (mSoundPoolLooper != null) {
3934 mSoundPoolLooper.quit();
3935 mSoundPoolLooper = null;
3936 }
3937 mSoundPoolListenerThread = null;
3938 mSoundPool.release();
3939 mSoundPool = null;
3940 return false;
3941 }
3942 /*
3943 * poolId table: The value -1 in this table indicates that corresponding
3944 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
3945 * Once loaded, the value in poolId is the sample ID and the same
3946 * sample can be reused for another effect using the same file.
3947 */
3948 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3949 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3950 poolId[fileIdx] = -1;
3951 }
3952 /*
3953 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
3954 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
3955 * this indicates we have a valid sample loaded for this effect.
3956 */
3957
3958 int numSamples = 0;
3959 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3960 // Do not load sample if this effect uses the MediaPlayer
3961 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
3962 continue;
3963 }
3964 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
3965 String filePath = Environment.getRootDirectory()
3966 + SOUND_EFFECTS_PATH
3967 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
3968 int sampleId = mSoundPool.load(filePath, 0);
3969 if (sampleId <= 0) {
3970 Log.w(TAG, "Soundpool could not load file: "+filePath);
3971 } else {
3972 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
3973 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
3974 numSamples++;
3975 }
3976 } else {
3977 SOUND_EFFECT_FILES_MAP[effect][1] =
3978 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
3979 }
3980 }
3981 // wait for all samples to be loaded
3982 if (numSamples > 0) {
3983 mSoundPoolCallBack.setSamples(poolId);
3984
3985 attempts = 3;
3986 status = 1;
3987 while ((status == 1) && (attempts-- > 0)) {
3988 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07003989 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003990 status = mSoundPoolCallBack.status();
3991 } catch (InterruptedException e) {
3992 Log.w(TAG, "Interrupted while waiting sound pool callback.");
3993 }
3994 }
3995 } else {
3996 status = -1;
3997 }
3998
3999 if (mSoundPoolLooper != null) {
4000 mSoundPoolLooper.quit();
4001 mSoundPoolLooper = null;
4002 }
4003 mSoundPoolListenerThread = null;
4004 if (status != 0) {
4005 Log.w(TAG,
4006 "onLoadSoundEffects(), Error "+status+ " while loading samples");
4007 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4008 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
4009 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4010 }
4011 }
4012
4013 mSoundPool.release();
4014 mSoundPool = null;
4015 }
4016 }
4017 return (status == 0);
4018 }
4019
4020 /**
4021 * Unloads samples from the sound pool.
4022 * This method can be called to free some memory when
4023 * sound effects are disabled.
4024 */
4025 private void onUnloadSoundEffects() {
4026 synchronized (mSoundEffectsLock) {
4027 if (mSoundPool == null) {
4028 return;
4029 }
4030
4031 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
4032 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
4033 poolId[fileIdx] = 0;
4034 }
4035
4036 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
4037 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
4038 continue;
4039 }
4040 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
4041 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
4042 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
4043 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
4044 }
4045 }
4046 mSoundPool.release();
4047 mSoundPool = null;
4048 }
4049 }
4050
4051 private void onPlaySoundEffect(int effectType, int volume) {
4052 synchronized (mSoundEffectsLock) {
4053
4054 onLoadSoundEffects();
4055
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004056 if (mSoundPool == null) {
4057 return;
4058 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004059 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08004060 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004061 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07004062 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004063 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07004064 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07004065 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004066
4067 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004068 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
4069 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004070 } else {
4071 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004072 try {
Eric Laurente78fced2013-03-15 16:03:47 -07004073 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
4074 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004075 mediaPlayer.setDataSource(filePath);
4076 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
4077 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08004078 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08004079 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
4080 public void onCompletion(MediaPlayer mp) {
4081 cleanupPlayer(mp);
4082 }
4083 });
4084 mediaPlayer.setOnErrorListener(new OnErrorListener() {
4085 public boolean onError(MediaPlayer mp, int what, int extra) {
4086 cleanupPlayer(mp);
4087 return true;
4088 }
4089 });
4090 mediaPlayer.start();
4091 } catch (IOException ex) {
4092 Log.w(TAG, "MediaPlayer IOException: "+ex);
4093 } catch (IllegalArgumentException ex) {
4094 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
4095 } catch (IllegalStateException ex) {
4096 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004097 }
4098 }
4099 }
4100 }
4101
4102 private void cleanupPlayer(MediaPlayer mp) {
4103 if (mp != null) {
4104 try {
4105 mp.stop();
4106 mp.release();
4107 } catch (IllegalStateException ex) {
4108 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
4109 }
4110 }
4111 }
4112
Eric Laurentfa640152011-03-12 15:59:51 -08004113 private void setForceUse(int usage, int config) {
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004114 synchronized (mConnectedDevices) {
4115 setForceUseInt_SyncDevices(usage, config);
4116 }
Eric Laurentfa640152011-03-12 15:59:51 -08004117 }
4118
Eric Laurent05274f32012-11-29 12:48:18 -08004119 private void onPersistSafeVolumeState(int state) {
4120 Settings.Global.putInt(mContentResolver,
4121 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
4122 state);
4123 }
4124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004125 @Override
4126 public void handleMessage(Message msg) {
Eric Laurentafbb0472011-12-15 09:04:23 -08004127 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004128
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004129 case MSG_SET_DEVICE_VOLUME:
4130 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
4131 break;
4132
4133 case MSG_SET_ALL_VOLUMES:
4134 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004135 break;
4136
4137 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07004138 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004139 break;
4140
Mike Lockwood5c55a052011-12-15 17:21:44 -05004141 case MSG_PERSIST_MASTER_VOLUME:
Eric Laurent83a017b2013-03-19 18:15:31 -07004142 if (mUseFixedVolume) {
4143 return;
4144 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004145 Settings.System.putFloatForUser(mContentResolver,
4146 Settings.System.VOLUME_MASTER,
RoboErik8a2cfc32014-05-16 11:19:38 -07004147 msg.arg1 / (float)1000.0,
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004148 UserHandle.USER_CURRENT);
Mike Lockwood5c55a052011-12-15 17:21:44 -05004149 break;
4150
Justin Koh57978ed2012-04-03 17:37:58 -07004151 case MSG_PERSIST_MASTER_VOLUME_MUTE:
Eric Laurent83a017b2013-03-19 18:15:31 -07004152 if (mUseFixedVolume) {
4153 return;
4154 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004155 Settings.System.putIntForUser(mContentResolver,
4156 Settings.System.VOLUME_MASTER_MUTE,
4157 msg.arg1,
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004158 msg.arg2);
Justin Koh57978ed2012-04-03 17:37:58 -07004159 break;
4160
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004161 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08004162 // note that the value persisted is the current ringer mode, not the
4163 // value of ringer mode as of the time the request was made to persist
John Spurlock661f2cf2014-11-17 10:29:10 -05004164 persistRingerMode(getRingerModeInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004165 break;
4166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004167 case MSG_MEDIA_SERVER_DIED:
Eric Laurenteb4b8a22014-07-21 13:10:07 -07004168 if (!mSystemReady ||
4169 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Eric Laurent89e74ba2009-09-30 18:26:36 -07004170 Log.e(TAG, "Media server died.");
Eric Laurentafbb0472011-12-15 09:04:23 -08004171 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent89e74ba2009-09-30 18:26:36 -07004172 null, 500);
Eric Laurentdfb881f2013-07-18 14:41:39 -07004173 break;
Eric Laurent89e74ba2009-09-30 18:26:36 -07004174 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004175 Log.e(TAG, "Media server started.");
Eric Laurentdfb881f2013-07-18 14:41:39 -07004176
Eric Laurent3c652ca2010-06-21 20:46:26 -07004177 // indicate to audio HAL that we start the reconfiguration phase after a media
4178 // server crash
Eric Laurentdfb881f2013-07-18 14:41:39 -07004179 // Note that we only execute this when the media server
Eric Laurent3c652ca2010-06-21 20:46:26 -07004180 // process restarts after a crash, not the first time it is started.
4181 AudioSystem.setParameters("restarting=true");
4182
Glenn Kastenfd116ad2013-07-12 17:10:39 -07004183 readAndSetLowRamDevice();
4184
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004185 // Restore device connection states
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004186 synchronized (mConnectedDevices) {
4187 Set set = mConnectedDevices.entrySet();
4188 Iterator i = set.iterator();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004189 while (i.hasNext()) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004190 Map.Entry device = (Map.Entry)i.next();
4191 AudioSystem.setDeviceConnectionState(
4192 ((Integer)device.getKey()).intValue(),
4193 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004194 (String)device.getValue(),
4195 "unknown-device");
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004196 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004197 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004198 // Restore call state
4199 AudioSystem.setPhoneState(mMode);
4200
Eric Laurentd5603c12009-08-06 08:49:39 -07004201 // Restore forced usage for communcations and record
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004202 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
Eric Laurentd5603c12009-08-06 08:49:39 -07004203 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
Eric Laurentdd45d012012-10-08 09:04:34 -07004204 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
4205 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004206
Eric Laurenta553c252009-07-17 12:17:14 -07004207 // Restore stream volumes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004208 int numStreamTypes = AudioSystem.getNumStreamTypes();
4209 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004210 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004211 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004212
4213 streamState.applyAllVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004214 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004215
4216 // Restore ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05004217 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3c652ca2010-06-21 20:46:26 -07004218
Mike Lockwood90631542012-01-06 11:20:37 -05004219 // Restore master volume
4220 restoreMasterVolume();
4221
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004222 // Reset device orientation (if monitored for this device)
Eric Laurentd640bd32012-09-28 18:01:48 -07004223 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004224 setOrientationForAudioSystem();
4225 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004226 if (mMonitorRotation) {
4227 setRotationForAudioSystem();
4228 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004229
Eric Laurent78472112012-05-21 08:57:21 -07004230 synchronized (mBluetoothA2dpEnabledLock) {
4231 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
4232 mBluetoothA2dpEnabled ?
4233 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
4234 }
Eric Laurentbff5ca52012-11-02 16:48:26 -07004235
4236 synchronized (mSettingsLock) {
4237 AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
4238 mDockAudioMediaEnabled ?
4239 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
4240 }
Eric Laurent212532b2014-07-21 15:43:18 -07004241 if (mHdmiManager != null) {
4242 synchronized (mHdmiManager) {
4243 if (mHdmiTvClient != null) {
4244 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
4245 }
4246 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004247 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08004248
4249 synchronized (mAudioPolicies) {
4250 for(AudioPolicyProxy policy : mAudioPolicies.values()) {
4251 policy.connectMixes();
4252 }
4253 }
4254
Eric Laurent3c652ca2010-06-21 20:46:26 -07004255 // indicate the end of reconfiguration phase to audio HAL
4256 AudioSystem.setParameters("restarting=false");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004257 break;
4258
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004259 case MSG_UNLOAD_SOUND_EFFECTS:
4260 onUnloadSoundEffects();
4261 break;
4262
Eric Laurent117b7bb2011-01-16 17:07:27 -08004263 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004264 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
4265 // can take several dozens of milliseconds to complete
4266 boolean loaded = onLoadSoundEffects();
4267 if (msg.obj != null) {
4268 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
4269 synchronized (reply) {
4270 reply.mStatus = loaded ? 0 : -1;
4271 reply.notify();
4272 }
4273 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08004274 break;
4275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004276 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004277 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004278 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004279
4280 case MSG_BTA2DP_DOCK_TIMEOUT:
4281 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004282 synchronized (mConnectedDevices) {
4283 makeA2dpDeviceUnavailableNow( (String) msg.obj );
4284 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004285 break;
Eric Laurentfa640152011-03-12 15:59:51 -08004286
4287 case MSG_SET_FORCE_USE:
Eric Laurentc390bed2012-07-03 12:24:05 -07004288 case MSG_SET_FORCE_BT_A2DP_USE:
Eric Laurentfa640152011-03-12 15:59:51 -08004289 setForceUse(msg.arg1, msg.arg2);
4290 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07004291
Eric Laurentdc03c612011-04-01 10:59:41 -07004292 case MSG_BT_HEADSET_CNCT_FAILED:
4293 resetBluetoothSco();
4294 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004295
4296 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
Paul McLean10804eb2015-01-28 11:16:35 -08004297 { WiredDeviceConnectionState connectState =
4298 (WiredDeviceConnectionState)msg.obj;
4299 onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
4300 connectState.mAddress, connectState.mName);
4301 mAudioEventWakeLock.release();
4302 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004303 break;
4304
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004305 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
4306 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
4307 mAudioEventWakeLock.release();
4308 break;
4309
4310 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
4311 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004312 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004313 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004314
4315 case MSG_REPORT_NEW_ROUTES: {
4316 int N = mRoutesObservers.beginBroadcast();
4317 if (N > 0) {
4318 AudioRoutesInfo routes;
4319 synchronized (mCurAudioRoutes) {
4320 routes = new AudioRoutesInfo(mCurAudioRoutes);
4321 }
4322 while (N > 0) {
4323 N--;
4324 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
4325 try {
4326 obs.dispatchAudioRoutesChanged(routes);
4327 } catch (RemoteException e) {
4328 }
4329 }
4330 }
4331 mRoutesObservers.finishBroadcast();
4332 break;
4333 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004334
Eric Laurentc34dcc12012-09-10 13:51:52 -07004335 case MSG_CHECK_MUSIC_ACTIVE:
4336 onCheckMusicActive();
4337 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004338
4339 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
4340 onSendBecomingNoisyIntent();
4341 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07004342
4343 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
4344 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
4345 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
4346 break;
Eric Laurent05274f32012-11-29 12:48:18 -08004347 case MSG_PERSIST_SAFE_VOLUME_STATE:
4348 onPersistSafeVolumeState(msg.arg1);
4349 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08004350
Eric Laurent2a57ca92013-03-07 17:29:27 -08004351 case MSG_BROADCAST_BT_CONNECTION_STATE:
4352 onBroadcastScoConnectionState(msg.arg1);
4353 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004354
4355 case MSG_SYSTEM_READY:
4356 onSystemReady();
4357 break;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004358
4359 case MSG_PERSIST_MUSIC_ACTIVE_MS:
4360 final int musicActiveMs = msg.arg1;
4361 Settings.Secure.putIntForUser(mContentResolver,
4362 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
4363 UserHandle.USER_CURRENT);
4364 break;
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004365 case MSG_PERSIST_MICROPHONE_MUTE:
4366 Settings.System.putIntForUser(mContentResolver,
4367 Settings.System.MICROPHONE_MUTE,
4368 msg.arg1,
4369 msg.arg2);
4370 break;
RoboErik5452e252015-02-06 15:33:53 -08004371 case MSG_UNMUTE_STREAM:
4372 onUnmuteStream(msg.arg1, msg.arg2);
4373 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004374 }
4375 }
4376 }
4377
Jason Parekhb1096152009-03-24 17:48:25 -07004378 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07004379
Jason Parekhb1096152009-03-24 17:48:25 -07004380 SettingsObserver() {
4381 super(new Handler());
4382 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4383 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004384 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4385 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07004386 }
4387
4388 @Override
4389 public void onChange(boolean selfChange) {
4390 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08004391 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
4392 // However there appear to be some missing locks around mRingerModeMutedStreams
4393 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
4394 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07004395 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004396 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07004397 /*
4398 * Ensure all stream types that should be affected by ringer mode
4399 * are in the proper state.
4400 */
John Spurlock661f2cf2014-11-17 10:29:10 -05004401 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurenta553c252009-07-17 12:17:14 -07004402 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004403 readDockAudioSettings(mContentResolver);
Eric Laurenta553c252009-07-17 12:17:14 -07004404 }
Jason Parekhb1096152009-03-24 17:48:25 -07004405 }
Jason Parekhb1096152009-03-24 17:48:25 -07004406 }
Eric Laurenta553c252009-07-17 12:17:14 -07004407
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004408 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004409 private void makeA2dpDeviceAvailable(String address) {
Eric Laurent78472112012-05-21 08:57:21 -07004410 // enable A2DP before notifying A2DP connection to avoid unecessary processing in
4411 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004412 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4413 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4414 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Eric Laurent78472112012-05-21 08:57:21 -07004415 setBluetoothA2dpOnInt(true);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004416 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4417 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004418 address,
4419 "a2dp-device");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004420 // Reset A2DP suspend state each time a new sink is connected
4421 AudioSystem.setParameters("A2dpSuspended=false");
4422 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
4423 address);
4424 }
4425
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004426 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004427 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07004428 }
4429
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004430 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004431 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004432 synchronized (mA2dpAvrcpLock) {
4433 mAvrcpAbsVolSupported = false;
4434 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004435 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4436 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004437 address,
4438 "a2dp-device");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004439 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
RoboErik5535ea82014-09-25 14:53:16 -07004440 synchronized (mCurAudioRoutes) {
4441 // Remove A2DP routes as well
John Spurlock61560172015-02-06 19:46:04 -05004442 if (mCurAudioRoutes.bluetoothName != null) {
4443 mCurAudioRoutes.bluetoothName = null;
RoboErik5535ea82014-09-25 14:53:16 -07004444 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4445 SENDMSG_NOOP, 0, 0, null, 0);
4446 }
4447 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004448 }
4449
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004450 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004451 private void makeA2dpDeviceUnavailableLater(String address) {
Eric Laurent3b591262010-04-20 07:01:00 -07004452 // prevent any activity on the A2DP audio output to avoid unwanted
4453 // reconnection of the sink.
4454 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004455 // the device will be made unavailable later, so consider it disconnected right away
4456 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
4457 // send the delayed message to make the device unavailable later
4458 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
4459 mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
4460
4461 }
4462
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004463 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004464 private void makeA2dpSrcAvailable(String address) {
4465 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
4466 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004467 address,
4468 "a2dp-device");
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004469 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
4470 address);
4471 }
4472
4473 // must be called synchronized on mConnectedDevices
4474 private void makeA2dpSrcUnavailable(String address) {
4475 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
4476 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004477 address,
4478 "a2dp-device");
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004479 mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
4480 }
4481
4482 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004483 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004484 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4485 }
4486
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004487 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004488 private boolean hasScheduledA2dpDockTimeout() {
4489 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4490 }
4491
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004492 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004493 {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004494 if (DEBUG_VOL) {
4495 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
4496 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004497 if (btDevice == null) {
4498 return;
4499 }
4500 String address = btDevice.getAddress();
4501 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4502 address = "";
4503 }
John Du5a0cf7a2013-07-19 11:30:34 -07004504
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004505 synchronized (mConnectedDevices) {
4506 boolean isConnected =
4507 (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
4508 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
4509
4510 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4511 if (btDevice.isBluetoothDock()) {
4512 if (state == BluetoothProfile.STATE_DISCONNECTED) {
4513 // introduction of a delay for transient disconnections of docks when
4514 // power is rapidly turned off/on, this message will be canceled if
4515 // we reconnect the dock under a preset delay
4516 makeA2dpDeviceUnavailableLater(address);
4517 // the next time isConnected is evaluated, it will be false for the dock
4518 }
4519 } else {
4520 makeA2dpDeviceUnavailableNow(address);
4521 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07004522 synchronized (mCurAudioRoutes) {
John Spurlock61560172015-02-06 19:46:04 -05004523 if (mCurAudioRoutes.bluetoothName != null) {
4524 mCurAudioRoutes.bluetoothName = null;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004525 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4526 SENDMSG_NOOP, 0, 0, null, 0);
4527 }
4528 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004529 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4530 if (btDevice.isBluetoothDock()) {
4531 // this could be a reconnection after a transient disconnection
4532 cancelA2dpDeviceTimeout();
4533 mDockAddress = address;
4534 } else {
4535 // this could be a connection of another A2DP device before the timeout of
4536 // a dock: cancel the dock timeout, and make the dock unavailable now
4537 if(hasScheduledA2dpDockTimeout()) {
4538 cancelA2dpDeviceTimeout();
4539 makeA2dpDeviceUnavailableNow(mDockAddress);
4540 }
4541 }
4542 makeA2dpDeviceAvailable(address);
Dianne Hackborn632ca412012-06-14 19:34:10 -07004543 synchronized (mCurAudioRoutes) {
4544 String name = btDevice.getAliasName();
John Spurlock61560172015-02-06 19:46:04 -05004545 if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
4546 mCurAudioRoutes.bluetoothName = name;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004547 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4548 SENDMSG_NOOP, 0, 0, null, 0);
4549 }
4550 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004551 }
4552 }
4553 }
4554
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004555 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
4556 {
4557 if (DEBUG_VOL) {
4558 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
4559 }
4560 if (btDevice == null) {
4561 return;
4562 }
4563 String address = btDevice.getAddress();
4564 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4565 address = "";
4566 }
4567
4568 synchronized (mConnectedDevices) {
4569 boolean isConnected =
4570 (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
4571 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));
4572
4573 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4574 makeA2dpSrcUnavailable(address);
4575 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4576 makeA2dpSrcAvailable(address);
4577 }
4578 }
4579 }
4580
John Du5a0cf7a2013-07-19 11:30:34 -07004581 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
4582 // address is not used for now, but may be used when multiple a2dp devices are supported
4583 synchronized (mA2dpAvrcpLock) {
4584 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004585 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07004586 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4587 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4588 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4589 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4590 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07004591 }
4592 }
4593
Paul McLean10804eb2015-01-28 11:16:35 -08004594 private boolean handleDeviceConnection(boolean connect, int device, String address, String deviceName) {
4595 Slog.i(TAG, "handleDeviceConnection(" + connect +
4596 " dev:" + Integer.toHexString(device) +
RoboErik5452e252015-02-06 15:33:53 -08004597 " address:" + address +
Paul McLean10804eb2015-01-28 11:16:35 -08004598 " name:" + deviceName + ")");
Eric Laurent59f48272012-04-05 19:42:21 -07004599 synchronized (mConnectedDevices) {
4600 boolean isConnected = (mConnectedDevices.containsKey(device) &&
Paul McLean10804eb2015-01-28 11:16:35 -08004601 (address.isEmpty() || mConnectedDevices.get(device).equals(address)));
Eric Laurent59f48272012-04-05 19:42:21 -07004602
Paul McLean10804eb2015-01-28 11:16:35 -08004603 if (isConnected && !connect) {
Eric Laurent59f48272012-04-05 19:42:21 -07004604 AudioSystem.setDeviceConnectionState(device,
4605 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004606 address, deviceName);
Eric Laurent59f48272012-04-05 19:42:21 -07004607 mConnectedDevices.remove(device);
4608 return true;
Paul McLean10804eb2015-01-28 11:16:35 -08004609 } else if (!isConnected && connect) {
Eric Laurent59f48272012-04-05 19:42:21 -07004610 AudioSystem.setDeviceConnectionState(device,
4611 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004612 address, deviceName);
4613 mConnectedDevices.put(new Integer(device), address);
Eric Laurent59f48272012-04-05 19:42:21 -07004614 return true;
4615 }
4616 }
4617 return false;
4618 }
4619
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004620 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4621 // sent if none of these devices is connected.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004622 // Access synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004623 int mBecomingNoisyIntentDevices =
4624 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07004625 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07004626 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004627 AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004628
4629 // must be called before removing the device from mConnectedDevices
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004630 // Called synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004631 private int checkSendBecomingNoisyIntent(int device, int state) {
4632 int delay = 0;
4633 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4634 int devices = 0;
4635 for (int dev : mConnectedDevices.keySet()) {
Eric Laurent27c30e42014-08-27 12:36:33 -07004636 if (((dev & AudioSystem.DEVICE_BIT_IN) == 0) &&
4637 ((dev & mBecomingNoisyIntentDevices) != 0)) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004638 devices |= dev;
4639 }
4640 }
4641 if (devices == device) {
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004642 sendMsg(mAudioHandler,
4643 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4644 SENDMSG_REPLACE,
4645 0,
4646 0,
4647 null,
4648 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004649 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004650 }
4651 }
4652
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004653 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
4654 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004655 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004656 synchronized (mLastDeviceConnectMsgTime) {
4657 long time = SystemClock.uptimeMillis();
4658 if (mLastDeviceConnectMsgTime > time) {
Matthew Xiec525cf72015-01-22 20:13:17 -08004659 delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004660 }
4661 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004662 }
4663 return delay;
4664 }
4665
Paul McLean10804eb2015-01-28 11:16:35 -08004666 private void sendDeviceConnectionIntent(int device, int state, String address, String deviceName)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004667 {
Paul McLean10804eb2015-01-28 11:16:35 -08004668 Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
4669 " state:0x" + Integer.toHexString(state) +
4670 " address:" + address +
4671 " name:" + deviceName + ");");
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004672 Intent intent = new Intent();
4673
Paul McLean10804eb2015-01-28 11:16:35 -08004674 intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
4675 intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
4676 intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
4677
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004678 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4679
Dianne Hackborn632ca412012-06-14 19:34:10 -07004680 int connType = 0;
4681
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004682 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004683 connType = AudioRoutesInfo.MAIN_HEADSET;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004684 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4685 intent.putExtra("microphone", 1);
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004686 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
4687 device == AudioSystem.DEVICE_OUT_LINE) {
4688 /*do apps care about line-out vs headphones?*/
Dianne Hackborn632ca412012-06-14 19:34:10 -07004689 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004690 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4691 intent.putExtra("microphone", 0);
Eric Laurent6fa42452015-01-09 15:09:40 -08004692 } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
4693 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004694 connType = AudioRoutesInfo.MAIN_HDMI;
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004695 configureHdmiPlugIntent(intent, state);
Paul McLean10804eb2015-01-28 11:16:35 -08004696 } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE) {
4697 connType = AudioRoutesInfo.MAIN_USB;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004698 }
4699
Dianne Hackborn632ca412012-06-14 19:34:10 -07004700 synchronized (mCurAudioRoutes) {
4701 if (connType != 0) {
John Spurlock61560172015-02-06 19:46:04 -05004702 int newConn = mCurAudioRoutes.mainType;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004703 if (state != 0) {
4704 newConn |= connType;
4705 } else {
4706 newConn &= ~connType;
4707 }
John Spurlock61560172015-02-06 19:46:04 -05004708 if (newConn != mCurAudioRoutes.mainType) {
4709 mCurAudioRoutes.mainType = newConn;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004710 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4711 SENDMSG_NOOP, 0, 0, null, 0);
4712 }
4713 }
4714 }
4715
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004716 final long ident = Binder.clearCallingIdentity();
4717 try {
4718 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
4719 } finally {
4720 Binder.restoreCallingIdentity(ident);
4721 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004722 }
4723
Paul McLean10804eb2015-01-28 11:16:35 -08004724 private void onSetWiredDeviceConnectionState(int device, int state, String address,
4725 String deviceName)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004726 {
Paul McLean10804eb2015-01-28 11:16:35 -08004727 Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
4728 + " state:" + Integer.toHexString(state)
4729 + " address:" + address
4730 + " deviceName:" + deviceName + ");");
4731
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004732 synchronized (mConnectedDevices) {
4733 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004734 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4735 (device == AudioSystem.DEVICE_OUT_LINE))) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004736 setBluetoothA2dpOnInt(true);
4737 }
Eric Laurentae4506e2014-05-29 16:04:32 -07004738 boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
4739 (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
4740 ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
Paul McLean10804eb2015-01-28 11:16:35 -08004741 handleDeviceConnection(state == 1, device, address, deviceName);
Eric Laurentf1a457d2012-09-20 16:27:23 -07004742 if (state != 0) {
4743 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004744 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4745 (device == AudioSystem.DEVICE_OUT_LINE)) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07004746 setBluetoothA2dpOnInt(false);
4747 }
4748 if ((device & mSafeMediaVolumeDevices) != 0) {
4749 sendMsg(mAudioHandler,
4750 MSG_CHECK_MUSIC_ACTIVE,
4751 SENDMSG_REPLACE,
4752 0,
4753 0,
4754 null,
4755 MUSIC_ACTIVE_POLL_PERIOD_MS);
4756 }
Eric Laurent212532b2014-07-21 15:43:18 -07004757 // Television devices without CEC service apply software volume on HDMI output
4758 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4759 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
4760 checkAllFixedVolumeDevices();
4761 if (mHdmiManager != null) {
4762 synchronized (mHdmiManager) {
4763 if (mHdmiPlaybackClient != null) {
4764 mHdmiCecSink = false;
4765 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
4766 }
4767 }
4768 }
4769 }
4770 } else {
4771 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4772 if (mHdmiManager != null) {
4773 synchronized (mHdmiManager) {
4774 mHdmiCecSink = false;
4775 }
4776 }
4777 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004778 }
Paul McLean10804eb2015-01-28 11:16:35 -08004779 if (!isUsb && device != AudioSystem.DEVICE_IN_WIRED_HEADSET) {
4780 sendDeviceConnectionIntent(device, state, address, deviceName);
Mike Lockwooddb454842012-09-18 11:16:57 -07004781 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004782 }
4783 }
4784
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004785 private void configureHdmiPlugIntent(Intent intent, int state) {
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004786 intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
4787 intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004788 if (state == 1) {
4789 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
4790 int[] portGeneration = new int[1];
4791 int status = AudioSystem.listAudioPorts(ports, portGeneration);
4792 if (status == AudioManager.SUCCESS) {
4793 for (AudioPort port : ports) {
4794 if (port instanceof AudioDevicePort) {
4795 final AudioDevicePort devicePort = (AudioDevicePort) port;
Eric Laurent6fa42452015-01-09 15:09:40 -08004796 if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
4797 devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004798 // format the list of supported encodings
4799 int[] formats = devicePort.formats();
4800 if (formats.length > 0) {
4801 ArrayList<Integer> encodingList = new ArrayList(1);
4802 for (int format : formats) {
4803 // a format in the list can be 0, skip it
4804 if (format != AudioFormat.ENCODING_INVALID) {
4805 encodingList.add(format);
4806 }
4807 }
4808 int[] encodingArray = new int[encodingList.size()];
4809 for (int i = 0 ; i < encodingArray.length ; i++) {
4810 encodingArray[i] = encodingList.get(i);
4811 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004812 intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004813 }
4814 // find the maximum supported number of channels
4815 int maxChannels = 0;
4816 for (int mask : devicePort.channelMasks()) {
4817 int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
4818 if (channelCount > maxChannels) {
4819 maxChannels = channelCount;
4820 }
4821 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004822 intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004823 }
4824 }
4825 }
4826 }
4827 }
4828 }
4829
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004830 /* cache of the address of the last dock the device was connected to */
4831 private String mDockAddress;
4832
Eric Laurenta553c252009-07-17 12:17:14 -07004833 /**
4834 * Receiver for misc intent broadcasts the Phone app cares about.
4835 */
4836 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4837 @Override
4838 public void onReceive(Context context, Intent intent) {
4839 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07004840 int outDevice;
4841 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07004842 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07004843
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004844 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4845 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4846 Intent.EXTRA_DOCK_STATE_UNDOCKED);
4847 int config;
4848 switch (dockState) {
4849 case Intent.EXTRA_DOCK_STATE_DESK:
4850 config = AudioSystem.FORCE_BT_DESK_DOCK;
4851 break;
4852 case Intent.EXTRA_DOCK_STATE_CAR:
4853 config = AudioSystem.FORCE_BT_CAR_DOCK;
4854 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004855 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08004856 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004857 break;
4858 case Intent.EXTRA_DOCK_STATE_HE_DESK:
4859 config = AudioSystem.FORCE_DIGITAL_DOCK;
4860 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004861 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4862 default:
4863 config = AudioSystem.FORCE_NONE;
4864 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08004865 // Low end docks have a menu to enable or disable audio
4866 // (see mDockAudioMediaEnabled)
4867 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
4868 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
4869 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
4870 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
4871 }
4872 mDockState = dockState;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004873 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
Eric Laurent59f48272012-04-05 19:42:21 -07004874 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004875 BluetoothProfile.STATE_DISCONNECTED);
Eric Laurentae4506e2014-05-29 16:04:32 -07004876 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
4877 inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
Nick Pellya56d1c72009-08-19 14:49:29 -07004878 String address = null;
Eric Laurentdca56b92011-09-02 14:20:56 -07004879
4880 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
4881 if (btDevice == null) {
4882 return;
4883 }
4884
4885 address = btDevice.getAddress();
4886 BluetoothClass btClass = btDevice.getBluetoothClass();
4887 if (btClass != null) {
4888 switch (btClass.getDeviceClass()) {
4889 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
4890 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
Eric Laurentae4506e2014-05-29 16:04:32 -07004891 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurentdca56b92011-09-02 14:20:56 -07004892 break;
4893 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
Eric Laurentae4506e2014-05-29 16:04:32 -07004894 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurentdca56b92011-09-02 14:20:56 -07004895 break;
Eric Laurentd5603c12009-08-06 08:49:39 -07004896 }
4897 }
4898
Eric Laurentdca56b92011-09-02 14:20:56 -07004899 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4900 address = "";
4901 }
Eric Laurentd5603c12009-08-06 08:49:39 -07004902
Eric Laurent59f48272012-04-05 19:42:21 -07004903 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
Paul McLean10804eb2015-01-28 11:16:35 -08004904 boolean success =
4905 handleDeviceConnection(connected, outDevice, address, "Bluetooth Headset") &&
4906 handleDeviceConnection(connected, inDevice, address, "Bluetooth Headset");
Eric Laurentae4506e2014-05-29 16:04:32 -07004907 if (success) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004908 synchronized (mScoClients) {
Eric Laurent59f48272012-04-05 19:42:21 -07004909 if (connected) {
4910 mBluetoothHeadsetDevice = btDevice;
4911 } else {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004912 mBluetoothHeadsetDevice = null;
4913 resetBluetoothSco();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004914 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004915 }
Eric Laurenta553c252009-07-17 12:17:14 -07004916 }
Paul McLeandf361462014-04-10 16:02:55 -07004917 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004918 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07004919 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004920 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004921 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07004922 // broadcast intent if the connection was initated by AudioService
4923 if (!mScoClients.isEmpty() &&
4924 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
4925 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
4926 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004927 broadcast = true;
4928 }
4929 switch (btState) {
4930 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004931 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07004932 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4933 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4934 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004935 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004936 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004937 break;
4938 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004939 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08004940 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07004941 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08004942 break;
4943 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07004944 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4945 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4946 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004947 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004948 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004949 default:
4950 // do not broadcast CONNECTING or invalid state
4951 broadcast = false;
4952 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004953 }
4954 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004955 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07004956 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07004957 //FIXME: this is to maintain compatibility with deprecated intent
4958 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08004959 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07004960 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004961 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08004962 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004963 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06004964 if (mMonitorRotation) {
4965 mOrientationListener.onOrientationChanged(0); //argument is ignored anyway
4966 mOrientationListener.enable();
4967 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004968 AudioSystem.setParameters("screen_state=on");
4969 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06004970 if (mMonitorRotation) {
4971 //reduce wakeups (save current) by only listening when display is on
4972 mOrientationListener.disable();
4973 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004974 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07004975 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004976 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004977 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004978 // attempt to stop music playback for background user
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004979 sendMsg(mAudioHandler,
4980 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4981 SENDMSG_REPLACE,
4982 0,
4983 0,
4984 null,
4985 0);
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004986 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004987 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004988
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004989 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004990 readAudioSettings(true /*userSwitch*/);
4991 // preserve STREAM_MUSIC volume from one user to the next.
4992 sendMsg(mAudioHandler,
4993 MSG_SET_ALL_VOLUMES,
4994 SENDMSG_QUEUE,
4995 0,
4996 0,
4997 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Eric Laurenta553c252009-07-17 12:17:14 -07004998 }
4999 }
Paul McLeanc837a452014-04-09 09:04:43 -07005000 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005001
5002 //==========================================================================================
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005003 // RemoteControlDisplay / RemoteControlClient / Remote info
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005004 //==========================================================================================
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07005005 public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
5006 ComponentName listenerComp) {
5007 return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
5008 }
5009
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07005010 public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07005011 return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07005012 }
Jean-Michel Trivid327f212010-03-16 21:44:33 -07005013
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005014 public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005015 mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005016 }
5017
5018 public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005019 mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07005020 }
5021
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07005022 public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
5023 boolean wantsSync) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005024 mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
5025 }
5026
John Spurlock3346a802014-05-20 16:25:37 -04005027 @Override
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005028 public void setRemoteStreamVolume(int index) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005029 enforceVolumeController("set the remote stream volume");
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005030 mMediaFocusControl.setRemoteStreamVolume(index);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005031 }
5032
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005033 //==========================================================================================
5034 // Audio Focus
5035 //==========================================================================================
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005036 public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005037 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005038 IAudioPolicyCallback pcb) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005039 // permission checks
5040 if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
John Spurlock61560172015-02-06 19:46:04 -05005041 if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005042 if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
5043 android.Manifest.permission.MODIFY_PHONE_STATE)) {
5044 Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
5045 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5046 }
5047 } else {
5048 // only a registered audio policy can be used to lock focus
5049 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005050 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
5051 Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005052 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5053 }
5054 }
5055 }
5056 }
5057
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08005058 return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
5059 clientId, callingPackageName, flags);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005060 }
5061
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005062 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
5063 return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005064 }
5065
5066 public void unregisterAudioFocusClient(String clientId) {
5067 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07005068 }
5069
Jean-Michel Trivi23805662013-07-31 14:19:18 -07005070 public int getCurrentAudioFocus() {
5071 return mMediaFocusControl.getCurrentAudioFocus();
5072 }
5073
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005074 //==========================================================================================
5075 // Device orientation
5076 //==========================================================================================
5077 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005078 * Handles device configuration changes that may map to a change in the orientation
5079 * or orientation.
5080 * Monitoring orientation and rotation is optional, and is defined by the definition and value
5081 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005082 */
5083 private void handleConfigurationChanged(Context context) {
5084 try {
5085 // reading new orientation "safely" (i.e. under try catch) in case anything
5086 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07005087 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005088 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07005089 if (mMonitorOrientation) {
5090 int newOrientation = config.orientation;
5091 if (newOrientation != mDeviceOrientation) {
5092 mDeviceOrientation = newOrientation;
5093 setOrientationForAudioSystem();
5094 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005095 }
Eric Laurentd640bd32012-09-28 18:01:48 -07005096 sendMsg(mAudioHandler,
5097 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
5098 SENDMSG_REPLACE,
5099 0,
5100 0,
5101 null,
5102 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07005103
5104 boolean cameraSoundForced = mContext.getResources().getBoolean(
5105 com.android.internal.R.bool.config_camera_sound_forced);
5106 synchronized (mSettingsLock) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005107 boolean cameraSoundForcedChanged = false;
Eric Laurentdd45d012012-10-08 09:04:34 -07005108 synchronized (mCameraSoundForced) {
5109 if (cameraSoundForced != mCameraSoundForced) {
5110 mCameraSoundForced = cameraSoundForced;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005111 cameraSoundForcedChanged = true;
Eric Laurentdd45d012012-10-08 09:04:34 -07005112 }
5113 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005114 if (cameraSoundForcedChanged) {
5115 if (!isPlatformTelevision()) {
5116 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
5117 if (cameraSoundForced) {
5118 s.setAllIndexesToMax();
5119 mRingerModeAffectedStreams &=
5120 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5121 } else {
5122 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
5123 mRingerModeAffectedStreams |=
5124 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5125 }
5126 // take new state into account for streams muted by ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05005127 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005128 }
5129
5130 sendMsg(mAudioHandler,
5131 MSG_SET_FORCE_USE,
5132 SENDMSG_QUEUE,
5133 AudioSystem.FOR_SYSTEM,
5134 cameraSoundForced ?
5135 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
5136 null,
5137 0);
5138
5139 sendMsg(mAudioHandler,
5140 MSG_SET_ALL_VOLUMES,
5141 SENDMSG_QUEUE,
5142 0,
5143 0,
5144 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
5145 }
Eric Laurentdd45d012012-10-08 09:04:34 -07005146 }
John Spurlock3346a802014-05-20 16:25:37 -04005147 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005148 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005149 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005150 }
5151 }
5152
5153 private void setOrientationForAudioSystem() {
5154 switch (mDeviceOrientation) {
5155 case Configuration.ORIENTATION_LANDSCAPE:
5156 //Log.i(TAG, "orientation is landscape");
5157 AudioSystem.setParameters("orientation=landscape");
5158 break;
5159 case Configuration.ORIENTATION_PORTRAIT:
5160 //Log.i(TAG, "orientation is portrait");
5161 AudioSystem.setParameters("orientation=portrait");
5162 break;
5163 case Configuration.ORIENTATION_SQUARE:
5164 //Log.i(TAG, "orientation is square");
5165 AudioSystem.setParameters("orientation=square");
5166 break;
5167 case Configuration.ORIENTATION_UNDEFINED:
5168 //Log.i(TAG, "orientation is undefined");
5169 AudioSystem.setParameters("orientation=undefined");
5170 break;
5171 default:
5172 Log.e(TAG, "Unknown orientation");
5173 }
5174 }
5175
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005176 private void setRotationForAudioSystem() {
5177 switch (mDeviceRotation) {
5178 case Surface.ROTATION_0:
5179 AudioSystem.setParameters("rotation=0");
5180 break;
5181 case Surface.ROTATION_90:
5182 AudioSystem.setParameters("rotation=90");
5183 break;
5184 case Surface.ROTATION_180:
5185 AudioSystem.setParameters("rotation=180");
5186 break;
5187 case Surface.ROTATION_270:
5188 AudioSystem.setParameters("rotation=270");
5189 break;
5190 default:
5191 Log.e(TAG, "Unknown device rotation");
5192 }
5193 }
5194
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005195
Eric Laurent78472112012-05-21 08:57:21 -07005196 // Handles request to override default use of A2DP for media.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005197 // Must be called synchronized on mConnectedDevices
Eric Laurent78472112012-05-21 08:57:21 -07005198 public void setBluetoothA2dpOnInt(boolean on) {
5199 synchronized (mBluetoothA2dpEnabledLock) {
5200 mBluetoothA2dpEnabled = on;
Eric Laurentc390bed2012-07-03 12:24:05 -07005201 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005202 setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
Eric Laurentc390bed2012-07-03 12:24:05 -07005203 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
Eric Laurent78472112012-05-21 08:57:21 -07005204 }
5205 }
5206
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005207 // Must be called synchronized on mConnectedDevices
5208 private void setForceUseInt_SyncDevices(int usage, int config) {
5209 switch (usage) {
5210 case AudioSystem.FOR_MEDIA:
5211 if (config == AudioSystem.FORCE_NO_BT_A2DP) {
5212 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ALL_A2DP;
5213 } else { // config == AudioSystem.FORCE_NONE
5214 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
5215 }
5216 break;
5217 case AudioSystem.FOR_DOCK:
5218 if (config == AudioSystem.FORCE_ANALOG_DOCK) {
5219 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5220 } else { // config == AudioSystem.FORCE_NONE
5221 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5222 }
5223 break;
5224 default:
5225 // usage doesn't affect the broadcast of ACTION_AUDIO_BECOMING_NOISY
5226 }
5227 AudioSystem.setForceUse(usage, config);
5228 }
5229
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005230 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07005231 public void setRingtonePlayer(IRingtonePlayer player) {
5232 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5233 mRingtonePlayer = player;
5234 }
5235
5236 @Override
5237 public IRingtonePlayer getRingtonePlayer() {
5238 return mRingtonePlayer;
5239 }
5240
5241 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07005242 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5243 synchronized (mCurAudioRoutes) {
5244 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5245 mRoutesObservers.register(observer);
5246 return routes;
5247 }
5248 }
5249
Eric Laurentc34dcc12012-09-10 13:51:52 -07005250
5251 //==========================================================================================
5252 // Safe media volume management.
5253 // MUSIC stream volume level is limited when headphones are connected according to safety
5254 // regulation. When the user attempts to raise the volume above the limit, a warning is
5255 // displayed and the user has to acknowlegde before the volume is actually changed.
5256 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
5257 // property. Platforms with a different limit must set this property accordingly in their
5258 // overlay.
5259 //==========================================================================================
5260
Eric Laurentd640bd32012-09-28 18:01:48 -07005261 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
5262 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
5263 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
5264 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
5265 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
5266 // (when user opts out).
John Spurlock35134602014-07-24 18:10:48 -04005267 private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
5268 private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
5269 private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed
5270 private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
Eric Laurentd640bd32012-09-28 18:01:48 -07005271 private Integer mSafeMediaVolumeState;
5272
5273 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005274 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07005275 private int mSafeMediaVolumeIndex;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005276 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
5277 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
5278 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
5279 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
5280 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
5281 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
5282 private int mMusicActiveMs;
5283 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
5284 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07005285 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07005286
5287 private void setSafeMediaVolumeEnabled(boolean on) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005288 synchronized (mSafeMediaVolumeState) {
5289 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
5290 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
5291 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
5292 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
5293 enforceSafeMediaVolume();
5294 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
5295 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005296 mMusicActiveMs = 1; // nonzero = confirmed
5297 saveMusicActiveMs();
Eric Laurentd640bd32012-09-28 18:01:48 -07005298 sendMsg(mAudioHandler,
5299 MSG_CHECK_MUSIC_ACTIVE,
5300 SENDMSG_REPLACE,
5301 0,
5302 0,
5303 null,
5304 MUSIC_ACTIVE_POLL_PERIOD_MS);
5305 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005306 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005307 }
5308 }
5309
5310 private void enforceSafeMediaVolume() {
5311 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07005312 int devices = mSafeMediaVolumeDevices;
5313 int i = 0;
5314
5315 while (devices != 0) {
5316 int device = 1 << i++;
5317 if ((device & devices) == 0) {
5318 continue;
5319 }
Eric Laurent42b041e2013-03-29 11:36:03 -07005320 int index = streamState.getIndex(device);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005321 if (index > mSafeMediaVolumeIndex) {
Eric Laurent42b041e2013-03-29 11:36:03 -07005322 streamState.setIndex(mSafeMediaVolumeIndex, device);
5323 sendMsg(mAudioHandler,
5324 MSG_SET_DEVICE_VOLUME,
5325 SENDMSG_QUEUE,
5326 device,
5327 0,
5328 streamState,
5329 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005330 }
5331 devices &= ~device;
5332 }
5333 }
5334
5335 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005336 synchronized (mSafeMediaVolumeState) {
5337 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07005338 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
5339 ((device & mSafeMediaVolumeDevices) != 0) &&
5340 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005341 return false;
5342 }
5343 return true;
5344 }
5345 }
5346
John Spurlock3346a802014-05-20 16:25:37 -04005347 @Override
Eric Laurentc34dcc12012-09-10 13:51:52 -07005348 public void disableSafeMediaVolume() {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005349 enforceVolumeController("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07005350 synchronized (mSafeMediaVolumeState) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005351 setSafeMediaVolumeEnabled(false);
Eric Laurentfde16d52012-12-03 14:42:39 -08005352 if (mPendingVolumeCommand != null) {
5353 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
5354 mPendingVolumeCommand.mIndex,
5355 mPendingVolumeCommand.mFlags,
5356 mPendingVolumeCommand.mDevice);
5357 mPendingVolumeCommand = null;
5358 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005359 }
5360 }
5361
Jungshik Jang41d97462014-06-30 22:26:29 +09005362 //==========================================================================================
5363 // Hdmi Cec system audio mode.
5364 // If Hdmi Cec's system audio mode is on, audio service should notify volume change
5365 // to HdmiControlService so that audio recevier can handle volume change.
5366 //==========================================================================================
5367
Eric Laurent212532b2014-07-21 15:43:18 -07005368 private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
5369 public void onComplete(int status) {
5370 if (mHdmiManager != null) {
5371 synchronized (mHdmiManager) {
5372 mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
5373 // Television devices without CEC service apply software volume on HDMI output
5374 if (isPlatformTelevision() && !mHdmiCecSink) {
5375 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5376 }
5377 checkAllFixedVolumeDevices();
5378 }
5379 }
5380 }
5381 };
5382
Jungshik Jang41d97462014-06-30 22:26:29 +09005383 // If HDMI-CEC system audio is supported
5384 private boolean mHdmiSystemAudioSupported = false;
5385 // Set only when device is tv.
5386 private HdmiTvClient mHdmiTvClient;
Eric Laurent0b03f992014-11-18 18:08:02 -08005387 // true if the device has system feature PackageManager.FEATURE_LEANBACK.
Eric Laurent212532b2014-07-21 15:43:18 -07005388 // cached HdmiControlManager interface
5389 private HdmiControlManager mHdmiManager;
5390 // Set only when device is a set-top box.
5391 private HdmiPlaybackClient mHdmiPlaybackClient;
5392 // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5393 private boolean mHdmiCecSink;
5394
5395 private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
Jungshik Jang41d97462014-06-30 22:26:29 +09005396
5397 @Override
Jungshik Jang12307ca2014-07-15 19:27:56 +09005398 public int setHdmiSystemAudioSupported(boolean on) {
Eric Laurent212532b2014-07-21 15:43:18 -07005399 int device = AudioSystem.DEVICE_NONE;
5400 if (mHdmiManager != null) {
5401 synchronized (mHdmiManager) {
5402 if (mHdmiTvClient == null) {
5403 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5404 return device;
5405 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005406
Eric Laurent212532b2014-07-21 15:43:18 -07005407 synchronized (mHdmiTvClient) {
5408 if (mHdmiSystemAudioSupported != on) {
5409 mHdmiSystemAudioSupported = on;
5410 AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5411 on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5412 AudioSystem.FORCE_NONE);
5413 }
5414 device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
5415 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005416 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005417 }
Eric Laurent212532b2014-07-21 15:43:18 -07005418 return device;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005419 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005420
Terry Heoe7d6d972014-09-04 21:05:28 +09005421 @Override
5422 public boolean isHdmiSystemAudioSupported() {
5423 return mHdmiSystemAudioSupported;
5424 }
5425
Eric Laurentdd45d012012-10-08 09:04:34 -07005426 //==========================================================================================
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005427 // Accessibility: taking touch exploration into account for selecting the default
5428 // stream override timeout when adjusting volume
5429 //==========================================================================================
5430 private static class StreamOverride
5431 implements AccessibilityManager.TouchExplorationStateChangeListener {
5432
5433 // AudioService.getActiveStreamType() will return:
5434 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
5435 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
5436 // stopped
5437 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
5438 private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
5439
5440 static int sDelayMs;
5441
5442 static void init(Context ctxt) {
5443 AccessibilityManager accessibilityManager =
5444 (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
5445 updateDefaultStreamOverrideDelay(
5446 accessibilityManager.isTouchExplorationEnabled());
5447 accessibilityManager.addTouchExplorationStateChangeListener(
5448 new StreamOverride());
5449 }
5450
5451 @Override
5452 public void onTouchExplorationStateChanged(boolean enabled) {
5453 updateDefaultStreamOverrideDelay(enabled);
5454 }
5455
5456 private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
5457 if (touchExploreEnabled) {
5458 sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
5459 } else {
5460 sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
5461 }
5462 if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
5463 + " stream override delay is now " + sDelayMs + " ms");
5464 }
5465 }
5466
5467 //==========================================================================================
Eric Laurentdd45d012012-10-08 09:04:34 -07005468 // Camera shutter sound policy.
5469 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5470 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5471 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5472 //==========================================================================================
5473
5474 // cached value of com.android.internal.R.bool.config_camera_sound_forced
5475 private Boolean mCameraSoundForced;
5476
5477 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5478 public boolean isCameraSoundForced() {
5479 synchronized (mCameraSoundForced) {
5480 return mCameraSoundForced;
5481 }
5482 }
5483
5484 private static final String[] RINGER_MODE_NAMES = new String[] {
5485 "SILENT",
5486 "VIBRATE",
5487 "NORMAL"
5488 };
5489
5490 private void dumpRingerMode(PrintWriter pw) {
5491 pw.println("\nRinger mode: ");
John Spurlock661f2cf2014-11-17 10:29:10 -05005492 pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
5493 pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
Eric Laurentdd45d012012-10-08 09:04:34 -07005494 pw.print("- ringer mode affected streams = 0x");
5495 pw.println(Integer.toHexString(mRingerModeAffectedStreams));
5496 pw.print("- ringer mode muted streams = 0x");
5497 pw.println(Integer.toHexString(mRingerModeMutedStreams));
John Spurlock661f2cf2014-11-17 10:29:10 -05005498 pw.print("- delegate = "); pw.println(mRingerModeDelegate);
Eric Laurentdd45d012012-10-08 09:04:34 -07005499 }
5500
Dianne Hackborn632ca412012-06-14 19:34:10 -07005501 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005502 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07005503 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5504
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005505 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07005506 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07005507 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005508 pw.println("\nAudio routes:");
John Spurlock61560172015-02-06 19:46:04 -05005509 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
5510 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
John Spurlock35134602014-07-24 18:10:48 -04005511
5512 pw.println("\nOther state:");
John Spurlock3346a802014-05-20 16:25:37 -04005513 pw.print(" mVolumeController="); pw.println(mVolumeController);
John Spurlock35134602014-07-24 18:10:48 -04005514 pw.print(" mSafeMediaVolumeState=");
5515 pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
5516 pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
5517 pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
5518 pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005519 pw.print(" mMcc="); pw.println(mMcc);
John Spurlock661f2cf2014-11-17 10:29:10 -05005520 pw.print(" mHasVibrator="); pw.println(mHasVibrator);
John Spurlockcdb57ae2015-02-11 19:04:11 -05005521 pw.print(" mControllerService="); pw.println(mControllerService);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005522
5523 dumpAudioPolicies(pw);
John Spurlock35134602014-07-24 18:10:48 -04005524 }
5525
5526 private static String safeMediaVolumeStateToString(Integer state) {
5527 switch(state) {
5528 case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
5529 case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
5530 case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
5531 case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
5532 }
5533 return null;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005534 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07005535
5536 // Inform AudioFlinger of our device's low RAM attribute
5537 private static void readAndSetLowRamDevice()
5538 {
5539 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
5540 if (status != 0) {
5541 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
5542 }
5543 }
John Spurlock3346a802014-05-20 16:25:37 -04005544
John Spurlockcdb57ae2015-02-11 19:04:11 -05005545 private void enforceVolumeController(String action) {
5546 if (mControllerService.mUid != 0 && Binder.getCallingUid() == mControllerService.mUid) {
5547 return;
5548 }
John Spurlock3346a802014-05-20 16:25:37 -04005549 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
5550 "Only SystemUI can " + action);
5551 }
5552
5553 @Override
5554 public void setVolumeController(final IVolumeController controller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005555 enforceVolumeController("set the volume controller");
John Spurlock3346a802014-05-20 16:25:37 -04005556
5557 // return early if things are not actually changing
5558 if (mVolumeController.isSameBinder(controller)) {
5559 return;
5560 }
5561
5562 // dismiss the old volume controller
5563 mVolumeController.postDismiss();
5564 if (controller != null) {
5565 // we are about to register a new controller, listen for its death
5566 try {
5567 controller.asBinder().linkToDeath(new DeathRecipient() {
5568 @Override
5569 public void binderDied() {
5570 if (mVolumeController.isSameBinder(controller)) {
5571 Log.w(TAG, "Current remote volume controller died, unregistering");
5572 setVolumeController(null);
5573 }
5574 }
5575 }, 0);
5576 } catch (RemoteException e) {
5577 // noop
5578 }
5579 }
5580 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04005581 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
5582 }
5583
5584 @Override
5585 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005586 enforceVolumeController("notify about volume controller visibility");
John Spurlock33f4e042014-07-11 13:10:58 -04005587
5588 // return early if the controller is not current
5589 if (!mVolumeController.isSameBinder(controller)) {
5590 return;
5591 }
5592
5593 mVolumeController.setVisible(visible);
5594 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04005595 }
RoboErikd09bd0c2014-06-24 17:45:19 -07005596
5597 public static class VolumeController {
5598 private static final String TAG = "VolumeController";
5599
5600 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04005601 private boolean mVisible;
5602 private long mNextLongPress;
5603 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07005604
5605 public void setController(IVolumeController controller) {
5606 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04005607 mVisible = false;
5608 }
5609
5610 public void loadSettings(ContentResolver cr) {
5611 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
5612 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
5613 }
5614
RoboErik4197cb62015-01-21 15:45:32 -08005615 public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
5616 if (isMute) {
5617 return false;
5618 }
John Spurlock33f4e042014-07-11 13:10:58 -04005619 boolean suppress = false;
5620 if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
5621 final long now = SystemClock.uptimeMillis();
5622 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
5623 // ui will become visible
5624 if (mNextLongPress < now) {
5625 mNextLongPress = now + mLongPressTimeout;
5626 }
5627 suppress = true;
5628 } else if (mNextLongPress > 0) { // in a long-press
5629 if (now > mNextLongPress) {
5630 // long press triggered, no more suppression
5631 mNextLongPress = 0;
5632 } else {
5633 // keep suppressing until the long press triggers
5634 suppress = true;
5635 }
5636 }
5637 }
5638 return suppress;
5639 }
5640
5641 public void setVisible(boolean visible) {
5642 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07005643 }
5644
5645 public boolean isSameBinder(IVolumeController controller) {
5646 return Objects.equals(asBinder(), binder(controller));
5647 }
5648
5649 public IBinder asBinder() {
5650 return binder(mController);
5651 }
5652
5653 private static IBinder binder(IVolumeController controller) {
5654 return controller == null ? null : controller.asBinder();
5655 }
5656
5657 @Override
5658 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04005659 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07005660 }
5661
5662 public void postDisplaySafeVolumeWarning(int flags) {
5663 if (mController == null)
5664 return;
5665 try {
5666 mController.displaySafeVolumeWarning(flags);
5667 } catch (RemoteException e) {
5668 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
5669 }
5670 }
5671
5672 public void postVolumeChanged(int streamType, int flags) {
5673 if (mController == null)
5674 return;
5675 try {
5676 mController.volumeChanged(streamType, flags);
5677 } catch (RemoteException e) {
5678 Log.w(TAG, "Error calling volumeChanged", e);
5679 }
5680 }
5681
5682 public void postMasterVolumeChanged(int flags) {
5683 if (mController == null)
5684 return;
5685 try {
5686 mController.masterVolumeChanged(flags);
5687 } catch (RemoteException e) {
5688 Log.w(TAG, "Error calling masterVolumeChanged", e);
5689 }
5690 }
5691
5692 public void postMasterMuteChanged(int flags) {
5693 if (mController == null)
5694 return;
5695 try {
5696 mController.masterMuteChanged(flags);
5697 } catch (RemoteException e) {
5698 Log.w(TAG, "Error calling masterMuteChanged", e);
5699 }
5700 }
5701
5702 public void setLayoutDirection(int layoutDirection) {
5703 if (mController == null)
5704 return;
5705 try {
5706 mController.setLayoutDirection(layoutDirection);
5707 } catch (RemoteException e) {
5708 Log.w(TAG, "Error calling setLayoutDirection", e);
5709 }
5710 }
5711
5712 public void postDismiss() {
5713 if (mController == null)
5714 return;
5715 try {
5716 mController.dismiss();
5717 } catch (RemoteException e) {
5718 Log.w(TAG, "Error calling dismiss", e);
5719 }
5720 }
5721 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005722
RoboErik0dac35a2014-08-12 15:48:49 -07005723 /**
5724 * Interface for system components to get some extra functionality through
5725 * LocalServices.
5726 */
5727 final class AudioServiceInternal extends AudioManagerInternal {
John Spurlock661f2cf2014-11-17 10:29:10 -05005728 @Override
5729 public void setRingerModeDelegate(RingerModeDelegate delegate) {
5730 mRingerModeDelegate = delegate;
5731 if (mRingerModeDelegate != null) {
5732 setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
5733 }
5734 }
RoboErik272e1612014-09-05 11:39:29 -07005735
5736 @Override
5737 public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
5738 String callingPackage, int uid) {
5739 // direction and stream type swap here because the public
5740 // adjustSuggested has a different order than the other methods.
5741 adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage, uid);
5742 }
5743
RoboErik0dac35a2014-08-12 15:48:49 -07005744 @Override
5745 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
5746 String callingPackage, int uid) {
5747 adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
5748 }
5749
5750 @Override
5751 public void setStreamVolumeForUid(int streamType, int direction, int flags,
5752 String callingPackage, int uid) {
5753 setStreamVolume(streamType, direction, flags, callingPackage, uid);
5754 }
RoboErik519c7742014-11-18 10:59:09 -08005755
5756 @Override
5757 public void adjustMasterVolumeForUid(int steps, int flags, String callingPackage,
5758 int uid) {
5759 adjustMasterVolume(steps, flags, callingPackage, uid);
5760 }
John Spurlock661f2cf2014-11-17 10:29:10 -05005761
5762 @Override
5763 public int getRingerModeInternal() {
5764 return AudioService.this.getRingerModeInternal();
5765 }
5766
5767 @Override
5768 public void setRingerModeInternal(int ringerMode, String caller) {
5769 AudioService.this.setRingerModeInternal(ringerMode, caller);
5770 }
John Spurlockcdb57ae2015-02-11 19:04:11 -05005771
5772 @Override
5773 public int getVolumeControllerUid() {
5774 return mControllerService.mUid;
5775 }
RoboErik0dac35a2014-08-12 15:48:49 -07005776 }
5777
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005778 //==========================================================================================
5779 // Audio policy management
5780 //==========================================================================================
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005781 public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
5782 boolean hasFocusListener) {
5783 if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
5784 + " with config:" + policyConfig);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005785 String regId = null;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005786 // error handling
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005787 boolean hasPermissionForPolicy =
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005788 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005789 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5790 if (!hasPermissionForPolicy) {
5791 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
5792 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005793 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005794 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005795
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005796 synchronized (mAudioPolicies) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005797 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005798 if (mAudioPolicies.containsKey(pcb.asBinder())) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005799 Slog.e(TAG, "Cannot re-register policy");
5800 return null;
5801 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005802 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
5803 pcb.asBinder().linkToDeath(app, 0/*flags*/);
5804 regId = app.getRegistrationId();
5805 mAudioPolicies.put(pcb.asBinder(), app);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005806 } catch (RemoteException e) {
5807 // audio policy owner has already died!
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005808 Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005809 " binder death", e);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005810 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005811 }
5812 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005813 return regId;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005814 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005815
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005816 public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
5817 if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005818 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005819 AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005820 if (app == null) {
5821 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
5822 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005823 return;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005824 } else {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005825 pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005826 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005827 app.release();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005828 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005829 // TODO implement clearing mix attribute matching info in native audio policy
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005830 }
5831
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005832 public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
5833 if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
5834 + " policy " + pcb.asBinder());
5835 // error handling
5836 boolean hasPermissionForPolicy =
5837 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
5838 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5839 if (!hasPermissionForPolicy) {
5840 Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
5841 + Binder.getCallingPid() + " / uid "
5842 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
5843 return AudioManager.ERROR;
5844 }
5845
5846 synchronized (mAudioPolicies) {
5847 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
5848 Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
5849 return AudioManager.ERROR;
5850 }
5851 final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
5852 if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5853 // is there already one policy managing ducking?
5854 for(AudioPolicyProxy policy : mAudioPolicies.values()) {
5855 if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5856 Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
5857 return AudioManager.ERROR;
5858 }
5859 }
5860 }
5861 app.mFocusDuckBehavior = duckingBehavior;
5862 mMediaFocusControl.setDuckingInExtPolicyAvailable(
5863 duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
5864 }
5865 return AudioManager.SUCCESS;
5866 }
5867
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005868 private void dumpAudioPolicies(PrintWriter pw) {
5869 pw.println("\nAudio policies:");
5870 synchronized (mAudioPolicies) {
5871 for(AudioPolicyProxy policy : mAudioPolicies.values()) {
5872 pw.println(policy.toLogFriendlyString());
5873 }
5874 }
5875 }
5876
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005877 //======================
5878 // Audio policy proxy
5879 //======================
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005880 /**
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005881 * This internal class inherits from AudioPolicyConfig, each instance contains all the
5882 * mixes of an AudioPolicy and their configurations.
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005883 */
5884 public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005885 private static final String TAG = "AudioPolicyProxy";
5886 AudioPolicyConfig mConfig;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005887 IAudioPolicyCallback mPolicyToken;
5888 boolean mHasFocusListener;
5889 /**
5890 * Audio focus ducking behavior for an audio policy.
5891 * This variable reflects the value that was successfully set in
5892 * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
5893 * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
5894 * is handling ducking for audio focus.
5895 */
5896 int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
5897
5898 AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
5899 boolean hasFocusListener) {
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005900 super(config);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005901 setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005902 mPolicyToken = token;
5903 mHasFocusListener = hasFocusListener;
5904 if (mHasFocusListener) {
5905 mMediaFocusControl.addFocusFollower(mPolicyToken);
5906 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08005907 connectMixes();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005908 }
5909
5910 public void binderDied() {
5911 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005912 Log.i(TAG, "audio policy " + mPolicyToken + " died");
5913 release();
5914 mAudioPolicies.remove(mPolicyToken.asBinder());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005915 }
5916 }
5917
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005918 String getRegistrationId() {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005919 return getRegistration();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005920 }
5921
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005922 void release() {
5923 if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5924 mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
5925 }
5926 if (mHasFocusListener) {
5927 mMediaFocusControl.removeFocusFollower(mPolicyToken);
5928 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08005929 AudioSystem.registerPolicyMixes(mMixes, false);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005930 }
5931
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08005932 void connectMixes() {
5933 AudioSystem.registerPolicyMixes(mMixes, true);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005934 }
5935 };
5936
5937 private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
5938 new HashMap<IBinder, AudioPolicyProxy>();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005939 private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
John Spurlockcdb57ae2015-02-11 19:04:11 -05005940
5941 private class ControllerService extends ContentObserver {
5942 private int mUid;
5943 private ComponentName mComponent;
5944
5945 public ControllerService() {
5946 super(null);
5947 }
5948
5949 @Override
5950 public String toString() {
5951 return String.format("{mUid=%d,mComponent=%s}", mUid, mComponent);
5952 }
5953
5954 public void init() {
5955 onChange(true);
5956 mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
5957 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT), false, this);
5958 }
5959
5960 @Override
5961 public void onChange(boolean selfChange) {
5962 mUid = 0;
5963 mComponent = null;
5964 final String setting = Settings.Secure.getString(mContentResolver,
5965 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
5966 if (setting == null) return;
5967 try {
5968 mComponent = ComponentName.unflattenFromString(setting);
5969 if (mComponent == null) return;
5970 mUid = mContext.getPackageManager()
5971 .getApplicationInfo(mComponent.getPackageName(), 0).uid;
5972 } catch (Exception e) {
5973 Log.w(TAG, "Error loading controller service", e);
5974 }
5975 if (DEBUG_VOL) Log.d(TAG, "Reloaded controller service: " + this);
5976 }
5977 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005978}