blob: fc949e05a8fe73d45d0ba346d0eb4a4f0bafc3a9 [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;
John Spurlock61560172015-02-06 19:46:04 -050057import android.media.IAudioFocusDispatcher;
58import android.media.IAudioRoutesObserver;
59import android.media.IAudioService;
60import android.media.IRemoteControlDisplay;
61import android.media.IRingtonePlayer;
62import android.media.IVolumeController;
63import android.media.MediaPlayer;
64import android.media.SoundPool;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065import android.media.MediaPlayer.OnCompletionListener;
66import android.media.MediaPlayer.OnErrorListener;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -080067import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070068import android.media.audiopolicy.AudioPolicyConfig;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -080069import android.media.audiopolicy.IAudioPolicyCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070import android.os.Binder;
Eric Laurentc18c9132013-04-12 17:24:56 -070071import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.os.Environment;
73import android.os.Handler;
74import android.os.IBinder;
75import android.os.Looper;
76import android.os.Message;
Jean-Michel Trivic6802222012-04-30 11:15:03 -070077import android.os.PowerManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070078import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079import android.os.RemoteException;
John Spurlock33f4e042014-07-11 13:10:58 -040080import android.os.SystemClock;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070081import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070082import android.os.UserHandle;
Eric Laurentbffc3d12012-05-07 17:43:49 -070083import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084import android.provider.Settings;
85import android.provider.Settings.System;
Tyler Gunnef9f6f92014-09-12 22:16:17 -070086import android.telecom.TelecomManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070087import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088import android.util.Log;
John Spurlockaa5ee4d2014-07-25 13:05:12 -040089import android.util.MathUtils;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070090import android.util.Slog;
John Spurlock2bb02ec2015-03-02 13:13:06 -050091import android.util.SparseIntArray;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070092import android.view.KeyEvent;
RoboErik519c7742014-11-18 10:59:09 -080093import android.view.OrientationEventListener;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -070094import android.view.Surface;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -070095import android.view.WindowManager;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -070096import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097
Eric Laurente78fced2013-03-15 16:03:47 -070098import com.android.internal.util.XmlUtils;
RoboErik0dac35a2014-08-12 15:48:49 -070099import com.android.server.LocalServices;
Eric Laurente78fced2013-03-15 16:03:47 -0700100
101import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800103import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104import java.io.IOException;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800105import java.io.PrintWriter;
Eric Laurente78fced2013-03-15 16:03:47 -0700106import java.lang.reflect.Field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107import java.util.ArrayList;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700108import java.util.HashMap;
109import java.util.Iterator;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -0700110import java.util.List;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700111import java.util.Map;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700112import java.util.NoSuchElementException;
RoboErikd09bd0c2014-06-24 17:45:19 -0700113import java.util.Objects;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700114import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115
116/**
117 * The implementation of the volume manager service.
118 * <p>
119 * This implementation focuses on delivering a responsive UI. Most methods are
120 * asynchronous to external calls. For example, the task of setting a volume
121 * will update our internal state, but in a separate thread will set the system
122 * volume and later persist to the database. Similarly, setting the ringer mode
123 * will update the state and broadcast a change and in a separate thread later
124 * persist the ringer mode.
125 *
126 * @hide
127 */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700128public class AudioService extends IAudioService.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129
130 private static final String TAG = "AudioService";
131
Jean-Michel Trivi339567d2014-07-29 09:53:34 -0700132 /** Debug audio mode */
133 protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -0700134
135 /** Debug audio policy feature */
136 protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);
137
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700138 /** Debug volumes */
John Spurlockae641c92014-06-30 18:11:40 -0400139 protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700140
RoboErik430fc482014-06-12 15:49:20 -0700141 /** debug calls to media session apis */
John Spurlockae641c92014-06-30 18:11:40 -0400142 private static final boolean DEBUG_SESSIONS = Log.isLoggable(TAG + ".SESSIONS", Log.DEBUG);
RoboErik8a2cfc32014-05-16 11:19:38 -0700143
Paul McLean394a8e12015-03-03 10:29:19 -0700144 /** debug calls to devices APIs */
145 protected static final boolean DEBUG_DEVICES = Log.isLoggable(TAG + ".DEVICES", Log.DEBUG);
146
John Spurlock86005342014-05-23 11:58:00 -0400147 /** Allow volume changes to set ringer mode to silent? */
148 private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
149
John Spurlocka11b4af2014-06-01 11:52:23 -0400150 /** In silent mode, are volume adjustments (raises) prevented? */
151 private static final boolean PREVENT_VOLUME_ADJUSTMENT_IF_SILENT = true;
152
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 /** How long to delay before persisting a change in volume/ringer mode. */
RoboErik45edba12012-03-27 17:54:36 -0700154 private static final int PERSIST_DELAY = 500;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155
RoboErik5452e252015-02-06 15:33:53 -0800156 /** How long to delay after a volume down event before unmuting a stream */
157 private static final int UNMUTE_STREAM_DELAY = 350;
158
John Spurlock3346a802014-05-20 16:25:37 -0400159 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400160 * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
161 */
162 private static final int FLAG_ADJUST_VOLUME = 1;
163
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700164 private final Context mContext;
165 private final ContentResolver mContentResolver;
166 private final AppOpsManager mAppOps;
Eric Laurent212532b2014-07-21 15:43:18 -0700167
Eric Laurent212532b2014-07-21 15:43:18 -0700168 // the platform type affects volume and silent mode behavior
169 private final int mPlatformType;
170
171 private boolean isPlatformVoice() {
John Spurlock61560172015-02-06 19:46:04 -0500172 return mPlatformType == AudioSystem.PLATFORM_VOICE;
Eric Laurent212532b2014-07-21 15:43:18 -0700173 }
174
175 private boolean isPlatformTelevision() {
John Spurlock61560172015-02-06 19:46:04 -0500176 return mPlatformType == AudioSystem.PLATFORM_TELEVISION;
Eric Laurent212532b2014-07-21 15:43:18 -0700177 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800178
John Spurlock3346a802014-05-20 16:25:37 -0400179 /** The controller for the volume UI. */
180 private final VolumeController mVolumeController = new VolumeController();
John Spurlockcdb57ae2015-02-11 19:04:11 -0500181 private final ControllerService mControllerService = new ControllerService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182
183 // sendMsg() flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184 /** If the msg is already queued, replace it with this one. */
185 private static final int SENDMSG_REPLACE = 0;
186 /** If the msg is already queued, ignore this one and leave the old. */
187 private static final int SENDMSG_NOOP = 1;
188 /** If the msg is already queued, queue this one and leave the old. */
189 private static final int SENDMSG_QUEUE = 2;
190
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700191 // AudioHandler messages
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800192 private static final int MSG_SET_DEVICE_VOLUME = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 private static final int MSG_PERSIST_VOLUME = 1;
194 private static final int MSG_PERSIST_RINGER_MODE = 3;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700195 private static final int MSG_MEDIA_SERVER_DIED = 4;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700196 private static final int MSG_PLAY_SOUND_EFFECT = 5;
197 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
198 private static final int MSG_LOAD_SOUND_EFFECTS = 7;
199 private static final int MSG_SET_FORCE_USE = 8;
200 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
201 private static final int MSG_SET_ALL_VOLUMES = 10;
202 private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
203 private static final int MSG_REPORT_NEW_ROUTES = 12;
204 private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
205 private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
206 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
207 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
208 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
209 private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
210 private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
211 private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700212 private static final int MSG_SYSTEM_READY = 21;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400213 private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
Julia Reynoldsb53453f2014-08-22 11:42:43 -0400214 private static final int MSG_PERSIST_MICROPHONE_MUTE = 23;
RoboErik5452e252015-02-06 15:33:53 -0800215 private static final int MSG_UNMUTE_STREAM = 24;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700216 // start of messages handled under wakelock
217 // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
Jean-Michel Trivie12c39b2012-06-06 10:51:58 -0700218 // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700219 private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
Mike Lockwood0a40ec22014-05-21 10:08:50 -0700220 private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
221 private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700222 // end of messages handled under wakelock
Eric Laurentafbb0472011-12-15 09:04:23 -0800223
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -0700224 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
Eric Laurentdc03c612011-04-01 10:59:41 -0700225 // Timeout for connection to bluetooth headset service
226 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 /** @see AudioSystemThread */
229 private AudioSystemThread mAudioSystemThread;
230 /** @see AudioHandler */
231 private AudioHandler mAudioHandler;
232 /** @see VolumeStreamState */
233 private VolumeStreamState[] mStreamStates;
Jason Parekhb1096152009-03-24 17:48:25 -0700234 private SettingsObserver mSettingsObserver;
Eric Laurenta553c252009-07-17 12:17:14 -0700235
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700236 private int mMode = AudioSystem.MODE_NORMAL;
Glenn Kastenba195eb2011-12-13 09:30:40 -0800237 // protects mRingerMode
238 private final Object mSettingsLock = new Object();
Eric Laurent45c90ce2012-04-24 18:44:22 -0700239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 private SoundPool mSoundPool;
Glenn Kasten30c918c2011-11-10 17:56:41 -0800241 private final Object mSoundEffectsLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 private static final int NUM_SOUNDPOOL_CHANNELS = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243
Lei Zhang6c798972012-03-02 11:40:12 -0800244 // Maximum volume adjust steps allowed in a single batch call.
245 private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 /* Sound effect file names */
248 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
Eric Laurente78fced2013-03-15 16:03:47 -0700249 private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250
251 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
252 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
253 * uses soundpool (second column) */
Eric Laurente78fced2013-03-15 16:03:47 -0700254 private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255
Jared Suttles59820132009-08-13 21:50:52 -0500256 /** @hide Maximum volume index values for audio streams */
Eric Laurent91377de2014-10-10 15:24:04 -0700257 private static int[] MAX_STREAM_VOLUME = new int[] {
Eric Laurent6ee99522009-08-25 06:30:59 -0700258 5, // STREAM_VOICE_CALL
259 7, // STREAM_SYSTEM
260 7, // STREAM_RING
261 15, // STREAM_MUSIC
262 7, // STREAM_ALARM
263 7, // STREAM_NOTIFICATION
264 15, // STREAM_BLUETOOTH_SCO
265 7, // STREAM_SYSTEM_ENFORCED
266 15, // STREAM_DTMF
267 15 // STREAM_TTS
Jared Suttles59820132009-08-13 21:50:52 -0500268 };
Eric Laurent91377de2014-10-10 15:24:04 -0700269
Eric Laurent6d517662012-04-23 18:42:39 -0700270 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
Eric Laurenta553c252009-07-17 12:17:14 -0700271 * of another stream: This avoids multiplying the volume settings for hidden
272 * stream types that follow other stream behavior for volume settings
Eric Laurent6d517662012-04-23 18:42:39 -0700273 * NOTE: do not create loops in aliases!
274 * Some streams alias to different streams according to device category (phone or tablet) or
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700275 * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
Eric Laurent212532b2014-07-21 15:43:18 -0700276 * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
277 * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
278 * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
279 private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700280 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
281 AudioSystem.STREAM_RING, // STREAM_SYSTEM
282 AudioSystem.STREAM_RING, // STREAM_RING
283 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
284 AudioSystem.STREAM_ALARM, // STREAM_ALARM
285 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
286 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
287 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
288 AudioSystem.STREAM_RING, // STREAM_DTMF
289 AudioSystem.STREAM_MUSIC // STREAM_TTS
Eric Laurenta553c252009-07-17 12:17:14 -0700290 };
Eric Laurent212532b2014-07-21 15:43:18 -0700291 private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
292 AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL
293 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
294 AudioSystem.STREAM_MUSIC, // STREAM_RING
295 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
296 AudioSystem.STREAM_MUSIC, // STREAM_ALARM
297 AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
298 AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO
299 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
300 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
301 AudioSystem.STREAM_MUSIC // STREAM_TTS
302 };
303 private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700304 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
John Spurlock4f0f1202014-08-05 13:28:33 -0400305 AudioSystem.STREAM_RING, // STREAM_SYSTEM
Eric Laurent6d517662012-04-23 18:42:39 -0700306 AudioSystem.STREAM_RING, // STREAM_RING
307 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
308 AudioSystem.STREAM_ALARM, // STREAM_ALARM
309 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
310 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
John Spurlock4f0f1202014-08-05 13:28:33 -0400311 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
312 AudioSystem.STREAM_RING, // STREAM_DTMF
Eric Laurent6d517662012-04-23 18:42:39 -0700313 AudioSystem.STREAM_MUSIC // STREAM_TTS
314 };
315 private int[] mStreamVolumeAlias;
Eric Laurenta553c252009-07-17 12:17:14 -0700316
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700317 /**
318 * Map AudioSystem.STREAM_* constants to app ops. This should be used
319 * after mapping through mStreamVolumeAlias.
320 */
John Spurlock59dc9c12015-03-02 11:20:15 -0500321 private static final int[] STREAM_VOLUME_OPS = new int[] {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700322 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL
323 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM
324 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING
325 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC
326 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM
327 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION
328 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO
329 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED
330 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF
331 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS
332 };
333
Eric Laurent83a017b2013-03-19 18:15:31 -0700334 private final boolean mUseFixedVolume;
335
Glenn Kasten30c918c2011-11-10 17:56:41 -0800336 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 public void onError(int error) {
338 switch (error) {
339 case AudioSystem.AUDIO_STATUS_SERVER_DIED:
Eric Laurentdfb881f2013-07-18 14:41:39 -0700340 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
341 SENDMSG_NOOP, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 break;
343 default:
344 break;
345 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700346 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800347 };
348
349 /**
350 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
351 * {@link AudioManager#RINGER_MODE_SILENT}, or
352 * {@link AudioManager#RINGER_MODE_VIBRATE}.
353 */
Glenn Kastenba195eb2011-12-13 09:30:40 -0800354 // protected by mSettingsLock
John Spurlock661f2cf2014-11-17 10:29:10 -0500355 private int mRingerMode; // internal ringer mode, affects muting of underlying streams
356 private int mRingerModeExternal = -1; // reported ringer mode to outside clients (AudioManager)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357
Eric Laurent9bcf4012009-06-12 06:09:28 -0700358 /** @see System#MODE_RINGER_STREAMS_AFFECTED */
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700359 private int mRingerModeAffectedStreams = 0;
Eric Laurent9bcf4012009-06-12 06:09:28 -0700360
Eric Laurent5b4e6542010-03-19 20:02:21 -0700361 // Streams currently muted by ringer mode
362 private int mRingerModeMutedStreams;
363
John Spurlock3ce37252015-02-17 13:20:45 -0500364 /** Streams that can be muted. Do not resolve to aliases when checking.
365 * @see System#MUTE_STREAMS_AFFECTED */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 private int mMuteAffectedStreams;
367
368 /**
Eric Laurentbffc3d12012-05-07 17:43:49 -0700369 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
370 * mVibrateSetting is just maintained during deprecation period but vibration policy is
371 * now only controlled by mHasVibrator and mRingerMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 */
373 private int mVibrateSetting;
374
Eric Laurentbffc3d12012-05-07 17:43:49 -0700375 // Is there a vibrator
376 private final boolean mHasVibrator;
377
Eric Laurenta553c252009-07-17 12:17:14 -0700378 // Broadcast receiver for device connections intent broadcasts
379 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
380
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700381 // Devices currently connected
Paul McLean394a8e12015-03-03 10:29:19 -0700382 // Use makeDeviceListKey() to make a unique key for this list.
383 private class DeviceListSpec {
384 int mDeviceType;
385 String mDeviceName;
386 String mDeviceAddress;
387
388 public DeviceListSpec(int deviceType, String deviceName, String deviceAddress) {
389 mDeviceType = deviceType;
390 mDeviceName = deviceName;
391 mDeviceAddress = deviceAddress;
392 }
393
394 public String toString() {
395 return "[type:0x" + Integer.toHexString(mDeviceType) + " name:" + mDeviceName
396 + " address:" + mDeviceAddress + "]";
397 }
398 }
399
400 // Generate a unique key for the mConnectedDevices List by composing the device "type"
401 // and the "address" associated with a specific instance of that device type
402 private String makeDeviceListKey(int device, String deviceAddress) {
403 return "0x" + Integer.toHexString(device) + ":" + deviceAddress;
404 }
405
406 private final HashMap<String, DeviceListSpec> mConnectedDevices =
407 new HashMap<String, DeviceListSpec>();
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700408
409 // Forced device usage for communications
410 private int mForcedUseForComm;
411
Eric Laurent9272b4b2010-01-23 17:12:59 -0800412 // List of binder death handlers for setMode() client processes.
413 // The last process to have called setMode() is at the top of the list.
Glenn Kasten30c918c2011-11-10 17:56:41 -0800414 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
Eric Laurenteb14a782009-12-17 03:12:59 -0800415
Eric Laurent3def1ee2010-03-17 23:26:26 -0700416 // List of clients having issued a SCO start request
Glenn Kasten30c918c2011-11-10 17:56:41 -0800417 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
Eric Laurent3def1ee2010-03-17 23:26:26 -0700418
419 // BluetoothHeadset API to control SCO connection
420 private BluetoothHeadset mBluetoothHeadset;
421
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700422 // Bluetooth headset device
423 private BluetoothDevice mBluetoothHeadsetDevice;
Eric Laurent3def1ee2010-03-17 23:26:26 -0700424
Eric Laurent62ef7672010-11-24 10:58:32 -0800425 // Indicate if SCO audio connection is currently active and if the initiator is
426 // audio service (internal) or bluetooth headset (external)
427 private int mScoAudioState;
428 // SCO audio state is not active
429 private static final int SCO_STATE_INACTIVE = 0;
Eric Laurentdc03c612011-04-01 10:59:41 -0700430 // SCO audio activation request waiting for headset service to connect
431 private static final int SCO_STATE_ACTIVATE_REQ = 1;
Eric Laurent25fc29b2013-04-05 12:13:54 -0700432 // SCO audio state is active or starting due to a request from AudioManager API
Eric Laurentdc03c612011-04-01 10:59:41 -0700433 private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
434 // SCO audio deactivation request waiting for headset service to connect
435 private static final int SCO_STATE_DEACTIVATE_REQ = 5;
436
Eric Laurent62ef7672010-11-24 10:58:32 -0800437 // SCO audio state is active due to an action in BT handsfree (either voice recognition or
438 // in call audio)
439 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
Eric Laurentdc03c612011-04-01 10:59:41 -0700440 // Deactivation request for all SCO connections (initiated by audio mode change)
441 // waiting for headset service to connect
442 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
443
Eric Laurentc18c9132013-04-12 17:24:56 -0700444 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
445 // originated from an app targeting an API version before JB MR2 and raw audio after that.
446 private int mScoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -0700447 // SCO audio mode is undefined
448 private static final int SCO_MODE_UNDEFINED = -1;
Eric Laurentc18c9132013-04-12 17:24:56 -0700449 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
450 private static final int SCO_MODE_VIRTUAL_CALL = 0;
451 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
452 private static final int SCO_MODE_RAW = 1;
Liejun Taof4e51d82014-07-16 11:18:29 -0700453 // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
454 private static final int SCO_MODE_VR = 2;
455
456 private static final int SCO_MODE_MAX = 2;
Eric Laurentc18c9132013-04-12 17:24:56 -0700457
Eric Laurentdc03c612011-04-01 10:59:41 -0700458 // Current connection state indicated by bluetooth headset
459 private int mScoConnectionState;
Eric Laurent62ef7672010-11-24 10:58:32 -0800460
Eric Laurenta60e2122010-12-28 16:49:07 -0800461 // true if boot sequence has been completed
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700462 private boolean mSystemReady;
Eric Laurenta60e2122010-12-28 16:49:07 -0800463 // listener for SoundPool sample load completion indication
464 private SoundPoolCallback mSoundPoolCallBack;
465 // thread for SoundPool listener
466 private SoundPoolListenerThread mSoundPoolListenerThread;
467 // message looper for SoundPool listener
468 private Looper mSoundPoolLooper = null;
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700469 // volume applied to sound played with playSoundEffect()
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700470 private static int sSoundEffectVolumeDb;
Eric Laurent25101b02011-02-02 09:33:30 -0800471 // previous volume adjustment direction received by checkForRingerModeChange()
472 private int mPrevVolDirection = AudioManager.ADJUST_SAME;
Amith Yamasani6243edd2011-12-05 19:58:48 -0800473 // Keyguard manager proxy
474 private KeyguardManager mKeyguardManager;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700475 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
476 // is controlled by Vol keys.
477 private int mVolumeControlStream = -1;
478 private final Object mForceControlStreamLock = new Object();
479 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
480 // server process so in theory it is not necessary to monitor the client death.
481 // However it is good to be ready for future evolutions.
482 private ForceControlStreamClient mForceControlStreamClient = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700483 // Used to play ringtones outside system_server
484 private volatile IRingtonePlayer mRingtonePlayer;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800485
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700486 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700487 private int mDeviceRotation = Surface.ROTATION_0;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700488
Eric Laurent78472112012-05-21 08:57:21 -0700489 // Request to override default use of A2DP for media.
490 private boolean mBluetoothA2dpEnabled;
491 private final Object mBluetoothA2dpEnabledLock = new Object();
492
Dianne Hackborn632ca412012-06-14 19:34:10 -0700493 // Monitoring of audio routes. Protected by mCurAudioRoutes.
494 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
495 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
496 = new RemoteCallbackList<IAudioRoutesObserver>();
497
Eric Laurent4bbcc652012-09-24 14:26:30 -0700498 // Devices for which the volume is fixed and VolumePanel slider should be disabled
Eric Laurent212532b2014-07-21 15:43:18 -0700499 int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700500 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Eric Laurent212532b2014-07-21 15:43:18 -0700501 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
502 AudioSystem.DEVICE_OUT_HDMI_ARC |
503 AudioSystem.DEVICE_OUT_SPDIF |
504 AudioSystem.DEVICE_OUT_AUX_LINE;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700505 int mFullVolumeDevices = 0;
Eric Laurent4bbcc652012-09-24 14:26:30 -0700506
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700507 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700508 private final boolean mMonitorOrientation;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700509 private final boolean mMonitorRotation;
Eric Laurentd640bd32012-09-28 18:01:48 -0700510
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700511 private boolean mDockAudioMediaEnabled = true;
512
Eric Laurent08ed1b92012-11-05 14:54:12 -0800513 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
514
Eric Laurentfde16d52012-12-03 14:42:39 -0800515 // Used when safe volume warning message display is requested by setStreamVolume(). In this
516 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
517 // and used later when/if disableSafeMediaVolume() is called.
518 private StreamVolumeCommand mPendingVolumeCommand;
519
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700520 private PowerManager.WakeLock mAudioEventWakeLock;
521
522 private final MediaFocusControl mMediaFocusControl;
523
John Du5a0cf7a2013-07-19 11:30:34 -0700524 // Reference to BluetoothA2dp to query for AbsoluteVolume.
525 private BluetoothA2dp mA2dp;
seunghwan.hong4fe77952014-10-29 17:43:20 +0900526 // lock always taken synchronized on mConnectedDevices
John Du5a0cf7a2013-07-19 11:30:34 -0700527 private final Object mA2dpAvrcpLock = new Object();
528 // If absolute volume is supported in AVRCP device
529 private boolean mAvrcpAbsVolSupported = false;
530
Jon Eklund318f0fe2014-01-23 17:53:48 -0600531 private AudioOrientationEventListener mOrientationListener;
532
Eric Laurentadbe8bf2014-11-03 18:26:32 -0800533 private static Long mLastDeviceConnectMsgTime = new Long(0);
534
John Spurlock661f2cf2014-11-17 10:29:10 -0500535 private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
536
Paul McLean10804eb2015-01-28 11:16:35 -0800537 // Intent "extra" data keys.
538 public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName";
539 public static final String CONNECT_INTENT_KEY_STATE = "state";
540 public static final String CONNECT_INTENT_KEY_ADDRESS = "address";
541 public static final String CONNECT_INTENT_KEY_HAS_PLAYBACK = "hasPlayback";
542 public static final String CONNECT_INTENT_KEY_HAS_CAPTURE = "hasCapture";
543 public static final String CONNECT_INTENT_KEY_HAS_MIDI = "hasMIDI";
544 public static final String CONNECT_INTENT_KEY_DEVICE_CLASS = "class";
545
546 // Defines the format for the connection "address" for ALSA devices
547 public static String makeAlsaAddressString(int card, int device) {
548 return "card=" + card + ";device=" + device + ";";
549 }
550
Paul McLean394a8e12015-03-03 10:29:19 -0700551 private final String DEVICE_NAME_A2DP = "a2dp-device";
552
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 ///////////////////////////////////////////////////////////////////////////
554 // Construction
555 ///////////////////////////////////////////////////////////////////////////
556
557 /** @hide */
558 public AudioService(Context context) {
559 mContext = context;
560 mContentResolver = context.getContentResolver();
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700561 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700562
John Spurlock61560172015-02-06 19:46:04 -0500563 mPlatformType = AudioSystem.getPlatformType(context);
Jared Suttles59820132009-08-13 21:50:52 -0500564
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700565 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700566 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700567
Eric Laurentbffc3d12012-05-07 17:43:49 -0700568 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
569 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
570
Jared Suttles59820132009-08-13 21:50:52 -0500571 // Intialized volume
Eric Laurent91377de2014-10-10 15:24:04 -0700572 int maxVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps",
573 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
574 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
575 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500576 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700577 }
578 maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
579 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
580 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
581 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500582 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700583 }
Jared Suttles59820132009-08-13 21:50:52 -0500584
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700585 sSoundEffectVolumeDb = context.getResources().getInteger(
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700586 com.android.internal.R.integer.config_soundEffectVolumeDb);
Eric Laurent25101b02011-02-02 09:33:30 -0800587
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700588 mForcedUseForComm = AudioSystem.FORCE_NONE;
Eric Laurentdd45d012012-10-08 09:04:34 -0700589
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 createAudioSystemThread();
Eric Laurentdd45d012012-10-08 09:04:34 -0700591
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700592 mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
John Spurlock3346a802014-05-20 16:25:37 -0400593 mContext, mVolumeController, this);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700594
Eric Laurentdfb881f2013-07-18 14:41:39 -0700595 AudioSystem.setErrorCallback(mAudioSystemCallback);
596
John Spurlock5e783732015-02-19 10:28:59 -0500597 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -0700598 mCameraSoundForced = new Boolean(cameraSoundForced);
599 sendMsg(mAudioHandler,
600 MSG_SET_FORCE_USE,
601 SENDMSG_QUEUE,
602 AudioSystem.FOR_SYSTEM,
603 cameraSoundForced ?
604 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
605 null,
606 0);
607
Eric Laurent05274f32012-11-29 12:48:18 -0800608 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
609 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
610 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
611 // The default safe volume index read here will be replaced by the actual value when
612 // the mcc is read by onConfigureSafeVolume()
613 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
614 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
615
Eric Laurent83a017b2013-03-19 18:15:31 -0700616 mUseFixedVolume = mContext.getResources().getBoolean(
617 com.android.internal.R.bool.config_useFixedVolume);
618
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700619 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
620 // array initialized by updateStreamVolumeAlias()
621 updateStreamVolumeAlias(false /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622 readPersistedSettings();
Eric Laurentc1d41662011-07-19 11:21:13 -0700623 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700624 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700625
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700626 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700627
628 // Call setRingerModeInt() to apply correct mute
629 // state on streams affected by ringer mode.
630 mRingerModeMutedStreams = 0;
John Spurlock661f2cf2014-11-17 10:29:10 -0500631 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3891c4c2010-04-20 09:40:57 -0700632
Eric Laurenta553c252009-07-17 12:17:14 -0700633 // Register for device connection intent broadcasts.
634 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700635 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700636 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
637 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700638 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
639 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700640 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Paul McLeanc837a452014-04-09 09:04:43 -0700641 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700642
Eric Laurentd640bd32012-09-28 18:01:48 -0700643 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700644 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700645 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
646 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700647 Log.v(TAG, "monitoring device orientation");
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700648 // initialize orientation in AudioSystem
649 setOrientationForAudioSystem();
650 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700651 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
652 if (mMonitorRotation) {
653 mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
654 .getDefaultDisplay().getRotation();
655 Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
Jon Eklund318f0fe2014-01-23 17:53:48 -0600656
657 mOrientationListener = new AudioOrientationEventListener(mContext);
658 mOrientationListener.enable();
659
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700660 // initialize rotation in AudioSystem
661 setRotationForAudioSystem();
662 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700663
Eric Laurenta553c252009-07-17 12:17:14 -0700664 context.registerReceiver(mReceiver, intentFilter);
Jared Suttles59820132009-08-13 21:50:52 -0500665
RoboErik0dac35a2014-08-12 15:48:49 -0700666 LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 }
668
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700669 public void systemReady() {
670 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
671 0, 0, null, 0);
672 }
673
674 public void onSystemReady() {
675 mSystemReady = true;
676 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
677 0, 0, null, 0);
678
679 mKeyguardManager =
680 (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
681 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
682 resetBluetoothSco();
683 getBluetoothHeadset();
684 //FIXME: this is to maintain compatibility with deprecated intent
685 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
686 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
687 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
688 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
689 sendStickyBroadcastToAll(newIntent);
690
691 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
692 if (adapter != null) {
693 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
694 BluetoothProfile.A2DP);
695 }
696
Eric Laurent212532b2014-07-21 15:43:18 -0700697 mHdmiManager =
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900698 (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700699 if (mHdmiManager != null) {
700 synchronized (mHdmiManager) {
701 mHdmiTvClient = mHdmiManager.getTvClient();
Jungshik Jangc9ff9682014-09-15 17:41:06 +0900702 if (mHdmiTvClient != null) {
703 mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
704 }
Eric Laurent212532b2014-07-21 15:43:18 -0700705 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
706 mHdmiCecSink = false;
707 }
708 }
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900709
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700710 sendMsg(mAudioHandler,
711 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
712 SENDMSG_REPLACE,
713 0,
714 0,
715 null,
716 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700717
718 StreamOverride.init(mContext);
John Spurlockcdb57ae2015-02-11 19:04:11 -0500719 mControllerService.init();
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700720 }
721
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800722 private void createAudioSystemThread() {
723 mAudioSystemThread = new AudioSystemThread();
724 mAudioSystemThread.start();
725 waitForAudioHandlerCreation();
726 }
727
728 /** Waits for the volume handler to be created by the other thread. */
729 private void waitForAudioHandlerCreation() {
730 synchronized(this) {
731 while (mAudioHandler == null) {
732 try {
733 // Wait for mAudioHandler to be set by the other thread
734 wait();
735 } catch (InterruptedException e) {
736 Log.e(TAG, "Interrupted while waiting on volume handler.");
737 }
738 }
739 }
740 }
741
Eric Laurent24482012012-05-10 09:41:17 -0700742 private void checkAllAliasStreamVolumes() {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700743 synchronized (VolumeStreamState.class) {
744 int numStreamTypes = AudioSystem.getNumStreamTypes();
745 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
746 if (streamType != mStreamVolumeAlias[streamType]) {
747 mStreamStates[streamType].
Eric Laurent42b041e2013-03-29 11:36:03 -0700748 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700749 }
750 // apply stream volume
RoboErik4197cb62015-01-21 15:45:32 -0800751 if (!mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700752 mStreamStates[streamType].applyAllVolumes();
753 }
Eric Laurent24482012012-05-10 09:41:17 -0700754 }
755 }
756 }
757
Eric Laurent212532b2014-07-21 15:43:18 -0700758 private void checkAllFixedVolumeDevices()
759 {
760 int numStreamTypes = AudioSystem.getNumStreamTypes();
761 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
762 mStreamStates[streamType].checkFixedVolumeDevices();
763 }
764 }
765
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700766 private void checkAllFixedVolumeDevices(int streamType) {
767 mStreamStates[streamType].checkFixedVolumeDevices();
768 }
769
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 int numStreamTypes = AudioSystem.getNumStreamTypes();
772 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
773
774 for (int i = 0; i < numStreamTypes; i++) {
Eric Laurent6d517662012-04-23 18:42:39 -0700775 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -0700776 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777
Eric Laurent212532b2014-07-21 15:43:18 -0700778 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -0700779 checkAllAliasStreamVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 }
781
Eric Laurentbffc3d12012-05-07 17:43:49 -0700782 private void dumpStreamStates(PrintWriter pw) {
783 pw.println("\nStream volumes (device: index)");
784 int numStreamTypes = AudioSystem.getNumStreamTypes();
785 for (int i = 0; i < numStreamTypes; i++) {
John Spurlock61560172015-02-06 19:46:04 -0500786 pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":");
Eric Laurentbffc3d12012-05-07 17:43:49 -0700787 mStreamStates[i].dump(pw);
788 pw.println("");
789 }
Eric Laurentdd45d012012-10-08 09:04:34 -0700790 pw.print("\n- mute affected streams = 0x");
791 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -0700792 }
793
Eric Laurent6d517662012-04-23 18:42:39 -0700794 private void updateStreamVolumeAlias(boolean updateVolumes) {
795 int dtmfStreamAlias;
Eric Laurent212532b2014-07-21 15:43:18 -0700796
797 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -0500798 case AudioSystem.PLATFORM_VOICE:
Eric Laurent212532b2014-07-21 15:43:18 -0700799 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
Eric Laurent6d517662012-04-23 18:42:39 -0700800 dtmfStreamAlias = AudioSystem.STREAM_RING;
Eric Laurent212532b2014-07-21 15:43:18 -0700801 break;
John Spurlock61560172015-02-06 19:46:04 -0500802 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -0700803 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
804 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
805 break;
806 default:
807 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
Eric Laurent6d517662012-04-23 18:42:39 -0700808 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
809 }
Eric Laurent212532b2014-07-21 15:43:18 -0700810
811 if (isPlatformTelevision()) {
812 mRingerModeAffectedStreams = 0;
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700813 } else {
Eric Laurent212532b2014-07-21 15:43:18 -0700814 if (isInCommunication()) {
815 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
816 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
817 } else {
818 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
819 }
Eric Laurent6d517662012-04-23 18:42:39 -0700820 }
Eric Laurent212532b2014-07-21 15:43:18 -0700821
Eric Laurent6d517662012-04-23 18:42:39 -0700822 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
823 if (updateVolumes) {
Eric Laurent42b041e2013-03-29 11:36:03 -0700824 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700825 // apply stream mute states according to new value of mRingerModeAffectedStreams
John Spurlock661f2cf2014-11-17 10:29:10 -0500826 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent6d517662012-04-23 18:42:39 -0700827 sendMsg(mAudioHandler,
828 MSG_SET_ALL_VOLUMES,
829 SENDMSG_QUEUE,
830 0,
831 0,
832 mStreamStates[AudioSystem.STREAM_DTMF], 0);
833 }
834 }
835
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700836 private void readDockAudioSettings(ContentResolver cr)
837 {
838 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -0700839 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700840
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700841 sendMsg(mAudioHandler,
842 MSG_SET_FORCE_USE,
843 SENDMSG_QUEUE,
844 AudioSystem.FOR_DOCK,
845 mDockAudioMediaEnabled ?
846 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
847 null,
848 0);
849 }
850
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800851 private void readPersistedSettings() {
852 final ContentResolver cr = mContentResolver;
853
Eric Laurentbffc3d12012-05-07 17:43:49 -0700854 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700855 Settings.Global.getInt(
856 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -0700857 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -0700858 // sanity check in case the settings are restored from a device with incompatible
859 // ringer modes
John Spurlock97559372014-10-24 16:27:36 -0400860 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -0800861 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700862 }
863 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
864 ringerMode = AudioManager.RINGER_MODE_SILENT;
865 }
866 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700867 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -0800868 }
Eric Laurent212532b2014-07-21 15:43:18 -0700869 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -0700870 ringerMode = AudioManager.RINGER_MODE_NORMAL;
871 }
Glenn Kastenba195eb2011-12-13 09:30:40 -0800872 synchronized(mSettingsLock) {
873 mRingerMode = ringerMode;
John Spurlock661f2cf2014-11-17 10:29:10 -0500874 if (mRingerModeExternal == -1) {
875 mRingerModeExternal = mRingerMode;
876 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800877
Eric Laurentdd45d012012-10-08 09:04:34 -0700878 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
879 // are still needed while setVibrateSetting() and getVibrateSetting() are being
880 // deprecated.
John Spurlock61560172015-02-06 19:46:04 -0500881 mVibrateSetting = AudioSystem.getValueForVibrateSetting(0,
Eric Laurentdd45d012012-10-08 09:04:34 -0700882 AudioManager.VIBRATE_TYPE_NOTIFICATION,
883 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
884 : AudioManager.VIBRATE_SETTING_OFF);
John Spurlock61560172015-02-06 19:46:04 -0500885 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting,
Eric Laurentdd45d012012-10-08 09:04:34 -0700886 AudioManager.VIBRATE_TYPE_RINGER,
887 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
888 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700890 updateRingerModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700891 readDockAudioSettings(cr);
Eric Laurent402f7f22011-02-04 12:30:32 -0800892 }
Eric Laurentc1d41662011-07-19 11:21:13 -0700893
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700894 mMuteAffectedStreams = System.getIntForUser(cr,
John Spurlock61560172015-02-06 19:46:04 -0500895 System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
John Spurlock24c05182015-02-05 12:30:36 -0500896 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700898 boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
John Spurlockee5ad722015-03-03 16:17:21 -0500899 0, UserHandle.USER_CURRENT) == 1;
Eric Laurent83a017b2013-03-19 18:15:31 -0700900 if (mUseFixedVolume) {
901 masterMute = false;
902 AudioSystem.setMasterVolume(1.0f);
903 }
Justin Koh57978ed2012-04-03 17:37:58 -0700904 AudioSystem.setMasterMute(masterMute);
905 broadcastMasterMuteStatus(masterMute);
906
Julia Reynoldsb53453f2014-08-22 11:42:43 -0400907 boolean microphoneMute =
908 System.getIntForUser(cr, System.MICROPHONE_MUTE, 0, UserHandle.USER_CURRENT) == 1;
909 AudioSystem.muteMicrophone(microphoneMute);
910
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 // Each stream will read its own persisted settings
912
John Spurlockbcc10872014-11-28 15:29:21 -0500913 // Broadcast the sticky intents
914 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
915 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916
917 // Broadcast vibrate settings
918 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
919 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -0700920
John Spurlock33f4e042014-07-11 13:10:58 -0400921 // Load settings for the volume controller
922 mVolumeController.loadSettings(cr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923 }
924
Eric Laurenta553c252009-07-17 12:17:14 -0700925 private int rescaleIndex(int index, int srcStream, int dstStream) {
926 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
927 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800928
Jon Eklund318f0fe2014-01-23 17:53:48 -0600929 private class AudioOrientationEventListener
930 extends OrientationEventListener {
931 public AudioOrientationEventListener(Context context) {
932 super(context);
933 }
934
935 @Override
936 public void onOrientationChanged(int orientation) {
937 //Even though we're responding to phone orientation events,
938 //use display rotation so audio stays in sync with video/dialogs
939 int newRotation = ((WindowManager) mContext.getSystemService(
940 Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
941 if (newRotation != mDeviceRotation) {
942 mDeviceRotation = newRotation;
943 setRotationForAudioSystem();
944 }
945 }
946 }
947
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800948 ///////////////////////////////////////////////////////////////////////////
949 // IPC methods
950 ///////////////////////////////////////////////////////////////////////////
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800951 /** @see AudioManager#adjustVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700952 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
953 String callingPackage) {
RoboErik272e1612014-09-05 11:39:29 -0700954 adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
955 Binder.getCallingUid());
956 }
957
958 private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
959 String callingPackage, int uid) {
John Spurlockae641c92014-06-30 18:11:40 -0400960 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType
961 + ", flags=" + flags);
Eric Laurent402f7f22011-02-04 12:30:32 -0800962 int streamType;
RoboErik4197cb62015-01-21 15:45:32 -0800963 boolean isMute = isMuteAdjust(direction);
Eric Laurent45c90ce2012-04-24 18:44:22 -0700964 if (mVolumeControlStream != -1) {
965 streamType = mVolumeControlStream;
Eric Laurent402f7f22011-02-04 12:30:32 -0800966 } else {
967 streamType = getActiveStreamType(suggestedStreamType);
968 }
John Spurlock33f4e042014-07-11 13:10:58 -0400969 final int resolvedStream = mStreamVolumeAlias[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970
RoboErik2811dd32014-08-12 09:48:13 -0700971 // Play sounds on STREAM_RING only.
972 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
John Spurlock33f4e042014-07-11 13:10:58 -0400973 resolvedStream != AudioSystem.STREAM_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974 flags &= ~AudioManager.FLAG_PLAY_SOUND;
975 }
976
John Spurlock33f4e042014-07-11 13:10:58 -0400977 // For notifications/ring, show the ui before making any adjustments
RoboErik4197cb62015-01-21 15:45:32 -0800978 // Don't suppress mute/unmute requests
979 if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
John Spurlock33f4e042014-07-11 13:10:58 -0400980 direction = 0;
981 flags &= ~AudioManager.FLAG_PLAY_SOUND;
982 flags &= ~AudioManager.FLAG_VIBRATE;
983 if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
984 }
985
RoboErik272e1612014-09-05 11:39:29 -0700986 adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987 }
988
989 /** @see AudioManager#adjustStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700990 public void adjustStreamVolume(int streamType, int direction, int flags,
991 String callingPackage) {
RoboErik0dac35a2014-08-12 15:48:49 -0700992 adjustStreamVolume(streamType, direction, flags, callingPackage, Binder.getCallingUid());
993 }
994
995 private void adjustStreamVolume(int streamType, int direction, int flags,
996 String callingPackage, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -0700997 if (mUseFixedVolume) {
998 return;
999 }
John Spurlockae641c92014-06-30 18:11:40 -04001000 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction
1001 + ", flags="+flags);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07001002
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001003 ensureValidDirection(direction);
1004 ensureValidStreamType(streamType);
1005
RoboErik4197cb62015-01-21 15:45:32 -08001006 boolean isMuteAdjust = isMuteAdjust(direction);
1007
John Spurlock3ce37252015-02-17 13:20:45 -05001008 if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
1009 return;
1010 }
1011
Eric Laurent96a33d12011-11-08 10:31:57 -08001012 // use stream type alias here so that streams with same alias have the same behavior,
1013 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
1014 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
Eric Laurent6d517662012-04-23 18:42:39 -07001015 int streamTypeAlias = mStreamVolumeAlias[streamType];
RoboErik4197cb62015-01-21 15:45:32 -08001016
Eric Laurentb024c302011-10-14 17:19:27 -07001017 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001018
1019 final int device = getDeviceForStream(streamTypeAlias);
Eric Laurent3ef75492012-11-28 12:12:23 -08001020
Eric Laurent42b041e2013-03-29 11:36:03 -07001021 int aliasIndex = streamState.getIndex(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001022 boolean adjustVolume = true;
Eric Laurent3ef75492012-11-28 12:12:23 -08001023 int step;
Eric Laurent24482012012-05-10 09:41:17 -07001024
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001025 // skip a2dp absolute volume control request when the device
1026 // is not an a2dp device
1027 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1028 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1029 return;
1030 }
1031
John Spurlock59dc9c12015-03-02 11:20:15 -05001032 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001033 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001034 return;
1035 }
1036
Eric Laurentfde16d52012-12-03 14:42:39 -08001037 // reset any pending volume command
1038 synchronized (mSafeMediaVolumeState) {
1039 mPendingVolumeCommand = null;
1040 }
1041
Eric Laurent3ef75492012-11-28 12:12:23 -08001042 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1043 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1044 ((device & mFixedVolumeDevices) != 0)) {
1045 flags |= AudioManager.FLAG_FIXED_VOLUME;
1046
1047 // Always toggle between max safe volume and 0 for fixed volume devices where safe
1048 // volume is enforced, and max and 0 for the others.
1049 // This is simulated by stepping by the full allowed volume range
1050 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1051 (device & mSafeMediaVolumeDevices) != 0) {
1052 step = mSafeMediaVolumeIndex;
1053 } else {
1054 step = streamState.getMaxIndex();
1055 }
1056 if (aliasIndex != 0) {
1057 aliasIndex = step;
1058 }
1059 } else {
1060 // convert one UI step (+/-1) into a number of internal units on the stream alias
1061 step = rescaleIndex(10, streamType, streamTypeAlias);
1062 }
1063
Eric Laurent42b041e2013-03-29 11:36:03 -07001064 // If either the client forces allowing ringer modes for this adjustment,
1065 // or the stream type is one that is affected by ringer modes
1066 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlockee5ad722015-03-03 16:17:21 -05001067 (streamTypeAlias == getUiSoundsStreamType())) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001068 int ringerMode = getRingerModeInternal();
Eric Laurent42b041e2013-03-29 11:36:03 -07001069 // do not vibrate if already in vibrate mode
1070 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
1071 flags &= ~AudioManager.FLAG_VIBRATE;
Eric Laurent3ef75492012-11-28 12:12:23 -08001072 }
RoboErik5452e252015-02-06 15:33:53 -08001073 // Check if the ringer mode handles this adjustment. If it does we don't
1074 // need to adjust the volume further.
1075 final int result = checkForRingerModeChange(aliasIndex, direction, step, streamState.mIsMuted);
John Spurlocka11b4af2014-06-01 11:52:23 -04001076 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
1077 // If suppressing a volume adjustment in silent mode, display the UI hint
1078 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
1079 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
1080 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001081 // If suppressing a volume down adjustment in vibrate mode, display the UI hint
1082 if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
1083 flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
1084 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001085 }
Eric Laurent3ef75492012-11-28 12:12:23 -08001086
Eric Laurent42b041e2013-03-29 11:36:03 -07001087 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001088
Eric Laurent42b041e2013-03-29 11:36:03 -07001089 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
RoboErik5452e252015-02-06 15:33:53 -08001090 mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001091
John Du5a0cf7a2013-07-19 11:30:34 -07001092 // Check if volume update should be send to AVRCP
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001093 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1094 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1095 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1096 synchronized (mA2dpAvrcpLock) {
1097 if (mA2dp != null && mAvrcpAbsVolSupported) {
1098 mA2dp.adjustAvrcpAbsoluteVolume(direction);
1099 }
John Du5a0cf7a2013-07-19 11:30:34 -07001100 }
1101 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001102
RoboErik4197cb62015-01-21 15:45:32 -08001103 if (isMuteAdjust) {
1104 boolean state;
1105 if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
1106 state = !streamState.mIsMuted;
1107 } else {
1108 state = direction == AudioManager.ADJUST_MUTE;
1109 }
1110 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1111 setSystemAudioMute(state);
1112 }
1113 for (int stream = 0; stream < mStreamStates.length; stream++) {
1114 if (streamTypeAlias == mStreamVolumeAlias[stream]) {
1115 mStreamStates[stream].mute(state);
RoboErik4197cb62015-01-21 15:45:32 -08001116 }
1117 }
1118 } else if ((direction == AudioManager.ADJUST_RAISE) &&
Eric Laurent42b041e2013-03-29 11:36:03 -07001119 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
RoboErik4197cb62015-01-21 15:45:32 -08001120 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -04001121 mVolumeController.postDisplaySafeVolumeWarning(flags);
RoboErik4197cb62015-01-21 15:45:32 -08001122 } else if (streamState.adjustIndex(direction * step, device) || streamState.mIsMuted) {
1123 // Post message to set system volume (it in turn will post a
1124 // message to persist).
1125 if (streamState.mIsMuted) {
1126 // Unmute the stream if it was previously muted
RoboErik5452e252015-02-06 15:33:53 -08001127 if (direction == AudioManager.ADJUST_RAISE) {
1128 // unmute immediately for volume up
1129 streamState.mute(false);
1130 } else if (direction == AudioManager.ADJUST_LOWER) {
1131 sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
1132 streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
1133 }
RoboErik4197cb62015-01-21 15:45:32 -08001134 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001135 sendMsg(mAudioHandler,
1136 MSG_SET_DEVICE_VOLUME,
1137 SENDMSG_QUEUE,
1138 device,
1139 0,
1140 streamState,
1141 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001142 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001143
RoboErik4197cb62015-01-21 15:45:32 -08001144 // Check if volume update should be sent to Hdmi system audio.
Jungshik Jang41d97462014-06-30 22:26:29 +09001145 int newIndex = mStreamStates[streamType].getIndex(device);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001146 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1147 setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
1148 }
Eric Laurent212532b2014-07-21 15:43:18 -07001149 if (mHdmiManager != null) {
1150 synchronized (mHdmiManager) {
Eric Laurent212532b2014-07-21 15:43:18 -07001151 // mHdmiCecSink true => mHdmiPlaybackClient != null
1152 if (mHdmiCecSink &&
1153 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1154 oldIndex != newIndex) {
1155 synchronized (mHdmiPlaybackClient) {
1156 int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
RoboErik4197cb62015-01-21 15:45:32 -08001157 KeyEvent.KEYCODE_VOLUME_UP;
Eric Laurent212532b2014-07-21 15:43:18 -07001158 mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1159 mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1160 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001161 }
1162 }
1163 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001164 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001165 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001166 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001167 }
1168
RoboErik5452e252015-02-06 15:33:53 -08001169 // Called after a delay when volume down is pressed while muted
1170 private void onUnmuteStream(int stream, int flags) {
1171 VolumeStreamState streamState = mStreamStates[stream];
1172 streamState.mute(false);
1173
1174 final int device = getDeviceForStream(stream);
1175 final int index = mStreamStates[stream].getIndex(device);
1176 sendVolumeUpdate(stream, index, index, flags);
1177 }
1178
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001179 private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
1180 if (mHdmiManager == null
1181 || mHdmiTvClient == null
1182 || oldVolume == newVolume
1183 || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
1184
1185 // Sets the audio volume of AVR when we are in system audio mode. The new volume info
1186 // is tranformed to HDMI-CEC commands and passed through CEC bus.
1187 synchronized (mHdmiManager) {
1188 if (!mHdmiSystemAudioSupported) return;
1189 synchronized (mHdmiTvClient) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001190 final long token = Binder.clearCallingIdentity();
1191 try {
Jinsuk Kim7a9ba422015-02-16 16:47:38 +09001192 mHdmiTvClient.setSystemAudioVolume(oldVolume, newVolume, maxVolume);
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001193 } finally {
1194 Binder.restoreCallingIdentity(token);
1195 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001196 }
1197 }
1198 }
1199
Eric Laurentfde16d52012-12-03 14:42:39 -08001200 // StreamVolumeCommand contains the information needed to defer the process of
1201 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1202 class StreamVolumeCommand {
1203 public final int mStreamType;
1204 public final int mIndex;
1205 public final int mFlags;
1206 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001207
Eric Laurentfde16d52012-12-03 14:42:39 -08001208 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1209 mStreamType = streamType;
1210 mIndex = index;
1211 mFlags = flags;
1212 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001213 }
John Spurlock35134602014-07-24 18:10:48 -04001214
1215 @Override
1216 public String toString() {
1217 return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1218 .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1219 .append(mDevice).append('}').toString();
1220 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001221 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001222
Eric Laurentfde16d52012-12-03 14:42:39 -08001223 private void onSetStreamVolume(int streamType, int index, int flags, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001224 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
John Spurlockee5ad722015-03-03 16:17:21 -05001225 // setting volume on ui sounds stream type also controls silent mode
Eric Laurent3ef75492012-11-28 12:12:23 -08001226 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlockee5ad722015-03-03 16:17:21 -05001227 (mStreamVolumeAlias[streamType] == getUiSoundsStreamType())) {
Eric Laurent3ef75492012-11-28 12:12:23 -08001228 int newRingerMode;
1229 if (index == 0) {
1230 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlock86005342014-05-23 11:58:00 -04001231 : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
1232 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001233 } else {
1234 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1235 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001236 setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/);
Eric Laurent3ef75492012-11-28 12:12:23 -08001237 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001238 }
1239
1240 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001241 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
RoboErik0dac35a2014-08-12 15:48:49 -07001242 setStreamVolume(streamType, index, flags, callingPackage, Binder.getCallingUid());
1243 }
1244
1245 private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
1246 int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001247 if (mUseFixedVolume) {
1248 return;
1249 }
1250
Eric Laurentfde16d52012-12-03 14:42:39 -08001251 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001252 int streamTypeAlias = mStreamVolumeAlias[streamType];
1253 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001254
1255 final int device = getDeviceForStream(streamType);
1256 int oldIndex;
1257
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001258 // skip a2dp absolute volume control request when the device
1259 // is not an a2dp device
1260 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1261 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1262 return;
1263 }
1264
John Spurlock59dc9c12015-03-02 11:20:15 -05001265 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001266 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001267 return;
1268 }
1269
Eric Laurentfde16d52012-12-03 14:42:39 -08001270 synchronized (mSafeMediaVolumeState) {
1271 // reset any pending volume command
1272 mPendingVolumeCommand = null;
1273
Eric Laurent42b041e2013-03-29 11:36:03 -07001274 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001275
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001276 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001277
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001278 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1279 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1280 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1281 synchronized (mA2dpAvrcpLock) {
1282 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001283 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001284 }
John Du5a0cf7a2013-07-19 11:30:34 -07001285 }
1286 }
1287
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001288 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1289 setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
Jungshik Jang41d97462014-06-30 22:26:29 +09001290 }
1291
Eric Laurentfde16d52012-12-03 14:42:39 -08001292 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001293 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001294 ((device & mFixedVolumeDevices) != 0)) {
1295 flags |= AudioManager.FLAG_FIXED_VOLUME;
1296
1297 // volume is either 0 or max allowed for fixed volume devices
1298 if (index != 0) {
1299 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1300 (device & mSafeMediaVolumeDevices) != 0) {
1301 index = mSafeMediaVolumeIndex;
1302 } else {
1303 index = streamState.getMaxIndex();
1304 }
1305 }
1306 }
1307
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001308 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001309 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001310 mPendingVolumeCommand = new StreamVolumeCommand(
1311 streamType, index, flags, device);
1312 } else {
1313 onSetStreamVolume(streamType, index, flags, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07001314 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001315 }
1316 }
Eric Laurent25101b02011-02-02 09:33:30 -08001317 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318 }
1319
Eric Laurent45c90ce2012-04-24 18:44:22 -07001320 /** @see AudioManager#forceVolumeControlStream(int) */
1321 public void forceVolumeControlStream(int streamType, IBinder cb) {
1322 synchronized(mForceControlStreamLock) {
1323 mVolumeControlStream = streamType;
1324 if (mVolumeControlStream == -1) {
1325 if (mForceControlStreamClient != null) {
1326 mForceControlStreamClient.release();
1327 mForceControlStreamClient = null;
1328 }
1329 } else {
1330 mForceControlStreamClient = new ForceControlStreamClient(cb);
1331 }
1332 }
1333 }
1334
1335 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1336 private IBinder mCb; // To be notified of client's death
1337
1338 ForceControlStreamClient(IBinder cb) {
1339 if (cb != null) {
1340 try {
1341 cb.linkToDeath(this, 0);
1342 } catch (RemoteException e) {
1343 // Client has died!
1344 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1345 cb = null;
1346 }
1347 }
1348 mCb = cb;
1349 }
1350
1351 public void binderDied() {
1352 synchronized(mForceControlStreamLock) {
1353 Log.w(TAG, "SCO client died");
1354 if (mForceControlStreamClient != this) {
1355 Log.w(TAG, "unregistered control stream client died");
1356 } else {
1357 mForceControlStreamClient = null;
1358 mVolumeControlStream = -1;
1359 }
1360 }
1361 }
1362
1363 public void release() {
1364 if (mCb != null) {
1365 mCb.unlinkToDeath(this, 0);
1366 mCb = null;
1367 }
1368 }
1369 }
1370
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001371 private void sendBroadcastToAll(Intent intent) {
Christopher Tate267603f2015-01-20 14:21:21 -08001372 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
John Spurlock86490862015-02-25 11:22:52 -05001373 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001374 final long ident = Binder.clearCallingIdentity();
1375 try {
1376 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1377 } finally {
1378 Binder.restoreCallingIdentity(ident);
1379 }
1380 }
1381
1382 private void sendStickyBroadcastToAll(Intent intent) {
John Spurlock86490862015-02-25 11:22:52 -05001383 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001384 final long ident = Binder.clearCallingIdentity();
1385 try {
1386 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1387 } finally {
1388 Binder.restoreCallingIdentity(ident);
1389 }
1390 }
1391
Eric Laurent25101b02011-02-02 09:33:30 -08001392 // UI update and Broadcast Intent
1393 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
Eric Laurent212532b2014-07-21 15:43:18 -07001394 if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) {
Eric Laurent25101b02011-02-02 09:33:30 -08001395 streamType = AudioSystem.STREAM_NOTIFICATION;
1396 }
1397
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001398 if (streamType == AudioSystem.STREAM_MUSIC) {
1399 flags = updateFlagsForSystemAudio(flags);
Jungshik Jang1a6be6e2014-09-16 11:04:54 +09001400 }
John Spurlock3346a802014-05-20 16:25:37 -04001401 mVolumeController.postVolumeChanged(streamType, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001402 }
1403
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001404 // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
1405 // receives volume notification from Audio Receiver.
1406 private int updateFlagsForSystemAudio(int flags) {
1407 if (mHdmiTvClient != null) {
1408 synchronized (mHdmiTvClient) {
1409 if (mHdmiSystemAudioSupported &&
1410 ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
1411 flags &= ~AudioManager.FLAG_SHOW_UI;
1412 }
1413 }
1414 }
1415 return flags;
1416 }
1417
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001418 // UI update and Broadcast Intent
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001419 private void sendMasterMuteUpdate(boolean muted, int flags) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001420 mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
Justin Koh57978ed2012-04-03 17:37:58 -07001421 broadcastMasterMuteStatus(muted);
1422 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001423
Justin Koh57978ed2012-04-03 17:37:58 -07001424 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001425 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1426 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001427 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1428 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001429 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001430 }
1431
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001432 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001433 * Sets the stream state's index, and posts a message to set system volume.
1434 * This will not call out to the UI. Assumes a valid stream type.
1435 *
1436 * @param streamType Type of the stream
1437 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001438 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001439 * @param force If true, set the volume even if the desired volume is same
1440 * as the current volume.
1441 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001442 private void setStreamVolumeInt(int streamType,
1443 int index,
1444 int device,
Eric Laurent42b041e2013-03-29 11:36:03 -07001445 boolean force) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001446 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07001447
Eric Laurent42b041e2013-03-29 11:36:03 -07001448 if (streamState.setIndex(index, device) || force) {
1449 // Post message to set system volume (it in turn will post a message
1450 // to persist).
1451 sendMsg(mAudioHandler,
1452 MSG_SET_DEVICE_VOLUME,
1453 SENDMSG_QUEUE,
1454 device,
1455 0,
1456 streamState,
1457 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001458 }
1459 }
1460
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001461 private void setSystemAudioMute(boolean state) {
1462 if (mHdmiManager == null || mHdmiTvClient == null) return;
1463 synchronized (mHdmiManager) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001464 if (!mHdmiSystemAudioSupported) return;
1465 synchronized (mHdmiTvClient) {
1466 final long token = Binder.clearCallingIdentity();
1467 try {
1468 mHdmiTvClient.setSystemAudioMute(state);
1469 } finally {
1470 Binder.restoreCallingIdentity(token);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001471 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001472 }
1473 }
1474 }
1475
Eric Laurent25101b02011-02-02 09:33:30 -08001476 /** get stream mute state. */
1477 public boolean isStreamMute(int streamType) {
RoboErik7c82ced2014-12-04 17:39:08 -08001478 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1479 streamType = getActiveStreamType(streamType);
1480 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001481 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08001482 return mStreamStates[streamType].mIsMuted;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001483 }
Eric Laurent25101b02011-02-02 09:33:30 -08001484 }
1485
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07001486 private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
1487 private IBinder mICallback; // To be notified of client's death
1488
1489 RmtSbmxFullVolDeathHandler(IBinder cb) {
1490 mICallback = cb;
1491 try {
1492 cb.linkToDeath(this, 0/*flags*/);
1493 } catch (RemoteException e) {
1494 Log.e(TAG, "can't link to death", e);
1495 }
1496 }
1497
1498 boolean isHandlerFor(IBinder cb) {
1499 return mICallback.equals(cb);
1500 }
1501
1502 void forget() {
1503 try {
1504 mICallback.unlinkToDeath(this, 0/*flags*/);
1505 } catch (NoSuchElementException e) {
1506 Log.e(TAG, "error unlinking to death", e);
1507 }
1508 }
1509
1510 public void binderDied() {
1511 Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
1512 forceRemoteSubmixFullVolume(false, mICallback);
1513 }
1514 }
1515
1516 /**
1517 * call must be synchronized on mRmtSbmxFullVolDeathHandlers
1518 * @return true if there is a registered death handler, false otherwise */
1519 private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1520 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1521 while (it.hasNext()) {
1522 final RmtSbmxFullVolDeathHandler handler = it.next();
1523 if (handler.isHandlerFor(cb)) {
1524 handler.forget();
1525 mRmtSbmxFullVolDeathHandlers.remove(handler);
1526 return true;
1527 }
1528 }
1529 return false;
1530 }
1531
1532 /** call synchronized on mRmtSbmxFullVolDeathHandlers */
1533 private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1534 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1535 while (it.hasNext()) {
1536 if (it.next().isHandlerFor(cb)) {
1537 return true;
1538 }
1539 }
1540 return false;
1541 }
1542
1543 private int mRmtSbmxFullVolRefCount = 0;
1544 private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
1545 new ArrayList<RmtSbmxFullVolDeathHandler>();
1546
1547 public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
1548 if (cb == null) {
1549 return;
1550 }
1551 if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
1552 android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
1553 Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
1554 return;
1555 }
1556 synchronized(mRmtSbmxFullVolDeathHandlers) {
1557 boolean applyRequired = false;
1558 if (startForcing) {
1559 if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
1560 mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
1561 if (mRmtSbmxFullVolRefCount == 0) {
1562 mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1563 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1564 applyRequired = true;
1565 }
1566 mRmtSbmxFullVolRefCount++;
1567 }
1568 } else {
1569 if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
1570 mRmtSbmxFullVolRefCount--;
1571 if (mRmtSbmxFullVolRefCount == 0) {
1572 mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1573 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1574 applyRequired = true;
1575 }
1576 }
1577 }
1578 if (applyRequired) {
1579 // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
1580 checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
1581 mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
1582 }
1583 }
1584 }
1585
John Spurlockee5ad722015-03-03 16:17:21 -05001586 private void setMasterMuteInternal(boolean mute, int flags, String callingPackage, int uid) {
RoboErik7c82ced2014-12-04 17:39:08 -08001587 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
1588 != AppOpsManager.MODE_ALLOWED) {
Julia Reynolds4a21b252014-06-04 11:11:43 -04001589 return;
1590 }
John Spurlockee5ad722015-03-03 16:17:21 -05001591 if (mute != AudioSystem.getMasterMute()) {
1592 setSystemAudioMute(mute);
1593 AudioSystem.setMasterMute(mute);
Justin Koh57978ed2012-04-03 17:37:58 -07001594 // Post a persist master volume msg
John Spurlockee5ad722015-03-03 16:17:21 -05001595 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, mute ? 1
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001596 : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
John Spurlockee5ad722015-03-03 16:17:21 -05001597 sendMasterMuteUpdate(mute, flags);
RoboErik7c82ced2014-12-04 17:39:08 -08001598
1599 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
John Spurlockee5ad722015-03-03 16:17:21 -05001600 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute);
RoboErik7c82ced2014-12-04 17:39:08 -08001601 sendBroadcastToAll(intent);
Jason Simmons1ce5b262012-02-02 13:00:17 -08001602 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08001603 }
1604
1605 /** get master mute state. */
1606 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08001607 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001608 }
1609
John Spurlockee5ad722015-03-03 16:17:21 -05001610 public void setMasterMute(boolean mute, int flags, String callingPackage) {
1611 setMasterMuteInternal(mute, flags, callingPackage, Binder.getCallingUid());
1612 }
1613
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07001614 protected static int getMaxStreamVolume(int streamType) {
1615 return MAX_STREAM_VOLUME[streamType];
1616 }
1617
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001618 /** @see AudioManager#getStreamVolume(int) */
1619 public int getStreamVolume(int streamType) {
1620 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001621 int device = getDeviceForStream(streamType);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001622 synchronized (VolumeStreamState.class) {
1623 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001624
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001625 // by convention getStreamVolume() returns 0 when a stream is muted.
RoboErik4197cb62015-01-21 15:45:32 -08001626 if (mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001627 index = 0;
1628 }
1629 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
1630 (device & mFixedVolumeDevices) != 0) {
1631 index = mStreamStates[streamType].getMaxIndex();
1632 }
1633 return (index + 5) / 10;
Eric Laurent42b041e2013-03-29 11:36:03 -07001634 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001635 }
1636
1637 /** @see AudioManager#getStreamMaxVolume(int) */
1638 public int getStreamMaxVolume(int streamType) {
1639 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07001640 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001641 }
1642
Eric Laurent25101b02011-02-02 09:33:30 -08001643 /** Get last audible volume before stream was muted. */
1644 public int getLastAudibleStreamVolume(int streamType) {
1645 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001646 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001647 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08001648 }
1649
John Spurlockee5ad722015-03-03 16:17:21 -05001650 /** @see AudioManager#getUiSoundsStreamType() */
1651 public int getUiSoundsStreamType() {
John Spurlock4f0f1202014-08-05 13:28:33 -04001652 return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
Eric Laurent6d517662012-04-23 18:42:39 -07001653 }
1654
Emily Bernier22c921a2014-05-28 11:01:32 -04001655 /** @see AudioManager#setMicrophoneMute(boolean) */
1656 public void setMicrophoneMute(boolean on, String callingPackage) {
1657 if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(),
1658 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1659 return;
1660 }
Jean-Michel Trivi4a4fea02014-08-29 18:14:09 -07001661 if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
1662 return;
1663 }
Emily Bernier22c921a2014-05-28 11:01:32 -04001664
1665 AudioSystem.muteMicrophone(on);
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001666 // Post a persist microphone msg.
1667 sendMsg(mAudioHandler, MSG_PERSIST_MICROPHONE_MUTE, SENDMSG_REPLACE, on ? 1
1668 : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
Emily Bernier22c921a2014-05-28 11:01:32 -04001669 }
1670
John Spurlock661f2cf2014-11-17 10:29:10 -05001671 @Override
1672 public int getRingerModeExternal() {
1673 synchronized(mSettingsLock) {
1674 return mRingerModeExternal;
1675 }
1676 }
1677
1678 @Override
1679 public int getRingerModeInternal() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001680 synchronized(mSettingsLock) {
1681 return mRingerMode;
1682 }
1683 }
1684
1685 private void ensureValidRingerMode(int ringerMode) {
John Spurlock97559372014-10-24 16:27:36 -04001686 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001687 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1688 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001689 }
1690
John Spurlock97559372014-10-24 16:27:36 -04001691 /** @see AudioManager#isValidRingerMode(int) */
1692 public boolean isValidRingerMode(int ringerMode) {
1693 return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
1694 }
1695
John Spurlock661f2cf2014-11-17 10:29:10 -05001696 public void setRingerModeExternal(int ringerMode, String caller) {
John Spurlockaf88a192014-12-23 16:14:44 -05001697 setRingerMode(ringerMode, caller, true /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05001698 }
1699
1700 public void setRingerModeInternal(int ringerMode, String caller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05001701 enforceVolumeController("setRingerModeInternal");
John Spurlockaf88a192014-12-23 16:14:44 -05001702 setRingerMode(ringerMode, caller, false /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05001703 }
1704
1705 private void setRingerMode(int ringerMode, String caller, boolean external) {
Eric Laurent212532b2014-07-21 15:43:18 -07001706 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001707 return;
1708 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001709 if (caller == null || caller.length() == 0) {
1710 throw new IllegalArgumentException("Bad caller: " + caller);
1711 }
John Spurlock97559372014-10-24 16:27:36 -04001712 ensureValidRingerMode(ringerMode);
Eric Laurent24482012012-05-10 09:41:17 -07001713 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1714 ringerMode = AudioManager.RINGER_MODE_SILENT;
1715 }
John Spurlockaf88a192014-12-23 16:14:44 -05001716 final long identity = Binder.clearCallingIdentity();
1717 try {
1718 synchronized (mSettingsLock) {
1719 final int ringerModeInternal = getRingerModeInternal();
1720 final int ringerModeExternal = getRingerModeExternal();
1721 if (external) {
1722 setRingerModeExt(ringerMode);
1723 if (mRingerModeDelegate != null) {
1724 ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
1725 ringerMode, caller, ringerModeInternal);
1726 }
1727 if (ringerMode != ringerModeInternal) {
1728 setRingerModeInt(ringerMode, true /*persist*/);
1729 }
1730 } else /*internal*/ {
1731 if (ringerMode != ringerModeInternal) {
1732 setRingerModeInt(ringerMode, true /*persist*/);
1733 }
1734 if (mRingerModeDelegate != null) {
1735 ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
1736 ringerMode, caller, ringerModeExternal);
1737 }
1738 setRingerModeExt(ringerMode);
John Spurlock57627792014-12-11 11:29:54 -05001739 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001740 }
John Spurlockaf88a192014-12-23 16:14:44 -05001741 } finally {
1742 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 }
1744 }
1745
John Spurlock661f2cf2014-11-17 10:29:10 -05001746 private void setRingerModeExt(int ringerMode) {
1747 synchronized(mSettingsLock) {
1748 if (ringerMode == mRingerModeExternal) return;
1749 mRingerModeExternal = ringerMode;
John Spurlocke5b42d92014-10-15 12:03:48 -04001750 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001751 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05001752 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
John Spurlocke5b42d92014-10-15 12:03:48 -04001753 }
1754
Eric Laurent4050c932009-07-08 02:52:14 -07001755 private void setRingerModeInt(int ringerMode, boolean persist) {
John Spurlockbcc10872014-11-28 15:29:21 -05001756 final boolean change;
Glenn Kastenba195eb2011-12-13 09:30:40 -08001757 synchronized(mSettingsLock) {
John Spurlockbcc10872014-11-28 15:29:21 -05001758 change = mRingerMode != ringerMode;
Glenn Kastenba195eb2011-12-13 09:30:40 -08001759 mRingerMode = ringerMode;
1760 }
Jason Parekhb1096152009-03-24 17:48:25 -07001761
Eric Laurent5b4e6542010-03-19 20:02:21 -07001762 // Mute stream if not previously muted by ringer mode and ringer mode
1763 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
1764 // Unmute stream if previously muted by ringer mode and ringer mode
1765 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07001766 int numStreamTypes = AudioSystem.getNumStreamTypes();
John Spurlock661f2cf2014-11-17 10:29:10 -05001767 final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE
1768 || ringerMode == AudioManager.RINGER_MODE_SILENT;
Eric Laurent5b4e6542010-03-19 20:02:21 -07001769 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001770 final boolean isMuted = isStreamMutedByRingerMode(streamType);
1771 final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
1772 if (isMuted == shouldMute) continue;
1773 if (!shouldMute) {
1774 // unmute
1775 // ring and notifications volume should never be 0 when not silenced
1776 // on voice capable devices or devices that support vibration
1777 if ((isPlatformVoice() || mHasVibrator) &&
1778 mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
1779 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05001780 SparseIntArray indexMap = mStreamStates[streamType].mIndexMap;
1781 for (int i = 0; i < indexMap.size(); i++) {
1782 int device = indexMap.keyAt(i);
1783 int value = indexMap.valueAt(i);
1784 if (value == 0) {
1785 indexMap.put(device, 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001786 }
1787 }
Eric Laurent9e0d25f2015-02-12 17:28:53 -08001788 // Persist volume for stream ring when it is changed here
1789 final int device = getDeviceForStream(streamType);
1790 sendMsg(mAudioHandler,
1791 MSG_PERSIST_VOLUME,
1792 SENDMSG_QUEUE,
1793 device,
1794 0,
1795 mStreamStates[streamType],
1796 PERSIST_DELAY);
Eric Laurentb024c302011-10-14 17:19:27 -07001797 }
Eric Laurent9bcf4012009-06-12 06:09:28 -07001798 }
RoboErik4197cb62015-01-21 15:45:32 -08001799 mStreamStates[streamType].mute(false);
John Spurlock661f2cf2014-11-17 10:29:10 -05001800 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent5b4e6542010-03-19 20:02:21 -07001801 } else {
John Spurlock661f2cf2014-11-17 10:29:10 -05001802 // mute
RoboErik4197cb62015-01-21 15:45:32 -08001803 mStreamStates[streamType].mute(true);
John Spurlock661f2cf2014-11-17 10:29:10 -05001804 mRingerModeMutedStreams |= (1 << streamType);
Jason Parekhb1096152009-03-24 17:48:25 -07001805 }
1806 }
Eric Laurenta553c252009-07-17 12:17:14 -07001807
Jason Parekhb1096152009-03-24 17:48:25 -07001808 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07001809 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08001810 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07001811 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
1812 }
John Spurlockbcc10872014-11-28 15:29:21 -05001813 if (change) {
1814 // Send sticky broadcast
1815 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
1816 }
Jason Parekhb1096152009-03-24 17:48:25 -07001817 }
1818
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001819 /** @see AudioManager#shouldVibrate(int) */
1820 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001821 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001822
1823 switch (getVibrateSetting(vibrateType)) {
1824
1825 case AudioManager.VIBRATE_SETTING_ON:
John Spurlock57627792014-12-11 11:29:54 -05001826 return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001827
1828 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
John Spurlock57627792014-12-11 11:29:54 -05001829 return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001830
1831 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04001832 // return false, even for incoming calls
1833 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001834
1835 default:
1836 return false;
1837 }
1838 }
1839
1840 /** @see AudioManager#getVibrateSetting(int) */
1841 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001842 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843 return (mVibrateSetting >> (vibrateType * 2)) & 3;
1844 }
1845
1846 /** @see AudioManager#setVibrateSetting(int, int) */
1847 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
1848
Eric Laurentbffc3d12012-05-07 17:43:49 -07001849 if (!mHasVibrator) return;
1850
John Spurlock61560172015-02-06 19:46:04 -05001851 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
1852 vibrateSetting);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001853
1854 // Broadcast change
1855 broadcastVibrateSetting(vibrateType);
1856
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001857 }
1858
Eric Laurent9272b4b2010-01-23 17:12:59 -08001859 private class SetModeDeathHandler implements IBinder.DeathRecipient {
1860 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07001861 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001862 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
1863
Eric Laurent9f103de2011-09-08 15:04:23 -07001864 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08001865 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07001866 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001867 }
1868
1869 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07001870 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001871 synchronized(mSetModeDeathHandlers) {
1872 Log.w(TAG, "setMode() client died");
1873 int index = mSetModeDeathHandlers.indexOf(this);
1874 if (index < 0) {
1875 Log.w(TAG, "unregistered setMode() client died");
1876 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07001877 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
Eric Laurent9272b4b2010-01-23 17:12:59 -08001878 }
1879 }
Eric Laurent9f103de2011-09-08 15:04:23 -07001880 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1881 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07001882 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07001883 final long ident = Binder.clearCallingIdentity();
1884 disconnectBluetoothSco(newModeOwnerPid);
1885 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07001886 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08001887 }
1888
Marco Nelissenf1ddd512011-08-10 14:15:44 -07001889 public int getPid() {
1890 return mPid;
1891 }
1892
Eric Laurent9272b4b2010-01-23 17:12:59 -08001893 public void setMode(int mode) {
1894 mMode = mode;
1895 }
1896
1897 public int getMode() {
1898 return mMode;
1899 }
1900
1901 public IBinder getBinder() {
1902 return mCb;
1903 }
1904 }
1905
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001906 /** @see AudioManager#setMode(int) */
Eric Laurent9272b4b2010-01-23 17:12:59 -08001907 public void setMode(int mode, IBinder cb) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07001908 if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ")"); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001909 if (!checkAudioSettingsPermission("setMode()")) {
1910 return;
1911 }
Eric Laurenta553c252009-07-17 12:17:14 -07001912
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07001913 if ( (mode == AudioSystem.MODE_IN_CALL) &&
1914 (mContext.checkCallingOrSelfPermission(
1915 android.Manifest.permission.MODIFY_PHONE_STATE)
1916 != PackageManager.PERMISSION_GRANTED)) {
1917 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
1918 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
1919 return;
1920 }
1921
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08001922 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07001923 return;
1924 }
1925
Eric Laurentd7454be2011-09-14 08:45:58 -07001926 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07001927 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07001928 if (mode == AudioSystem.MODE_CURRENT) {
1929 mode = mMode;
1930 }
Eric Laurentd7454be2011-09-14 08:45:58 -07001931 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
Eric Laurent9f103de2011-09-08 15:04:23 -07001932 }
1933 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1934 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07001935 if (newModeOwnerPid != 0) {
1936 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07001937 }
1938 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08001939
Eric Laurent9f103de2011-09-08 15:04:23 -07001940 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07001941 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07001942 // any mode other than NORMAL.
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07001943 private int setModeInt(int mode, IBinder cb, int pid) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07001944 if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ")"); }
Eric Laurentd7454be2011-09-14 08:45:58 -07001945 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07001946 if (cb == null) {
1947 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07001948 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07001949 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08001950
Eric Laurent9f103de2011-09-08 15:04:23 -07001951 SetModeDeathHandler hdlr = null;
1952 Iterator iter = mSetModeDeathHandlers.iterator();
1953 while (iter.hasNext()) {
1954 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
1955 if (h.getPid() == pid) {
1956 hdlr = h;
1957 // Remove from client list so that it is re-inserted at top of list
1958 iter.remove();
1959 hdlr.getBinder().unlinkToDeath(hdlr, 0);
1960 break;
1961 }
1962 }
1963 int status = AudioSystem.AUDIO_STATUS_OK;
1964 do {
1965 if (mode == AudioSystem.MODE_NORMAL) {
1966 // get new mode from client at top the list if any
1967 if (!mSetModeDeathHandlers.isEmpty()) {
1968 hdlr = mSetModeDeathHandlers.get(0);
1969 cb = hdlr.getBinder();
1970 mode = hdlr.getMode();
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07001971 if (DEBUG_MODE) {
1972 Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
1973 + hdlr.mPid);
1974 }
Eric Laurentb9c9d262009-05-06 08:13:20 -07001975 }
Eric Laurent9f103de2011-09-08 15:04:23 -07001976 } else {
1977 if (hdlr == null) {
1978 hdlr = new SetModeDeathHandler(cb, pid);
1979 }
1980 // Register for client death notification
1981 try {
1982 cb.linkToDeath(hdlr, 0);
1983 } catch (RemoteException e) {
1984 // Client has died!
1985 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
1986 }
1987
1988 // Last client to call setMode() is always at top of client list
1989 // as required by SetModeDeathHandler.binderDied()
1990 mSetModeDeathHandlers.add(0, hdlr);
1991 hdlr.setMode(mode);
1992 }
1993
1994 if (mode != mMode) {
1995 status = AudioSystem.setPhoneState(mode);
1996 if (status == AudioSystem.AUDIO_STATUS_OK) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07001997 if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
Eric Laurent9f103de2011-09-08 15:04:23 -07001998 mMode = mode;
1999 } else {
2000 if (hdlr != null) {
2001 mSetModeDeathHandlers.remove(hdlr);
2002 cb.unlinkToDeath(hdlr, 0);
2003 }
2004 // force reading new top of mSetModeDeathHandlers stack
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07002005 if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
Eric Laurent9f103de2011-09-08 15:04:23 -07002006 mode = AudioSystem.MODE_NORMAL;
2007 }
2008 } else {
2009 status = AudioSystem.AUDIO_STATUS_OK;
2010 }
2011 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
2012
2013 if (status == AudioSystem.AUDIO_STATUS_OK) {
2014 if (mode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002015 if (mSetModeDeathHandlers.isEmpty()) {
2016 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
2017 } else {
2018 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2019 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002020 }
2021 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08002022 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07002023 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
2024 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
Eric Laurent6d517662012-04-23 18:42:39 -07002025
2026 updateStreamVolumeAlias(true /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002027 }
Eric Laurentd7454be2011-09-14 08:45:58 -07002028 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002029 }
2030
2031 /** @see AudioManager#getMode() */
2032 public int getMode() {
2033 return mMode;
2034 }
2035
Eric Laurente78fced2013-03-15 16:03:47 -07002036 //==========================================================================================
2037 // Sound Effects
2038 //==========================================================================================
2039
2040 private static final String TAG_AUDIO_ASSETS = "audio_assets";
2041 private static final String ATTR_VERSION = "version";
2042 private static final String TAG_GROUP = "group";
2043 private static final String ATTR_GROUP_NAME = "name";
2044 private static final String TAG_ASSET = "asset";
2045 private static final String ATTR_ASSET_ID = "id";
2046 private static final String ATTR_ASSET_FILE = "file";
2047
2048 private static final String ASSET_FILE_VERSION = "1.0";
2049 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
2050
Glenn Kasten167d1a22013-07-23 16:24:41 -07002051 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002052
2053 class LoadSoundEffectReply {
2054 public int mStatus = 1;
2055 };
2056
Eric Laurente78fced2013-03-15 16:03:47 -07002057 private void loadTouchSoundAssetDefaults() {
2058 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
2059 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
2060 SOUND_EFFECT_FILES_MAP[i][0] = 0;
2061 SOUND_EFFECT_FILES_MAP[i][1] = -1;
2062 }
2063 }
2064
2065 private void loadTouchSoundAssets() {
2066 XmlResourceParser parser = null;
2067
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002068 // only load assets once.
2069 if (!SOUND_EFFECT_FILES.isEmpty()) {
2070 return;
2071 }
2072
Eric Laurente78fced2013-03-15 16:03:47 -07002073 loadTouchSoundAssetDefaults();
2074
2075 try {
2076 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
2077
2078 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
2079 String version = parser.getAttributeValue(null, ATTR_VERSION);
2080 boolean inTouchSoundsGroup = false;
2081
2082 if (ASSET_FILE_VERSION.equals(version)) {
2083 while (true) {
2084 XmlUtils.nextElement(parser);
2085 String element = parser.getName();
2086 if (element == null) {
2087 break;
2088 }
2089 if (element.equals(TAG_GROUP)) {
2090 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
2091 if (GROUP_TOUCH_SOUNDS.equals(name)) {
2092 inTouchSoundsGroup = true;
2093 break;
2094 }
2095 }
2096 }
2097 while (inTouchSoundsGroup) {
2098 XmlUtils.nextElement(parser);
2099 String element = parser.getName();
2100 if (element == null) {
2101 break;
2102 }
2103 if (element.equals(TAG_ASSET)) {
2104 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
2105 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
2106 int fx;
2107
2108 try {
2109 Field field = AudioManager.class.getField(id);
2110 fx = field.getInt(null);
2111 } catch (Exception e) {
2112 Log.w(TAG, "Invalid touch sound ID: "+id);
2113 continue;
2114 }
2115
2116 int i = SOUND_EFFECT_FILES.indexOf(file);
2117 if (i == -1) {
2118 i = SOUND_EFFECT_FILES.size();
2119 SOUND_EFFECT_FILES.add(file);
2120 }
2121 SOUND_EFFECT_FILES_MAP[fx][0] = i;
2122 } else {
2123 break;
2124 }
2125 }
2126 }
2127 } catch (Resources.NotFoundException e) {
2128 Log.w(TAG, "audio assets file not found", e);
2129 } catch (XmlPullParserException e) {
2130 Log.w(TAG, "XML parser exception reading touch sound assets", e);
2131 } catch (IOException e) {
2132 Log.w(TAG, "I/O exception reading touch sound assets", e);
2133 } finally {
2134 if (parser != null) {
2135 parser.close();
2136 }
2137 }
2138 }
2139
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002140 /** @see AudioManager#playSoundEffect(int) */
2141 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002142 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002143 }
2144
2145 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002146 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07002147 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
2148 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
2149 return;
2150 }
2151
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002152 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002153 effectType, (int) (volume * 1000), null, 0);
2154 }
2155
2156 /**
2157 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08002158 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002159 */
2160 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002161 int attempts = 3;
2162 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08002163
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002164 synchronized (reply) {
2165 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
2166 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08002167 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07002168 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002169 } catch (InterruptedException e) {
2170 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08002171 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002172 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002173 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002174 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002175 }
2176
2177 /**
2178 * Unloads samples from the sound pool.
2179 * This method can be called to free some memory when
2180 * sound effects are disabled.
2181 */
2182 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002183 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002184 }
2185
Eric Laurenta60e2122010-12-28 16:49:07 -08002186 class SoundPoolListenerThread extends Thread {
2187 public SoundPoolListenerThread() {
2188 super("SoundPoolListenerThread");
2189 }
2190
2191 @Override
2192 public void run() {
2193
2194 Looper.prepare();
2195 mSoundPoolLooper = Looper.myLooper();
2196
2197 synchronized (mSoundEffectsLock) {
2198 if (mSoundPool != null) {
2199 mSoundPoolCallBack = new SoundPoolCallback();
2200 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2201 }
2202 mSoundEffectsLock.notify();
2203 }
2204 Looper.loop();
2205 }
2206 }
2207
2208 private final class SoundPoolCallback implements
2209 android.media.SoundPool.OnLoadCompleteListener {
2210
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002211 int mStatus = 1; // 1 means neither error nor last sample loaded yet
2212 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08002213
2214 public int status() {
2215 return mStatus;
2216 }
2217
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002218 public void setSamples(int[] samples) {
2219 for (int i = 0; i < samples.length; i++) {
2220 // do not wait ack for samples rejected upfront by SoundPool
2221 if (samples[i] > 0) {
2222 mSamples.add(samples[i]);
2223 }
2224 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002225 }
2226
2227 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2228 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002229 int i = mSamples.indexOf(sampleId);
2230 if (i >= 0) {
2231 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08002232 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002233 if ((status != 0) || mSamples. isEmpty()) {
2234 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08002235 mSoundEffectsLock.notify();
2236 }
2237 }
2238 }
2239 }
2240
Eric Laurent4050c932009-07-08 02:52:14 -07002241 /** @see AudioManager#reloadAudioSettings() */
2242 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002243 readAudioSettings(false /*userSwitch*/);
2244 }
2245
2246 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07002247 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2248 readPersistedSettings();
2249
2250 // restore volume settings
2251 int numStreamTypes = AudioSystem.getNumStreamTypes();
2252 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2253 VolumeStreamState streamState = mStreamStates[streamType];
2254
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002255 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2256 continue;
2257 }
2258
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002259 streamState.readSettings();
2260 synchronized (VolumeStreamState.class) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002261 // unmute stream that was muted but is not affect by mute anymore
RoboErik4197cb62015-01-21 15:45:32 -08002262 if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07002263 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
RoboErik4197cb62015-01-21 15:45:32 -08002264 streamState.mIsMuted = false;
Eric Laurent4050c932009-07-08 02:52:14 -07002265 }
Eric Laurent4050c932009-07-08 02:52:14 -07002266 }
2267 }
2268
Eric Laurent33902db2012-10-07 16:15:07 -07002269 // apply new ringer mode before checking volume for alias streams so that streams
2270 // muted by ringer mode have the correct volume
John Spurlock661f2cf2014-11-17 10:29:10 -05002271 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent33902db2012-10-07 16:15:07 -07002272
Eric Laurent212532b2014-07-21 15:43:18 -07002273 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07002274 checkAllAliasStreamVolumes();
2275
Eric Laurentd640bd32012-09-28 18:01:48 -07002276 synchronized (mSafeMediaVolumeState) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002277 mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2278 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2279 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
Eric Laurentd640bd32012-09-28 18:01:48 -07002280 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07002281 enforceSafeMediaVolume();
2282 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07002283 }
Eric Laurent4050c932009-07-08 02:52:14 -07002284 }
2285
Dianne Hackborn961cae92013-03-20 14:59:43 -07002286 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002287 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002288 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2289 return;
2290 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002291
2292 if (on) {
2293 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2294 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2295 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
2296 }
2297 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2298 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2299 mForcedUseForComm = AudioSystem.FORCE_NONE;
2300 }
Eric Laurentfa640152011-03-12 15:59:51 -08002301
Eric Laurentafbb0472011-12-15 09:04:23 -08002302 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002303 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002304 }
2305
2306 /** @see AudioManager#isSpeakerphoneOn() */
2307 public boolean isSpeakerphoneOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002308 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002309 }
2310
Dianne Hackborn961cae92013-03-20 14:59:43 -07002311 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002312 public void setBluetoothScoOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002313 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2314 return;
2315 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002316
2317 if (on) {
2318 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2319 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2320 mForcedUseForComm = AudioSystem.FORCE_NONE;
2321 }
Eric Laurentfa640152011-03-12 15:59:51 -08002322
Eric Laurentafbb0472011-12-15 09:04:23 -08002323 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002324 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08002325 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002326 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002327 }
2328
2329 /** @see AudioManager#isBluetoothScoOn() */
2330 public boolean isBluetoothScoOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002331 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002332 }
2333
Dianne Hackborn961cae92013-03-20 14:59:43 -07002334 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07002335 public void setBluetoothA2dpOn(boolean on) {
Eric Laurentc390bed2012-07-03 12:24:05 -07002336 synchronized (mBluetoothA2dpEnabledLock) {
2337 mBluetoothA2dpEnabled = on;
2338 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2339 AudioSystem.FOR_MEDIA,
2340 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2341 null, 0);
2342 }
Eric Laurent78472112012-05-21 08:57:21 -07002343 }
2344
2345 /** @see AudioManager#isBluetoothA2dpOn() */
2346 public boolean isBluetoothA2dpOn() {
2347 synchronized (mBluetoothA2dpEnabledLock) {
2348 return mBluetoothA2dpEnabled;
2349 }
2350 }
2351
Eric Laurent3def1ee2010-03-17 23:26:26 -07002352 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07002353 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
2354 int scoAudioMode =
2355 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
Liejun Taof4e51d82014-07-16 11:18:29 -07002356 SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
Eric Laurent83900752014-05-15 15:14:22 -07002357 startBluetoothScoInt(cb, scoAudioMode);
2358 }
2359
2360 /** @see AudioManager#startBluetoothScoVirtualCall() */
2361 public void startBluetoothScoVirtualCall(IBinder cb) {
2362 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
2363 }
2364
2365 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07002366 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002367 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002368 return;
2369 }
Eric Laurent854938a2011-02-22 12:05:20 -08002370 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002371 // The calling identity must be cleared before calling ScoClient.incCount().
2372 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2373 // and this must be done on behalf of system server to make sure permissions are granted.
2374 // The caller identity must be cleared after getScoClient() because it is needed if a new
2375 // client is created.
2376 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07002377 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08002378 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002379 }
2380
2381 /** @see AudioManager#stopBluetoothSco() */
2382 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07002383 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002384 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002385 return;
2386 }
Eric Laurent854938a2011-02-22 12:05:20 -08002387 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002388 // The calling identity must be cleared before calling ScoClient.decCount().
2389 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2390 // and this must be done on behalf of system server to make sure permissions are granted.
2391 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08002392 if (client != null) {
2393 client.decCount();
2394 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08002395 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002396 }
2397
Eric Laurent78472112012-05-21 08:57:21 -07002398
Eric Laurent3def1ee2010-03-17 23:26:26 -07002399 private class ScoClient implements IBinder.DeathRecipient {
2400 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002401 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002402 private int mStartcount; // number of SCO connections started by this client
2403
2404 ScoClient(IBinder cb) {
2405 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002406 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002407 mStartcount = 0;
2408 }
2409
2410 public void binderDied() {
2411 synchronized(mScoClients) {
2412 Log.w(TAG, "SCO client died");
2413 int index = mScoClients.indexOf(this);
2414 if (index < 0) {
2415 Log.w(TAG, "unregistered SCO client died");
2416 } else {
2417 clearCount(true);
2418 mScoClients.remove(this);
2419 }
2420 }
2421 }
2422
Eric Laurent83900752014-05-15 15:14:22 -07002423 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002424 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07002425 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002426 if (mStartcount == 0) {
2427 try {
2428 mCb.linkToDeath(this, 0);
2429 } catch (RemoteException e) {
2430 // client has already died!
2431 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
2432 }
2433 }
2434 mStartcount++;
2435 }
2436 }
2437
2438 public void decCount() {
2439 synchronized(mScoClients) {
2440 if (mStartcount == 0) {
2441 Log.w(TAG, "ScoClient.decCount() already 0");
2442 } else {
2443 mStartcount--;
2444 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002445 try {
2446 mCb.unlinkToDeath(this, 0);
2447 } catch (NoSuchElementException e) {
2448 Log.w(TAG, "decCount() going to 0 but not registered to binder");
2449 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002450 }
Eric Laurentc18c9132013-04-12 17:24:56 -07002451 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002452 }
2453 }
2454 }
2455
2456 public void clearCount(boolean stopSco) {
2457 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002458 if (mStartcount != 0) {
2459 try {
2460 mCb.unlinkToDeath(this, 0);
2461 } catch (NoSuchElementException e) {
2462 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2463 }
2464 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002465 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002466 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002467 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002468 }
2469 }
2470 }
2471
2472 public int getCount() {
2473 return mStartcount;
2474 }
2475
2476 public IBinder getBinder() {
2477 return mCb;
2478 }
2479
Eric Laurentd7454be2011-09-14 08:45:58 -07002480 public int getPid() {
2481 return mCreatorPid;
2482 }
2483
Eric Laurent3def1ee2010-03-17 23:26:26 -07002484 public int totalCount() {
2485 synchronized(mScoClients) {
2486 int count = 0;
2487 int size = mScoClients.size();
2488 for (int i = 0; i < size; i++) {
2489 count += mScoClients.get(i).getCount();
2490 }
2491 return count;
2492 }
2493 }
2494
Eric Laurent83900752014-05-15 15:14:22 -07002495 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08002496 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07002497 if (totalCount() == 0) {
2498 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2499 // Make sure that the state transitions to CONNECTING even if we cannot initiate
2500 // the connection.
2501 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2502 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002503 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07002504 synchronized(mSetModeDeathHandlers) {
2505 if ((mSetModeDeathHandlers.isEmpty() ||
2506 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2507 (mScoAudioState == SCO_STATE_INACTIVE ||
2508 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2509 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07002510 mScoAudioMode = scoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -07002511 if (scoAudioMode == SCO_MODE_UNDEFINED) {
Andre Eisenbach570cc532014-10-28 17:03:18 -07002512 if (mBluetoothHeadsetDevice != null) {
2513 mScoAudioMode = new Integer(Settings.Global.getInt(
2514 mContentResolver,
2515 "bluetooth_sco_channel_"+
2516 mBluetoothHeadsetDevice.getAddress(),
2517 SCO_MODE_VIRTUAL_CALL));
2518 if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2519 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2520 }
2521 } else {
2522 mScoAudioMode = SCO_MODE_RAW;
Liejun Taof4e51d82014-07-16 11:18:29 -07002523 }
2524 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002525 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002526 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002527 if (mScoAudioMode == SCO_MODE_RAW) {
2528 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002529 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002530 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2531 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002532 } else if (mScoAudioMode == SCO_MODE_VR) {
2533 status = mBluetoothHeadset.startVoiceRecognition(
2534 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002535 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002536
Eric Laurentc18c9132013-04-12 17:24:56 -07002537 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07002538 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2539 } else {
2540 broadcastScoConnectionState(
2541 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2542 }
2543 } else if (getBluetoothHeadset()) {
2544 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07002545 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002546 } else {
2547 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2548 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002549 }
2550 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07002551 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002552 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002553 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002554 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002555 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2556 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2557 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07002558 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002559 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002560 if (mScoAudioMode == SCO_MODE_RAW) {
2561 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002562 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002563 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2564 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002565 } else if (mScoAudioMode == SCO_MODE_VR) {
2566 status = mBluetoothHeadset.stopVoiceRecognition(
2567 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002568 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002569
Eric Laurentc18c9132013-04-12 17:24:56 -07002570 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002571 mScoAudioState = SCO_STATE_INACTIVE;
2572 broadcastScoConnectionState(
2573 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2574 }
2575 } else if (getBluetoothHeadset()) {
2576 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2577 }
2578 } else {
2579 mScoAudioState = SCO_STATE_INACTIVE;
2580 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2581 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002582 }
2583 }
2584 }
2585 }
2586
Eric Laurent62ef7672010-11-24 10:58:32 -08002587 private void checkScoAudioState() {
2588 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002589 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08002590 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2591 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2592 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2593 }
2594 }
2595
Eric Laurent854938a2011-02-22 12:05:20 -08002596 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002597 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002598 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002599 int size = mScoClients.size();
2600 for (int i = 0; i < size; i++) {
2601 client = mScoClients.get(i);
2602 if (client.getBinder() == cb)
2603 return client;
2604 }
Eric Laurent854938a2011-02-22 12:05:20 -08002605 if (create) {
2606 client = new ScoClient(cb);
2607 mScoClients.add(client);
2608 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002609 return client;
2610 }
2611 }
2612
Eric Laurentd7454be2011-09-14 08:45:58 -07002613 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002614 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002615 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002616 int size = mScoClients.size();
2617 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08002618 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07002619 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08002620 cl.clearCount(stopSco);
2621 } else {
2622 savedClient = cl;
2623 }
2624 }
2625 mScoClients.clear();
2626 if (savedClient != null) {
2627 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002628 }
2629 }
2630 }
2631
Eric Laurentdc03c612011-04-01 10:59:41 -07002632 private boolean getBluetoothHeadset() {
2633 boolean result = false;
2634 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2635 if (adapter != null) {
2636 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2637 BluetoothProfile.HEADSET);
2638 }
2639 // If we could not get a bluetooth headset proxy, send a failure message
2640 // without delay to reset the SCO audio state and clear SCO clients.
2641 // If we could get a proxy, send a delayed failure message that will reset our state
2642 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08002643 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002644 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2645 return result;
2646 }
2647
Eric Laurentd7454be2011-09-14 08:45:58 -07002648 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002649 synchronized(mScoClients) {
2650 checkScoAudioState();
2651 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2652 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2653 if (mBluetoothHeadsetDevice != null) {
2654 if (mBluetoothHeadset != null) {
2655 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07002656 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002657 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002658 SENDMSG_REPLACE, 0, 0, null, 0);
2659 }
2660 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2661 getBluetoothHeadset()) {
2662 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2663 }
2664 }
2665 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07002666 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07002667 }
2668 }
2669 }
2670
2671 private void resetBluetoothSco() {
2672 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002673 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07002674 mScoAudioState = SCO_STATE_INACTIVE;
2675 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2676 }
2677 }
2678
2679 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08002680 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
2681 SENDMSG_QUEUE, state, 0, null, 0);
2682 }
2683
2684 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002685 if (state != mScoConnectionState) {
2686 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2687 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2688 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2689 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002690 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07002691 mScoConnectionState = state;
2692 }
2693 }
2694
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002695 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
2696 new BluetoothProfile.ServiceListener() {
2697 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002698 BluetoothDevice btDevice;
2699 List<BluetoothDevice> deviceList;
2700 switch(profile) {
2701 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09002702 synchronized (mConnectedDevices) {
2703 synchronized (mA2dpAvrcpLock) {
2704 mA2dp = (BluetoothA2dp) proxy;
2705 deviceList = mA2dp.getConnectedDevices();
2706 if (deviceList.size() > 0) {
2707 btDevice = deviceList.get(0);
John Du5a0cf7a2013-07-19 11:30:34 -07002708 int state = mA2dp.getConnectionState(btDevice);
2709 int delay = checkSendBecomingNoisyIntent(
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002710 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2711 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
John Du5a0cf7a2013-07-19 11:30:34 -07002712 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002713 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07002714 state,
2715 0,
2716 btDevice,
2717 delay);
2718 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002719 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002720 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002721 break;
2722
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002723 case BluetoothProfile.A2DP_SINK:
2724 deviceList = proxy.getConnectedDevices();
2725 if (deviceList.size() > 0) {
2726 btDevice = deviceList.get(0);
2727 synchronized (mConnectedDevices) {
2728 int state = proxy.getConnectionState(btDevice);
2729 queueMsgUnderWakeLock(mAudioHandler,
2730 MSG_SET_A2DP_SRC_CONNECTION_STATE,
2731 state,
2732 0,
2733 btDevice,
2734 0 /* delay */);
2735 }
2736 }
2737 break;
2738
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002739 case BluetoothProfile.HEADSET:
2740 synchronized (mScoClients) {
2741 // Discard timeout message
2742 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
2743 mBluetoothHeadset = (BluetoothHeadset) proxy;
2744 deviceList = mBluetoothHeadset.getConnectedDevices();
2745 if (deviceList.size() > 0) {
2746 mBluetoothHeadsetDevice = deviceList.get(0);
2747 } else {
2748 mBluetoothHeadsetDevice = null;
2749 }
2750 // Refresh SCO audio state
2751 checkScoAudioState();
2752 // Continue pending action if any
2753 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
2754 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
2755 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2756 boolean status = false;
2757 if (mBluetoothHeadsetDevice != null) {
2758 switch (mScoAudioState) {
2759 case SCO_STATE_ACTIVATE_REQ:
2760 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07002761 if (mScoAudioMode == SCO_MODE_RAW) {
2762 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002763 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002764 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2765 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002766 } else if (mScoAudioMode == SCO_MODE_VR) {
2767 status = mBluetoothHeadset.startVoiceRecognition(
2768 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002769 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002770 break;
2771 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07002772 if (mScoAudioMode == SCO_MODE_RAW) {
2773 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002774 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002775 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2776 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002777 } else if (mScoAudioMode == SCO_MODE_VR) {
2778 status = mBluetoothHeadset.stopVoiceRecognition(
2779 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002780 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002781 break;
2782 case SCO_STATE_DEACTIVATE_EXT_REQ:
2783 status = mBluetoothHeadset.stopVoiceRecognition(
2784 mBluetoothHeadsetDevice);
2785 }
2786 }
2787 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002788 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002789 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07002790 }
2791 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002792 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002793 break;
2794
2795 default:
2796 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002797 }
2798 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002799 public void onServiceDisconnected(int profile) {
Paul McLean394a8e12015-03-03 10:29:19 -07002800 switch (profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002801 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09002802 synchronized (mConnectedDevices) {
2803 synchronized (mA2dpAvrcpLock) {
Paul McLean394a8e12015-03-03 10:29:19 -07002804 // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
2805 for(Map.Entry<String, DeviceListSpec> entry
2806 : mConnectedDevices.entrySet()) {
2807 DeviceListSpec deviceSpec = entry.getValue();
2808 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
2809 makeA2dpDeviceUnavailableNow(deviceSpec.mDeviceAddress);
2810 }
John Du5a0cf7a2013-07-19 11:30:34 -07002811 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002812 }
2813 }
2814 break;
2815
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002816 case BluetoothProfile.A2DP_SINK:
2817 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07002818 // Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
2819 for(Map.Entry<String, DeviceListSpec> entry
2820 : mConnectedDevices.entrySet()) {
2821 DeviceListSpec deviceSpec = entry.getValue();
2822 if (deviceSpec.mDeviceType == AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) {
2823 makeA2dpSrcUnavailable(deviceSpec.mDeviceAddress);
2824 }
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002825 }
2826 }
2827 break;
2828
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002829 case BluetoothProfile.HEADSET:
2830 synchronized (mScoClients) {
2831 mBluetoothHeadset = null;
2832 }
2833 break;
2834
2835 default:
2836 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002837 }
2838 }
2839 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08002840
Eric Laurentc34dcc12012-09-10 13:51:52 -07002841 private void onCheckMusicActive() {
Eric Laurentd640bd32012-09-28 18:01:48 -07002842 synchronized (mSafeMediaVolumeState) {
2843 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002844 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
2845
2846 if ((device & mSafeMediaVolumeDevices) != 0) {
2847 sendMsg(mAudioHandler,
2848 MSG_CHECK_MUSIC_ACTIVE,
2849 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07002850 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07002851 0,
2852 null,
2853 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07002854 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07002855 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
2856 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002857 // Approximate cumulative active music time
2858 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
2859 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
2860 setSafeMediaVolumeEnabled(true);
2861 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07002862 }
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002863 saveMusicActiveMs();
Eric Laurentc34dcc12012-09-10 13:51:52 -07002864 }
2865 }
2866 }
2867 }
2868 }
2869
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002870 private void saveMusicActiveMs() {
2871 mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
2872 }
2873
Eric Laurentd640bd32012-09-28 18:01:48 -07002874 private void onConfigureSafeVolume(boolean force) {
2875 synchronized (mSafeMediaVolumeState) {
2876 int mcc = mContext.getResources().getConfiguration().mcc;
2877 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
2878 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
2879 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
John Spurlock35134602014-07-24 18:10:48 -04002880 boolean safeMediaVolumeEnabled =
2881 SystemProperties.getBoolean("audio.safemedia.force", false)
2882 || mContext.getResources().getBoolean(
2883 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08002884
2885 // The persisted state is either "disabled" or "active": this is the state applied
2886 // next time we boot and cannot be "inactive"
2887 int persistedState;
Eric Laurentd640bd32012-09-28 18:01:48 -07002888 if (safeMediaVolumeEnabled) {
Eric Laurent05274f32012-11-29 12:48:18 -08002889 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
2890 // The state can already be "inactive" here if the user has forced it before
2891 // the 30 seconds timeout for forced configuration. In this case we don't reset
2892 // it to "active".
2893 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002894 if (mMusicActiveMs == 0) {
2895 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
2896 enforceSafeMediaVolume();
2897 } else {
2898 // We have existing playback time recorded, already confirmed.
2899 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
2900 }
Eric Laurent05274f32012-11-29 12:48:18 -08002901 }
Eric Laurentd640bd32012-09-28 18:01:48 -07002902 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08002903 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07002904 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
2905 }
2906 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08002907 sendMsg(mAudioHandler,
2908 MSG_PERSIST_SAFE_VOLUME_STATE,
2909 SENDMSG_QUEUE,
2910 persistedState,
2911 0,
2912 null,
2913 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07002914 }
2915 }
2916 }
2917
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002918 ///////////////////////////////////////////////////////////////////////////
2919 // Internal methods
2920 ///////////////////////////////////////////////////////////////////////////
2921
2922 /**
2923 * Checks if the adjustment should change ringer mode instead of just
2924 * adjusting volume. If so, this will set the proper ringer mode and volume
2925 * indices on the stream states.
2926 */
RoboErik5452e252015-02-06 15:33:53 -08002927 private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted) {
John Spurlocka11b4af2014-06-01 11:52:23 -04002928 int result = FLAG_ADJUST_VOLUME;
John Spurlock661f2cf2014-11-17 10:29:10 -05002929 int ringerMode = getRingerModeInternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002930
Eric Laurentbffc3d12012-05-07 17:43:49 -07002931 switch (ringerMode) {
2932 case RINGER_MODE_NORMAL:
2933 if (direction == AudioManager.ADJUST_LOWER) {
2934 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07002935 // "step" is the delta in internal index units corresponding to a
2936 // change of 1 in UI index units.
2937 // Because of rounding when rescaling from one stream index range to its alias
2938 // index range, we cannot simply test oldIndex == step:
2939 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
2940 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002941 ringerMode = RINGER_MODE_VIBRATE;
2942 }
2943 } else {
Eric Laurent24482012012-05-10 09:41:17 -07002944 // (oldIndex < step) is equivalent to (old UI index == 0)
John Spurlock86005342014-05-23 11:58:00 -04002945 if ((oldIndex < step)
2946 && VOLUME_SETS_RINGER_MODE_SILENT
2947 && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002948 ringerMode = RINGER_MODE_SILENT;
2949 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07002950 }
RoboErik5452e252015-02-06 15:33:53 -08002951 } else if (direction == AudioManager.ADJUST_TOGGLE_MUTE
2952 || direction == AudioManager.ADJUST_MUTE) {
2953 if (mHasVibrator) {
2954 ringerMode = RINGER_MODE_VIBRATE;
2955 } else {
2956 ringerMode = RINGER_MODE_SILENT;
2957 }
2958 // Setting the ringer mode will toggle mute
2959 result &= ~FLAG_ADJUST_VOLUME;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002960 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07002961 break;
2962 case RINGER_MODE_VIBRATE:
2963 if (!mHasVibrator) {
2964 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
2965 "but no vibrator is present");
2966 break;
2967 }
Amith Yamasanic696a532011-10-28 17:02:37 -07002968 if ((direction == AudioManager.ADJUST_LOWER)) {
RoboErik5452e252015-02-06 15:33:53 -08002969 // This is the case we were muted with the volume turned up
2970 if (oldIndex >= 2 * step && isMuted) {
2971 ringerMode = RINGER_MODE_NORMAL;
2972 } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
John Spurlock795a5142014-12-08 14:09:35 -05002973 if (VOLUME_SETS_RINGER_MODE_SILENT) {
2974 ringerMode = RINGER_MODE_SILENT;
2975 } else {
2976 result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
2977 }
Amith Yamasanic696a532011-10-28 17:02:37 -07002978 }
RoboErik5452e252015-02-06 15:33:53 -08002979 } else if (direction == AudioManager.ADJUST_RAISE
2980 || direction == AudioManager.ADJUST_TOGGLE_MUTE
2981 || direction == AudioManager.ADJUST_UNMUTE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002982 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07002983 }
John Spurlocka11b4af2014-06-01 11:52:23 -04002984 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07002985 break;
2986 case RINGER_MODE_SILENT:
RoboErik5452e252015-02-06 15:33:53 -08002987 if (direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
2988 // This is the case we were muted with the volume turned up
2989 ringerMode = RINGER_MODE_NORMAL;
2990 } else if (direction == AudioManager.ADJUST_RAISE
2991 || direction == AudioManager.ADJUST_TOGGLE_MUTE
2992 || direction == AudioManager.ADJUST_UNMUTE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04002993 if (PREVENT_VOLUME_ADJUSTMENT_IF_SILENT) {
2994 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07002995 } else {
RoboErik5452e252015-02-06 15:33:53 -08002996 if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04002997 ringerMode = RINGER_MODE_VIBRATE;
2998 } else {
RoboErik5452e252015-02-06 15:33:53 -08002999 // If we don't have a vibrator or they were toggling mute
3000 // go straight back to normal.
John Spurlocka11b4af2014-06-01 11:52:23 -04003001 ringerMode = RINGER_MODE_NORMAL;
3002 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003003 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05003004 }
John Spurlocka11b4af2014-06-01 11:52:23 -04003005 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07003006 break;
3007 default:
3008 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
3009 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003010 }
3011
John Spurlock661f2cf2014-11-17 10:29:10 -05003012 setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003013
Eric Laurent25101b02011-02-02 09:33:30 -08003014 mPrevVolDirection = direction;
3015
John Spurlocka11b4af2014-06-01 11:52:23 -04003016 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003017 }
3018
John Spurlock3346a802014-05-20 16:25:37 -04003019 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003020 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07003021 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003022 }
3023
Eric Laurent5b4e6542010-03-19 20:02:21 -07003024 private boolean isStreamMutedByRingerMode(int streamType) {
3025 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
3026 }
3027
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003028 boolean updateRingerModeAffectedStreams() {
3029 int ringerModeAffectedStreams;
3030 // make sure settings for ringer mode are consistent with device type: non voice capable
3031 // devices (tablets) include media stream in silent mode whereas phones don't.
3032 ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
3033 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3034 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
3035 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
3036 UserHandle.USER_CURRENT);
3037
3038 // ringtone, notification and system streams are always affected by ringer mode
3039 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
3040 (1 << AudioSystem.STREAM_NOTIFICATION)|
3041 (1 << AudioSystem.STREAM_SYSTEM);
3042
Eric Laurent212532b2014-07-21 15:43:18 -07003043 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003044 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -07003045 ringerModeAffectedStreams = 0;
3046 break;
3047 default:
John Spurlock77e54d92014-08-11 12:16:24 -04003048 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
Eric Laurent212532b2014-07-21 15:43:18 -07003049 break;
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003050 }
Eric Laurent212532b2014-07-21 15:43:18 -07003051
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003052 synchronized (mCameraSoundForced) {
3053 if (mCameraSoundForced) {
3054 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3055 } else {
3056 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3057 }
3058 }
3059 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
3060 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
3061 } else {
3062 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
3063 }
3064
3065 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3066 Settings.System.putIntForUser(mContentResolver,
3067 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3068 ringerModeAffectedStreams,
3069 UserHandle.USER_CURRENT);
3070 mRingerModeAffectedStreams = ringerModeAffectedStreams;
3071 return true;
3072 }
3073 return false;
3074 }
3075
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05003076 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003077 public boolean isStreamAffectedByMute(int streamType) {
3078 return (mMuteAffectedStreams & (1 << streamType)) != 0;
3079 }
3080
3081 private void ensureValidDirection(int direction) {
RoboErik4197cb62015-01-21 15:45:32 -08003082 switch (direction) {
3083 case AudioManager.ADJUST_LOWER:
3084 case AudioManager.ADJUST_RAISE:
3085 case AudioManager.ADJUST_SAME:
3086 case AudioManager.ADJUST_MUTE:
3087 case AudioManager.ADJUST_UNMUTE:
3088 case AudioManager.ADJUST_TOGGLE_MUTE:
3089 break;
3090 default:
3091 throw new IllegalArgumentException("Bad direction " + direction);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003092 }
3093 }
3094
Lei Zhang6c798972012-03-02 11:40:12 -08003095 private void ensureValidSteps(int steps) {
3096 if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
3097 throw new IllegalArgumentException("Bad volume adjust steps " + steps);
3098 }
3099 }
3100
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003101 private void ensureValidStreamType(int streamType) {
3102 if (streamType < 0 || streamType >= mStreamStates.length) {
3103 throw new IllegalArgumentException("Bad stream type " + streamType);
3104 }
3105 }
3106
RoboErik4197cb62015-01-21 15:45:32 -08003107 private boolean isMuteAdjust(int adjust) {
3108 return adjust == AudioManager.ADJUST_MUTE || adjust == AudioManager.ADJUST_UNMUTE
3109 || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
3110 }
3111
Eric Laurent6d517662012-04-23 18:42:39 -07003112 private boolean isInCommunication() {
Nancy Chen0eb1e402014-08-21 22:52:29 -07003113 boolean IsInCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003114
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003115 TelecomManager telecomManager =
3116 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
Eric Laurent38edfda2014-12-18 17:38:04 -08003117
3118 final long ident = Binder.clearCallingIdentity();
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003119 IsInCall = telecomManager.isInCall();
Eric Laurent38edfda2014-12-18 17:38:04 -08003120 Binder.restoreCallingIdentity(ident);
Santos Cordon9eb45932014-06-27 12:28:43 -07003121
Nancy Chen0eb1e402014-08-21 22:52:29 -07003122 return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
Eric Laurent6d517662012-04-23 18:42:39 -07003123 }
Eric Laurent25101b02011-02-02 09:33:30 -08003124
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003125 /**
3126 * For code clarity for getActiveStreamType(int)
3127 * @param delay_ms max time since last STREAM_MUSIC activity to consider
3128 * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
3129 * in the last "delay_ms" ms.
3130 */
3131 private boolean isAfMusicActiveRecently(int delay_ms) {
3132 return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
3133 || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
3134 }
3135
Eric Laurent6d517662012-04-23 18:42:39 -07003136 private int getActiveStreamType(int suggestedStreamType) {
Eric Laurent212532b2014-07-21 15:43:18 -07003137 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003138 case AudioSystem.PLATFORM_VOICE:
Eric Laurent6d517662012-04-23 18:42:39 -07003139 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003140 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3141 == AudioSystem.FORCE_BT_SCO) {
3142 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
3143 return AudioSystem.STREAM_BLUETOOTH_SCO;
3144 } else {
3145 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
3146 return AudioSystem.STREAM_VOICE_CALL;
3147 }
Eric Laurent25101b02011-02-02 09:33:30 -08003148 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003149 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003150 if (DEBUG_VOL)
3151 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3152 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003153 } else {
3154 if (DEBUG_VOL)
3155 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
3156 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003157 }
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003158 } else if (isAfMusicActiveRecently(0)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003159 if (DEBUG_VOL)
3160 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3161 return AudioSystem.STREAM_MUSIC;
Eric Laurent25101b02011-02-02 09:33:30 -08003162 }
Eric Laurent212532b2014-07-21 15:43:18 -07003163 break;
John Spurlock61560172015-02-06 19:46:04 -05003164 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -07003165 if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
RoboErik2811dd32014-08-12 09:48:13 -07003166 // TV always defaults to STREAM_MUSIC
Eric Laurent212532b2014-07-21 15:43:18 -07003167 return AudioSystem.STREAM_MUSIC;
Eric Laurent212532b2014-07-21 15:43:18 -07003168 }
3169 break;
3170 default:
Eric Laurent6d517662012-04-23 18:42:39 -07003171 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003172 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3173 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003174 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08003175 return AudioSystem.STREAM_BLUETOOTH_SCO;
3176 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003177 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08003178 return AudioSystem.STREAM_VOICE_CALL;
3179 }
3180 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003181 StreamOverride.sDelayMs) ||
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003182 AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003183 StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003184 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08003185 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003186 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003187 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003188 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
3189 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003190 } else {
John Spurlockeb1d88d2014-07-19 14:49:19 -04003191 if (DEBUG_VOL) Log.v(TAG,
3192 "getActiveStreamType: using STREAM_NOTIFICATION as default");
3193 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003194 }
Joe Onoratoc7fcba42011-01-05 16:53:11 -08003195 }
Eric Laurent212532b2014-07-21 15:43:18 -07003196 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003197 }
Eric Laurent212532b2014-07-21 15:43:18 -07003198 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
3199 + suggestedStreamType);
3200 return suggestedStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003201 }
3202
John Spurlockbcc10872014-11-28 15:29:21 -05003203 private void broadcastRingerMode(String action, int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003204 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05003205 Intent broadcast = new Intent(action);
Glenn Kastenba195eb2011-12-13 09:30:40 -08003206 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003207 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
3208 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003209 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003210 }
3211
3212 private void broadcastVibrateSetting(int vibrateType) {
3213 // Send broadcast
3214 if (ActivityManagerNative.isSystemReady()) {
3215 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
3216 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
3217 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003218 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003219 }
3220 }
3221
3222 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003223 /**
3224 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
3225 * Note that the wake lock needs to be released after the message has been handled.
3226 */
3227 private void queueMsgUnderWakeLock(Handler handler, int msg,
3228 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003229 final long ident = Binder.clearCallingIdentity();
3230 // Always acquire the wake lock as AudioService because it is released by the
3231 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003232 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003233 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003234 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
3235 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003236
Eric Laurentafbb0472011-12-15 09:04:23 -08003237 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003238 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003239
3240 if (existingMsgPolicy == SENDMSG_REPLACE) {
3241 handler.removeMessages(msg);
3242 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
3243 return;
3244 }
Eric Laurentadbe8bf2014-11-03 18:26:32 -08003245 synchronized (mLastDeviceConnectMsgTime) {
3246 long time = SystemClock.uptimeMillis() + delay;
3247 handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
3248 if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
3249 msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
3250 msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
3251 mLastDeviceConnectMsgTime = time;
3252 }
3253 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003254 }
3255
3256 boolean checkAudioSettingsPermission(String method) {
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07003257 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003258 == PackageManager.PERMISSION_GRANTED) {
3259 return true;
3260 }
3261 String msg = "Audio Settings Permission Denial: " + method + " from pid="
3262 + Binder.getCallingPid()
3263 + ", uid=" + Binder.getCallingUid();
3264 Log.w(TAG, msg);
3265 return false;
3266 }
3267
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003268 private int getDeviceForStream(int stream) {
3269 int device = AudioSystem.getDevicesForStream(stream);
3270 if ((device & (device - 1)) != 0) {
3271 // Multiple device selection is either:
3272 // - speaker + one other device: give priority to speaker in this case.
3273 // - one A2DP device + another device: happens with duplicated output. In this case
3274 // retain the device on the A2DP output as the other must not correspond to an active
3275 // selection if not the speaker.
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003276 // - HDMI-CEC system audio mode only output: give priority to available item in order.
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003277 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
3278 device = AudioSystem.DEVICE_OUT_SPEAKER;
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003279 } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
3280 device = AudioSystem.DEVICE_OUT_HDMI_ARC;
3281 } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
3282 device = AudioSystem.DEVICE_OUT_SPDIF;
3283 } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
3284 device = AudioSystem.DEVICE_OUT_AUX_LINE;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003285 } else {
3286 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
3287 }
3288 }
3289 return device;
3290 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003291
Paul McLean10804eb2015-01-28 11:16:35 -08003292 /*
3293 * A class just for packaging up a set of connection parameters.
3294 */
3295 private class WiredDeviceConnectionState {
3296 public int mType;
3297 public int mState;
3298 public String mAddress;
3299 public String mName;
3300
3301 public WiredDeviceConnectionState(int type, int state, String address, String name) {
3302 mType = type;
3303 mState = state;
3304 mAddress = address;
3305 mName = name;
3306 }
3307 }
3308
3309 public void setWiredDeviceConnectionState(int type, int state, String address,
3310 String name) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003311 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07003312 if (DEBUG_DEVICES) {
3313 Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
3314 + address + ")");
3315 }
Paul McLean10804eb2015-01-28 11:16:35 -08003316 int delay = checkSendBecomingNoisyIntent(type, state);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003317 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003318 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Paul McLean10804eb2015-01-28 11:16:35 -08003319 0,
3320 0,
3321 new WiredDeviceConnectionState(type, state, address, name),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003322 delay);
3323 }
3324 }
3325
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003326 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003327 {
3328 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003329 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
3330 throw new IllegalArgumentException("invalid profile " + profile);
3331 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003332 synchronized (mConnectedDevices) {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003333 if (profile == BluetoothProfile.A2DP) {
3334 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3335 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
3336 } else {
3337 delay = 0;
3338 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003339 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003340 (profile == BluetoothProfile.A2DP ?
3341 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003342 state,
3343 0,
3344 device,
3345 delay);
3346 }
3347 return delay;
3348 }
3349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003350 ///////////////////////////////////////////////////////////////////////////
3351 // Inner classes
3352 ///////////////////////////////////////////////////////////////////////////
3353
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003354 // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
3355 // 1 mScoclient OR mSafeMediaVolumeState
3356 // 2 mSetModeDeathHandlers
3357 // 3 mSettingsLock
3358 // 4 VolumeStreamState.class
3359 // 5 mCameraSoundForced
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003360 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003361 private final int mStreamType;
3362
RoboErik4197cb62015-01-21 15:45:32 -08003363 private boolean mIsMuted;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003364 private String mVolumeIndexSettingName;
Eric Laurenta553c252009-07-17 12:17:14 -07003365 private int mIndexMax;
John Spurlock2bb02ec2015-03-02 13:13:06 -05003366 private final SparseIntArray mIndexMap = new SparseIntArray(8);
John Spurlockf63860c2015-02-19 09:46:27 -05003367 private final Intent mVolumeChanged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003368
Eric Laurenta553c252009-07-17 12:17:14 -07003369 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003370
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003371 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003372
3373 mStreamType = streamType;
Jared Suttles59820132009-08-13 21:50:52 -05003374 mIndexMax = MAX_STREAM_VOLUME[streamType];
Eric Laurenta553c252009-07-17 12:17:14 -07003375 AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
3376 mIndexMax *= 10;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003377
Eric Laurent33902db2012-10-07 16:15:07 -07003378 readSettings();
John Spurlockf63860c2015-02-19 09:46:27 -05003379 mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
3380 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003381 }
3382
Eric Laurent42b041e2013-03-29 11:36:03 -07003383 public String getSettingNameForDevice(int device) {
3384 String name = mVolumeIndexSettingName;
Eric Laurent948d3272014-05-16 15:18:45 -07003385 String suffix = AudioSystem.getOutputDeviceName(device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003386 if (suffix.isEmpty()) {
3387 return name;
3388 }
3389 return name + "_" + suffix;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003390 }
3391
Eric Laurentfdbee862014-05-12 15:26:12 -07003392 public void readSettings() {
3393 synchronized (VolumeStreamState.class) {
John Spurlockee5ad722015-03-03 16:17:21 -05003394 // force maximum volume on all streams if fixed volume property is set
3395 if (mUseFixedVolume) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003396 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07003397 return;
3398 }
3399 // do not read system stream volume from settings: this stream is always aliased
3400 // to another stream type and its volume is never persisted. Values in settings can
3401 // only be stale values
3402 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3403 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
John Spurlock61560172015-02-06 19:46:04 -05003404 int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
Eric Laurentfdbee862014-05-12 15:26:12 -07003405 synchronized (mCameraSoundForced) {
3406 if (mCameraSoundForced) {
3407 index = mIndexMax;
3408 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003409 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003410 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003411 return;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003412 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003413
Eric Laurentfdbee862014-05-12 15:26:12 -07003414 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
3415
3416 for (int i = 0; remainingDevices != 0; i++) {
3417 int device = (1 << i);
3418 if ((device & remainingDevices) == 0) {
3419 continue;
3420 }
3421 remainingDevices &= ~device;
3422
3423 // retrieve current volume for device
3424 String name = getSettingNameForDevice(device);
3425 // if no volume stored for current stream and device, use default volume if default
3426 // device, continue otherwise
3427 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
John Spurlock61560172015-02-06 19:46:04 -05003428 AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
Eric Laurentfdbee862014-05-12 15:26:12 -07003429 int index = Settings.System.getIntForUser(
3430 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3431 if (index == -1) {
3432 continue;
3433 }
3434
John Spurlock2bb02ec2015-03-02 13:13:06 -05003435 mIndexMap.put(device, getValidIndex(10 * index));
Eric Laurentdd45d012012-10-08 09:04:34 -07003436 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003437 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003438 }
3439
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003440 // must be called while synchronized VolumeStreamState.class
3441 public void applyDeviceVolume_syncVSS(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003442 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003443 if (mIsMuted) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003444 index = 0;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003445 } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported)
3446 || ((device & mFullVolumeDevices) != 0)) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003447 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07003448 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07003449 index = (getIndex(device) + 5)/10;
3450 }
3451 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003452 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003453
Eric Laurentfdbee862014-05-12 15:26:12 -07003454 public void applyAllVolumes() {
3455 synchronized (VolumeStreamState.class) {
3456 // apply default volume first: by convention this will reset all
3457 // devices volumes in audio policy manager to the supplied value
3458 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003459 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003460 index = 0;
3461 } else {
3462 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3463 }
3464 AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3465 // then apply device specific volumes
John Spurlock2bb02ec2015-03-02 13:13:06 -05003466 for (int i = 0; i < mIndexMap.size(); i++) {
3467 int device = mIndexMap.keyAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07003468 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
RoboErik4197cb62015-01-21 15:45:32 -08003469 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003470 index = 0;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003471 } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3472 mAvrcpAbsVolSupported)
3473 || ((device & mFullVolumeDevices) != 0))
3474 {
Eric Laurentfdbee862014-05-12 15:26:12 -07003475 index = (mIndexMax + 5)/10;
3476 } else {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003477 index = (mIndexMap.valueAt(i) + 5)/10;
Eric Laurentfdbee862014-05-12 15:26:12 -07003478 }
3479 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07003480 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003481 }
3482 }
3483 }
3484
3485 public boolean adjustIndex(int deltaIndex, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003486 return setIndex(getIndex(device) + deltaIndex,
3487 device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003488 }
3489
Eric Laurentfdbee862014-05-12 15:26:12 -07003490 public boolean setIndex(int index, int device) {
John Spurlockf63860c2015-02-19 09:46:27 -05003491 boolean changed = false;
3492 int oldIndex;
Eric Laurentfdbee862014-05-12 15:26:12 -07003493 synchronized (VolumeStreamState.class) {
John Spurlockf63860c2015-02-19 09:46:27 -05003494 oldIndex = getIndex(device);
Eric Laurentfdbee862014-05-12 15:26:12 -07003495 index = getValidIndex(index);
3496 synchronized (mCameraSoundForced) {
3497 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3498 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07003499 }
3500 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003501 mIndexMap.put(device, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003502
John Spurlockf63860c2015-02-19 09:46:27 -05003503 changed = oldIndex != index;
3504 if (changed) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003505 // Apply change to all streams using this one as alias
3506 // if changing volume of current device, also change volume of current
3507 // device on aliased stream
3508 boolean currentDevice = (device == getDeviceForStream(mStreamType));
3509 int numStreamTypes = AudioSystem.getNumStreamTypes();
3510 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3511 if (streamType != mStreamType &&
3512 mStreamVolumeAlias[streamType] == mStreamType) {
3513 int scaledIndex = rescaleIndex(index, mStreamType, streamType);
3514 mStreamStates[streamType].setIndex(scaledIndex,
3515 device);
3516 if (currentDevice) {
3517 mStreamStates[streamType].setIndex(scaledIndex,
3518 getDeviceForStream(streamType));
3519 }
3520 }
3521 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003522 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003523 }
John Spurlockf63860c2015-02-19 09:46:27 -05003524 if (changed) {
3525 oldIndex = (oldIndex + 5) / 10;
3526 index = (index + 5) / 10;
3527 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
3528 mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
3529 sendBroadcastToAll(mVolumeChanged);
3530 }
3531 return changed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003532 }
3533
Eric Laurentfdbee862014-05-12 15:26:12 -07003534 public int getIndex(int device) {
3535 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003536 int index = mIndexMap.get(device, -1);
3537 if (index == -1) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003538 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
John Spurlock2bb02ec2015-03-02 13:13:06 -05003539 index = mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurentfdbee862014-05-12 15:26:12 -07003540 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003541 return index;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003542 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07003543 }
3544
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003545 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07003546 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003547 }
3548
Eric Laurentfdbee862014-05-12 15:26:12 -07003549 public void setAllIndexes(VolumeStreamState srcStream) {
3550 synchronized (VolumeStreamState.class) {
3551 int srcStreamType = srcStream.getStreamType();
3552 // apply default device volume from source stream to all devices first in case
3553 // some devices are present in this stream state but not in source stream state
3554 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003555 index = rescaleIndex(index, srcStreamType, mStreamType);
John Spurlock2bb02ec2015-03-02 13:13:06 -05003556 for (int i = 0; i < mIndexMap.size(); i++) {
3557 mIndexMap.put(mIndexMap.keyAt(i), index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003558 }
3559 // Now apply actual volume for devices in source stream state
John Spurlock2bb02ec2015-03-02 13:13:06 -05003560 SparseIntArray srcMap = srcStream.mIndexMap;
3561 for (int i = 0; i < srcMap.size(); i++) {
3562 int device = srcMap.keyAt(i);
3563 index = srcMap.valueAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07003564 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07003565
Eric Laurentfdbee862014-05-12 15:26:12 -07003566 setIndex(index, device);
3567 }
Eric Laurent6d517662012-04-23 18:42:39 -07003568 }
3569 }
3570
Eric Laurentfdbee862014-05-12 15:26:12 -07003571 public void setAllIndexesToMax() {
3572 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003573 for (int i = 0; i < mIndexMap.size(); i++) {
3574 mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07003575 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003576 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003577 }
3578
RoboErik4197cb62015-01-21 15:45:32 -08003579 public void mute(boolean state) {
John Spurlock22b9ee12015-02-18 22:51:44 -05003580 boolean changed = false;
Eric Laurentfdbee862014-05-12 15:26:12 -07003581 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08003582 if (state != mIsMuted) {
John Spurlock22b9ee12015-02-18 22:51:44 -05003583 changed = true;
RoboErik4197cb62015-01-21 15:45:32 -08003584 mIsMuted = state;
John Spurlock22b9ee12015-02-18 22:51:44 -05003585
RoboErik4197cb62015-01-21 15:45:32 -08003586 // Set the new mute volume. This propagates the values to
3587 // the audio system, otherwise the volume won't be changed
3588 // at the lower level.
3589 sendMsg(mAudioHandler,
3590 MSG_SET_ALL_VOLUMES,
3591 SENDMSG_QUEUE,
3592 0,
3593 0,
3594 this, 0);
Eric Laurentfdbee862014-05-12 15:26:12 -07003595 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003596 }
John Spurlock22b9ee12015-02-18 22:51:44 -05003597 if (changed) {
3598 // Stream mute changed, fire the intent.
3599 Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
3600 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
3601 intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
3602 sendBroadcastToAll(intent);
3603 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003604 }
3605
Eric Laurent6d517662012-04-23 18:42:39 -07003606 public int getStreamType() {
3607 return mStreamType;
3608 }
3609
Eric Laurent212532b2014-07-21 15:43:18 -07003610 public void checkFixedVolumeDevices() {
3611 synchronized (VolumeStreamState.class) {
3612 // ignore settings for fixed volume devices: volume should always be at max or 0
3613 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003614 for (int i = 0; i < mIndexMap.size(); i++) {
3615 int device = mIndexMap.keyAt(i);
3616 int index = mIndexMap.valueAt(i);
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003617 if (((device & mFullVolumeDevices) != 0)
3618 || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003619 mIndexMap.put(device, mIndexMax);
Eric Laurent212532b2014-07-21 15:43:18 -07003620 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003621 applyDeviceVolume_syncVSS(device);
Eric Laurent212532b2014-07-21 15:43:18 -07003622 }
3623 }
3624 }
3625 }
3626
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003627 private int getValidIndex(int index) {
3628 if (index < 0) {
3629 return 0;
John Spurlockee5ad722015-03-03 16:17:21 -05003630 } else if (mUseFixedVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07003631 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003632 }
3633
3634 return index;
3635 }
3636
Eric Laurentbffc3d12012-05-07 17:43:49 -07003637 private void dump(PrintWriter pw) {
RoboErik4197cb62015-01-21 15:45:32 -08003638 pw.print(" Muted: ");
3639 pw.println(mIsMuted);
John Spurlock2b29bc42014-08-26 16:40:35 -04003640 pw.print(" Max: ");
3641 pw.println((mIndexMax + 5) / 10);
Eric Laurentbffc3d12012-05-07 17:43:49 -07003642 pw.print(" Current: ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05003643 for (int i = 0; i < mIndexMap.size(); i++) {
3644 if (i > 0) {
3645 pw.print(", ");
3646 }
3647 final int device = mIndexMap.keyAt(i);
John Spurlock2b29bc42014-08-26 16:40:35 -04003648 pw.print(Integer.toHexString(device));
3649 final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
3650 : AudioSystem.getOutputDeviceName(device);
3651 if (!deviceName.isEmpty()) {
3652 pw.print(" (");
3653 pw.print(deviceName);
3654 pw.print(")");
3655 }
3656 pw.print(": ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05003657 final int index = (mIndexMap.valueAt(i) + 5) / 10;
John Spurlock2b29bc42014-08-26 16:40:35 -04003658 pw.print(index);
Eric Laurentbffc3d12012-05-07 17:43:49 -07003659 }
John Spurlockb32fc972015-03-05 13:58:00 -05003660 pw.println();
3661 pw.print(" Devices: ");
3662 final int devices = AudioSystem.getDevicesForStream(mStreamType);
3663 int device, i = 0, n = 0;
John Spurlock1ff1e6e2015-03-09 14:21:20 -04003664 // iterate all devices from 1 to DEVICE_OUT_DEFAULT exclusive
3665 // (the default device is not returned by getDevicesForStream)
3666 while ((device = 1 << i) != AudioSystem.DEVICE_OUT_DEFAULT) {
John Spurlockb32fc972015-03-05 13:58:00 -05003667 if ((devices & device) != 0) {
3668 if (n++ > 0) {
3669 pw.print(", ");
3670 }
3671 pw.print(AudioSystem.getOutputDeviceName(device));
3672 }
3673 i++;
3674 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003675 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003676 }
3677
3678 /** Thread that handles native AudioSystem control. */
3679 private class AudioSystemThread extends Thread {
3680 AudioSystemThread() {
3681 super("AudioService");
3682 }
3683
3684 @Override
3685 public void run() {
3686 // Set this thread up so the handler will work on it
3687 Looper.prepare();
3688
3689 synchronized(AudioService.this) {
3690 mAudioHandler = new AudioHandler();
3691
3692 // Notify that the handler has been created
3693 AudioService.this.notify();
3694 }
3695
3696 // Listen for volume change requests that are set by VolumePanel
3697 Looper.loop();
3698 }
3699 }
3700
3701 /** Handles internal volume messages in separate volume thread. */
3702 private class AudioHandler extends Handler {
3703
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003704 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003705
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003706 synchronized (VolumeStreamState.class) {
3707 // Apply volume
3708 streamState.applyDeviceVolume_syncVSS(device);
Eric Laurenta553c252009-07-17 12:17:14 -07003709
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003710 // Apply change to all streams using this one as alias
3711 int numStreamTypes = AudioSystem.getNumStreamTypes();
3712 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3713 if (streamType != streamState.mStreamType &&
3714 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
3715 // Make sure volume is also maxed out on A2DP device for aliased stream
3716 // that may have a different device selected
3717 int streamDevice = getDeviceForStream(streamType);
3718 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
3719 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
3720 mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
3721 }
3722 mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
Eric Laurentcd772d02013-10-30 18:31:07 -07003723 }
Eric Laurenta553c252009-07-17 12:17:14 -07003724 }
3725 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003726 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08003727 sendMsg(mAudioHandler,
3728 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08003729 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003730 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07003731 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08003732 streamState,
3733 PERSIST_DELAY);
3734
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003735 }
3736
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003737 private void setAllVolumes(VolumeStreamState streamState) {
3738
3739 // Apply volume
3740 streamState.applyAllVolumes();
3741
3742 // Apply change to all streams using this one as alias
3743 int numStreamTypes = AudioSystem.getNumStreamTypes();
3744 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3745 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07003746 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003747 mStreamStates[streamType].applyAllVolumes();
3748 }
3749 }
3750 }
3751
Eric Laurent42b041e2013-03-29 11:36:03 -07003752 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003753 if (mUseFixedVolume) {
3754 return;
3755 }
Eric Laurent212532b2014-07-21 15:43:18 -07003756 if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
3757 return;
3758 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003759 System.putIntForUser(mContentResolver,
3760 streamState.getSettingNameForDevice(device),
3761 (streamState.getIndex(device) + 5)/ 10,
3762 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003763 }
3764
Glenn Kastenba195eb2011-12-13 09:30:40 -08003765 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003766 if (mUseFixedVolume) {
3767 return;
3768 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07003769 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003770 }
3771
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003772 private boolean onLoadSoundEffects() {
3773 int status;
3774
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003775 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07003776 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003777 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
3778 return false;
3779 }
3780
3781 if (mSoundPool != null) {
3782 return true;
3783 }
3784
3785 loadTouchSoundAssets();
3786
Jean-Michel Trivi55a30c42014-07-20 17:56:11 -07003787 mSoundPool = new SoundPool.Builder()
3788 .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
3789 .setAudioAttributes(new AudioAttributes.Builder()
3790 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
3791 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
3792 .build())
3793 .build();
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003794 mSoundPoolCallBack = null;
3795 mSoundPoolListenerThread = new SoundPoolListenerThread();
3796 mSoundPoolListenerThread.start();
3797 int attempts = 3;
3798 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
3799 try {
3800 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07003801 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003802 } catch (InterruptedException e) {
3803 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
3804 }
3805 }
3806
3807 if (mSoundPoolCallBack == null) {
3808 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
3809 if (mSoundPoolLooper != null) {
3810 mSoundPoolLooper.quit();
3811 mSoundPoolLooper = null;
3812 }
3813 mSoundPoolListenerThread = null;
3814 mSoundPool.release();
3815 mSoundPool = null;
3816 return false;
3817 }
3818 /*
3819 * poolId table: The value -1 in this table indicates that corresponding
3820 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
3821 * Once loaded, the value in poolId is the sample ID and the same
3822 * sample can be reused for another effect using the same file.
3823 */
3824 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3825 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3826 poolId[fileIdx] = -1;
3827 }
3828 /*
3829 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
3830 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
3831 * this indicates we have a valid sample loaded for this effect.
3832 */
3833
3834 int numSamples = 0;
3835 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3836 // Do not load sample if this effect uses the MediaPlayer
3837 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
3838 continue;
3839 }
3840 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
3841 String filePath = Environment.getRootDirectory()
3842 + SOUND_EFFECTS_PATH
3843 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
3844 int sampleId = mSoundPool.load(filePath, 0);
3845 if (sampleId <= 0) {
3846 Log.w(TAG, "Soundpool could not load file: "+filePath);
3847 } else {
3848 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
3849 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
3850 numSamples++;
3851 }
3852 } else {
3853 SOUND_EFFECT_FILES_MAP[effect][1] =
3854 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
3855 }
3856 }
3857 // wait for all samples to be loaded
3858 if (numSamples > 0) {
3859 mSoundPoolCallBack.setSamples(poolId);
3860
3861 attempts = 3;
3862 status = 1;
3863 while ((status == 1) && (attempts-- > 0)) {
3864 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07003865 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003866 status = mSoundPoolCallBack.status();
3867 } catch (InterruptedException e) {
3868 Log.w(TAG, "Interrupted while waiting sound pool callback.");
3869 }
3870 }
3871 } else {
3872 status = -1;
3873 }
3874
3875 if (mSoundPoolLooper != null) {
3876 mSoundPoolLooper.quit();
3877 mSoundPoolLooper = null;
3878 }
3879 mSoundPoolListenerThread = null;
3880 if (status != 0) {
3881 Log.w(TAG,
3882 "onLoadSoundEffects(), Error "+status+ " while loading samples");
3883 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3884 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
3885 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3886 }
3887 }
3888
3889 mSoundPool.release();
3890 mSoundPool = null;
3891 }
3892 }
3893 return (status == 0);
3894 }
3895
3896 /**
3897 * Unloads samples from the sound pool.
3898 * This method can be called to free some memory when
3899 * sound effects are disabled.
3900 */
3901 private void onUnloadSoundEffects() {
3902 synchronized (mSoundEffectsLock) {
3903 if (mSoundPool == null) {
3904 return;
3905 }
3906
3907 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3908 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3909 poolId[fileIdx] = 0;
3910 }
3911
3912 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3913 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
3914 continue;
3915 }
3916 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
3917 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
3918 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3919 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
3920 }
3921 }
3922 mSoundPool.release();
3923 mSoundPool = null;
3924 }
3925 }
3926
3927 private void onPlaySoundEffect(int effectType, int volume) {
3928 synchronized (mSoundEffectsLock) {
3929
3930 onLoadSoundEffects();
3931
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003932 if (mSoundPool == null) {
3933 return;
3934 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003935 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08003936 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003937 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07003938 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003939 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07003940 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003941 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003942
3943 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003944 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
3945 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003946 } else {
3947 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003948 try {
Eric Laurente78fced2013-03-15 16:03:47 -07003949 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
3950 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003951 mediaPlayer.setDataSource(filePath);
3952 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
3953 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08003954 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003955 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
3956 public void onCompletion(MediaPlayer mp) {
3957 cleanupPlayer(mp);
3958 }
3959 });
3960 mediaPlayer.setOnErrorListener(new OnErrorListener() {
3961 public boolean onError(MediaPlayer mp, int what, int extra) {
3962 cleanupPlayer(mp);
3963 return true;
3964 }
3965 });
3966 mediaPlayer.start();
3967 } catch (IOException ex) {
3968 Log.w(TAG, "MediaPlayer IOException: "+ex);
3969 } catch (IllegalArgumentException ex) {
3970 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
3971 } catch (IllegalStateException ex) {
3972 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003973 }
3974 }
3975 }
3976 }
3977
3978 private void cleanupPlayer(MediaPlayer mp) {
3979 if (mp != null) {
3980 try {
3981 mp.stop();
3982 mp.release();
3983 } catch (IllegalStateException ex) {
3984 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
3985 }
3986 }
3987 }
3988
Eric Laurentfa640152011-03-12 15:59:51 -08003989 private void setForceUse(int usage, int config) {
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08003990 synchronized (mConnectedDevices) {
3991 setForceUseInt_SyncDevices(usage, config);
3992 }
Eric Laurentfa640152011-03-12 15:59:51 -08003993 }
3994
Eric Laurent05274f32012-11-29 12:48:18 -08003995 private void onPersistSafeVolumeState(int state) {
3996 Settings.Global.putInt(mContentResolver,
3997 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
3998 state);
3999 }
4000
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004001 @Override
4002 public void handleMessage(Message msg) {
Eric Laurentafbb0472011-12-15 09:04:23 -08004003 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004004
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004005 case MSG_SET_DEVICE_VOLUME:
4006 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
4007 break;
4008
4009 case MSG_SET_ALL_VOLUMES:
4010 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004011 break;
4012
4013 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07004014 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004015 break;
4016
Justin Koh57978ed2012-04-03 17:37:58 -07004017 case MSG_PERSIST_MASTER_VOLUME_MUTE:
Eric Laurent83a017b2013-03-19 18:15:31 -07004018 if (mUseFixedVolume) {
4019 return;
4020 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004021 Settings.System.putIntForUser(mContentResolver,
4022 Settings.System.VOLUME_MASTER_MUTE,
4023 msg.arg1,
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004024 msg.arg2);
Justin Koh57978ed2012-04-03 17:37:58 -07004025 break;
4026
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004027 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08004028 // note that the value persisted is the current ringer mode, not the
4029 // value of ringer mode as of the time the request was made to persist
John Spurlock661f2cf2014-11-17 10:29:10 -05004030 persistRingerMode(getRingerModeInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004031 break;
4032
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004033 case MSG_MEDIA_SERVER_DIED:
Eric Laurenteb4b8a22014-07-21 13:10:07 -07004034 if (!mSystemReady ||
4035 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Eric Laurent89e74ba2009-09-30 18:26:36 -07004036 Log.e(TAG, "Media server died.");
Eric Laurentafbb0472011-12-15 09:04:23 -08004037 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent89e74ba2009-09-30 18:26:36 -07004038 null, 500);
Eric Laurentdfb881f2013-07-18 14:41:39 -07004039 break;
Eric Laurent89e74ba2009-09-30 18:26:36 -07004040 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004041 Log.e(TAG, "Media server started.");
Eric Laurentdfb881f2013-07-18 14:41:39 -07004042
Eric Laurent3c652ca2010-06-21 20:46:26 -07004043 // indicate to audio HAL that we start the reconfiguration phase after a media
4044 // server crash
Eric Laurentdfb881f2013-07-18 14:41:39 -07004045 // Note that we only execute this when the media server
Eric Laurent3c652ca2010-06-21 20:46:26 -07004046 // process restarts after a crash, not the first time it is started.
4047 AudioSystem.setParameters("restarting=true");
4048
Glenn Kastenfd116ad2013-07-12 17:10:39 -07004049 readAndSetLowRamDevice();
4050
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004051 // Restore device connection states
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004052 synchronized (mConnectedDevices) {
4053 Set set = mConnectedDevices.entrySet();
4054 Iterator i = set.iterator();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004055 while (i.hasNext()) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004056 Map.Entry device = (Map.Entry)i.next();
4057 AudioSystem.setDeviceConnectionState(
4058 ((Integer)device.getKey()).intValue(),
4059 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004060 (String)device.getValue(),
4061 "unknown-device");
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004062 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004063 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004064 // Restore call state
4065 AudioSystem.setPhoneState(mMode);
4066
Eric Laurentd5603c12009-08-06 08:49:39 -07004067 // Restore forced usage for communcations and record
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004068 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
Eric Laurentd5603c12009-08-06 08:49:39 -07004069 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
Eric Laurentdd45d012012-10-08 09:04:34 -07004070 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
4071 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004072
Eric Laurenta553c252009-07-17 12:17:14 -07004073 // Restore stream volumes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004074 int numStreamTypes = AudioSystem.getNumStreamTypes();
4075 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004076 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004077 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004078
4079 streamState.applyAllVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004080 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004081
4082 // Restore ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05004083 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3c652ca2010-06-21 20:46:26 -07004084
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004085 // Reset device orientation (if monitored for this device)
Eric Laurentd640bd32012-09-28 18:01:48 -07004086 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004087 setOrientationForAudioSystem();
4088 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004089 if (mMonitorRotation) {
4090 setRotationForAudioSystem();
4091 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004092
Eric Laurent78472112012-05-21 08:57:21 -07004093 synchronized (mBluetoothA2dpEnabledLock) {
4094 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
4095 mBluetoothA2dpEnabled ?
4096 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
4097 }
Eric Laurentbff5ca52012-11-02 16:48:26 -07004098
4099 synchronized (mSettingsLock) {
4100 AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
4101 mDockAudioMediaEnabled ?
4102 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
4103 }
Eric Laurent212532b2014-07-21 15:43:18 -07004104 if (mHdmiManager != null) {
4105 synchronized (mHdmiManager) {
4106 if (mHdmiTvClient != null) {
4107 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
4108 }
4109 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004110 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08004111
4112 synchronized (mAudioPolicies) {
4113 for(AudioPolicyProxy policy : mAudioPolicies.values()) {
4114 policy.connectMixes();
4115 }
4116 }
4117
Eric Laurent3c652ca2010-06-21 20:46:26 -07004118 // indicate the end of reconfiguration phase to audio HAL
4119 AudioSystem.setParameters("restarting=false");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004120 break;
4121
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004122 case MSG_UNLOAD_SOUND_EFFECTS:
4123 onUnloadSoundEffects();
4124 break;
4125
Eric Laurent117b7bb2011-01-16 17:07:27 -08004126 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004127 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
4128 // can take several dozens of milliseconds to complete
4129 boolean loaded = onLoadSoundEffects();
4130 if (msg.obj != null) {
4131 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
4132 synchronized (reply) {
4133 reply.mStatus = loaded ? 0 : -1;
4134 reply.notify();
4135 }
4136 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08004137 break;
4138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004139 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004140 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004141 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004142
4143 case MSG_BTA2DP_DOCK_TIMEOUT:
4144 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004145 synchronized (mConnectedDevices) {
4146 makeA2dpDeviceUnavailableNow( (String) msg.obj );
4147 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004148 break;
Eric Laurentfa640152011-03-12 15:59:51 -08004149
4150 case MSG_SET_FORCE_USE:
Eric Laurentc390bed2012-07-03 12:24:05 -07004151 case MSG_SET_FORCE_BT_A2DP_USE:
Eric Laurentfa640152011-03-12 15:59:51 -08004152 setForceUse(msg.arg1, msg.arg2);
4153 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07004154
Eric Laurentdc03c612011-04-01 10:59:41 -07004155 case MSG_BT_HEADSET_CNCT_FAILED:
4156 resetBluetoothSco();
4157 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004158
4159 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
Paul McLean10804eb2015-01-28 11:16:35 -08004160 { WiredDeviceConnectionState connectState =
4161 (WiredDeviceConnectionState)msg.obj;
4162 onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
4163 connectState.mAddress, connectState.mName);
4164 mAudioEventWakeLock.release();
4165 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004166 break;
4167
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004168 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
4169 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
4170 mAudioEventWakeLock.release();
4171 break;
4172
4173 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
4174 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004175 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004176 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004177
4178 case MSG_REPORT_NEW_ROUTES: {
4179 int N = mRoutesObservers.beginBroadcast();
4180 if (N > 0) {
4181 AudioRoutesInfo routes;
4182 synchronized (mCurAudioRoutes) {
4183 routes = new AudioRoutesInfo(mCurAudioRoutes);
4184 }
4185 while (N > 0) {
4186 N--;
4187 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
4188 try {
4189 obs.dispatchAudioRoutesChanged(routes);
4190 } catch (RemoteException e) {
4191 }
4192 }
4193 }
4194 mRoutesObservers.finishBroadcast();
4195 break;
4196 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004197
Eric Laurentc34dcc12012-09-10 13:51:52 -07004198 case MSG_CHECK_MUSIC_ACTIVE:
4199 onCheckMusicActive();
4200 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004201
4202 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
4203 onSendBecomingNoisyIntent();
4204 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07004205
4206 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
4207 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
4208 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
4209 break;
Eric Laurent05274f32012-11-29 12:48:18 -08004210 case MSG_PERSIST_SAFE_VOLUME_STATE:
4211 onPersistSafeVolumeState(msg.arg1);
4212 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08004213
Eric Laurent2a57ca92013-03-07 17:29:27 -08004214 case MSG_BROADCAST_BT_CONNECTION_STATE:
4215 onBroadcastScoConnectionState(msg.arg1);
4216 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004217
4218 case MSG_SYSTEM_READY:
4219 onSystemReady();
4220 break;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004221
4222 case MSG_PERSIST_MUSIC_ACTIVE_MS:
4223 final int musicActiveMs = msg.arg1;
4224 Settings.Secure.putIntForUser(mContentResolver,
4225 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
4226 UserHandle.USER_CURRENT);
4227 break;
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004228 case MSG_PERSIST_MICROPHONE_MUTE:
4229 Settings.System.putIntForUser(mContentResolver,
4230 Settings.System.MICROPHONE_MUTE,
4231 msg.arg1,
4232 msg.arg2);
4233 break;
RoboErik5452e252015-02-06 15:33:53 -08004234 case MSG_UNMUTE_STREAM:
4235 onUnmuteStream(msg.arg1, msg.arg2);
4236 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004237 }
4238 }
4239 }
4240
Jason Parekhb1096152009-03-24 17:48:25 -07004241 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07004242
Jason Parekhb1096152009-03-24 17:48:25 -07004243 SettingsObserver() {
4244 super(new Handler());
4245 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4246 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004247 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4248 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07004249 }
4250
4251 @Override
4252 public void onChange(boolean selfChange) {
4253 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08004254 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
4255 // However there appear to be some missing locks around mRingerModeMutedStreams
4256 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
4257 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07004258 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004259 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07004260 /*
4261 * Ensure all stream types that should be affected by ringer mode
4262 * are in the proper state.
4263 */
John Spurlock661f2cf2014-11-17 10:29:10 -05004264 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurenta553c252009-07-17 12:17:14 -07004265 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004266 readDockAudioSettings(mContentResolver);
Eric Laurenta553c252009-07-17 12:17:14 -07004267 }
Jason Parekhb1096152009-03-24 17:48:25 -07004268 }
Jason Parekhb1096152009-03-24 17:48:25 -07004269 }
Eric Laurenta553c252009-07-17 12:17:14 -07004270
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004271 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004272 private void makeA2dpDeviceAvailable(String address) {
Eric Laurent78472112012-05-21 08:57:21 -07004273 // enable A2DP before notifying A2DP connection to avoid unecessary processing in
4274 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004275 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4276 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4277 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Eric Laurent78472112012-05-21 08:57:21 -07004278 setBluetoothA2dpOnInt(true);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004279 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean394a8e12015-03-03 10:29:19 -07004280 AudioSystem.DEVICE_STATE_AVAILABLE, address, DEVICE_NAME_A2DP);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004281 // Reset A2DP suspend state each time a new sink is connected
4282 AudioSystem.setParameters("A2dpSuspended=false");
Paul McLean394a8e12015-03-03 10:29:19 -07004283 mConnectedDevices.put(
4284 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
4285 new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, DEVICE_NAME_A2DP,
4286 address));
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004287 }
4288
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004289 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004290 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07004291 }
4292
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004293 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004294 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004295 synchronized (mA2dpAvrcpLock) {
4296 mAvrcpAbsVolSupported = false;
4297 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004298 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
Paul McLean394a8e12015-03-03 10:29:19 -07004299 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, DEVICE_NAME_A2DP);
4300 mConnectedDevices.remove(
4301 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
RoboErik5535ea82014-09-25 14:53:16 -07004302 synchronized (mCurAudioRoutes) {
4303 // Remove A2DP routes as well
John Spurlock61560172015-02-06 19:46:04 -05004304 if (mCurAudioRoutes.bluetoothName != null) {
4305 mCurAudioRoutes.bluetoothName = null;
RoboErik5535ea82014-09-25 14:53:16 -07004306 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4307 SENDMSG_NOOP, 0, 0, null, 0);
4308 }
4309 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004310 }
4311
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004312 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004313 private void makeA2dpDeviceUnavailableLater(String address) {
Eric Laurent3b591262010-04-20 07:01:00 -07004314 // prevent any activity on the A2DP audio output to avoid unwanted
4315 // reconnection of the sink.
4316 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004317 // the device will be made unavailable later, so consider it disconnected right away
Paul McLean394a8e12015-03-03 10:29:19 -07004318 mConnectedDevices.remove(
4319 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004320 // send the delayed message to make the device unavailable later
4321 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
4322 mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
4323
4324 }
4325
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004326 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004327 private void makeA2dpSrcAvailable(String address) {
4328 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean394a8e12015-03-03 10:29:19 -07004329 AudioSystem.DEVICE_STATE_AVAILABLE, address, DEVICE_NAME_A2DP);
4330 mConnectedDevices.put(
4331 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
4332 new DeviceListSpec(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, DEVICE_NAME_A2DP,
4333 address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004334 }
4335
4336 // must be called synchronized on mConnectedDevices
4337 private void makeA2dpSrcUnavailable(String address) {
4338 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
Paul McLean394a8e12015-03-03 10:29:19 -07004339 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, DEVICE_NAME_A2DP);
4340 mConnectedDevices.remove(
4341 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004342 }
4343
4344 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004345 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004346 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4347 }
4348
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004349 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004350 private boolean hasScheduledA2dpDockTimeout() {
4351 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4352 }
4353
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004354 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004355 {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004356 if (DEBUG_VOL) {
4357 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
4358 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004359 if (btDevice == null) {
4360 return;
4361 }
4362 String address = btDevice.getAddress();
4363 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4364 address = "";
4365 }
John Du5a0cf7a2013-07-19 11:30:34 -07004366
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004367 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004368 String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4369 btDevice.getAddress());
4370 DeviceListSpec deviceSpec = mConnectedDevices.get(key);
4371 boolean isConnected = deviceSpec != null;
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004372
4373 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4374 if (btDevice.isBluetoothDock()) {
4375 if (state == BluetoothProfile.STATE_DISCONNECTED) {
4376 // introduction of a delay for transient disconnections of docks when
4377 // power is rapidly turned off/on, this message will be canceled if
4378 // we reconnect the dock under a preset delay
4379 makeA2dpDeviceUnavailableLater(address);
4380 // the next time isConnected is evaluated, it will be false for the dock
4381 }
4382 } else {
4383 makeA2dpDeviceUnavailableNow(address);
4384 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07004385 synchronized (mCurAudioRoutes) {
John Spurlock61560172015-02-06 19:46:04 -05004386 if (mCurAudioRoutes.bluetoothName != null) {
4387 mCurAudioRoutes.bluetoothName = null;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004388 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4389 SENDMSG_NOOP, 0, 0, null, 0);
4390 }
4391 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004392 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4393 if (btDevice.isBluetoothDock()) {
4394 // this could be a reconnection after a transient disconnection
4395 cancelA2dpDeviceTimeout();
4396 mDockAddress = address;
4397 } else {
4398 // this could be a connection of another A2DP device before the timeout of
4399 // a dock: cancel the dock timeout, and make the dock unavailable now
4400 if(hasScheduledA2dpDockTimeout()) {
4401 cancelA2dpDeviceTimeout();
4402 makeA2dpDeviceUnavailableNow(mDockAddress);
4403 }
4404 }
4405 makeA2dpDeviceAvailable(address);
Dianne Hackborn632ca412012-06-14 19:34:10 -07004406 synchronized (mCurAudioRoutes) {
4407 String name = btDevice.getAliasName();
John Spurlock61560172015-02-06 19:46:04 -05004408 if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
4409 mCurAudioRoutes.bluetoothName = name;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004410 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4411 SENDMSG_NOOP, 0, 0, null, 0);
4412 }
4413 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004414 }
4415 }
4416 }
4417
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004418 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
4419 {
4420 if (DEBUG_VOL) {
4421 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
4422 }
4423 if (btDevice == null) {
4424 return;
4425 }
4426 String address = btDevice.getAddress();
4427 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4428 address = "";
4429 }
4430
4431 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004432 String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
4433 DeviceListSpec deviceSpec = mConnectedDevices.get(key);
4434 boolean isConnected = deviceSpec != null;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004435
4436 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4437 makeA2dpSrcUnavailable(address);
4438 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4439 makeA2dpSrcAvailable(address);
4440 }
4441 }
4442 }
4443
John Du5a0cf7a2013-07-19 11:30:34 -07004444 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
4445 // address is not used for now, but may be used when multiple a2dp devices are supported
4446 synchronized (mA2dpAvrcpLock) {
4447 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004448 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07004449 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4450 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4451 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4452 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4453 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07004454 }
4455 }
4456
Paul McLean394a8e12015-03-03 10:29:19 -07004457 private boolean handleDeviceConnection(boolean connect, int device, String address,
4458 String deviceName) {
4459 if (DEBUG_DEVICES) {
4460 Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device)
4461 + " address:" + address + " name:" + deviceName + ")");
4462 }
Eric Laurent59f48272012-04-05 19:42:21 -07004463 synchronized (mConnectedDevices) {
Paul McLean394a8e12015-03-03 10:29:19 -07004464 String deviceKey = makeDeviceListKey(device, address);
4465 if (DEBUG_DEVICES) {
4466 Slog.i(TAG, "deviceKey:" + deviceKey);
4467 }
4468 DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
4469 boolean isConnected = deviceSpec != null;
4470 if (DEBUG_DEVICES) {
4471 Slog.i(TAG, "deviceSpec:" + deviceSpec + " is(already)Connected:" + isConnected);
4472 }
4473 if (connect && !isConnected) {
4474 AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_AVAILABLE,
4475 address, deviceName);
4476 mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
4477 return true;
4478 } else if (!connect && isConnected) {
4479 AudioSystem.setDeviceConnectionState(device, AudioSystem.DEVICE_STATE_UNAVAILABLE,
4480 address, deviceName);
4481 mConnectedDevices.remove(deviceKey);
4482 return true;
Eric Laurent59f48272012-04-05 19:42:21 -07004483 }
4484 }
4485 return false;
4486 }
4487
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004488 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4489 // sent if none of these devices is connected.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004490 // Access synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004491 int mBecomingNoisyIntentDevices =
4492 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07004493 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07004494 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004495 AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004496
4497 // must be called before removing the device from mConnectedDevices
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004498 // Called synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004499 private int checkSendBecomingNoisyIntent(int device, int state) {
4500 int delay = 0;
4501 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4502 int devices = 0;
Paul McLean394a8e12015-03-03 10:29:19 -07004503 for (String key : mConnectedDevices.keySet()) {
4504 int dev = mConnectedDevices.get(key).mDeviceType;
4505 if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
4506 && ((dev & mBecomingNoisyIntentDevices) != 0)) {
4507 devices |= dev;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004508 }
4509 }
4510 if (devices == device) {
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004511 sendMsg(mAudioHandler,
4512 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4513 SENDMSG_REPLACE,
4514 0,
4515 0,
4516 null,
4517 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004518 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004519 }
4520 }
4521
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004522 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
4523 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004524 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004525 synchronized (mLastDeviceConnectMsgTime) {
4526 long time = SystemClock.uptimeMillis();
4527 if (mLastDeviceConnectMsgTime > time) {
Matthew Xiec525cf72015-01-22 20:13:17 -08004528 delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004529 }
4530 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004531 }
4532 return delay;
4533 }
4534
Paul McLean394a8e12015-03-03 10:29:19 -07004535 private void sendDeviceConnectionIntent(int device, int state, String address,
4536 String deviceName) {
4537 if (DEBUG_DEVICES) {
4538 Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
4539 " state:0x" + Integer.toHexString(state) + " address:" + address +
4540 " name:" + deviceName + ");");
4541 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004542 Intent intent = new Intent();
4543
Paul McLean10804eb2015-01-28 11:16:35 -08004544 intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
4545 intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
4546 intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
4547
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004548 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4549
Dianne Hackborn632ca412012-06-14 19:34:10 -07004550 int connType = 0;
4551
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004552 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004553 connType = AudioRoutesInfo.MAIN_HEADSET;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004554 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4555 intent.putExtra("microphone", 1);
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004556 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
4557 device == AudioSystem.DEVICE_OUT_LINE) {
4558 /*do apps care about line-out vs headphones?*/
Dianne Hackborn632ca412012-06-14 19:34:10 -07004559 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004560 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4561 intent.putExtra("microphone", 0);
Eric Laurent6fa42452015-01-09 15:09:40 -08004562 } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
4563 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004564 connType = AudioRoutesInfo.MAIN_HDMI;
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004565 configureHdmiPlugIntent(intent, state);
Paul McLean10804eb2015-01-28 11:16:35 -08004566 } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE) {
4567 connType = AudioRoutesInfo.MAIN_USB;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004568 }
4569
Dianne Hackborn632ca412012-06-14 19:34:10 -07004570 synchronized (mCurAudioRoutes) {
4571 if (connType != 0) {
John Spurlock61560172015-02-06 19:46:04 -05004572 int newConn = mCurAudioRoutes.mainType;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004573 if (state != 0) {
4574 newConn |= connType;
4575 } else {
4576 newConn &= ~connType;
4577 }
John Spurlock61560172015-02-06 19:46:04 -05004578 if (newConn != mCurAudioRoutes.mainType) {
4579 mCurAudioRoutes.mainType = newConn;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004580 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4581 SENDMSG_NOOP, 0, 0, null, 0);
4582 }
4583 }
4584 }
4585
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004586 final long ident = Binder.clearCallingIdentity();
4587 try {
4588 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
4589 } finally {
4590 Binder.restoreCallingIdentity(ident);
4591 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004592 }
4593
Paul McLean10804eb2015-01-28 11:16:35 -08004594 private void onSetWiredDeviceConnectionState(int device, int state, String address,
Paul McLean394a8e12015-03-03 10:29:19 -07004595 String deviceName) {
4596 if (DEBUG_DEVICES) {
4597 Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device) +
4598 " state:" + Integer.toHexString(state) + " address:" + address +
4599 " deviceName:" + deviceName + ");");
4600 }
Paul McLean10804eb2015-01-28 11:16:35 -08004601
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004602 synchronized (mConnectedDevices) {
4603 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004604 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4605 (device == AudioSystem.DEVICE_OUT_LINE))) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004606 setBluetoothA2dpOnInt(true);
4607 }
Eric Laurentae4506e2014-05-29 16:04:32 -07004608 boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
4609 (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
4610 ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
Paul McLean10804eb2015-01-28 11:16:35 -08004611 handleDeviceConnection(state == 1, device, address, deviceName);
Eric Laurentf1a457d2012-09-20 16:27:23 -07004612 if (state != 0) {
4613 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004614 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4615 (device == AudioSystem.DEVICE_OUT_LINE)) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07004616 setBluetoothA2dpOnInt(false);
4617 }
4618 if ((device & mSafeMediaVolumeDevices) != 0) {
4619 sendMsg(mAudioHandler,
4620 MSG_CHECK_MUSIC_ACTIVE,
4621 SENDMSG_REPLACE,
4622 0,
4623 0,
4624 null,
4625 MUSIC_ACTIVE_POLL_PERIOD_MS);
4626 }
Eric Laurent212532b2014-07-21 15:43:18 -07004627 // Television devices without CEC service apply software volume on HDMI output
4628 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4629 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
4630 checkAllFixedVolumeDevices();
4631 if (mHdmiManager != null) {
4632 synchronized (mHdmiManager) {
4633 if (mHdmiPlaybackClient != null) {
4634 mHdmiCecSink = false;
4635 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
4636 }
4637 }
4638 }
4639 }
4640 } else {
4641 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4642 if (mHdmiManager != null) {
4643 synchronized (mHdmiManager) {
4644 mHdmiCecSink = false;
4645 }
4646 }
4647 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004648 }
Paul McLean10804eb2015-01-28 11:16:35 -08004649 if (!isUsb && device != AudioSystem.DEVICE_IN_WIRED_HEADSET) {
4650 sendDeviceConnectionIntent(device, state, address, deviceName);
Mike Lockwooddb454842012-09-18 11:16:57 -07004651 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004652 }
4653 }
4654
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004655 private void configureHdmiPlugIntent(Intent intent, int state) {
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004656 intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
4657 intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004658 if (state == 1) {
4659 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
4660 int[] portGeneration = new int[1];
4661 int status = AudioSystem.listAudioPorts(ports, portGeneration);
4662 if (status == AudioManager.SUCCESS) {
4663 for (AudioPort port : ports) {
4664 if (port instanceof AudioDevicePort) {
4665 final AudioDevicePort devicePort = (AudioDevicePort) port;
Eric Laurent6fa42452015-01-09 15:09:40 -08004666 if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
4667 devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004668 // format the list of supported encodings
4669 int[] formats = devicePort.formats();
4670 if (formats.length > 0) {
4671 ArrayList<Integer> encodingList = new ArrayList(1);
4672 for (int format : formats) {
4673 // a format in the list can be 0, skip it
4674 if (format != AudioFormat.ENCODING_INVALID) {
4675 encodingList.add(format);
4676 }
4677 }
4678 int[] encodingArray = new int[encodingList.size()];
4679 for (int i = 0 ; i < encodingArray.length ; i++) {
4680 encodingArray[i] = encodingList.get(i);
4681 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004682 intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004683 }
4684 // find the maximum supported number of channels
4685 int maxChannels = 0;
4686 for (int mask : devicePort.channelMasks()) {
4687 int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
4688 if (channelCount > maxChannels) {
4689 maxChannels = channelCount;
4690 }
4691 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004692 intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004693 }
4694 }
4695 }
4696 }
4697 }
4698 }
4699
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004700 /* cache of the address of the last dock the device was connected to */
4701 private String mDockAddress;
4702
Eric Laurenta553c252009-07-17 12:17:14 -07004703 /**
4704 * Receiver for misc intent broadcasts the Phone app cares about.
4705 */
4706 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4707 @Override
4708 public void onReceive(Context context, Intent intent) {
4709 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07004710 int outDevice;
4711 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07004712 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07004713
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004714 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4715 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4716 Intent.EXTRA_DOCK_STATE_UNDOCKED);
4717 int config;
4718 switch (dockState) {
4719 case Intent.EXTRA_DOCK_STATE_DESK:
4720 config = AudioSystem.FORCE_BT_DESK_DOCK;
4721 break;
4722 case Intent.EXTRA_DOCK_STATE_CAR:
4723 config = AudioSystem.FORCE_BT_CAR_DOCK;
4724 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004725 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08004726 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004727 break;
4728 case Intent.EXTRA_DOCK_STATE_HE_DESK:
4729 config = AudioSystem.FORCE_DIGITAL_DOCK;
4730 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004731 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4732 default:
4733 config = AudioSystem.FORCE_NONE;
4734 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08004735 // Low end docks have a menu to enable or disable audio
4736 // (see mDockAudioMediaEnabled)
4737 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
4738 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
4739 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
4740 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
4741 }
4742 mDockState = dockState;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004743 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
Eric Laurent59f48272012-04-05 19:42:21 -07004744 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004745 BluetoothProfile.STATE_DISCONNECTED);
Eric Laurentae4506e2014-05-29 16:04:32 -07004746 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
4747 inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
Nick Pellya56d1c72009-08-19 14:49:29 -07004748 String address = null;
Eric Laurentdca56b92011-09-02 14:20:56 -07004749
4750 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
4751 if (btDevice == null) {
4752 return;
4753 }
4754
4755 address = btDevice.getAddress();
4756 BluetoothClass btClass = btDevice.getBluetoothClass();
4757 if (btClass != null) {
4758 switch (btClass.getDeviceClass()) {
4759 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
4760 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
Eric Laurentae4506e2014-05-29 16:04:32 -07004761 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurentdca56b92011-09-02 14:20:56 -07004762 break;
4763 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
Eric Laurentae4506e2014-05-29 16:04:32 -07004764 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurentdca56b92011-09-02 14:20:56 -07004765 break;
Eric Laurentd5603c12009-08-06 08:49:39 -07004766 }
4767 }
4768
Eric Laurentdca56b92011-09-02 14:20:56 -07004769 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4770 address = "";
4771 }
Eric Laurentd5603c12009-08-06 08:49:39 -07004772
Eric Laurent59f48272012-04-05 19:42:21 -07004773 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
Paul McLean10804eb2015-01-28 11:16:35 -08004774 boolean success =
4775 handleDeviceConnection(connected, outDevice, address, "Bluetooth Headset") &&
4776 handleDeviceConnection(connected, inDevice, address, "Bluetooth Headset");
Eric Laurentae4506e2014-05-29 16:04:32 -07004777 if (success) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004778 synchronized (mScoClients) {
Eric Laurent59f48272012-04-05 19:42:21 -07004779 if (connected) {
4780 mBluetoothHeadsetDevice = btDevice;
4781 } else {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004782 mBluetoothHeadsetDevice = null;
4783 resetBluetoothSco();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004784 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004785 }
Eric Laurenta553c252009-07-17 12:17:14 -07004786 }
Paul McLeandf361462014-04-10 16:02:55 -07004787 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004788 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07004789 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004790 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004791 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07004792 // broadcast intent if the connection was initated by AudioService
4793 if (!mScoClients.isEmpty() &&
4794 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
4795 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
4796 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004797 broadcast = true;
4798 }
4799 switch (btState) {
4800 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004801 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07004802 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4803 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4804 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004805 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004806 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004807 break;
4808 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004809 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08004810 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07004811 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08004812 break;
4813 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07004814 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4815 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4816 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004817 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004818 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004819 default:
4820 // do not broadcast CONNECTING or invalid state
4821 broadcast = false;
4822 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004823 }
4824 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004825 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07004826 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07004827 //FIXME: this is to maintain compatibility with deprecated intent
4828 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08004829 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07004830 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004831 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08004832 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004833 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06004834 if (mMonitorRotation) {
4835 mOrientationListener.onOrientationChanged(0); //argument is ignored anyway
4836 mOrientationListener.enable();
4837 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004838 AudioSystem.setParameters("screen_state=on");
4839 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06004840 if (mMonitorRotation) {
4841 //reduce wakeups (save current) by only listening when display is on
4842 mOrientationListener.disable();
4843 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004844 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07004845 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004846 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004847 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004848 // attempt to stop music playback for background user
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004849 sendMsg(mAudioHandler,
4850 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4851 SENDMSG_REPLACE,
4852 0,
4853 0,
4854 null,
4855 0);
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004856 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004857 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004858
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004859 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004860 readAudioSettings(true /*userSwitch*/);
4861 // preserve STREAM_MUSIC volume from one user to the next.
4862 sendMsg(mAudioHandler,
4863 MSG_SET_ALL_VOLUMES,
4864 SENDMSG_QUEUE,
4865 0,
4866 0,
4867 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Eric Laurenta553c252009-07-17 12:17:14 -07004868 }
4869 }
Paul McLeanc837a452014-04-09 09:04:43 -07004870 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004871
4872 //==========================================================================================
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004873 // RemoteControlDisplay / RemoteControlClient / Remote info
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004874 //==========================================================================================
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004875 public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
4876 ComponentName listenerComp) {
4877 return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
4878 }
4879
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004880 public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004881 return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004882 }
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004883
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004884 public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004885 mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004886 }
4887
4888 public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004889 mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004890 }
4891
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07004892 public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
4893 boolean wantsSync) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004894 mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
4895 }
4896
John Spurlock3346a802014-05-20 16:25:37 -04004897 @Override
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004898 public void setRemoteStreamVolume(int index) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05004899 enforceVolumeController("set the remote stream volume");
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004900 mMediaFocusControl.setRemoteStreamVolume(index);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004901 }
4902
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004903 //==========================================================================================
4904 // Audio Focus
4905 //==========================================================================================
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004906 public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004907 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004908 IAudioPolicyCallback pcb) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004909 // permission checks
4910 if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
John Spurlock61560172015-02-06 19:46:04 -05004911 if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004912 if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
4913 android.Manifest.permission.MODIFY_PHONE_STATE)) {
4914 Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
4915 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4916 }
4917 } else {
4918 // only a registered audio policy can be used to lock focus
4919 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004920 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
4921 Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004922 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4923 }
4924 }
4925 }
4926 }
4927
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004928 return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
4929 clientId, callingPackageName, flags);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004930 }
4931
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004932 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
4933 return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004934 }
4935
4936 public void unregisterAudioFocusClient(String clientId) {
4937 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004938 }
4939
Jean-Michel Trivi23805662013-07-31 14:19:18 -07004940 public int getCurrentAudioFocus() {
4941 return mMediaFocusControl.getCurrentAudioFocus();
4942 }
4943
John Spurlock5e783732015-02-19 10:28:59 -05004944 private boolean readCameraSoundForced() {
4945 return SystemProperties.getBoolean("audio.camerasound.force", false) ||
4946 mContext.getResources().getBoolean(
4947 com.android.internal.R.bool.config_camera_sound_forced);
4948 }
4949
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004950 //==========================================================================================
4951 // Device orientation
4952 //==========================================================================================
4953 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004954 * Handles device configuration changes that may map to a change in the orientation
4955 * or orientation.
4956 * Monitoring orientation and rotation is optional, and is defined by the definition and value
4957 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004958 */
4959 private void handleConfigurationChanged(Context context) {
4960 try {
4961 // reading new orientation "safely" (i.e. under try catch) in case anything
4962 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07004963 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004964 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07004965 if (mMonitorOrientation) {
4966 int newOrientation = config.orientation;
4967 if (newOrientation != mDeviceOrientation) {
4968 mDeviceOrientation = newOrientation;
4969 setOrientationForAudioSystem();
4970 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004971 }
Eric Laurentd640bd32012-09-28 18:01:48 -07004972 sendMsg(mAudioHandler,
4973 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
4974 SENDMSG_REPLACE,
4975 0,
4976 0,
4977 null,
4978 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07004979
John Spurlock5e783732015-02-19 10:28:59 -05004980 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -07004981 synchronized (mSettingsLock) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004982 boolean cameraSoundForcedChanged = false;
Eric Laurentdd45d012012-10-08 09:04:34 -07004983 synchronized (mCameraSoundForced) {
4984 if (cameraSoundForced != mCameraSoundForced) {
4985 mCameraSoundForced = cameraSoundForced;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004986 cameraSoundForcedChanged = true;
Eric Laurentdd45d012012-10-08 09:04:34 -07004987 }
4988 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004989 if (cameraSoundForcedChanged) {
4990 if (!isPlatformTelevision()) {
4991 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
4992 if (cameraSoundForced) {
4993 s.setAllIndexesToMax();
4994 mRingerModeAffectedStreams &=
4995 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4996 } else {
4997 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
4998 mRingerModeAffectedStreams |=
4999 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5000 }
5001 // take new state into account for streams muted by ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05005002 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07005003 }
5004
5005 sendMsg(mAudioHandler,
5006 MSG_SET_FORCE_USE,
5007 SENDMSG_QUEUE,
5008 AudioSystem.FOR_SYSTEM,
5009 cameraSoundForced ?
5010 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
5011 null,
5012 0);
5013
5014 sendMsg(mAudioHandler,
5015 MSG_SET_ALL_VOLUMES,
5016 SENDMSG_QUEUE,
5017 0,
5018 0,
5019 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
5020 }
Eric Laurentdd45d012012-10-08 09:04:34 -07005021 }
John Spurlock3346a802014-05-20 16:25:37 -04005022 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005023 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005024 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005025 }
5026 }
5027
5028 private void setOrientationForAudioSystem() {
5029 switch (mDeviceOrientation) {
5030 case Configuration.ORIENTATION_LANDSCAPE:
5031 //Log.i(TAG, "orientation is landscape");
5032 AudioSystem.setParameters("orientation=landscape");
5033 break;
5034 case Configuration.ORIENTATION_PORTRAIT:
5035 //Log.i(TAG, "orientation is portrait");
5036 AudioSystem.setParameters("orientation=portrait");
5037 break;
5038 case Configuration.ORIENTATION_SQUARE:
5039 //Log.i(TAG, "orientation is square");
5040 AudioSystem.setParameters("orientation=square");
5041 break;
5042 case Configuration.ORIENTATION_UNDEFINED:
5043 //Log.i(TAG, "orientation is undefined");
5044 AudioSystem.setParameters("orientation=undefined");
5045 break;
5046 default:
5047 Log.e(TAG, "Unknown orientation");
5048 }
5049 }
5050
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005051 private void setRotationForAudioSystem() {
5052 switch (mDeviceRotation) {
5053 case Surface.ROTATION_0:
5054 AudioSystem.setParameters("rotation=0");
5055 break;
5056 case Surface.ROTATION_90:
5057 AudioSystem.setParameters("rotation=90");
5058 break;
5059 case Surface.ROTATION_180:
5060 AudioSystem.setParameters("rotation=180");
5061 break;
5062 case Surface.ROTATION_270:
5063 AudioSystem.setParameters("rotation=270");
5064 break;
5065 default:
5066 Log.e(TAG, "Unknown device rotation");
5067 }
5068 }
5069
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005070
Eric Laurent78472112012-05-21 08:57:21 -07005071 // Handles request to override default use of A2DP for media.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005072 // Must be called synchronized on mConnectedDevices
Eric Laurent78472112012-05-21 08:57:21 -07005073 public void setBluetoothA2dpOnInt(boolean on) {
5074 synchronized (mBluetoothA2dpEnabledLock) {
5075 mBluetoothA2dpEnabled = on;
Eric Laurentc390bed2012-07-03 12:24:05 -07005076 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005077 setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
Eric Laurentc390bed2012-07-03 12:24:05 -07005078 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
Eric Laurent78472112012-05-21 08:57:21 -07005079 }
5080 }
5081
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005082 // Must be called synchronized on mConnectedDevices
5083 private void setForceUseInt_SyncDevices(int usage, int config) {
5084 switch (usage) {
5085 case AudioSystem.FOR_MEDIA:
5086 if (config == AudioSystem.FORCE_NO_BT_A2DP) {
5087 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ALL_A2DP;
5088 } else { // config == AudioSystem.FORCE_NONE
5089 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
5090 }
5091 break;
5092 case AudioSystem.FOR_DOCK:
5093 if (config == AudioSystem.FORCE_ANALOG_DOCK) {
5094 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5095 } else { // config == AudioSystem.FORCE_NONE
5096 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5097 }
5098 break;
5099 default:
5100 // usage doesn't affect the broadcast of ACTION_AUDIO_BECOMING_NOISY
5101 }
5102 AudioSystem.setForceUse(usage, config);
5103 }
5104
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005105 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07005106 public void setRingtonePlayer(IRingtonePlayer player) {
5107 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5108 mRingtonePlayer = player;
5109 }
5110
5111 @Override
5112 public IRingtonePlayer getRingtonePlayer() {
5113 return mRingtonePlayer;
5114 }
5115
5116 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07005117 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5118 synchronized (mCurAudioRoutes) {
5119 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5120 mRoutesObservers.register(observer);
5121 return routes;
5122 }
5123 }
5124
Eric Laurentc34dcc12012-09-10 13:51:52 -07005125
5126 //==========================================================================================
5127 // Safe media volume management.
5128 // MUSIC stream volume level is limited when headphones are connected according to safety
5129 // regulation. When the user attempts to raise the volume above the limit, a warning is
5130 // displayed and the user has to acknowlegde before the volume is actually changed.
5131 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
5132 // property. Platforms with a different limit must set this property accordingly in their
5133 // overlay.
5134 //==========================================================================================
5135
Eric Laurentd640bd32012-09-28 18:01:48 -07005136 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
5137 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
5138 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
5139 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
5140 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
5141 // (when user opts out).
John Spurlock35134602014-07-24 18:10:48 -04005142 private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
5143 private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
5144 private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed
5145 private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
Eric Laurentd640bd32012-09-28 18:01:48 -07005146 private Integer mSafeMediaVolumeState;
5147
5148 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005149 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07005150 private int mSafeMediaVolumeIndex;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005151 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
5152 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
5153 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
5154 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
5155 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
5156 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
5157 private int mMusicActiveMs;
5158 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
5159 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07005160 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07005161
5162 private void setSafeMediaVolumeEnabled(boolean on) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005163 synchronized (mSafeMediaVolumeState) {
5164 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
5165 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
5166 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
5167 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
5168 enforceSafeMediaVolume();
5169 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
5170 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005171 mMusicActiveMs = 1; // nonzero = confirmed
5172 saveMusicActiveMs();
Eric Laurentd640bd32012-09-28 18:01:48 -07005173 sendMsg(mAudioHandler,
5174 MSG_CHECK_MUSIC_ACTIVE,
5175 SENDMSG_REPLACE,
5176 0,
5177 0,
5178 null,
5179 MUSIC_ACTIVE_POLL_PERIOD_MS);
5180 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005181 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005182 }
5183 }
5184
5185 private void enforceSafeMediaVolume() {
5186 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07005187 int devices = mSafeMediaVolumeDevices;
5188 int i = 0;
5189
5190 while (devices != 0) {
5191 int device = 1 << i++;
5192 if ((device & devices) == 0) {
5193 continue;
5194 }
Eric Laurent42b041e2013-03-29 11:36:03 -07005195 int index = streamState.getIndex(device);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005196 if (index > mSafeMediaVolumeIndex) {
Eric Laurent42b041e2013-03-29 11:36:03 -07005197 streamState.setIndex(mSafeMediaVolumeIndex, device);
5198 sendMsg(mAudioHandler,
5199 MSG_SET_DEVICE_VOLUME,
5200 SENDMSG_QUEUE,
5201 device,
5202 0,
5203 streamState,
5204 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005205 }
5206 devices &= ~device;
5207 }
5208 }
5209
5210 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005211 synchronized (mSafeMediaVolumeState) {
5212 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07005213 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
5214 ((device & mSafeMediaVolumeDevices) != 0) &&
5215 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005216 return false;
5217 }
5218 return true;
5219 }
5220 }
5221
John Spurlock3346a802014-05-20 16:25:37 -04005222 @Override
Eric Laurentc34dcc12012-09-10 13:51:52 -07005223 public void disableSafeMediaVolume() {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005224 enforceVolumeController("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07005225 synchronized (mSafeMediaVolumeState) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005226 setSafeMediaVolumeEnabled(false);
Eric Laurentfde16d52012-12-03 14:42:39 -08005227 if (mPendingVolumeCommand != null) {
5228 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
5229 mPendingVolumeCommand.mIndex,
5230 mPendingVolumeCommand.mFlags,
5231 mPendingVolumeCommand.mDevice);
5232 mPendingVolumeCommand = null;
5233 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005234 }
5235 }
5236
Jungshik Jang41d97462014-06-30 22:26:29 +09005237 //==========================================================================================
5238 // Hdmi Cec system audio mode.
John Spurlockbc82b122015-03-02 16:12:38 -05005239 // If Hdmi Cec's system audio mode is on, audio service should send the volume change
5240 // to HdmiControlService so that the audio receiver can handle it.
Jungshik Jang41d97462014-06-30 22:26:29 +09005241 //==========================================================================================
5242
Eric Laurent212532b2014-07-21 15:43:18 -07005243 private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
5244 public void onComplete(int status) {
5245 if (mHdmiManager != null) {
5246 synchronized (mHdmiManager) {
5247 mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
5248 // Television devices without CEC service apply software volume on HDMI output
5249 if (isPlatformTelevision() && !mHdmiCecSink) {
5250 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5251 }
5252 checkAllFixedVolumeDevices();
5253 }
5254 }
5255 }
5256 };
5257
Jungshik Jang41d97462014-06-30 22:26:29 +09005258 // If HDMI-CEC system audio is supported
5259 private boolean mHdmiSystemAudioSupported = false;
5260 // Set only when device is tv.
5261 private HdmiTvClient mHdmiTvClient;
Eric Laurent0b03f992014-11-18 18:08:02 -08005262 // true if the device has system feature PackageManager.FEATURE_LEANBACK.
Eric Laurent212532b2014-07-21 15:43:18 -07005263 // cached HdmiControlManager interface
5264 private HdmiControlManager mHdmiManager;
5265 // Set only when device is a set-top box.
5266 private HdmiPlaybackClient mHdmiPlaybackClient;
5267 // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5268 private boolean mHdmiCecSink;
5269
5270 private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
Jungshik Jang41d97462014-06-30 22:26:29 +09005271
5272 @Override
Jungshik Jang12307ca2014-07-15 19:27:56 +09005273 public int setHdmiSystemAudioSupported(boolean on) {
Eric Laurent212532b2014-07-21 15:43:18 -07005274 int device = AudioSystem.DEVICE_NONE;
5275 if (mHdmiManager != null) {
5276 synchronized (mHdmiManager) {
5277 if (mHdmiTvClient == null) {
5278 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5279 return device;
5280 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005281
Eric Laurent212532b2014-07-21 15:43:18 -07005282 synchronized (mHdmiTvClient) {
5283 if (mHdmiSystemAudioSupported != on) {
5284 mHdmiSystemAudioSupported = on;
5285 AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5286 on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5287 AudioSystem.FORCE_NONE);
5288 }
5289 device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
5290 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005291 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005292 }
Eric Laurent212532b2014-07-21 15:43:18 -07005293 return device;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005294 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005295
Terry Heoe7d6d972014-09-04 21:05:28 +09005296 @Override
5297 public boolean isHdmiSystemAudioSupported() {
5298 return mHdmiSystemAudioSupported;
5299 }
5300
Eric Laurentdd45d012012-10-08 09:04:34 -07005301 //==========================================================================================
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005302 // Accessibility: taking touch exploration into account for selecting the default
5303 // stream override timeout when adjusting volume
5304 //==========================================================================================
5305 private static class StreamOverride
5306 implements AccessibilityManager.TouchExplorationStateChangeListener {
5307
5308 // AudioService.getActiveStreamType() will return:
5309 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
5310 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
5311 // stopped
5312 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
5313 private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
5314
5315 static int sDelayMs;
5316
5317 static void init(Context ctxt) {
5318 AccessibilityManager accessibilityManager =
5319 (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
5320 updateDefaultStreamOverrideDelay(
5321 accessibilityManager.isTouchExplorationEnabled());
5322 accessibilityManager.addTouchExplorationStateChangeListener(
5323 new StreamOverride());
5324 }
5325
5326 @Override
5327 public void onTouchExplorationStateChanged(boolean enabled) {
5328 updateDefaultStreamOverrideDelay(enabled);
5329 }
5330
5331 private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
5332 if (touchExploreEnabled) {
5333 sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
5334 } else {
5335 sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
5336 }
5337 if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
5338 + " stream override delay is now " + sDelayMs + " ms");
5339 }
5340 }
5341
5342 //==========================================================================================
Eric Laurentdd45d012012-10-08 09:04:34 -07005343 // Camera shutter sound policy.
5344 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5345 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5346 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5347 //==========================================================================================
5348
5349 // cached value of com.android.internal.R.bool.config_camera_sound_forced
5350 private Boolean mCameraSoundForced;
5351
5352 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5353 public boolean isCameraSoundForced() {
5354 synchronized (mCameraSoundForced) {
5355 return mCameraSoundForced;
5356 }
5357 }
5358
5359 private static final String[] RINGER_MODE_NAMES = new String[] {
5360 "SILENT",
5361 "VIBRATE",
5362 "NORMAL"
5363 };
5364
5365 private void dumpRingerMode(PrintWriter pw) {
5366 pw.println("\nRinger mode: ");
John Spurlock661f2cf2014-11-17 10:29:10 -05005367 pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
5368 pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
Eric Laurentdd45d012012-10-08 09:04:34 -07005369 pw.print("- ringer mode affected streams = 0x");
5370 pw.println(Integer.toHexString(mRingerModeAffectedStreams));
5371 pw.print("- ringer mode muted streams = 0x");
5372 pw.println(Integer.toHexString(mRingerModeMutedStreams));
John Spurlock661f2cf2014-11-17 10:29:10 -05005373 pw.print("- delegate = "); pw.println(mRingerModeDelegate);
Eric Laurentdd45d012012-10-08 09:04:34 -07005374 }
5375
Dianne Hackborn632ca412012-06-14 19:34:10 -07005376 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005377 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07005378 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5379
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005380 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07005381 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07005382 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005383 pw.println("\nAudio routes:");
John Spurlock61560172015-02-06 19:46:04 -05005384 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
5385 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
John Spurlock35134602014-07-24 18:10:48 -04005386
5387 pw.println("\nOther state:");
John Spurlock3346a802014-05-20 16:25:37 -04005388 pw.print(" mVolumeController="); pw.println(mVolumeController);
John Spurlock35134602014-07-24 18:10:48 -04005389 pw.print(" mSafeMediaVolumeState=");
5390 pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
5391 pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
5392 pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
5393 pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005394 pw.print(" mMcc="); pw.println(mMcc);
John Spurlock5e783732015-02-19 10:28:59 -05005395 pw.print(" mCameraSoundForced="); pw.println(mCameraSoundForced);
John Spurlock661f2cf2014-11-17 10:29:10 -05005396 pw.print(" mHasVibrator="); pw.println(mHasVibrator);
John Spurlockcdb57ae2015-02-11 19:04:11 -05005397 pw.print(" mControllerService="); pw.println(mControllerService);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005398
5399 dumpAudioPolicies(pw);
John Spurlock35134602014-07-24 18:10:48 -04005400 }
5401
5402 private static String safeMediaVolumeStateToString(Integer state) {
5403 switch(state) {
5404 case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
5405 case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
5406 case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
5407 case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
5408 }
5409 return null;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005410 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07005411
5412 // Inform AudioFlinger of our device's low RAM attribute
5413 private static void readAndSetLowRamDevice()
5414 {
5415 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
5416 if (status != 0) {
5417 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
5418 }
5419 }
John Spurlock3346a802014-05-20 16:25:37 -04005420
John Spurlockcdb57ae2015-02-11 19:04:11 -05005421 private void enforceVolumeController(String action) {
5422 if (mControllerService.mUid != 0 && Binder.getCallingUid() == mControllerService.mUid) {
5423 return;
5424 }
John Spurlock3346a802014-05-20 16:25:37 -04005425 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
5426 "Only SystemUI can " + action);
5427 }
5428
5429 @Override
5430 public void setVolumeController(final IVolumeController controller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005431 enforceVolumeController("set the volume controller");
John Spurlock3346a802014-05-20 16:25:37 -04005432
5433 // return early if things are not actually changing
5434 if (mVolumeController.isSameBinder(controller)) {
5435 return;
5436 }
5437
5438 // dismiss the old volume controller
5439 mVolumeController.postDismiss();
5440 if (controller != null) {
5441 // we are about to register a new controller, listen for its death
5442 try {
5443 controller.asBinder().linkToDeath(new DeathRecipient() {
5444 @Override
5445 public void binderDied() {
5446 if (mVolumeController.isSameBinder(controller)) {
5447 Log.w(TAG, "Current remote volume controller died, unregistering");
5448 setVolumeController(null);
5449 }
5450 }
5451 }, 0);
5452 } catch (RemoteException e) {
5453 // noop
5454 }
5455 }
5456 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04005457 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
5458 }
5459
5460 @Override
5461 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005462 enforceVolumeController("notify about volume controller visibility");
John Spurlock33f4e042014-07-11 13:10:58 -04005463
5464 // return early if the controller is not current
5465 if (!mVolumeController.isSameBinder(controller)) {
5466 return;
5467 }
5468
5469 mVolumeController.setVisible(visible);
5470 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04005471 }
RoboErikd09bd0c2014-06-24 17:45:19 -07005472
5473 public static class VolumeController {
5474 private static final String TAG = "VolumeController";
5475
5476 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04005477 private boolean mVisible;
5478 private long mNextLongPress;
5479 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07005480
5481 public void setController(IVolumeController controller) {
5482 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04005483 mVisible = false;
5484 }
5485
5486 public void loadSettings(ContentResolver cr) {
5487 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
5488 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
5489 }
5490
RoboErik4197cb62015-01-21 15:45:32 -08005491 public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
5492 if (isMute) {
5493 return false;
5494 }
John Spurlock33f4e042014-07-11 13:10:58 -04005495 boolean suppress = false;
5496 if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
5497 final long now = SystemClock.uptimeMillis();
5498 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
5499 // ui will become visible
5500 if (mNextLongPress < now) {
5501 mNextLongPress = now + mLongPressTimeout;
5502 }
5503 suppress = true;
5504 } else if (mNextLongPress > 0) { // in a long-press
5505 if (now > mNextLongPress) {
5506 // long press triggered, no more suppression
5507 mNextLongPress = 0;
5508 } else {
5509 // keep suppressing until the long press triggers
5510 suppress = true;
5511 }
5512 }
5513 }
5514 return suppress;
5515 }
5516
5517 public void setVisible(boolean visible) {
5518 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07005519 }
5520
5521 public boolean isSameBinder(IVolumeController controller) {
5522 return Objects.equals(asBinder(), binder(controller));
5523 }
5524
5525 public IBinder asBinder() {
5526 return binder(mController);
5527 }
5528
5529 private static IBinder binder(IVolumeController controller) {
5530 return controller == null ? null : controller.asBinder();
5531 }
5532
5533 @Override
5534 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04005535 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07005536 }
5537
5538 public void postDisplaySafeVolumeWarning(int flags) {
5539 if (mController == null)
5540 return;
5541 try {
5542 mController.displaySafeVolumeWarning(flags);
5543 } catch (RemoteException e) {
5544 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
5545 }
5546 }
5547
5548 public void postVolumeChanged(int streamType, int flags) {
5549 if (mController == null)
5550 return;
5551 try {
5552 mController.volumeChanged(streamType, flags);
5553 } catch (RemoteException e) {
5554 Log.w(TAG, "Error calling volumeChanged", e);
5555 }
5556 }
5557
RoboErikd09bd0c2014-06-24 17:45:19 -07005558 public void postMasterMuteChanged(int flags) {
5559 if (mController == null)
5560 return;
5561 try {
5562 mController.masterMuteChanged(flags);
5563 } catch (RemoteException e) {
5564 Log.w(TAG, "Error calling masterMuteChanged", e);
5565 }
5566 }
5567
5568 public void setLayoutDirection(int layoutDirection) {
5569 if (mController == null)
5570 return;
5571 try {
5572 mController.setLayoutDirection(layoutDirection);
5573 } catch (RemoteException e) {
5574 Log.w(TAG, "Error calling setLayoutDirection", e);
5575 }
5576 }
5577
5578 public void postDismiss() {
5579 if (mController == null)
5580 return;
5581 try {
5582 mController.dismiss();
5583 } catch (RemoteException e) {
5584 Log.w(TAG, "Error calling dismiss", e);
5585 }
5586 }
5587 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005588
RoboErik0dac35a2014-08-12 15:48:49 -07005589 /**
5590 * Interface for system components to get some extra functionality through
5591 * LocalServices.
5592 */
5593 final class AudioServiceInternal extends AudioManagerInternal {
John Spurlock661f2cf2014-11-17 10:29:10 -05005594 @Override
5595 public void setRingerModeDelegate(RingerModeDelegate delegate) {
5596 mRingerModeDelegate = delegate;
5597 if (mRingerModeDelegate != null) {
5598 setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
5599 }
5600 }
RoboErik272e1612014-09-05 11:39:29 -07005601
5602 @Override
5603 public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
5604 String callingPackage, int uid) {
5605 // direction and stream type swap here because the public
5606 // adjustSuggested has a different order than the other methods.
5607 adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage, uid);
5608 }
5609
RoboErik0dac35a2014-08-12 15:48:49 -07005610 @Override
5611 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
5612 String callingPackage, int uid) {
5613 adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
5614 }
5615
5616 @Override
5617 public void setStreamVolumeForUid(int streamType, int direction, int flags,
5618 String callingPackage, int uid) {
5619 setStreamVolume(streamType, direction, flags, callingPackage, uid);
5620 }
RoboErik519c7742014-11-18 10:59:09 -08005621
5622 @Override
John Spurlock661f2cf2014-11-17 10:29:10 -05005623 public int getRingerModeInternal() {
5624 return AudioService.this.getRingerModeInternal();
5625 }
5626
5627 @Override
5628 public void setRingerModeInternal(int ringerMode, String caller) {
5629 AudioService.this.setRingerModeInternal(ringerMode, caller);
5630 }
John Spurlockcdb57ae2015-02-11 19:04:11 -05005631
5632 @Override
5633 public int getVolumeControllerUid() {
5634 return mControllerService.mUid;
5635 }
RoboErik0dac35a2014-08-12 15:48:49 -07005636 }
5637
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005638 //==========================================================================================
5639 // Audio policy management
5640 //==========================================================================================
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005641 public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
5642 boolean hasFocusListener) {
5643 if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
5644 + " with config:" + policyConfig);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005645 String regId = null;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005646 // error handling
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005647 boolean hasPermissionForPolicy =
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005648 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005649 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5650 if (!hasPermissionForPolicy) {
5651 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
5652 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005653 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005654 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005655
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005656 synchronized (mAudioPolicies) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005657 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005658 if (mAudioPolicies.containsKey(pcb.asBinder())) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005659 Slog.e(TAG, "Cannot re-register policy");
5660 return null;
5661 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005662 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
5663 pcb.asBinder().linkToDeath(app, 0/*flags*/);
5664 regId = app.getRegistrationId();
5665 mAudioPolicies.put(pcb.asBinder(), app);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005666 } catch (RemoteException e) {
5667 // audio policy owner has already died!
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005668 Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005669 " binder death", e);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005670 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005671 }
5672 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005673 return regId;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005674 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005675
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005676 public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
5677 if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005678 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005679 AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005680 if (app == null) {
5681 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
5682 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005683 return;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005684 } else {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005685 pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005686 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005687 app.release();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005688 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005689 // TODO implement clearing mix attribute matching info in native audio policy
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005690 }
5691
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005692 public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
5693 if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
5694 + " policy " + pcb.asBinder());
5695 // error handling
5696 boolean hasPermissionForPolicy =
5697 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
5698 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5699 if (!hasPermissionForPolicy) {
5700 Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
5701 + Binder.getCallingPid() + " / uid "
5702 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
5703 return AudioManager.ERROR;
5704 }
5705
5706 synchronized (mAudioPolicies) {
5707 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
5708 Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
5709 return AudioManager.ERROR;
5710 }
5711 final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
5712 if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5713 // is there already one policy managing ducking?
5714 for(AudioPolicyProxy policy : mAudioPolicies.values()) {
5715 if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5716 Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
5717 return AudioManager.ERROR;
5718 }
5719 }
5720 }
5721 app.mFocusDuckBehavior = duckingBehavior;
5722 mMediaFocusControl.setDuckingInExtPolicyAvailable(
5723 duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
5724 }
5725 return AudioManager.SUCCESS;
5726 }
5727
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005728 private void dumpAudioPolicies(PrintWriter pw) {
5729 pw.println("\nAudio policies:");
5730 synchronized (mAudioPolicies) {
5731 for(AudioPolicyProxy policy : mAudioPolicies.values()) {
5732 pw.println(policy.toLogFriendlyString());
5733 }
5734 }
5735 }
5736
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005737 //======================
5738 // Audio policy proxy
5739 //======================
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005740 /**
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005741 * This internal class inherits from AudioPolicyConfig, each instance contains all the
5742 * mixes of an AudioPolicy and their configurations.
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005743 */
5744 public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005745 private static final String TAG = "AudioPolicyProxy";
5746 AudioPolicyConfig mConfig;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005747 IAudioPolicyCallback mPolicyToken;
5748 boolean mHasFocusListener;
5749 /**
5750 * Audio focus ducking behavior for an audio policy.
5751 * This variable reflects the value that was successfully set in
5752 * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
5753 * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
5754 * is handling ducking for audio focus.
5755 */
5756 int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
5757
5758 AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
5759 boolean hasFocusListener) {
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005760 super(config);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005761 setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005762 mPolicyToken = token;
5763 mHasFocusListener = hasFocusListener;
5764 if (mHasFocusListener) {
5765 mMediaFocusControl.addFocusFollower(mPolicyToken);
5766 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08005767 connectMixes();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005768 }
5769
5770 public void binderDied() {
5771 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005772 Log.i(TAG, "audio policy " + mPolicyToken + " died");
5773 release();
5774 mAudioPolicies.remove(mPolicyToken.asBinder());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005775 }
5776 }
5777
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005778 String getRegistrationId() {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005779 return getRegistration();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005780 }
5781
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005782 void release() {
5783 if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5784 mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
5785 }
5786 if (mHasFocusListener) {
5787 mMediaFocusControl.removeFocusFollower(mPolicyToken);
5788 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08005789 AudioSystem.registerPolicyMixes(mMixes, false);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005790 }
5791
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08005792 void connectMixes() {
5793 AudioSystem.registerPolicyMixes(mMixes, true);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005794 }
5795 };
5796
5797 private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
5798 new HashMap<IBinder, AudioPolicyProxy>();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005799 private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
John Spurlockcdb57ae2015-02-11 19:04:11 -05005800
5801 private class ControllerService extends ContentObserver {
5802 private int mUid;
5803 private ComponentName mComponent;
5804
5805 public ControllerService() {
5806 super(null);
5807 }
5808
5809 @Override
5810 public String toString() {
5811 return String.format("{mUid=%d,mComponent=%s}", mUid, mComponent);
5812 }
5813
5814 public void init() {
5815 onChange(true);
5816 mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
5817 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT), false, this);
5818 }
5819
5820 @Override
5821 public void onChange(boolean selfChange) {
5822 mUid = 0;
5823 mComponent = null;
5824 final String setting = Settings.Secure.getString(mContentResolver,
5825 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
5826 if (setting == null) return;
5827 try {
5828 mComponent = ComponentName.unflattenFromString(setting);
5829 if (mComponent == null) return;
5830 mUid = mContext.getPackageManager()
5831 .getApplicationInfo(mComponent.getPackageName(), 0).uid;
5832 } catch (Exception e) {
5833 Log.w(TAG, "Error loading controller service", e);
5834 }
5835 if (DEBUG_VOL) Log.d(TAG, "Reloaded controller service: " + this);
5836 }
5837 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005838}