blob: 74ac6310194b44c9457077b2d6e0095dd91994f4 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 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
17package android.media;
18
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -080019import android.annotation.CallbackExecutor;
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -080020import android.annotation.IntDef;
Hayden Gomes695f8022019-04-11 10:44:18 -070021import android.annotation.IntRange;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -080022import android.annotation.NonNull;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -070023import android.annotation.Nullable;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060024import android.annotation.RequiresPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.annotation.SdkConstant;
26import android.annotation.SdkConstant.SdkConstantType;
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -070027import android.annotation.SuppressLint;
Terry Heoe7d6d972014-09-04 21:05:28 +090028import android.annotation.SystemApi;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060029import android.annotation.SystemService;
Jean-Michel Triviec977322019-04-12 11:20:35 -070030import android.annotation.TestApi;
Julia Reynolds48034f82016-03-09 10:15:16 -050031import android.app.NotificationManager;
Jean-Michel Trivif0cff042011-09-14 18:11:09 -070032import android.app.PendingIntent;
Arun Mirpuricb102fa2019-01-11 18:39:21 -080033import android.bluetooth.BluetoothCodecConfig;
Eric Laurentb1fbaac2012-05-29 09:24:28 -070034import android.bluetooth.BluetoothDevice;
Jean-Michel Trivi58850372018-09-14 16:01:28 -070035import android.bluetooth.BluetoothProfile;
Artur Satayev53fe9662019-12-10 17:47:55 +000036import android.compat.annotation.UnsupportedAppUsage;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070037import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.content.Context;
Jean-Michel Trivif0cff042011-09-14 18:11:09 -070039import android.content.Intent;
Hayden Gomes62812aa2019-12-23 11:40:27 -080040import android.media.AudioAttributes.AttributeSystemUsage;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070041import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080042import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener;
Hayden Gomes6d69bde2019-04-04 13:10:13 -070043import android.media.audiopolicy.AudioProductStrategy;
Hayden Gomesebd6aaa2019-04-04 13:14:21 -070044import android.media.audiopolicy.AudioVolumeGroup;
François Gaffieadcd00a2018-09-18 17:06:26 +020045import android.media.audiopolicy.AudioVolumeGroupChangeHandler;
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -080046import android.media.projection.MediaProjection;
RoboErikb214efb2014-07-24 13:20:30 -070047import android.media.session.MediaController;
48import android.media.session.MediaSession;
RoboErikf1372422014-04-23 14:38:17 -070049import android.media.session.MediaSessionLegacyHelper;
RoboErikb214efb2014-07-24 13:20:30 -070050import android.media.session.MediaSessionManager;
jiabinad225202019-03-20 15:22:50 -070051import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.os.Binder;
Jean-Michel Trivi461922f2017-04-25 15:23:17 -070053import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.os.Handler;
55import android.os.IBinder;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -080056import android.os.Looper;
57import android.os.Message;
Jason Monk0c37ba32014-09-08 15:34:23 -040058import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.os.RemoteException;
60import android.os.ServiceManager;
Beverlye2d9a232017-11-08 18:14:59 -050061import android.os.SystemClock;
Kenny Guy70e0c582015-06-30 19:18:28 +010062import android.os.UserHandle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.provider.Settings;
jiabinc0f49442018-01-05 10:23:50 -080064import android.text.TextUtils;
Paul McLeane3383cc2015-05-08 11:41:20 -070065import android.util.ArrayMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066import android.util.Log;
jiabin589a2362018-02-22 16:21:53 -080067import android.util.Pair;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070068import android.view.KeyEvent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080070import com.android.internal.annotations.GuardedBy;
François Gaffieadcd00a2018-09-18 17:06:26 +020071import com.android.internal.util.Preconditions;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080072
jiabinc0f49442018-01-05 10:23:50 -080073import java.io.IOException;
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -080074import java.lang.annotation.Retention;
75import java.lang.annotation.RetentionPolicy;
Eric Laurenta198a292014-02-18 16:26:17 -080076import java.util.ArrayList;
jiabinf40141d2020-08-07 17:27:48 -070077import java.util.Arrays;
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -080078import java.util.HashMap;
jiabind0be5b22018-04-10 14:10:04 -070079import java.util.HashSet;
Wonsik Kimb561cce2015-01-30 17:48:51 +090080import java.util.Iterator;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -080081import java.util.List;
jiabin39940752018-04-02 18:18:45 -070082import java.util.Map;
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -070083import java.util.Objects;
Hyundo Moonca0080d2018-12-26 16:16:55 +090084import java.util.TreeMap;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -070085import java.util.concurrent.ConcurrentHashMap;
Eric Laurent1d3cdce2018-01-20 10:31:21 -080086import java.util.concurrent.Executor;
87
Eric Laurent700e7342014-05-02 18:33:15 -070088
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089/**
90 * AudioManager provides access to volume and ringer mode control.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060092@SystemService(Context.AUDIO_SERVICE)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093public class AudioManager {
94
Marco Nelissen29f16932015-04-17 09:50:56 -070095 private Context mOriginalContext;
96 private Context mApplicationContext;
Joe Onorato86f67862010-11-05 18:57:34 -070097 private long mVolumeKeyUpTime;
Jean-Michel Trivia0513082020-09-22 18:43:53 -070098 private boolean mUseFixedVolumeInitialized;
99 private boolean mUseFixedVolume;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -0800100 private static final String TAG = "AudioManager";
101 private static final boolean DEBUG = false;
Eric Laurentf076db42015-01-14 13:23:27 -0800102 private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler();
François Gaffieadcd00a2018-09-18 17:06:26 +0200103 private static final AudioVolumeGroupChangeHandler sAudioAudioVolumeGroupChangedHandler =
104 new AudioVolumeGroupChangeHandler();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105
jiabincfcf1032021-07-01 16:30:50 -0700106 private static Context sContext;
107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 /**
109 * Broadcast intent, a hint for applications that audio is about to become
110 * 'noisy' due to a change in audio outputs. For example, this intent may
111 * be sent when a wired headset is unplugged, or when an A2DP audio
112 * sink is disconnected, and the audio system is about to automatically
113 * switch audio route to the speaker. Applications that are controlling
114 * audio streams may consider pausing, reducing volume or some other action
115 * on receipt of this intent so as not to surprise the user with audio
116 * from the speaker.
117 */
118 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
119 public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY";
120
121 /**
122 * Sticky broadcast intent action indicating that the ringer mode has
123 * changed. Includes the new ringer mode.
124 *
125 * @see #EXTRA_RINGER_MODE
126 */
127 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
128 public static final String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED";
129
130 /**
John Spurlockbcc10872014-11-28 15:29:21 -0500131 * @hide
132 * Sticky broadcast intent action indicating that the internal ringer mode has
133 * changed. Includes the new ringer mode.
134 *
135 * @see #EXTRA_RINGER_MODE
136 */
137 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
138 public static final String INTERNAL_RINGER_MODE_CHANGED_ACTION =
139 "android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION";
140
141 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 * The new ringer mode.
143 *
144 * @see #RINGER_MODE_CHANGED_ACTION
145 * @see #RINGER_MODE_NORMAL
146 * @see #RINGER_MODE_SILENT
147 * @see #RINGER_MODE_VIBRATE
148 */
149 public static final String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE";
150
151 /**
152 * Broadcast intent action indicating that the vibrate setting has
153 * changed. Includes the vibrate type and its new setting.
154 *
155 * @see #EXTRA_VIBRATE_TYPE
156 * @see #EXTRA_VIBRATE_SETTING
Eric Laurentcd1cd732012-05-01 11:23:07 -0700157 * @deprecated Applications should maintain their own vibrate policy based on
158 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 */
160 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500161 public static final String VIBRATE_SETTING_CHANGED_ACTION =
162 "android.media.VIBRATE_SETTING_CHANGED";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163
164 /**
165 * @hide Broadcast intent when the volume for a particular stream type changes.
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700166 * Includes the stream, the new volume and previous volumes.
167 * Notes:
168 * - for internal platform use only, do not make public,
169 * - never used for "remote" volume changes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 *
171 * @see #EXTRA_VOLUME_STREAM_TYPE
172 * @see #EXTRA_VOLUME_STREAM_VALUE
Eric Laurent9ce379a2010-02-16 06:00:26 -0800173 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174 */
175 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
Mathew Inwood31a792a2018-08-17 08:54:26 +0100176 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
178
179 /**
John Spurlock8a52c442015-03-26 14:23:58 -0400180 * @hide Broadcast intent when the devices for a particular stream type changes.
181 * Includes the stream, the new devices and previous devices.
182 * Notes:
183 * - for internal platform use only, do not make public,
184 * - never used for "remote" volume changes
185 *
186 * @see #EXTRA_VOLUME_STREAM_TYPE
187 * @see #EXTRA_VOLUME_STREAM_DEVICES
188 * @see #EXTRA_PREV_VOLUME_STREAM_DEVICES
189 * @see #getDevicesForStream
190 */
191 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
192 public static final String STREAM_DEVICES_CHANGED_ACTION =
193 "android.media.STREAM_DEVICES_CHANGED_ACTION";
194
195 /**
RoboErik7c82ced2014-12-04 17:39:08 -0800196 * @hide Broadcast intent when a stream mute state changes.
197 * Includes the stream that changed and the new mute state
198 *
199 * @see #EXTRA_VOLUME_STREAM_TYPE
200 * @see #EXTRA_STREAM_VOLUME_MUTED
201 */
202 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
203 public static final String STREAM_MUTE_CHANGED_ACTION =
204 "android.media.STREAM_MUTE_CHANGED_ACTION";
205
206 /**
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500207 * @hide Broadcast intent when the master mute state changes.
208 * Includes the the new volume
209 *
210 * @see #EXTRA_MASTER_VOLUME_MUTED
211 */
212 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
213 public static final String MASTER_MUTE_CHANGED_ACTION =
214 "android.media.MASTER_MUTE_CHANGED_ACTION";
215
216 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 * The new vibrate setting for a particular type.
218 *
219 * @see #VIBRATE_SETTING_CHANGED_ACTION
220 * @see #EXTRA_VIBRATE_TYPE
221 * @see #VIBRATE_SETTING_ON
222 * @see #VIBRATE_SETTING_OFF
223 * @see #VIBRATE_SETTING_ONLY_SILENT
Eric Laurentcd1cd732012-05-01 11:23:07 -0700224 * @deprecated Applications should maintain their own vibrate policy based on
225 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 */
227 public static final String EXTRA_VIBRATE_SETTING = "android.media.EXTRA_VIBRATE_SETTING";
228
229 /**
230 * The vibrate type whose setting has changed.
231 *
232 * @see #VIBRATE_SETTING_CHANGED_ACTION
233 * @see #VIBRATE_TYPE_NOTIFICATION
234 * @see #VIBRATE_TYPE_RINGER
Eric Laurentcd1cd732012-05-01 11:23:07 -0700235 * @deprecated Applications should maintain their own vibrate policy based on
236 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 */
238 public static final String EXTRA_VIBRATE_TYPE = "android.media.EXTRA_VIBRATE_TYPE";
239
240 /**
241 * @hide The stream type for the volume changed intent.
242 */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100243 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 public static final String EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE";
245
246 /**
Jean-Michel Trivi560877d2015-06-25 17:38:35 -0700247 * @hide
248 * The stream type alias for the volume changed intent.
249 * For instance the intent may indicate a change of the {@link #STREAM_NOTIFICATION} stream
250 * type (as indicated by the {@link #EXTRA_VOLUME_STREAM_TYPE} extra), but this is also
251 * reflected by a change of the volume of its alias, {@link #STREAM_RING} on some devices,
252 * {@link #STREAM_MUSIC} on others (e.g. a television).
253 */
254 public static final String EXTRA_VOLUME_STREAM_TYPE_ALIAS =
255 "android.media.EXTRA_VOLUME_STREAM_TYPE_ALIAS";
256
257 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 * @hide The volume associated with the stream for the volume changed intent.
259 */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100260 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 public static final String EXTRA_VOLUME_STREAM_VALUE =
262 "android.media.EXTRA_VOLUME_STREAM_VALUE";
263
Eric Laurent9ce379a2010-02-16 06:00:26 -0800264 /**
265 * @hide The previous volume associated with the stream for the volume changed intent.
266 */
267 public static final String EXTRA_PREV_VOLUME_STREAM_VALUE =
268 "android.media.EXTRA_PREV_VOLUME_STREAM_VALUE";
269
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500270 /**
John Spurlock8a52c442015-03-26 14:23:58 -0400271 * @hide The devices associated with the stream for the stream devices changed intent.
272 */
273 public static final String EXTRA_VOLUME_STREAM_DEVICES =
274 "android.media.EXTRA_VOLUME_STREAM_DEVICES";
275
276 /**
277 * @hide The previous devices associated with the stream for the stream devices changed intent.
278 */
279 public static final String EXTRA_PREV_VOLUME_STREAM_DEVICES =
280 "android.media.EXTRA_PREV_VOLUME_STREAM_DEVICES";
281
282 /**
Mike Lockwood0dc37cc2011-12-01 16:14:19 -0500283 * @hide The new master volume mute state for the master mute changed intent.
284 * Value is boolean
285 */
286 public static final String EXTRA_MASTER_VOLUME_MUTED =
287 "android.media.EXTRA_MASTER_VOLUME_MUTED";
288
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700289 /**
RoboErik7c82ced2014-12-04 17:39:08 -0800290 * @hide The new stream volume mute state for the stream mute changed intent.
291 * Value is boolean
292 */
293 public static final String EXTRA_STREAM_VOLUME_MUTED =
294 "android.media.EXTRA_STREAM_VOLUME_MUTED";
295
296 /**
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700297 * Broadcast Action: Wired Headset plugged in or unplugged.
298 *
299 * You <em>cannot</em> receive this through components declared
300 * in manifests, only by explicitly registering for it with
301 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
302 * Context.registerReceiver()}.
303 *
304 * <p>The intent will have the following extra values:
305 * <ul>
306 * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
307 * <li><em>name</em> - Headset type, human readable string </li>
308 * <li><em>microphone</em> - 1 if headset has a microphone, 0 otherwise </li>
309 * </ul>
310 * </ul>
311 */
312 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
313 public static final String ACTION_HEADSET_PLUG =
314 "android.intent.action.HEADSET_PLUG";
315
316 /**
Eemi Haukkalabc682562015-03-06 23:03:30 +0200317 * Broadcast Action: A sticky broadcast indicating an HDMI cable was plugged or unplugged.
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700318 *
319 * The intent will have the following extra values: {@link #EXTRA_AUDIO_PLUG_STATE},
320 * {@link #EXTRA_MAX_CHANNEL_COUNT}, {@link #EXTRA_ENCODINGS}.
321 * <p>It can only be received by explicitly registering for it with
322 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)}.
323 */
324 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
325 public static final String ACTION_HDMI_AUDIO_PLUG =
326 "android.media.action.HDMI_AUDIO_PLUG";
327
328 /**
329 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to communicate whether HDMI is plugged in
330 * or unplugged.
331 * An integer value of 1 indicates a plugged-in state, 0 is unplugged.
332 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700333 public static final String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.AUDIO_PLUG_STATE";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700334
335 /**
336 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the maximum number of channels
337 * supported by the HDMI device.
338 * The corresponding integer value is only available when the device is plugged in (as expressed
339 * by {@link #EXTRA_AUDIO_PLUG_STATE}).
340 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700341 public static final String EXTRA_MAX_CHANNEL_COUNT = "android.media.extra.MAX_CHANNEL_COUNT";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700342
343 /**
344 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the audio encodings supported by
345 * the connected HDMI device.
346 * The corresponding array of encoding values is only available when the device is plugged in
347 * (as expressed by {@link #EXTRA_AUDIO_PLUG_STATE}). Encoding values are defined in
348 * {@link AudioFormat} (for instance see {@link AudioFormat#ENCODING_PCM_16BIT}). Use
349 * {@link android.content.Intent#getIntArrayExtra(String)} to retrieve the encoding values.
350 */
Jean-Michel Trivideddda52014-09-05 14:38:47 -0700351 public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS";
Jean-Michel Trivic5258432014-08-27 15:46:54 -0700352
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700353 /** Used to identify the volume of audio streams for phone calls */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354 public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700355 /** Used to identify the volume of audio streams for system sounds */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356 public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700357 /** Used to identify the volume of audio streams for the phone ring */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 public static final int STREAM_RING = AudioSystem.STREAM_RING;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700359 /** Used to identify the volume of audio streams for music playback */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700361 /** Used to identify the volume of audio streams for alarms */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700363 /** Used to identify the volume of audio streams for notifications */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364 public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700365 /** @hide Used to identify the volume of audio streams for phone calls when connected
366 * to bluetooth */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100367 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700369 /** @hide Used to identify the volume of audio streams for enforced system sounds
370 * in certain countries (e.g camera in Japan) */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100371 @UnsupportedAppUsage
Eric Laurenta553c252009-07-17 12:17:14 -0700372 public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700373 /** Used to identify the volume of audio streams for DTMF Tones */
Eric Laurenta553c252009-07-17 12:17:14 -0700374 public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF;
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700375 /** @hide Used to identify the volume of audio streams exclusively transmitted through the
376 * speaker (TTS) of the device */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100377 @UnsupportedAppUsage
Eric Laurenta553c252009-07-17 12:17:14 -0700378 public static final int STREAM_TTS = AudioSystem.STREAM_TTS;
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800379 /** Used to identify the volume of audio streams for accessibility prompts */
380 public static final int STREAM_ACCESSIBILITY = AudioSystem.STREAM_ACCESSIBILITY;
Kim Baekgyeongb64fac72019-12-09 10:35:58 +0000381 /** @hide Used to identify the volume of audio streams for virtual assistant */
382 @SystemApi
383 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
384 public static final int STREAM_ASSISTANT = AudioSystem.STREAM_ASSISTANT;
Jean-Michel Trivi3f0945a2016-11-11 10:05:18 -0800385
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 /** Number of audio streams */
387 /**
Jean-Michel Trivi46d5b822016-10-04 12:37:53 -0700388 * @deprecated Do not iterate on volume stream type values.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 */
Eric Laurenta553c252009-07-17 12:17:14 -0700390 @Deprecated public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391
Paul McLeand6f87c82021-03-31 13:02:41 -0600392 /** @hide */
393 private static final int[] PUBLIC_STREAM_TYPES = { AudioManager.STREAM_VOICE_CALL,
394 AudioManager.STREAM_SYSTEM, AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC,
395 AudioManager.STREAM_ALARM, AudioManager.STREAM_NOTIFICATION,
396 AudioManager.STREAM_DTMF, AudioManager.STREAM_ACCESSIBILITY };
397
398 /** @hide */
399 @TestApi
400 public static final int[] getPublicStreamTypes() {
401 return PUBLIC_STREAM_TYPES;
402 }
403
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 /**
405 * Increase the ringer volume.
406 *
407 * @see #adjustVolume(int, int)
408 * @see #adjustStreamVolume(int, int, int)
409 */
410 public static final int ADJUST_RAISE = 1;
411
412 /**
413 * Decrease the ringer volume.
414 *
415 * @see #adjustVolume(int, int)
416 * @see #adjustStreamVolume(int, int, int)
417 */
418 public static final int ADJUST_LOWER = -1;
419
420 /**
421 * Maintain the previous ringer volume. This may be useful when needing to
422 * show the volume toast without actually modifying the volume.
423 *
424 * @see #adjustVolume(int, int)
425 * @see #adjustStreamVolume(int, int, int)
426 */
427 public static final int ADJUST_SAME = 0;
428
RoboErik4197cb62015-01-21 15:45:32 -0800429 /**
430 * Mute the volume. Has no effect if the stream is already muted.
431 *
432 * @see #adjustVolume(int, int)
433 * @see #adjustStreamVolume(int, int, int)
434 */
435 public static final int ADJUST_MUTE = -100;
436
437 /**
438 * Unmute the volume. Has no effect if the stream is not muted.
439 *
440 * @see #adjustVolume(int, int)
441 * @see #adjustStreamVolume(int, int, int)
442 */
443 public static final int ADJUST_UNMUTE = 100;
444
445 /**
446 * Toggle the mute state. If muted the stream will be unmuted. If not muted
447 * the stream will be muted.
448 *
449 * @see #adjustVolume(int, int)
450 * @see #adjustStreamVolume(int, int, int)
451 */
452 public static final int ADJUST_TOGGLE_MUTE = 101;
453
Jean-Michel Trivicf170362017-08-24 17:24:57 -0700454 /** @hide */
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -0800455 @IntDef(flag = false, prefix = "ADJUST", value = {
456 ADJUST_RAISE,
457 ADJUST_LOWER,
458 ADJUST_SAME,
459 ADJUST_MUTE,
460 ADJUST_UNMUTE,
461 ADJUST_TOGGLE_MUTE }
462 )
463 @Retention(RetentionPolicy.SOURCE)
Jean-Michel Trivi1b926e72018-01-29 16:06:51 -0800464 public @interface VolumeAdjustment {}
Jean-Michel Trivi610aa9b2018-01-27 15:42:42 -0800465
466 /** @hide */
Jean-Michel Trivicf170362017-08-24 17:24:57 -0700467 public static final String adjustToString(int adj) {
468 switch (adj) {
469 case ADJUST_RAISE: return "ADJUST_RAISE";
470 case ADJUST_LOWER: return "ADJUST_LOWER";
471 case ADJUST_SAME: return "ADJUST_SAME";
472 case ADJUST_MUTE: return "ADJUST_MUTE";
473 case ADJUST_UNMUTE: return "ADJUST_UNMUTE";
474 case ADJUST_TOGGLE_MUTE: return "ADJUST_TOGGLE_MUTE";
475 default: return new StringBuilder("unknown adjust mode ").append(adj).toString();
476 }
477 }
478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 // Flags should be powers of 2!
480
481 /**
482 * Show a toast containing the current volume.
483 *
484 * @see #adjustStreamVolume(int, int, int)
485 * @see #adjustVolume(int, int)
486 * @see #setStreamVolume(int, int, int)
487 * @see #setRingerMode(int)
488 */
489 public static final int FLAG_SHOW_UI = 1 << 0;
490
491 /**
492 * Whether to include ringer modes as possible options when changing volume.
493 * For example, if true and volume level is 0 and the volume is adjusted
494 * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent or
495 * vibrate mode.
496 * <p>
497 * By default this is on for the ring stream. If this flag is included,
498 * this behavior will be present regardless of the stream type being
499 * affected by the ringer mode.
The Android Open Source Project10592532009-03-18 17:39:46 -0700500 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 * @see #adjustVolume(int, int)
502 * @see #adjustStreamVolume(int, int, int)
503 */
504 public static final int FLAG_ALLOW_RINGER_MODES = 1 << 1;
505
506 /**
507 * Whether to play a sound when changing the volume.
508 * <p>
509 * If this is given to {@link #adjustVolume(int, int)} or
510 * {@link #adjustSuggestedStreamVolume(int, int, int)}, it may be ignored
511 * in some cases (for example, the decided stream type is not
512 * {@link AudioManager#STREAM_RING}, or the volume is being adjusted
513 * downward).
514 *
515 * @see #adjustStreamVolume(int, int, int)
516 * @see #adjustVolume(int, int)
517 * @see #setStreamVolume(int, int, int)
518 */
519 public static final int FLAG_PLAY_SOUND = 1 << 2;
520
521 /**
522 * Removes any sounds/vibrate that may be in the queue, or are playing (related to
523 * changing volume).
524 */
525 public static final int FLAG_REMOVE_SOUND_AND_VIBRATE = 1 << 3;
526
527 /**
528 * Whether to vibrate if going into the vibrate ringer mode.
529 */
530 public static final int FLAG_VIBRATE = 1 << 4;
531
532 /**
Eric Laurent4bbcc652012-09-24 14:26:30 -0700533 * Indicates to VolumePanel that the volume slider should be disabled as user
534 * cannot change the stream volume
535 * @hide
536 */
537 public static final int FLAG_FIXED_VOLUME = 1 << 5;
538
539 /**
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700540 * Indicates the volume set/adjust call is for Bluetooth absolute volume
541 * @hide
542 */
543 public static final int FLAG_BLUETOOTH_ABS_VOLUME = 1 << 6;
544
545 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400546 * Adjusting the volume was prevented due to silent mode, display a hint in the UI.
547 * @hide
548 */
549 public static final int FLAG_SHOW_SILENT_HINT = 1 << 7;
550
551 /**
Jungshik Jang41d97462014-06-30 22:26:29 +0900552 * Indicates the volume call is for Hdmi Cec system audio volume
553 * @hide
554 */
555 public static final int FLAG_HDMI_SYSTEM_AUDIO_VOLUME = 1 << 8;
556
557 /**
RoboErik3c45c292014-07-08 16:47:31 -0700558 * Indicates that this should only be handled if media is actively playing.
559 * @hide
560 */
561 public static final int FLAG_ACTIVE_MEDIA_ONLY = 1 << 9;
562
563 /**
John Spurlock35134602014-07-24 18:10:48 -0400564 * Like FLAG_SHOW_UI, but only dialog warnings and confirmations, no sliders.
565 * @hide
566 */
567 public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10;
568
569 /**
John Spurlock661f2cf42014-11-17 10:29:10 -0500570 * Adjusting the volume down from vibrated was prevented, display a hint in the UI.
571 * @hide
572 */
573 public static final int FLAG_SHOW_VIBRATE_HINT = 1 << 11;
574
John Spurlockb94f2d62015-03-17 14:11:57 -0400575 /**
576 * Adjusting the volume due to a hardware key press.
Hyundo Moonca0080d2018-12-26 16:16:55 +0900577 * This flag can be used in the places in order to denote (or check) that a volume adjustment
578 * request is from a hardware key press. (e.g. {@link MediaController}).
John Spurlockb94f2d62015-03-17 14:11:57 -0400579 * @hide
580 */
Jin Seok Park4abc23e2020-07-30 22:28:50 +0900581 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
Hyundo Moonc3ce09e2019-03-11 20:00:00 +0900582 public static final int FLAG_FROM_KEY = 1 << 12;
John Spurlockb94f2d62015-03-17 14:11:57 -0400583
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900584 /** @hide */
Kriti Dang527e66c2021-03-04 10:37:22 +0100585 @IntDef(prefix = {"ENCODED_SURROUND_OUTPUT_"}, value = {
Kriti Dang98fdb262021-04-01 13:26:00 +0200586 ENCODED_SURROUND_OUTPUT_UNKNOWN,
Kriti Dang527e66c2021-03-04 10:37:22 +0100587 ENCODED_SURROUND_OUTPUT_AUTO,
588 ENCODED_SURROUND_OUTPUT_NEVER,
589 ENCODED_SURROUND_OUTPUT_ALWAYS,
590 ENCODED_SURROUND_OUTPUT_MANUAL
591 })
592 @Retention(RetentionPolicy.SOURCE)
593 public @interface EncodedSurroundOutputMode {}
594
595 /**
Kriti Dang98fdb262021-04-01 13:26:00 +0200596 * The mode for surround sound formats is unknown.
597 */
598 public static final int ENCODED_SURROUND_OUTPUT_UNKNOWN = -1;
599
600 /**
Kriti Dang527e66c2021-03-04 10:37:22 +0100601 * The surround sound formats are available for use if they are detected. This is the default
602 * mode.
603 */
604 public static final int ENCODED_SURROUND_OUTPUT_AUTO = 0;
605
606 /**
607 * The surround sound formats are NEVER available, even if they are detected by the hardware.
608 * Those formats will not be reported.
609 */
610 public static final int ENCODED_SURROUND_OUTPUT_NEVER = 1;
611
612 /**
613 * The surround sound formats are ALWAYS available, even if they are not detected by the
614 * hardware. Those formats will be reported as part of the HDMI output capability.
615 * Applications are then free to use either PCM or encoded output.
616 */
617 public static final int ENCODED_SURROUND_OUTPUT_ALWAYS = 2;
618
619 /**
620 * Surround sound formats are available according to the choice of user, even if they are not
621 * detected by the hardware. Those formats will be reported as part of the HDMI output
622 * capability. Applications are then free to use either PCM or encoded output.
623 */
624 public static final int ENCODED_SURROUND_OUTPUT_MANUAL = 3;
625
626 /** @hide */
Jin Seok Parkfc9db6c2021-02-26 02:37:20 +0900627 @IntDef(flag = true, prefix = "FLAG", value = {
Jin Seok Park5ccb6cc2021-02-05 01:47:13 +0900628 FLAG_SHOW_UI,
629 FLAG_ALLOW_RINGER_MODES,
630 FLAG_PLAY_SOUND,
631 FLAG_REMOVE_SOUND_AND_VIBRATE,
632 FLAG_VIBRATE,
633 FLAG_FIXED_VOLUME,
634 FLAG_BLUETOOTH_ABS_VOLUME,
635 FLAG_SHOW_SILENT_HINT,
636 FLAG_HDMI_SYSTEM_AUDIO_VOLUME,
637 FLAG_ACTIVE_MEDIA_ONLY,
638 FLAG_SHOW_UI_WARNINGS,
639 FLAG_SHOW_VIBRATE_HINT,
640 FLAG_FROM_KEY,
641 })
642 @Retention(RetentionPolicy.SOURCE)
643 public @interface Flags {}
644
Hyundo Moonca0080d2018-12-26 16:16:55 +0900645 // The iterator of TreeMap#entrySet() returns the entries in ascending key order.
646 private static final TreeMap<Integer, String> FLAG_NAMES = new TreeMap<>();
647
648 static {
649 FLAG_NAMES.put(FLAG_SHOW_UI, "FLAG_SHOW_UI");
650 FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES");
651 FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND");
652 FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE");
653 FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE");
654 FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME");
655 FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME");
656 FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT");
657 FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME");
658 FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY");
659 FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS");
660 FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT");
661 FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY");
662 }
John Spurlock661f2cf42014-11-17 10:29:10 -0500663
664 /** @hide */
665 public static String flagsToString(int flags) {
666 final StringBuilder sb = new StringBuilder();
Hyundo Moonca0080d2018-12-26 16:16:55 +0900667 for (Map.Entry<Integer, String> entry : FLAG_NAMES.entrySet()) {
668 final int flag = entry.getKey();
John Spurlock661f2cf42014-11-17 10:29:10 -0500669 if ((flags & flag) != 0) {
670 if (sb.length() > 0) {
671 sb.append(',');
672 }
Hyundo Moonca0080d2018-12-26 16:16:55 +0900673 sb.append(entry.getValue());
John Spurlock661f2cf42014-11-17 10:29:10 -0500674 flags &= ~flag;
675 }
676 }
677 if (flags != 0) {
678 if (sb.length() > 0) {
679 sb.append(',');
680 }
681 sb.append(flags);
682 }
683 return sb.toString();
684 }
685
686 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687 * Ringer mode that will be silent and will not vibrate. (This overrides the
688 * vibrate setting.)
689 *
690 * @see #setRingerMode(int)
691 * @see #getRingerMode()
692 */
693 public static final int RINGER_MODE_SILENT = 0;
694
695 /**
696 * Ringer mode that will be silent and will vibrate. (This will cause the
697 * phone ringer to always vibrate, but the notification vibrate to only
698 * vibrate if set.)
699 *
700 * @see #setRingerMode(int)
701 * @see #getRingerMode()
702 */
703 public static final int RINGER_MODE_VIBRATE = 1;
704
705 /**
706 * Ringer mode that may be audible and may vibrate. It will be audible if
707 * the volume before changing out of this mode was audible. It will vibrate
708 * if the vibrate setting is on.
709 *
710 * @see #setRingerMode(int)
711 * @see #getRingerMode()
712 */
713 public static final int RINGER_MODE_NORMAL = 2;
714
John Spurlock97559372014-10-24 16:27:36 -0400715 /**
716 * Maximum valid ringer mode value. Values must start from 0 and be contiguous.
717 * @hide
718 */
719 public static final int RINGER_MODE_MAX = RINGER_MODE_NORMAL;
Eric Laurent72668b22011-07-19 16:04:27 -0700720
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 /**
722 * Vibrate type that corresponds to the ringer.
723 *
724 * @see #setVibrateSetting(int, int)
725 * @see #getVibrateSetting(int)
726 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700727 * @deprecated Applications should maintain their own vibrate policy based on
728 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729 */
730 public static final int VIBRATE_TYPE_RINGER = 0;
731
732 /**
733 * Vibrate type that corresponds to notifications.
734 *
735 * @see #setVibrateSetting(int, int)
736 * @see #getVibrateSetting(int)
737 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700738 * @deprecated Applications should maintain their own vibrate policy based on
739 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 */
741 public static final int VIBRATE_TYPE_NOTIFICATION = 1;
742
743 /**
744 * Vibrate setting that suggests to never vibrate.
745 *
746 * @see #setVibrateSetting(int, int)
747 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700748 * @deprecated Applications should maintain their own vibrate policy based on
749 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 */
751 public static final int VIBRATE_SETTING_OFF = 0;
752
753 /**
754 * Vibrate setting that suggests to vibrate when possible.
755 *
756 * @see #setVibrateSetting(int, int)
757 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700758 * @deprecated Applications should maintain their own vibrate policy based on
759 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 */
761 public static final int VIBRATE_SETTING_ON = 1;
762
763 /**
764 * Vibrate setting that suggests to only vibrate when in the vibrate ringer
765 * mode.
766 *
767 * @see #setVibrateSetting(int, int)
768 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -0700769 * @deprecated Applications should maintain their own vibrate policy based on
770 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 */
772 public static final int VIBRATE_SETTING_ONLY_SILENT = 2;
773
774 /**
775 * Suggests using the default stream type. This may not be used in all
776 * places a stream type is needed.
777 */
778 public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE;
779
780 private static IAudioService sService;
781
782 /**
783 * @hide
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800784 * For test purposes only, will throw NPE with some methods that require a Context.
785 */
Mathew Inwood8e742f92020-10-27 11:47:29 +0000786 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800787 public AudioManager() {
Jean-Michel Trivi9dc22c22017-01-05 18:06:03 -0800788 }
789
790 /**
791 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 */
Mathew Inwood31a792a2018-08-17 08:54:26 +0100793 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 public AudioManager(Context context) {
Marco Nelissen29f16932015-04-17 09:50:56 -0700795 setContext(context);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796 }
797
Marco Nelissen29f16932015-04-17 09:50:56 -0700798 private Context getContext() {
799 if (mApplicationContext == null) {
800 setContext(mOriginalContext);
801 }
802 if (mApplicationContext != null) {
803 return mApplicationContext;
804 }
805 return mOriginalContext;
806 }
807
808 private void setContext(Context context) {
809 mApplicationContext = context.getApplicationContext();
810 if (mApplicationContext != null) {
811 mOriginalContext = null;
812 } else {
813 mOriginalContext = context;
814 }
jiabincfcf1032021-07-01 16:30:50 -0700815 sContext = context;
Marco Nelissen29f16932015-04-17 09:50:56 -0700816 }
817
Mathew Inwood31a792a2018-08-17 08:54:26 +0100818 @UnsupportedAppUsage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 private static IAudioService getService()
820 {
821 if (sService != null) {
822 return sService;
823 }
824 IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
825 sService = IAudioService.Stub.asInterface(b);
826 return sService;
827 }
828
829 /**
Jean-Michel Trivia83487e2013-09-17 21:19:30 -0700830 * Sends a simulated key event for a media button.
831 * To simulate a key press, you must first send a KeyEvent built with a
832 * {@link KeyEvent#ACTION_DOWN} action, then another event with the {@link KeyEvent#ACTION_UP}
833 * action.
834 * <p>The key event will be sent to the current media key event consumer which registered with
835 * {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}.
836 * @param keyEvent a {@link KeyEvent} instance whose key code is one of
837 * {@link KeyEvent#KEYCODE_MUTE},
838 * {@link KeyEvent#KEYCODE_HEADSETHOOK},
839 * {@link KeyEvent#KEYCODE_MEDIA_PLAY},
840 * {@link KeyEvent#KEYCODE_MEDIA_PAUSE},
841 * {@link KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE},
842 * {@link KeyEvent#KEYCODE_MEDIA_STOP},
843 * {@link KeyEvent#KEYCODE_MEDIA_NEXT},
844 * {@link KeyEvent#KEYCODE_MEDIA_PREVIOUS},
845 * {@link KeyEvent#KEYCODE_MEDIA_REWIND},
846 * {@link KeyEvent#KEYCODE_MEDIA_RECORD},
847 * {@link KeyEvent#KEYCODE_MEDIA_FAST_FORWARD},
848 * {@link KeyEvent#KEYCODE_MEDIA_CLOSE},
849 * {@link KeyEvent#KEYCODE_MEDIA_EJECT},
850 * or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -0700851 */
Jean-Michel Trivia83487e2013-09-17 21:19:30 -0700852 public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
Marco Nelissen29f16932015-04-17 09:50:56 -0700853 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
RoboErik430fc482014-06-12 15:49:20 -0700854 helper.sendMediaButtonEvent(keyEvent, false);
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -0700855 }
856
857 /**
858 * @hide
Joe Onorato86f67862010-11-05 18:57:34 -0700859 */
Mike Lockwoodce952c82011-11-14 10:47:42 -0800860 public void preDispatchKeyEvent(KeyEvent event, int stream) {
Joe Onorato86f67862010-11-05 18:57:34 -0700861 /*
862 * If the user hits another key within the play sound delay, then
863 * cancel the sound
864 */
Mike Lockwoodce952c82011-11-14 10:47:42 -0800865 int keyCode = event.getKeyCode();
Joe Onorato86f67862010-11-05 18:57:34 -0700866 if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
867 && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
John Spurlock61560172015-02-06 19:46:04 -0500868 && mVolumeKeyUpTime + AudioSystem.PLAY_SOUND_DELAY > SystemClock.uptimeMillis()) {
Joe Onorato86f67862010-11-05 18:57:34 -0700869 /*
870 * The user has hit another key during the delay (e.g., 300ms)
871 * since the last volume key up, so cancel any sounds.
872 */
John Spurlockee5ad722015-03-03 16:17:21 -0500873 adjustSuggestedStreamVolume(ADJUST_SAME,
874 stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
Joe Onorato86f67862010-11-05 18:57:34 -0700875 }
876 }
877
878 /**
Eric Laurentba207e72014-05-15 17:08:16 -0700879 * Indicates if the device implements a fixed volume policy.
880 * <p>Some devices may not have volume control and may operate at a fixed volume,
881 * and may not enable muting or changing the volume of audio streams.
882 * This method will return true on such devices.
883 * <p>The following APIs have no effect when volume is fixed:
884 * <ul>
885 * <li> {@link #adjustVolume(int, int)}
886 * <li> {@link #adjustSuggestedStreamVolume(int, int, int)}
887 * <li> {@link #adjustStreamVolume(int, int, int)}
888 * <li> {@link #setStreamVolume(int, int, int)}
889 * <li> {@link #setRingerMode(int)}
890 * <li> {@link #setStreamSolo(int, boolean)}
891 * <li> {@link #setStreamMute(int, boolean)}
892 * </ul>
893 */
894 public boolean isVolumeFixed() {
Jean-Michel Trivia0513082020-09-22 18:43:53 -0700895 synchronized (this) {
896 try {
897 if (!mUseFixedVolumeInitialized) {
898 mUseFixedVolume = getContext().getResources().getBoolean(
899 com.android.internal.R.bool.config_useFixedVolume);
900 }
901 } catch (Exception e) {
902 } finally {
903 // only ever try once, so always consider initialized even if query failed
904 mUseFixedVolumeInitialized = true;
905 }
906 }
Eric Laurentba207e72014-05-15 17:08:16 -0700907 return mUseFixedVolume;
908 }
909
910 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 * Adjusts the volume of a particular stream by one step in a direction.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700912 * <p>
913 * This method should only be used by applications that replace the platform-wide
914 * management of audio settings or the main telephony application.
Jean-Michel Trivi59773622018-06-19 17:17:57 -0700915 * <p>This method has no effect if the device implements a fixed volume policy
916 * as indicated by {@link #isVolumeFixed()}.
917 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
918 * unless the app has been granted Do Not Disturb Access.
919 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800920 *
921 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -0800922 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
923 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924 * @param direction The direction to adjust the volume. One of
925 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
926 * {@link #ADJUST_SAME}.
927 * @param flags One or more flags.
928 * @see #adjustVolume(int, int)
929 * @see #setStreamVolume(int, int, int)
Jean-Michel Trivi59773622018-06-19 17:17:57 -0700930 * @throws SecurityException if the adjustment triggers a Do Not Disturb change
931 * and the caller is not granted notification policy access.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 */
933 public void adjustStreamVolume(int streamType, int direction, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -0700934 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935 try {
John Wu4f7e5102021-06-22 17:29:11 +0000936 service.adjustStreamVolumeWithAttribution(streamType, direction, flags,
937 getContext().getOpPackageName(), getContext().getAttributionTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800938 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -0700939 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940 }
941 }
942
943 /**
944 * Adjusts the volume of the most relevant stream. For example, if a call is
945 * active, it will have the highest priority regardless of if the in-call
946 * screen is showing. Another example, if music is playing in the background
947 * and a call is not active, the music stream will be adjusted.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700948 * <p>
RoboErik4197cb62015-01-21 15:45:32 -0800949 * This method should only be used by applications that replace the
950 * platform-wide management of audio settings or the main telephony
951 * application.
952 * <p>
953 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -0700954 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -0800955 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 * @param direction The direction to adjust the volume. One of
RoboErik4197cb62015-01-21 15:45:32 -0800957 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
958 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
959 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800960 * @param flags One or more flags.
961 * @see #adjustSuggestedStreamVolume(int, int, int)
962 * @see #adjustStreamVolume(int, int, int)
963 * @see #setStreamVolume(int, int, int)
Eric Laurentba207e72014-05-15 17:08:16 -0700964 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800965 */
966 public void adjustVolume(int direction, int flags) {
Marco Nelissen8dc50412015-04-28 09:42:54 -0700967 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
John Spurlockee5ad722015-03-03 16:17:21 -0500968 helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 }
970
971 /**
972 * Adjusts the volume of the most relevant stream, or the given fallback
973 * stream.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -0700974 * <p>
RoboErik4197cb62015-01-21 15:45:32 -0800975 * This method should only be used by applications that replace the
976 * platform-wide management of audio settings or the main telephony
977 * application.
978 * <p>
979 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -0700980 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -0800981 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 * @param direction The direction to adjust the volume. One of
RoboErik4197cb62015-01-21 15:45:32 -0800983 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
984 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
985 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 * @param suggestedStreamType The stream type that will be used if there
RoboErik4197cb62015-01-21 15:45:32 -0800987 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
988 * valid here.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989 * @param flags One or more flags.
990 * @see #adjustVolume(int, int)
991 * @see #adjustStreamVolume(int, int, int)
992 * @see #setStreamVolume(int, int, int)
Eric Laurentba207e72014-05-15 17:08:16 -0700993 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 */
995 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
Marco Nelissen8dc50412015-04-28 09:42:54 -0700996 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
John Spurlockee5ad722015-03-03 16:17:21 -0500997 helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags);
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -0400998 }
999
John Spurlockee5ad722015-03-03 16:17:21 -05001000 /** @hide */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001001 @UnsupportedAppUsage
Jean-Michel Trivi582ccf62019-11-01 11:07:09 -07001002 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
John Spurlockee5ad722015-03-03 16:17:21 -05001003 public void setMasterMute(boolean mute, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001004 final IAudioService service = getService();
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001005 try {
Kenny Guy70e0c582015-06-30 19:18:28 +01001006 service.setMasterMute(mute, flags, getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00001007 UserHandle.getCallingUserId(), getContext().getAttributionTag());
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -04001008 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001009 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 }
1011 }
1012
1013 /**
1014 * Returns the current ringtone mode.
1015 *
1016 * @return The current ringtone mode, one of {@link #RINGER_MODE_NORMAL},
1017 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1018 * @see #setRingerMode(int)
1019 */
1020 public int getRingerMode() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001021 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001022 try {
John Spurlock661f2cf42014-11-17 10:29:10 -05001023 return service.getRingerModeExternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001025 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 }
1027 }
1028
1029 /**
Eric Laurent72668b22011-07-19 16:04:27 -07001030 * Checks valid ringer mode values.
1031 *
1032 * @return true if the ringer mode indicated is valid, false otherwise.
1033 *
1034 * @see #setRingerMode(int)
1035 * @hide
1036 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00001037 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent72668b22011-07-19 16:04:27 -07001038 public static boolean isValidRingerMode(int ringerMode) {
1039 if (ringerMode < 0 || ringerMode > RINGER_MODE_MAX) {
1040 return false;
1041 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001042 final IAudioService service = getService();
John Spurlock97559372014-10-24 16:27:36 -04001043 try {
1044 return service.isValidRingerMode(ringerMode);
1045 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001046 throw e.rethrowFromSystemServer();
John Spurlock97559372014-10-24 16:27:36 -04001047 }
Eric Laurent72668b22011-07-19 16:04:27 -07001048 }
1049
1050 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 * Returns the maximum volume index for a particular stream.
1052 *
1053 * @param streamType The stream type whose maximum volume index is returned.
1054 * @return The maximum valid volume index for the stream.
1055 * @see #getStreamVolume(int)
1056 */
1057 public int getStreamMaxVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001058 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001059 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001060 return service.getStreamMaxVolume(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001062 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001063 }
1064 }
1065
1066 /**
John Spurlockb6e19e32015-03-10 21:33:44 -04001067 * Returns the minimum volume index for a particular stream.
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001068 * @param streamType The stream type whose minimum volume index is returned. Must be one of
1069 * {@link #STREAM_VOICE_CALL}, {@link #STREAM_SYSTEM},
1070 * {@link #STREAM_RING}, {@link #STREAM_MUSIC}, {@link #STREAM_ALARM},
1071 * {@link #STREAM_NOTIFICATION}, {@link #STREAM_DTMF} or {@link #STREAM_ACCESSIBILITY}.
1072 * @return The minimum valid volume index for the stream.
1073 * @see #getStreamVolume(int)
1074 */
1075 public int getStreamMinVolume(int streamType) {
1076 if (!isPublicStreamType(streamType)) {
1077 throw new IllegalArgumentException("Invalid stream type " + streamType);
1078 }
1079 return getStreamMinVolumeInt(streamType);
1080 }
1081
1082 /**
1083 * @hide
1084 * Same as {@link #getStreamMinVolume(int)} but without the check on the public stream type.
John Spurlockb6e19e32015-03-10 21:33:44 -04001085 * @param streamType The stream type whose minimum volume index is returned.
1086 * @return The minimum valid volume index for the stream.
1087 * @see #getStreamVolume(int)
John Spurlockb6e19e32015-03-10 21:33:44 -04001088 */
Paul McLeand6f87c82021-03-31 13:02:41 -06001089 @TestApi
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001090 public int getStreamMinVolumeInt(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001091 final IAudioService service = getService();
John Spurlockb6e19e32015-03-10 21:33:44 -04001092 try {
1093 return service.getStreamMinVolume(streamType);
1094 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001095 throw e.rethrowFromSystemServer();
John Spurlockb6e19e32015-03-10 21:33:44 -04001096 }
1097 }
1098
1099 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001100 * Returns the current volume index for a particular stream.
1101 *
1102 * @param streamType The stream type whose volume index is returned.
1103 * @return The current volume index for the stream.
1104 * @see #getStreamMaxVolume(int)
1105 * @see #setStreamVolume(int, int, int)
1106 */
1107 public int getStreamVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001108 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001110 return service.getStreamVolume(streamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001111 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001112 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001113 }
1114 }
1115
Jean-Michel Trivi8e7aca32017-11-28 18:12:38 -08001116 // keep in sync with frameworks/av/services/audiopolicy/common/include/Volume.h
1117 private static final float VOLUME_MIN_DB = -758.0f;
1118
1119 /** @hide */
1120 @IntDef(flag = false, prefix = "STREAM", value = {
1121 STREAM_VOICE_CALL,
1122 STREAM_SYSTEM,
1123 STREAM_RING,
1124 STREAM_MUSIC,
1125 STREAM_ALARM,
1126 STREAM_NOTIFICATION,
1127 STREAM_DTMF,
1128 STREAM_ACCESSIBILITY }
1129 )
1130 @Retention(RetentionPolicy.SOURCE)
1131 public @interface PublicStreamTypes {}
1132
1133 /**
1134 * Returns the volume in dB (decibel) for the given stream type at the given volume index, on
1135 * the given type of audio output device.
1136 * @param streamType stream type for which the volume is queried.
1137 * @param index the volume index for which the volume is queried. The index value must be
1138 * between the minimum and maximum index values for the given stream type (see
1139 * {@link #getStreamMinVolume(int)} and {@link #getStreamMaxVolume(int)}).
1140 * @param deviceType the type of audio output device for which volume is queried.
1141 * @return a volume expressed in dB.
1142 * A negative value indicates the audio signal is attenuated. A typical maximum value
1143 * at the maximum volume index is 0 dB (no attenuation nor amplification). Muting is
1144 * reflected by a value of {@link Float#NEGATIVE_INFINITY}.
1145 */
1146 public float getStreamVolumeDb(@PublicStreamTypes int streamType, int index,
1147 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
1148 if (!isPublicStreamType(streamType)) {
1149 throw new IllegalArgumentException("Invalid stream type " + streamType);
1150 }
1151 if (index > getStreamMaxVolume(streamType) || index < getStreamMinVolume(streamType)) {
1152 throw new IllegalArgumentException("Invalid stream volume index " + index);
1153 }
1154 if (!AudioDeviceInfo.isValidAudioDeviceTypeOut(deviceType)) {
1155 throw new IllegalArgumentException("Invalid audio output device type " + deviceType);
1156 }
1157 final float gain = AudioSystem.getStreamVolumeDB(streamType, index,
1158 AudioDeviceInfo.convertDeviceTypeToInternalDevice(deviceType));
1159 if (gain <= VOLUME_MIN_DB) {
1160 return Float.NEGATIVE_INFINITY;
1161 } else {
1162 return gain;
1163 }
1164 }
1165
1166 private static boolean isPublicStreamType(int streamType) {
1167 switch (streamType) {
1168 case STREAM_VOICE_CALL:
1169 case STREAM_SYSTEM:
1170 case STREAM_RING:
1171 case STREAM_MUSIC:
1172 case STREAM_ALARM:
1173 case STREAM_NOTIFICATION:
1174 case STREAM_DTMF:
1175 case STREAM_ACCESSIBILITY:
1176 return true;
1177 default:
1178 return false;
1179 }
1180 }
1181
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 /**
Eric Laurent25101b02011-02-02 09:33:30 -08001183 * Get last audible volume before stream was muted.
1184 *
1185 * @hide
1186 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001187 @UnsupportedAppUsage
Eric Laurent25101b02011-02-02 09:33:30 -08001188 public int getLastAudibleStreamVolume(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001189 final IAudioService service = getService();
Eric Laurent25101b02011-02-02 09:33:30 -08001190 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001191 return service.getLastAudibleStreamVolume(streamType);
Eric Laurent25101b02011-02-02 09:33:30 -08001192 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001193 throw e.rethrowFromSystemServer();
Eric Laurent25101b02011-02-02 09:33:30 -08001194 }
1195 }
1196
1197 /**
Eric Laurent6d517662012-04-23 18:42:39 -07001198 * Get the stream type whose volume is driving the UI sounds volume.
1199 * UI sounds are screen lock/unlock, camera shutter, key clicks...
John Spurlock4f0f1202014-08-05 13:28:33 -04001200 * It is assumed that this stream type is also tied to ringer mode changes.
Eric Laurent6d517662012-04-23 18:42:39 -07001201 * @hide
1202 */
John Spurlockee5ad722015-03-03 16:17:21 -05001203 public int getUiSoundsStreamType() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001204 final IAudioService service = getService();
Eric Laurent6d517662012-04-23 18:42:39 -07001205 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001206 return service.getUiSoundsStreamType();
Eric Laurent6d517662012-04-23 18:42:39 -07001207 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001208 throw e.rethrowFromSystemServer();
Eric Laurent6d517662012-04-23 18:42:39 -07001209 }
1210 }
1211
1212 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001213 * Sets the ringer mode.
1214 * <p>
1215 * Silent mode will mute the volume and will not vibrate. Vibrate mode will
1216 * mute the volume and vibrate. Normal mode will be audible and may vibrate
1217 * according to user settings.
Eric Laurentba207e72014-05-15 17:08:16 -07001218 * <p>This method has no effect if the device implements a fixed volume policy
1219 * as indicated by {@link #isVolumeFixed()}.
Julia Reynolds48034f82016-03-09 10:15:16 -05001220 * * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
1221 * unless the app has been granted Do Not Disturb Access.
1222 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001223 * @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL},
1224 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}.
1225 * @see #getRingerMode()
Eric Laurentba207e72014-05-15 17:08:16 -07001226 * @see #isVolumeFixed()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001227 */
1228 public void setRingerMode(int ringerMode) {
Eric Laurent72668b22011-07-19 16:04:27 -07001229 if (!isValidRingerMode(ringerMode)) {
1230 return;
1231 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001232 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001233 try {
Marco Nelissen29f16932015-04-17 09:50:56 -07001234 service.setRingerModeExternal(ringerMode, getContext().getOpPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001235 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001236 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001237 }
1238 }
1239
1240 /**
1241 * Sets the volume index for a particular stream.
Eric Laurentba207e72014-05-15 17:08:16 -07001242 * <p>This method has no effect if the device implements a fixed volume policy
1243 * as indicated by {@link #isVolumeFixed()}.
Julia Reynolds48034f82016-03-09 10:15:16 -05001244 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
1245 * the app has been granted Do Not Disturb Access.
1246 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001247 * @param streamType The stream whose volume index should be set.
1248 * @param index The volume index to set. See
1249 * {@link #getStreamMaxVolume(int)} for the largest valid value.
1250 * @param flags One or more flags.
1251 * @see #getStreamMaxVolume(int)
1252 * @see #getStreamVolume(int)
Eric Laurentba207e72014-05-15 17:08:16 -07001253 * @see #isVolumeFixed()
Jean-Michel Trivi59773622018-06-19 17:17:57 -07001254 * @throws SecurityException if the volume change triggers a Do Not Disturb change
1255 * and the caller is not granted notification policy access.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 */
1257 public void setStreamVolume(int streamType, int index, int flags) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001258 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001259 try {
John Wu4f7e5102021-06-22 17:29:11 +00001260 service.setStreamVolumeWithAttribution(streamType, index, flags,
1261 getContext().getOpPackageName(), getContext().getAttributionTag());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001262 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001263 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001264 }
1265 }
1266
1267 /**
François Gaffie9c362102018-09-21 17:43:52 +02001268 * Sets the volume index for a particular {@link AudioAttributes}.
1269 * @param attr The {@link AudioAttributes} whose volume index should be set.
1270 * @param index The volume index to set. See
1271 * {@link #getMaxVolumeIndexForAttributes(AudioAttributes)} for the largest valid value
1272 * {@link #getMinVolumeIndexForAttributes(AudioAttributes)} for the lowest valid value.
1273 * @param flags One or more flags.
1274 * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1275 * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1276 * @see #isVolumeFixed()
1277 * @hide
1278 */
1279 @SystemApi
1280 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1281 public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags) {
1282 Preconditions.checkNotNull(attr, "attr must not be null");
1283 final IAudioService service = getService();
1284 try {
1285 service.setVolumeIndexForAttributes(attr, index, flags,
John Wu4f7e5102021-06-22 17:29:11 +00001286 getContext().getOpPackageName(), getContext().getAttributionTag());
François Gaffie9c362102018-09-21 17:43:52 +02001287 } catch (RemoteException e) {
1288 throw e.rethrowFromSystemServer();
1289 }
1290 }
1291
1292 /**
1293 * Returns the current volume index for a particular {@link AudioAttributes}.
1294 *
1295 * @param attr The {@link AudioAttributes} whose volume index is returned.
1296 * @return The current volume index for the stream.
1297 * @see #getMaxVolumeIndexForAttributes(AudioAttributes)
1298 * @see #getMinVolumeIndexForAttributes(AudioAttributes)
1299 * @see #setVolumeForAttributes(AudioAttributes, int, int)
1300 * @hide
1301 */
1302 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001303 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001304 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1305 public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1306 Preconditions.checkNotNull(attr, "attr must not be null");
1307 final IAudioService service = getService();
1308 try {
1309 return service.getVolumeIndexForAttributes(attr);
1310 } catch (RemoteException e) {
1311 throw e.rethrowFromSystemServer();
1312 }
1313 }
1314
1315 /**
1316 * Returns the maximum volume index for a particular {@link AudioAttributes}.
1317 *
1318 * @param attr The {@link AudioAttributes} whose maximum volume index is returned.
1319 * @return The maximum valid volume index for the {@link AudioAttributes}.
1320 * @see #getVolumeIndexForAttributes(AudioAttributes)
1321 * @hide
1322 */
1323 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001324 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001325 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1326 public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1327 Preconditions.checkNotNull(attr, "attr must not be null");
1328 final IAudioService service = getService();
1329 try {
1330 return service.getMaxVolumeIndexForAttributes(attr);
1331 } catch (RemoteException e) {
1332 throw e.rethrowFromSystemServer();
1333 }
1334 }
1335
1336 /**
1337 * Returns the minimum volume index for a particular {@link AudioAttributes}.
1338 *
1339 * @param attr The {@link AudioAttributes} whose minimum volume index is returned.
1340 * @return The minimum valid volume index for the {@link AudioAttributes}.
1341 * @see #getVolumeIndexForAttributes(AudioAttributes)
1342 * @hide
1343 */
1344 @SystemApi
Hayden Gomes695f8022019-04-11 10:44:18 -07001345 @IntRange(from = 0)
François Gaffie9c362102018-09-21 17:43:52 +02001346 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1347 public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) {
1348 Preconditions.checkNotNull(attr, "attr must not be null");
1349 final IAudioService service = getService();
1350 try {
1351 return service.getMinVolumeIndexForAttributes(attr);
1352 } catch (RemoteException e) {
1353 throw e.rethrowFromSystemServer();
1354 }
1355 }
1356
1357 /**
Hayden Gomes62812aa2019-12-23 11:40:27 -08001358 * Set the system usages to be supported on this device.
1359 * @param systemUsages array of system usages to support {@link AttributeSystemUsage}
1360 * @hide
1361 */
1362 @SystemApi
1363 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1364 public void setSupportedSystemUsages(@NonNull @AttributeSystemUsage int[] systemUsages) {
1365 Objects.requireNonNull(systemUsages, "systemUsages must not be null");
1366 final IAudioService service = getService();
1367 try {
1368 service.setSupportedSystemUsages(systemUsages);
1369 } catch (RemoteException e) {
1370 throw e.rethrowFromSystemServer();
1371 }
1372 }
1373
1374 /**
1375 * Get the system usages supported on this device.
1376 * @return array of supported system usages {@link AttributeSystemUsage}
1377 * @hide
1378 */
1379 @SystemApi
1380 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1381 public @NonNull @AttributeSystemUsage int[] getSupportedSystemUsages() {
1382 final IAudioService service = getService();
1383 try {
1384 return service.getSupportedSystemUsages();
1385 } catch (RemoteException e) {
1386 throw e.rethrowFromSystemServer();
1387 }
1388 }
1389
1390 /**
RoboErik4197cb62015-01-21 15:45:32 -08001391 * Solo or unsolo a particular stream.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001393 * Do not use. This method has been deprecated and is now a no-op.
1394 * {@link #requestAudioFocus} should be used for exclusive audio playback.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001395 *
1396 * @param streamType The stream to be soloed/unsoloed.
RoboErik4197cb62015-01-21 15:45:32 -08001397 * @param state The required solo state: true for solo ON, false for solo
1398 * OFF
Eric Laurentba207e72014-05-15 17:08:16 -07001399 * @see #isVolumeFixed()
RoboErik4197cb62015-01-21 15:45:32 -08001400 * @deprecated Do not use. If you need exclusive audio playback use
1401 * {@link #requestAudioFocus}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001402 */
RoboErik4197cb62015-01-21 15:45:32 -08001403 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 public void setStreamSolo(int streamType, boolean state) {
RoboErik4197cb62015-01-21 15:45:32 -08001405 Log.w(TAG, "setStreamSolo has been deprecated. Do not use.");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001406 }
1407
1408 /**
1409 * Mute or unmute an audio stream.
1410 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001411 * This method should only be used by applications that replace the
1412 * platform-wide management of audio settings or the main telephony
1413 * application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001414 * <p>
RoboErik4197cb62015-01-21 15:45:32 -08001415 * This method has no effect if the device implements a fixed volume policy
Eric Laurentba207e72014-05-15 17:08:16 -07001416 * as indicated by {@link #isVolumeFixed()}.
RoboErik4197cb62015-01-21 15:45:32 -08001417 * <p>
1418 * This method was deprecated in API level 22. Prior to API level 22 this
1419 * method had significantly different behavior and should be used carefully.
1420 * The following applies only to pre-22 platforms:
1421 * <ul>
1422 * <li>The mute command is protected against client process death: if a
1423 * process with an active mute request on a stream dies, this stream will be
1424 * unmuted automatically.</li>
1425 * <li>The mute requests for a given stream are cumulative: the AudioManager
1426 * can receive several mute requests from one or more clients and the stream
1427 * will be unmuted only when the same number of unmute requests are
1428 * received.</li>
1429 * <li>For a better user experience, applications MUST unmute a muted stream
1430 * in onPause() and mute is again in onResume() if appropriate.</li>
1431 * </ul>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001432 *
1433 * @param streamType The stream to be muted/unmuted.
RoboErik4197cb62015-01-21 15:45:32 -08001434 * @param state The required mute state: true for mute ON, false for mute
1435 * OFF
Eric Laurentba207e72014-05-15 17:08:16 -07001436 * @see #isVolumeFixed()
RoboErik4197cb62015-01-21 15:45:32 -08001437 * @deprecated Use {@link #adjustStreamVolume(int, int, int)} with
1438 * {@link #ADJUST_MUTE} or {@link #ADJUST_UNMUTE} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001439 */
RoboErik4197cb62015-01-21 15:45:32 -08001440 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001441 public void setStreamMute(int streamType, boolean state) {
RoboErik4197cb62015-01-21 15:45:32 -08001442 Log.w(TAG, "setStreamMute is deprecated. adjustStreamVolume should be used instead.");
1443 int direction = state ? ADJUST_MUTE : ADJUST_UNMUTE;
1444 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1445 adjustSuggestedStreamVolume(direction, streamType, 0);
1446 } else {
1447 adjustStreamVolume(streamType, direction, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 }
1449 }
1450
1451 /**
RoboErik4197cb62015-01-21 15:45:32 -08001452 * Returns the current mute state for a particular stream.
Eric Laurent25101b02011-02-02 09:33:30 -08001453 *
RoboErik4197cb62015-01-21 15:45:32 -08001454 * @param streamType The stream to get mute state for.
1455 * @return The mute state for the given stream.
1456 * @see #adjustStreamVolume(int, int, int)
Eric Laurent25101b02011-02-02 09:33:30 -08001457 */
1458 public boolean isStreamMute(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001459 final IAudioService service = getService();
Eric Laurent25101b02011-02-02 09:33:30 -08001460 try {
John Spurlockee5ad722015-03-03 16:17:21 -05001461 return service.isStreamMute(streamType);
Eric Laurent25101b02011-02-02 09:33:30 -08001462 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001463 throw e.rethrowFromSystemServer();
Eric Laurent25101b02011-02-02 09:33:30 -08001464 }
1465 }
1466
1467 /**
Mike Lockwoodce952c82011-11-14 10:47:42 -08001468 * get master mute state.
1469 *
1470 * @hide
1471 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01001472 @UnsupportedAppUsage
Mike Lockwoodce952c82011-11-14 10:47:42 -08001473 public boolean isMasterMute() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001474 final IAudioService service = getService();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001475 try {
1476 return service.isMasterMute();
1477 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001478 throw e.rethrowFromSystemServer();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001479 }
1480 }
1481
1482 /**
Eric Laurent402f7f22011-02-04 12:30:32 -08001483 * forces the stream controlled by hard volume keys
1484 * specifying streamType == -1 releases control to the
1485 * logic.
1486 *
1487 * @hide
1488 */
Jean-Michel Trivi60eddfd2018-03-09 15:31:12 -08001489 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
Mathew Inwood31a792a2018-08-17 08:54:26 +01001490 @UnsupportedAppUsage
Eric Laurent402f7f22011-02-04 12:30:32 -08001491 public void forceVolumeControlStream(int streamType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001492 final IAudioService service = getService();
Eric Laurent45c90ce2012-04-24 18:44:22 -07001493 try {
1494 service.forceVolumeControlStream(streamType, mICallBack);
1495 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001496 throw e.rethrowFromSystemServer();
Eric Laurent45c90ce2012-04-24 18:44:22 -07001497 }
Eric Laurent402f7f22011-02-04 12:30:32 -08001498 }
1499
1500 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001501 * Returns whether a particular type should vibrate according to user
1502 * settings and the current ringer mode.
1503 * <p>
1504 * This shouldn't be needed by most clients that use notifications to
1505 * vibrate. The notification manager will not vibrate if the policy doesn't
1506 * allow it, so the client should always set a vibrate pattern and let the
1507 * notification manager control whether or not to actually vibrate.
1508 *
1509 * @param vibrateType The type of vibrate. One of
1510 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1511 * {@link #VIBRATE_TYPE_RINGER}.
1512 * @return Whether the type should vibrate at the instant this method is
1513 * called.
1514 * @see #setVibrateSetting(int, int)
1515 * @see #getVibrateSetting(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001516 * @deprecated Applications should maintain their own vibrate policy based on
1517 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001518 */
1519 public boolean shouldVibrate(int vibrateType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001520 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001521 try {
1522 return service.shouldVibrate(vibrateType);
1523 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001524 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001525 }
1526 }
1527
1528 /**
1529 * Returns whether the user's vibrate setting for a vibrate type.
1530 * <p>
1531 * This shouldn't be needed by most clients that want to vibrate, instead
1532 * see {@link #shouldVibrate(int)}.
1533 *
1534 * @param vibrateType The type of vibrate. One of
1535 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1536 * {@link #VIBRATE_TYPE_RINGER}.
1537 * @return The vibrate setting, one of {@link #VIBRATE_SETTING_ON},
1538 * {@link #VIBRATE_SETTING_OFF}, or
1539 * {@link #VIBRATE_SETTING_ONLY_SILENT}.
1540 * @see #setVibrateSetting(int, int)
1541 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001542 * @deprecated Applications should maintain their own vibrate policy based on
1543 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001544 */
1545 public int getVibrateSetting(int vibrateType) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001546 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001547 try {
1548 return service.getVibrateSetting(vibrateType);
1549 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001550 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001551 }
1552 }
1553
1554 /**
1555 * Sets the setting for when the vibrate type should vibrate.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001556 * <p>
1557 * This method should only be used by applications that replace the platform-wide
1558 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001559 *
1560 * @param vibrateType The type of vibrate. One of
1561 * {@link #VIBRATE_TYPE_NOTIFICATION} or
1562 * {@link #VIBRATE_TYPE_RINGER}.
1563 * @param vibrateSetting The vibrate setting, one of
1564 * {@link #VIBRATE_SETTING_ON},
1565 * {@link #VIBRATE_SETTING_OFF}, or
1566 * {@link #VIBRATE_SETTING_ONLY_SILENT}.
1567 * @see #getVibrateSetting(int)
1568 * @see #shouldVibrate(int)
Eric Laurentcd1cd732012-05-01 11:23:07 -07001569 * @deprecated Applications should maintain their own vibrate policy based on
1570 * current ringer mode that can be queried via {@link #getRingerMode()}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001571 */
1572 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001573 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001574 try {
1575 service.setVibrateSetting(vibrateType, vibrateSetting);
1576 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001577 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001578 }
1579 }
1580
1581 /**
1582 * Sets the speakerphone on or off.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07001583 * <p>
1584 * This method should only be used by applications that replace the platform-wide
1585 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001586 *
1587 * @param on set <var>true</var> to turn on speakerphone;
1588 * <var>false</var> to turn it off
1589 */
1590 public void setSpeakerphoneOn(boolean on){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001591 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001592 try {
Eric Laurent3aad0ad2020-05-14 12:45:18 -07001593 service.setSpeakerphoneOn(mICallBack, on);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001594 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001595 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07001596 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001597 }
1598
1599 /**
1600 * Checks whether the speakerphone is on or off.
1601 *
1602 * @return true if speakerphone is on, false if it's off
1603 */
1604 public boolean isSpeakerphoneOn() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07001605 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07001606 try {
1607 return service.isSpeakerphoneOn();
1608 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07001609 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07001610 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001611 }
1612
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001613 /**
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001614 * Specifies whether the audio played by this app may or may not be captured by other apps or
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001615 * the system.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001616 *
1617 * The default is {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}.
1618 *
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001619 * There are multiple ways to set this policy:
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001620 * <ul>
1621 * <li> for each track independently, see
1622 * {@link AudioAttributes.Builder#setAllowedCapturePolicy(int)} </li>
1623 * <li> application-wide at runtime, with this method </li>
1624 * <li> application-wide at build time, see {@code allowAudioPlaybackCapture} in the application
1625 * manifest. </li>
1626 * </ul>
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001627 * The most restrictive policy is always applied.
1628 *
Kevin Rocarddb0ff412019-05-02 17:55:35 -07001629 * See {@link AudioPlaybackCaptureConfiguration} for more details on
Kevin Rocard654b3cb2019-04-03 16:51:11 -07001630 * which audio signals can be captured.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001631 *
1632 * @param capturePolicy one of
1633 * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
1634 * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
1635 * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
jiabinb33f3692019-12-23 13:09:58 -08001636 * @throws RuntimeException if the argument is not a valid value.
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001637 */
1638 public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) {
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001639 // TODO: also pass the package in case multiple packages have the same UID
jiabinb33f3692019-12-23 13:09:58 -08001640 final IAudioService service = getService();
1641 try {
1642 int result = service.setAllowedCapturePolicy(capturePolicy);
1643 if (result != AudioSystem.AUDIO_STATUS_OK) {
1644 Log.e(TAG, "Could not setAllowedCapturePolicy: " + result);
1645 return;
1646 }
1647 } catch (RemoteException e) {
1648 throw e.rethrowFromSystemServer();
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001649 }
Kevin Rocard019f60d2019-04-09 16:25:26 -07001650 }
1651
Kevin Rocard019f60d2019-04-09 16:25:26 -07001652 /**
1653 * Return the capture policy.
1654 * @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or
1655 * the default if it was not called.
1656 */
1657 @AudioAttributes.CapturePolicy
1658 public int getAllowedCapturePolicy() {
jiabinb33f3692019-12-23 13:09:58 -08001659 int result = AudioAttributes.ALLOW_CAPTURE_BY_ALL;
1660 try {
1661 result = getService().getAllowedCapturePolicy();
1662 } catch (RemoteException e) {
1663 Log.e(TAG, "Failed to query allowed capture policy: " + e);
1664 }
1665 return result;
Kevin Rocard7919c2a2019-03-21 10:28:01 -07001666 }
1667
Eric Laurent3def1ee2010-03-17 23:26:26 -07001668 //====================================================================
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001669 // Audio Product Strategy routing
1670
1671 /**
1672 * @hide
1673 * Set the preferred device for a given strategy, i.e. the audio routing to be used by
1674 * this audio strategy. Note that the device may not be available at the time the preferred
1675 * device is set, but it will be used once made available.
1676 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
1677 * this preference for this strategy.</p>
1678 * @param strategy the audio strategy whose routing will be affected
1679 * @param device the audio device to route to when available
1680 * @return true if the operation was successful, false otherwise
1681 */
1682 @SystemApi
1683 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1684 public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy,
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001685 @NonNull AudioDeviceAttributes device) {
jiabinf40141d2020-08-07 17:27:48 -07001686 return setPreferredDevicesForStrategy(strategy, Arrays.asList(device));
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001687 }
1688
1689 /**
1690 * @hide
jiabinf40141d2020-08-07 17:27:48 -07001691 * Removes the preferred audio device(s) previously set with
1692 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1693 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}.
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001694 * @param strategy the audio strategy whose routing will be affected
1695 * @return true if the operation was successful, false otherwise (invalid strategy, or no
1696 * device set for example)
1697 */
1698 @SystemApi
1699 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1700 public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) {
1701 Objects.requireNonNull(strategy);
1702 try {
1703 final int status =
jiabinf40141d2020-08-07 17:27:48 -07001704 getService().removePreferredDevicesForStrategy(strategy.getId());
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001705 return status == AudioSystem.SUCCESS;
1706 } catch (RemoteException e) {
1707 throw e.rethrowFromSystemServer();
1708 }
1709 }
1710
1711 /**
1712 * @hide
1713 * Return the preferred device for an audio strategy, previously set with
jiabinf40141d2020-08-07 17:27:48 -07001714 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1715 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
1716 * @param strategy the strategy to query
1717 * @return the preferred device for that strategy, if multiple devices are set as preferred
1718 * devices, the first one in the list will be returned. Null will be returned if none was
1719 * ever set or if the strategy is invalid
1720 */
1721 @SystemApi
1722 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1723 @Nullable
1724 public AudioDeviceAttributes getPreferredDeviceForStrategy(
1725 @NonNull AudioProductStrategy strategy) {
1726 List<AudioDeviceAttributes> devices = getPreferredDevicesForStrategy(strategy);
1727 return devices.isEmpty() ? null : devices.get(0);
1728 }
1729
1730 /**
1731 * @hide
1732 * Set the preferred devices for a given strategy, i.e. the audio routing to be used by
1733 * this audio strategy. Note that the devices may not be available at the time the preferred
1734 * devices is set, but it will be used once made available.
1735 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting
1736 * this preference for this strategy.</p>
1737 * Note that the list of devices is not a list ranked by preference, but a list of one or more
1738 * devices used simultaneously to output the same audio signal.
1739 * @param strategy the audio strategy whose routing will be affected
1740 * @param devices a non-empty list of the audio devices to route to when available
1741 * @return true if the operation was successful, false otherwise
1742 */
1743 @SystemApi
1744 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1745 public boolean setPreferredDevicesForStrategy(@NonNull AudioProductStrategy strategy,
1746 @NonNull List<AudioDeviceAttributes> devices) {
1747 Objects.requireNonNull(strategy);
1748 Objects.requireNonNull(devices);
1749 if (devices.isEmpty()) {
1750 throw new IllegalArgumentException(
1751 "Tried to set preferred devices for strategy with a empty list");
1752 }
1753 for (AudioDeviceAttributes device : devices) {
1754 Objects.requireNonNull(device);
1755 }
1756 try {
1757 final int status =
1758 getService().setPreferredDevicesForStrategy(strategy.getId(), devices);
1759 return status == AudioSystem.SUCCESS;
1760 } catch (RemoteException e) {
1761 throw e.rethrowFromSystemServer();
1762 }
1763 }
1764
1765 /**
1766 * @hide
1767 * Return the preferred devices for an audio strategy, previously set with
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001768 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)}
jiabinf40141d2020-08-07 17:27:48 -07001769 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001770 * @param strategy the strategy to query
1771 * @return the preferred device for that strategy, or null if none was ever set or if the
1772 * strategy is invalid
1773 */
1774 @SystemApi
1775 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001776 @NonNull
1777 public List<AudioDeviceAttributes> getPreferredDevicesForStrategy(
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001778 @NonNull AudioProductStrategy strategy) {
1779 Objects.requireNonNull(strategy);
1780 try {
jiabinf40141d2020-08-07 17:27:48 -07001781 return getService().getPreferredDevicesForStrategy(strategy.getId());
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07001782 } catch (RemoteException e) {
1783 throw e.rethrowFromSystemServer();
1784 }
1785 }
1786
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001787 /**
1788 * @hide
1789 * Interface to be notified of changes in the preferred audio device set for a given audio
1790 * strategy.
Jean-Michel Trivicf9c5d32020-02-20 10:45:35 -08001791 * <p>Note that this listener will only be invoked whenever
1792 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
jiabinf40141d2020-08-07 17:27:48 -07001793 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
Jean-Michel Trivicf9c5d32020-02-20 10:45:35 -08001794 * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
1795 * preferred device. It will not be invoked directly after registration with
1796 * {@link #addOnPreferredDeviceForStrategyChangedListener(Executor, OnPreferredDeviceForStrategyChangedListener)}
1797 * to indicate which strategies had preferred devices at the time of registration.</p>
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001798 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001799 * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
1800 * @see #getPreferredDeviceForStrategy(AudioProductStrategy)
jiabinf40141d2020-08-07 17:27:48 -07001801 * @deprecated use #OnPreferredDevicesForStrategyChangedListener
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001802 */
1803 @SystemApi
jiabinf40141d2020-08-07 17:27:48 -07001804 @Deprecated
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001805 public interface OnPreferredDeviceForStrategyChangedListener {
1806 /**
1807 * Called on the listener to indicate that the preferred audio device for the given
1808 * strategy has changed.
1809 * @param strategy the {@link AudioProductStrategy} whose preferred device changed
1810 * @param device <code>null</code> if the preferred device was removed, or the newly set
1811 * preferred audio device
1812 */
1813 void onPreferredDeviceForStrategyChanged(@NonNull AudioProductStrategy strategy,
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08001814 @Nullable AudioDeviceAttributes device);
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001815 }
1816
1817 /**
1818 * @hide
jiabinf40141d2020-08-07 17:27:48 -07001819 * Interface to be notified of changes in the preferred audio devices set for a given audio
1820 * strategy.
1821 * <p>Note that this listener will only be invoked whenever
1822 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or
1823 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}
1824 * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in
1825 * preferred device(s). It will not be invoked directly after registration with
1826 * {@link #addOnPreferredDevicesForStrategyChangedListener(
1827 * Executor, OnPreferredDevicesForStrategyChangedListener)}
1828 * to indicate which strategies had preferred devices at the time of registration.</p>
1829 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)
1830 * @see #setPreferredDevicesForStrategy(AudioProductStrategy, List)
1831 * @see #removePreferredDeviceForStrategy(AudioProductStrategy)
1832 * @see #getPreferredDeviceForStrategy(AudioProductStrategy)
1833 * @see #getPreferredDevicesForStrategy(AudioProductStrategy)
1834 */
1835 @SystemApi
1836 public interface OnPreferredDevicesForStrategyChangedListener {
1837 /**
1838 * Called on the listener to indicate that the preferred audio devices for the given
1839 * strategy has changed.
1840 * @param strategy the {@link AudioProductStrategy} whose preferred device changed
1841 * @param devices a list of newly set preferred audio devices
1842 */
1843 void onPreferredDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy,
1844 @NonNull List<AudioDeviceAttributes> devices);
1845 }
1846
1847 /**
1848 * @hide
1849 * Adds a listener for being notified of changes to the strategy-preferred audio device.
1850 * @param executor
1851 * @param listener
1852 * @throws SecurityException if the caller doesn't hold the required permission
1853 * @deprecated use {@link #addOnPreferredDevicesForStrategyChangedListener(
1854 * Executor, AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
1855 */
1856 @SystemApi
1857 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1858 @Deprecated
1859 public void addOnPreferredDeviceForStrategyChangedListener(
1860 @NonNull @CallbackExecutor Executor executor,
1861 @NonNull OnPreferredDeviceForStrategyChangedListener listener)
1862 throws SecurityException {
1863 // No-op, the method is deprecated.
1864 }
1865
1866 /**
1867 * @hide
1868 * Removes a previously added listener of changes to the strategy-preferred audio device.
1869 * @param listener
1870 * @deprecated use {@link #removeOnPreferredDevicesForStrategyChangedListener(
1871 * AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead
1872 */
1873 @SystemApi
1874 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
1875 @Deprecated
1876 public void removeOnPreferredDeviceForStrategyChangedListener(
1877 @NonNull OnPreferredDeviceForStrategyChangedListener listener) {
1878 // No-op, the method is deprecated.
1879 }
1880
1881 /**
1882 * @hide
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001883 * Adds a listener for being notified of changes to the strategy-preferred audio device.
1884 * @param executor
1885 * @param listener
1886 * @throws SecurityException if the caller doesn't hold the required permission
1887 */
1888 @SystemApi
1889 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001890 public void addOnPreferredDevicesForStrategyChangedListener(
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001891 @NonNull @CallbackExecutor Executor executor,
jiabinf40141d2020-08-07 17:27:48 -07001892 @NonNull OnPreferredDevicesForStrategyChangedListener listener)
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001893 throws SecurityException {
1894 Objects.requireNonNull(executor);
1895 Objects.requireNonNull(listener);
1896 synchronized (mPrefDevListenerLock) {
1897 if (hasPrefDevListener(listener)) {
1898 throw new IllegalArgumentException(
jiabinf40141d2020-08-07 17:27:48 -07001899 "attempt to call addOnPreferredDevicesForStrategyChangedListener() "
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001900 + "on a previously registered listener");
1901 }
1902 // lazy initialization of the list of strategy-preferred device listener
1903 if (mPrefDevListeners == null) {
1904 mPrefDevListeners = new ArrayList<>();
1905 }
1906 final int oldCbCount = mPrefDevListeners.size();
1907 mPrefDevListeners.add(new PrefDevListenerInfo(listener, executor));
1908 if (oldCbCount == 0 && mPrefDevListeners.size() > 0) {
1909 // register binder for callbacks
1910 if (mPrefDevDispatcherStub == null) {
jiabinf40141d2020-08-07 17:27:48 -07001911 mPrefDevDispatcherStub = new StrategyPreferredDevicesDispatcherStub();
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001912 }
1913 try {
jiabinf40141d2020-08-07 17:27:48 -07001914 getService().registerStrategyPreferredDevicesDispatcher(mPrefDevDispatcherStub);
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001915 } catch (RemoteException e) {
1916 throw e.rethrowFromSystemServer();
1917 }
1918 }
1919 }
1920 }
1921
1922 /**
1923 * @hide
1924 * Removes a previously added listener of changes to the strategy-preferred audio device.
1925 * @param listener
1926 */
1927 @SystemApi
1928 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabinf40141d2020-08-07 17:27:48 -07001929 public void removeOnPreferredDevicesForStrategyChangedListener(
1930 @NonNull OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001931 Objects.requireNonNull(listener);
1932 synchronized (mPrefDevListenerLock) {
1933 if (!removePrefDevListener(listener)) {
1934 throw new IllegalArgumentException(
1935 "attempt to call removeOnPreferredDeviceForStrategyChangedListener() "
1936 + "on an unregistered listener");
1937 }
1938 if (mPrefDevListeners.size() == 0) {
1939 // unregister binder for callbacks
1940 try {
jiabinf40141d2020-08-07 17:27:48 -07001941 getService().unregisterStrategyPreferredDevicesDispatcher(
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001942 mPrefDevDispatcherStub);
1943 } catch (RemoteException e) {
1944 throw e.rethrowFromSystemServer();
1945 } finally {
1946 mPrefDevDispatcherStub = null;
1947 mPrefDevListeners = null;
1948 }
1949 }
1950 }
1951 }
1952
1953
1954 private final Object mPrefDevListenerLock = new Object();
1955 /**
1956 * List of listeners for preferred device for strategy and their associated Executor.
1957 * List is lazy-initialized on first registration
1958 */
1959 @GuardedBy("mPrefDevListenerLock")
1960 private @Nullable ArrayList<PrefDevListenerInfo> mPrefDevListeners;
1961
1962 private static class PrefDevListenerInfo {
jiabinf40141d2020-08-07 17:27:48 -07001963 final @NonNull OnPreferredDevicesForStrategyChangedListener mListener;
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001964 final @NonNull Executor mExecutor;
jiabinf40141d2020-08-07 17:27:48 -07001965 PrefDevListenerInfo(OnPreferredDevicesForStrategyChangedListener listener, Executor exe) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001966 mListener = listener;
1967 mExecutor = exe;
1968 }
1969 }
1970
1971 @GuardedBy("mPrefDevListenerLock")
jiabinf40141d2020-08-07 17:27:48 -07001972 private StrategyPreferredDevicesDispatcherStub mPrefDevDispatcherStub;
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001973
jiabinf40141d2020-08-07 17:27:48 -07001974 private final class StrategyPreferredDevicesDispatcherStub
1975 extends IStrategyPreferredDevicesDispatcher.Stub {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001976
1977 @Override
jiabinf40141d2020-08-07 17:27:48 -07001978 public void dispatchPrefDevicesChanged(int strategyId,
1979 @NonNull List<AudioDeviceAttributes> devices) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001980 // make a shallow copy of listeners so callback is not executed under lock
1981 final ArrayList<PrefDevListenerInfo> prefDevListeners;
1982 synchronized (mPrefDevListenerLock) {
1983 if (mPrefDevListeners == null || mPrefDevListeners.size() == 0) {
1984 return;
1985 }
1986 prefDevListeners = (ArrayList<PrefDevListenerInfo>) mPrefDevListeners.clone();
1987 }
1988 final AudioProductStrategy strategy =
1989 AudioProductStrategy.getAudioProductStrategyWithId(strategyId);
1990 final long ident = Binder.clearCallingIdentity();
1991 try {
1992 for (PrefDevListenerInfo info : prefDevListeners) {
1993 info.mExecutor.execute(() ->
jiabinf40141d2020-08-07 17:27:48 -07001994 info.mListener.onPreferredDevicesForStrategyChanged(strategy, devices));
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08001995 }
1996 } finally {
1997 Binder.restoreCallingIdentity(ident);
1998 }
1999 }
2000 }
2001
2002 @GuardedBy("mPrefDevListenerLock")
2003 private @Nullable PrefDevListenerInfo getPrefDevListenerInfo(
jiabinf40141d2020-08-07 17:27:48 -07002004 OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002005 if (mPrefDevListeners == null) {
2006 return null;
2007 }
2008 for (PrefDevListenerInfo info : mPrefDevListeners) {
2009 if (info.mListener == listener) {
2010 return info;
2011 }
2012 }
2013 return null;
2014 }
2015
2016 @GuardedBy("mPrefDevListenerLock")
jiabinf40141d2020-08-07 17:27:48 -07002017 private boolean hasPrefDevListener(OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002018 return getPrefDevListenerInfo(listener) != null;
2019 }
2020
2021 @GuardedBy("mPrefDevListenerLock")
2022 /**
2023 * @return true if the listener was removed from the list
2024 */
jiabinf40141d2020-08-07 17:27:48 -07002025 private boolean removePrefDevListener(OnPreferredDevicesForStrategyChangedListener listener) {
Jean-Michel Trivi8d64ebb2020-02-05 15:44:42 -08002026 final PrefDevListenerInfo infoToRemove = getPrefDevListenerInfo(listener);
2027 if (infoToRemove != null) {
2028 mPrefDevListeners.remove(infoToRemove);
2029 return true;
2030 }
2031 return false;
2032 }
2033
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07002034 //====================================================================
Jiabin Huangb55305f2020-09-03 17:54:16 +00002035 // Audio Capture Preset routing
2036
2037 /**
2038 * @hide
2039 * Set the preferred device for a given capture preset, i.e. the audio routing to be used by
2040 * this capture preset. Note that the device may not be available at the time the preferred
2041 * device is set, but it will be used once made available.
2042 * <p>Use {@link #clearPreferredDevicesForCapturePreset(int)} to cancel setting this preference
2043 * for this capture preset.</p>
2044 * @param capturePreset the audio capture preset whose routing will be affected
2045 * @param device the audio device to route to when available
2046 * @return true if the operation was successful, false otherwise
2047 */
2048 @SystemApi
2049 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002050 public boolean setPreferredDeviceForCapturePreset(@MediaRecorder.SystemSource int capturePreset,
Jiabin Huangb55305f2020-09-03 17:54:16 +00002051 @NonNull AudioDeviceAttributes device) {
2052 return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device));
2053 }
2054
2055 /**
2056 * @hide
2057 * Remove all the preferred audio devices previously set
2058 * @param capturePreset the audio capture preset whose routing will be affected
2059 * @return true if the operation was successful, false otherwise (invalid capture preset, or no
2060 * device set for example)
2061 */
2062 @SystemApi
2063 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002064 public boolean clearPreferredDevicesForCapturePreset(
2065 @MediaRecorder.SystemSource int capturePreset) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002066 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2067 return false;
2068 }
2069 try {
2070 final int status = getService().clearPreferredDevicesForCapturePreset(capturePreset);
2071 return status == AudioSystem.SUCCESS;
2072 } catch (RemoteException e) {
2073 throw e.rethrowFromSystemServer();
2074 }
2075 }
2076
2077 /**
2078 * @hide
2079 * Return the preferred devices for an audio capture preset, previously set with
2080 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)}
2081 * @param capturePreset the capture preset to query
2082 * @return a list that contains preferred devices for that capture preset.
2083 */
2084 @NonNull
2085 @SystemApi
2086 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
jiabin958faf92021-03-12 20:00:05 +00002087 public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset(
2088 @MediaRecorder.SystemSource int capturePreset) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002089 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2090 return new ArrayList<AudioDeviceAttributes>();
2091 }
2092 try {
2093 return getService().getPreferredDevicesForCapturePreset(capturePreset);
2094 } catch (RemoteException e) {
2095 throw e.rethrowFromSystemServer();
2096 }
2097 }
2098
2099 private boolean setPreferredDevicesForCapturePreset(
jiabin958faf92021-03-12 20:00:05 +00002100 @MediaRecorder.SystemSource int capturePreset,
2101 @NonNull List<AudioDeviceAttributes> devices) {
Jiabin Huangb55305f2020-09-03 17:54:16 +00002102 Objects.requireNonNull(devices);
2103 if (!MediaRecorder.isValidAudioSource(capturePreset)) {
2104 return false;
2105 }
2106 if (devices.size() != 1) {
2107 throw new IllegalArgumentException(
2108 "Only support setting one preferred devices for capture preset");
2109 }
2110 for (AudioDeviceAttributes device : devices) {
2111 Objects.requireNonNull(device);
2112 }
2113 try {
2114 final int status =
2115 getService().setPreferredDevicesForCapturePreset(capturePreset, devices);
2116 return status == AudioSystem.SUCCESS;
2117 } catch (RemoteException e) {
2118 throw e.rethrowFromSystemServer();
2119 }
2120 }
2121
2122 /**
2123 * @hide
2124 * Interface to be notified of changes in the preferred audio devices set for a given capture
2125 * preset.
2126 * <p>Note that this listener will only be invoked whenever
2127 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} or
2128 * {@link #clearPreferredDevicesForCapturePreset(int)} causes a change in
2129 * preferred device. It will not be invoked directly after registration with
2130 * {@link #addOnPreferredDevicesForCapturePresetChangedListener(
2131 * Executor, OnPreferredDevicesForCapturePresetChangedListener)}
2132 * to indicate which strategies had preferred devices at the time of registration.</p>
2133 * @see #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)
2134 * @see #clearPreferredDevicesForCapturePreset(int)
2135 * @see #getPreferredDevicesForCapturePreset(int)
2136 */
2137 @SystemApi
2138 public interface OnPreferredDevicesForCapturePresetChangedListener {
2139 /**
2140 * Called on the listener to indicate that the preferred audio devices for the given
2141 * capture preset has changed.
2142 * @param capturePreset the capture preset whose preferred device changed
2143 * @param devices a list of newly set preferred audio devices
2144 */
2145 void onPreferredDevicesForCapturePresetChanged(
jiabin958faf92021-03-12 20:00:05 +00002146 @MediaRecorder.SystemSource int capturePreset,
2147 @NonNull List<AudioDeviceAttributes> devices);
Jiabin Huangb55305f2020-09-03 17:54:16 +00002148 }
2149
2150 /**
2151 * @hide
2152 * Adds a listener for being notified of changes to the capture-preset-preferred audio device.
2153 * @param executor
2154 * @param listener
2155 * @throws SecurityException if the caller doesn't hold the required permission
2156 */
2157 @SystemApi
2158 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
2159 public void addOnPreferredDevicesForCapturePresetChangedListener(
2160 @NonNull @CallbackExecutor Executor executor,
2161 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener)
2162 throws SecurityException {
2163 Objects.requireNonNull(executor);
2164 Objects.requireNonNull(listener);
2165 int status = addOnDevRoleForCapturePresetChangedListener(
2166 executor, listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2167 if (status == AudioSystem.ERROR) {
2168 // This must not happen
2169 throw new RuntimeException("Unknown error happened");
2170 }
2171 if (status == AudioSystem.BAD_VALUE) {
2172 throw new IllegalArgumentException(
2173 "attempt to call addOnPreferredDevicesForCapturePresetChangedListener() "
2174 + "on a previously registered listener");
2175 }
2176 }
2177
2178 /**
2179 * @hide
2180 * Removes a previously added listener of changes to the capture-preset-preferred audio device.
2181 * @param listener
2182 */
2183 @SystemApi
2184 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
2185 public void removeOnPreferredDevicesForCapturePresetChangedListener(
2186 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) {
2187 Objects.requireNonNull(listener);
2188 int status = removeOnDevRoleForCapturePresetChangedListener(
2189 listener, AudioSystem.DEVICE_ROLE_PREFERRED);
2190 if (status == AudioSystem.ERROR) {
2191 // This must not happen
2192 throw new RuntimeException("Unknown error happened");
2193 }
2194 if (status == AudioSystem.BAD_VALUE) {
2195 throw new IllegalArgumentException(
2196 "attempt to call removeOnPreferredDevicesForCapturePresetChangedListener() "
2197 + "on an unregistered listener");
2198 }
2199 }
2200
2201 private <T> int addOnDevRoleForCapturePresetChangedListener(
2202 @NonNull @CallbackExecutor Executor executor,
2203 @NonNull T listener, int deviceRole) {
2204 Objects.requireNonNull(executor);
2205 Objects.requireNonNull(listener);
2206 DevRoleListeners<T> devRoleListeners =
2207 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2208 if (devRoleListeners == null) {
2209 return AudioSystem.ERROR;
2210 }
2211 synchronized (devRoleListeners.mDevRoleListenersLock) {
2212 if (devRoleListeners.hasDevRoleListener(listener)) {
2213 return AudioSystem.BAD_VALUE;
2214 }
2215 // lazy initialization of the list of device role listener
2216 if (devRoleListeners.mListenerInfos == null) {
2217 devRoleListeners.mListenerInfos = new ArrayList<>();
2218 }
2219 final int oldCbCount = devRoleListeners.mListenerInfos.size();
2220 devRoleListeners.mListenerInfos.add(new DevRoleListenerInfo<T>(executor, listener));
2221 if (oldCbCount == 0 && devRoleListeners.mListenerInfos.size() > 0) {
2222 // register binder for callbacks
2223 synchronized (mDevRoleForCapturePresetListenersLock) {
2224 int deviceRoleListenerStatus = mDeviceRoleListenersStatus;
2225 mDeviceRoleListenersStatus |= (1 << deviceRole);
2226 if (deviceRoleListenerStatus != 0) {
2227 // There are already device role changed listeners active.
2228 return AudioSystem.SUCCESS;
2229 }
2230 if (mDevicesRoleForCapturePresetDispatcherStub == null) {
2231 mDevicesRoleForCapturePresetDispatcherStub =
2232 new CapturePresetDevicesRoleDispatcherStub();
2233 }
2234 try {
2235 getService().registerCapturePresetDevicesRoleDispatcher(
2236 mDevicesRoleForCapturePresetDispatcherStub);
2237 } catch (RemoteException e) {
2238 throw e.rethrowFromSystemServer();
2239 }
2240 }
2241 }
2242 }
2243 return AudioSystem.SUCCESS;
2244 }
2245
2246 private <T> int removeOnDevRoleForCapturePresetChangedListener(
2247 @NonNull T listener, int deviceRole) {
2248 Objects.requireNonNull(listener);
2249 DevRoleListeners<T> devRoleListeners =
2250 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole);
2251 if (devRoleListeners == null) {
2252 return AudioSystem.ERROR;
2253 }
2254 synchronized (devRoleListeners.mDevRoleListenersLock) {
2255 if (!devRoleListeners.removeDevRoleListener(listener)) {
2256 return AudioSystem.BAD_VALUE;
2257 }
2258 if (devRoleListeners.mListenerInfos.size() == 0) {
2259 // unregister binder for callbacks
2260 synchronized (mDevRoleForCapturePresetListenersLock) {
2261 mDeviceRoleListenersStatus ^= (1 << deviceRole);
2262 if (mDeviceRoleListenersStatus != 0) {
2263 // There are some other device role changed listeners active.
2264 return AudioSystem.SUCCESS;
2265 }
2266 try {
2267 getService().unregisterCapturePresetDevicesRoleDispatcher(
2268 mDevicesRoleForCapturePresetDispatcherStub);
2269 } catch (RemoteException e) {
2270 throw e.rethrowFromSystemServer();
2271 }
2272 }
2273 }
2274 }
2275 return AudioSystem.SUCCESS;
2276 }
2277
2278 private final Map<Integer, Object> mDevRoleForCapturePresetListeners = new HashMap<>(){{
2279 put(AudioSystem.DEVICE_ROLE_PREFERRED,
2280 new DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>());
2281 }};
2282
2283 private class DevRoleListenerInfo<T> {
2284 final @NonNull Executor mExecutor;
2285 final @NonNull T mListener;
2286 DevRoleListenerInfo(Executor executor, T listener) {
2287 mExecutor = executor;
2288 mListener = listener;
2289 }
2290 }
2291
2292 private class DevRoleListeners<T> {
2293 private final Object mDevRoleListenersLock = new Object();
2294 @GuardedBy("mDevRoleListenersLock")
2295 private @Nullable ArrayList<DevRoleListenerInfo<T>> mListenerInfos;
2296
2297 @GuardedBy("mDevRoleListenersLock")
2298 private @Nullable DevRoleListenerInfo<T> getDevRoleListenerInfo(T listener) {
2299 if (mListenerInfos == null) {
2300 return null;
2301 }
2302 for (DevRoleListenerInfo<T> listenerInfo : mListenerInfos) {
2303 if (listenerInfo.mListener == listener) {
2304 return listenerInfo;
2305 }
2306 }
2307 return null;
2308 }
2309
2310 @GuardedBy("mDevRoleListenersLock")
2311 private boolean hasDevRoleListener(T listener) {
2312 return getDevRoleListenerInfo(listener) != null;
2313 }
2314
2315 @GuardedBy("mDevRoleListenersLock")
2316 private boolean removeDevRoleListener(T listener) {
2317 final DevRoleListenerInfo<T> infoToRemove = getDevRoleListenerInfo(listener);
2318 if (infoToRemove != null) {
2319 mListenerInfos.remove(infoToRemove);
2320 return true;
2321 }
2322 return false;
2323 }
2324 }
2325
2326 private final Object mDevRoleForCapturePresetListenersLock = new Object();
2327 /**
2328 * Record if there is a listener added for device role change. If there is a listener added for
2329 * a specified device role change, the bit at position `1 << device_role` is set.
2330 */
2331 @GuardedBy("mDevRoleForCapturePresetListenersLock")
2332 private int mDeviceRoleListenersStatus = 0;
2333 @GuardedBy("mDevRoleForCapturePresetListenersLock")
2334 private CapturePresetDevicesRoleDispatcherStub mDevicesRoleForCapturePresetDispatcherStub;
2335
2336 private final class CapturePresetDevicesRoleDispatcherStub
2337 extends ICapturePresetDevicesRoleDispatcher.Stub {
2338
2339 @Override
2340 public void dispatchDevicesRoleChanged(
2341 int capturePreset, int role, List<AudioDeviceAttributes> devices) {
2342 final Object listenersObj = mDevRoleForCapturePresetListeners.get(role);
2343 if (listenersObj == null) {
2344 return;
2345 }
2346 switch (role) {
2347 case AudioSystem.DEVICE_ROLE_PREFERRED: {
2348 final DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>
2349 listeners =
2350 (DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>)
2351 listenersObj;
2352 final ArrayList<DevRoleListenerInfo<
2353 OnPreferredDevicesForCapturePresetChangedListener>> prefDevListeners;
2354 synchronized (listeners.mDevRoleListenersLock) {
2355 if (listeners.mListenerInfos.isEmpty()) {
2356 return;
2357 }
2358 prefDevListeners = (ArrayList<DevRoleListenerInfo<
2359 OnPreferredDevicesForCapturePresetChangedListener>>)
2360 listeners.mListenerInfos.clone();
2361 }
2362 final long ident = Binder.clearCallingIdentity();
2363 try {
2364 for (DevRoleListenerInfo<
2365 OnPreferredDevicesForCapturePresetChangedListener> info :
2366 prefDevListeners) {
2367 info.mExecutor.execute(() ->
2368 info.mListener.onPreferredDevicesForCapturePresetChanged(
2369 capturePreset, devices));
2370 }
2371 } finally {
2372 Binder.restoreCallingIdentity(ident);
2373 }
2374 } break;
2375 default:
2376 break;
2377 }
2378 }
2379 }
2380
2381 //====================================================================
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002382 // Offload query
2383 /**
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002384 * Returns whether offloaded playback of an audio format is supported on the device.
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002385 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2386 * is not competing with other software resources. In general, it is supported by dedicated
2387 * hardware, such as audio DSPs.
2388 * <p>Note that this query only provides information about the support of an audio format,
2389 * it does not indicate whether the resources necessary for the offloaded playback are
2390 * available at that instant.
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002391 * @param format the audio format (codec, sample rate, channels) being checked.
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002392 * @param attributes the {@link AudioAttributes} to be used for playback
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002393 * @return true if the given audio format can be offloaded.
2394 */
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002395 public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format,
2396 @NonNull AudioAttributes attributes) {
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002397 if (format == null) {
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002398 throw new NullPointerException("Illegal null AudioFormat");
Jean-Michel Trivi03f51392018-08-31 15:47:13 -07002399 }
Jean-Michel Trivif3fd84a2019-03-21 16:08:50 -07002400 if (attributes == null) {
2401 throw new NullPointerException("Illegal null AudioAttributes");
2402 }
Eric Laurentba3b3a62020-11-26 20:10:51 +01002403 return AudioSystem.getOffloadSupport(format, attributes) != PLAYBACK_OFFLOAD_NOT_SUPPORTED;
2404 }
2405
2406 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2407 offload playback not supported */
2408 public static final int PLAYBACK_OFFLOAD_NOT_SUPPORTED = AudioSystem.OFFLOAD_NOT_SUPPORTED;
2409 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2410 offload playback supported */
2411 public static final int PLAYBACK_OFFLOAD_SUPPORTED = AudioSystem.OFFLOAD_SUPPORTED;
2412 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}:
2413 offload playback supported with gapless transitions */
2414 public static final int PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED =
2415 AudioSystem.OFFLOAD_GAPLESS_SUPPORTED;
2416
2417 /** @hide */
2418 @IntDef(flag = false, prefix = "PLAYBACK_OFFLOAD_", value = {
2419 PLAYBACK_OFFLOAD_NOT_SUPPORTED,
2420 PLAYBACK_OFFLOAD_SUPPORTED,
2421 PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED }
2422 )
2423 @Retention(RetentionPolicy.SOURCE)
2424 public @interface AudioOffloadMode {}
2425
2426 /**
2427 * Returns whether offloaded playback of an audio format is supported on the device or not and
2428 * when supported whether gapless transitions are possible or not.
2429 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream
2430 * is not competing with other software resources. In general, it is supported by dedicated
2431 * hardware, such as audio DSPs.
2432 * <p>Note that this query only provides information about the support of an audio format,
2433 * it does not indicate whether the resources necessary for the offloaded playback are
2434 * available at that instant.
2435 * @param format the audio format (codec, sample rate, channels) being checked.
2436 * @param attributes the {@link AudioAttributes} to be used for playback
2437 * @return {@link #PLAYBACK_OFFLOAD_NOT_SUPPORTED} if offload playback if not supported,
2438 * {@link #PLAYBACK_OFFLOAD_SUPPORTED} if offload playback is supported or
2439 * {@link #PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} if gapless transitions are
2440 * also supported.
2441 */
2442 @AudioOffloadMode
2443 public static int getPlaybackOffloadSupport(@NonNull AudioFormat format,
2444 @NonNull AudioAttributes attributes) {
2445 if (format == null) {
2446 throw new NullPointerException("Illegal null AudioFormat");
2447 }
2448 if (attributes == null) {
2449 throw new NullPointerException("Illegal null AudioAttributes");
2450 }
2451 return AudioSystem.getOffloadSupport(format, attributes);
Jean-Michel Trivi980d38f2018-01-08 15:43:35 -08002452 }
2453
2454 //====================================================================
Eric Laurent3def1ee2010-03-17 23:26:26 -07002455 // Bluetooth SCO control
2456 /**
Glenn Kastena24e9912017-08-25 08:14:08 -07002457 * Sticky broadcast intent action indicating that the Bluetooth SCO audio
Eric Laurent95b88fb2010-03-18 20:35:49 -07002458 * connection state has changed. The intent contains on extra {@link #EXTRA_SCO_AUDIO_STATE}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002459 * indicating the new state which is either {@link #SCO_AUDIO_STATE_DISCONNECTED}
2460 * or {@link #SCO_AUDIO_STATE_CONNECTED}
2461 *
2462 * @see #startBluetoothSco()
Eric Laurentdc03c612011-04-01 10:59:41 -07002463 * @deprecated Use {@link #ACTION_SCO_AUDIO_STATE_UPDATED} instead
Eric Laurent3def1ee2010-03-17 23:26:26 -07002464 */
Eric Laurentdc03c612011-04-01 10:59:41 -07002465 @Deprecated
Eric Laurent3def1ee2010-03-17 23:26:26 -07002466 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2467 public static final String ACTION_SCO_AUDIO_STATE_CHANGED =
2468 "android.media.SCO_AUDIO_STATE_CHANGED";
Eric Laurentdc03c612011-04-01 10:59:41 -07002469
2470 /**
Glenn Kastena24e9912017-08-25 08:14:08 -07002471 * Sticky broadcast intent action indicating that the Bluetooth SCO audio
Eric Laurentdc03c612011-04-01 10:59:41 -07002472 * connection state has been updated.
2473 * <p>This intent has two extras:
2474 * <ul>
2475 * <li> {@link #EXTRA_SCO_AUDIO_STATE} - The new SCO audio state. </li>
2476 * <li> {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}- The previous SCO audio state. </li>
2477 * </ul>
2478 * <p> EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE can be any of:
2479 * <ul>
2480 * <li> {@link #SCO_AUDIO_STATE_DISCONNECTED}, </li>
2481 * <li> {@link #SCO_AUDIO_STATE_CONNECTING} or </li>
2482 * <li> {@link #SCO_AUDIO_STATE_CONNECTED}, </li>
2483 * </ul>
2484 * @see #startBluetoothSco()
2485 */
2486 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2487 public static final String ACTION_SCO_AUDIO_STATE_UPDATED =
2488 "android.media.ACTION_SCO_AUDIO_STATE_UPDATED";
2489
Eric Laurent3def1ee2010-03-17 23:26:26 -07002490 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002491 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED} or
2492 * {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the new bluetooth SCO connection state.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002493 */
2494 public static final String EXTRA_SCO_AUDIO_STATE =
2495 "android.media.extra.SCO_AUDIO_STATE";
2496
2497 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002498 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the previous
2499 * bluetooth SCO connection state.
2500 */
2501 public static final String EXTRA_SCO_AUDIO_PREVIOUS_STATE =
2502 "android.media.extra.SCO_AUDIO_PREVIOUS_STATE";
2503
2504 /**
2505 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
2506 * indicating that the SCO audio channel is not established
Eric Laurent3def1ee2010-03-17 23:26:26 -07002507 */
2508 public static final int SCO_AUDIO_STATE_DISCONNECTED = 0;
2509 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002510 * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} or {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}
2511 * indicating that the SCO audio channel is established
Eric Laurent3def1ee2010-03-17 23:26:26 -07002512 */
2513 public static final int SCO_AUDIO_STATE_CONNECTED = 1;
2514 /**
Eric Laurentdc03c612011-04-01 10:59:41 -07002515 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE
2516 * indicating that the SCO audio channel is being established
2517 */
2518 public static final int SCO_AUDIO_STATE_CONNECTING = 2;
2519 /**
2520 * Value for extra EXTRA_SCO_AUDIO_STATE indicating that
Eric Laurent3def1ee2010-03-17 23:26:26 -07002521 * there was an error trying to obtain the state
2522 */
2523 public static final int SCO_AUDIO_STATE_ERROR = -1;
2524
2525
2526 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002527 * Indicates if current platform supports use of SCO for off call use cases.
2528 * Application wanted to use bluetooth SCO audio when the phone is not in call
Jean-Michel Trivi2ac2afe2012-08-21 11:16:55 -07002529 * must first call this method to make sure that the platform supports this
Eric Laurent3def1ee2010-03-17 23:26:26 -07002530 * feature.
2531 * @return true if bluetooth SCO can be used for audio when not in call
2532 * false otherwise
2533 * @see #startBluetoothSco()
2534 */
2535 public boolean isBluetoothScoAvailableOffCall() {
Marco Nelissen29f16932015-04-17 09:50:56 -07002536 return getContext().getResources().getBoolean(
Eric Laurent3def1ee2010-03-17 23:26:26 -07002537 com.android.internal.R.bool.config_bluetooth_sco_off_call);
2538 }
2539
2540 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002541 * Start bluetooth SCO audio connection.
2542 * <p>Requires Permission:
2543 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2544 * <p>This method can be used by applications wanting to send and received audio
2545 * to/from a bluetooth SCO headset while the phone is not in call.
2546 * <p>As the SCO connection establishment can take several seconds,
2547 * applications should not rely on the connection to be available when the method
Eric Laurentdc03c612011-04-01 10:59:41 -07002548 * returns but instead register to receive the intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002549 * and wait for the state to be {@link #SCO_AUDIO_STATE_CONNECTED}.
Eric Laurentdc03c612011-04-01 10:59:41 -07002550 * <p>As the ACTION_SCO_AUDIO_STATE_UPDATED intent is sticky, the application can check the SCO
2551 * audio state before calling startBluetoothSco() by reading the intent returned by the receiver
2552 * registration. If the state is already CONNECTED, no state change will be received via the
2553 * intent after calling startBluetoothSco(). It is however useful to call startBluetoothSco()
2554 * so that the connection stays active in case the current initiator stops the connection.
2555 * <p>Unless the connection is already active as described above, the state will always
2556 * transition from DISCONNECTED to CONNECTING and then either to CONNECTED if the connection
2557 * succeeds or back to DISCONNECTED if the connection fails (e.g no headset is connected).
2558 * <p>When finished with the SCO connection or if the establishment fails, the application must
2559 * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002560 * <p>Even if a SCO connection is established, the following restrictions apply on audio
2561 * output streams so that they can be routed to SCO headset:
Eric Laurentdc03c612011-04-01 10:59:41 -07002562 * <ul>
2563 * <li> the stream type must be {@link #STREAM_VOICE_CALL} </li>
2564 * <li> the format must be mono </li>
2565 * <li> the sampling must be 16kHz or 8kHz </li>
2566 * </ul>
Eric Laurent3def1ee2010-03-17 23:26:26 -07002567 * <p>The following restrictions apply on input streams:
Eric Laurentdc03c612011-04-01 10:59:41 -07002568 * <ul>
2569 * <li> the format must be mono </li>
2570 * <li> the sampling must be 8kHz </li>
2571 * </ul>
Eric Laurent3def1ee2010-03-17 23:26:26 -07002572 * <p>Note that the phone application always has the priority on the usage of the SCO
2573 * connection for telephony. If this method is called while the phone is in call
2574 * it will be ignored. Similarly, if a call is received or sent while an application
2575 * is using the SCO connection, the connection will be lost for the application and NOT
2576 * returned automatically when the call ends.
Eric Laurent83900752014-05-15 15:14:22 -07002577 * <p>NOTE: up to and including API version
2578 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual
2579 * voice call to the bluetooth headset.
2580 * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio
2581 * connection is established.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002582 * @see #stopBluetoothSco()
Eric Laurentdc03c612011-04-01 10:59:41 -07002583 * @see #ACTION_SCO_AUDIO_STATE_UPDATED
Eric Laurent3def1ee2010-03-17 23:26:26 -07002584 */
2585 public void startBluetoothSco(){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002586 final IAudioService service = getService();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002587 try {
Marco Nelissen926ebb82015-03-11 09:59:49 -07002588 service.startBluetoothSco(mICallBack,
Marco Nelissen29f16932015-04-17 09:50:56 -07002589 getContext().getApplicationInfo().targetSdkVersion);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002590 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002591 throw e.rethrowFromSystemServer();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002592 }
2593 }
2594
2595 /**
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002596 * @hide
Eric Laurent83900752014-05-15 15:14:22 -07002597 * Start bluetooth SCO audio connection in virtual call mode.
2598 * <p>Requires Permission:
2599 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2600 * <p>Similar to {@link #startBluetoothSco()} with explicit selection of virtual call mode.
2601 * Telephony and communication applications (VoIP, Video Chat) should preferably select
2602 * virtual call mode.
2603 * Applications using voice input for search or commands should first try raw audio connection
2604 * with {@link #startBluetoothSco()} and fall back to startBluetoothScoVirtualCall() in case of
2605 * failure.
2606 * @see #startBluetoothSco()
2607 * @see #stopBluetoothSco()
2608 * @see #ACTION_SCO_AUDIO_STATE_UPDATED
2609 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00002610 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent83900752014-05-15 15:14:22 -07002611 public void startBluetoothScoVirtualCall() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002612 final IAudioService service = getService();
Eric Laurent83900752014-05-15 15:14:22 -07002613 try {
2614 service.startBluetoothScoVirtualCall(mICallBack);
2615 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002616 throw e.rethrowFromSystemServer();
Eric Laurent83900752014-05-15 15:14:22 -07002617 }
2618 }
2619
2620 /**
Eric Laurent3def1ee2010-03-17 23:26:26 -07002621 * Stop bluetooth SCO audio connection.
2622 * <p>Requires Permission:
2623 * {@link android.Manifest.permission#MODIFY_AUDIO_SETTINGS}.
2624 * <p>This method must be called by applications having requested the use of
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002625 * bluetooth SCO audio with {@link #startBluetoothSco()} when finished with the SCO
2626 * connection or if connection fails.
Eric Laurent3def1ee2010-03-17 23:26:26 -07002627 * @see #startBluetoothSco()
2628 */
Jean-Michel Trivi0daab222014-07-18 15:31:29 -07002629 // Also used for connections started with {@link #startBluetoothScoVirtualCall()}
Eric Laurent3def1ee2010-03-17 23:26:26 -07002630 public void stopBluetoothSco(){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002631 final IAudioService service = getService();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002632 try {
2633 service.stopBluetoothSco(mICallBack);
2634 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002635 throw e.rethrowFromSystemServer();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002636 }
2637 }
2638
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002639 /**
Eric Laurenta553c252009-07-17 12:17:14 -07002640 * Request use of Bluetooth SCO headset for communications.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07002641 * <p>
2642 * This method should only be used by applications that replace the platform-wide
2643 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002644 *
Eric Laurenta553c252009-07-17 12:17:14 -07002645 * @param on set <var>true</var> to use bluetooth SCO for communications;
2646 * <var>false</var> to not use bluetooth SCO for communications
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002647 */
2648 public void setBluetoothScoOn(boolean on){
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002649 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002650 try {
2651 service.setBluetoothScoOn(on);
2652 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002653 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07002654 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002655 }
2656
2657 /**
Eric Laurenta553c252009-07-17 12:17:14 -07002658 * Checks whether communications use Bluetooth SCO.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002659 *
Eric Laurenta553c252009-07-17 12:17:14 -07002660 * @return true if SCO is used for communications;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002661 * false if otherwise
2662 */
2663 public boolean isBluetoothScoOn() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002664 final IAudioService service = getService();
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002665 try {
2666 return service.isBluetoothScoOn();
2667 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002668 throw e.rethrowFromSystemServer();
Eric Laurenta553c252009-07-17 12:17:14 -07002669 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002670 }
2671
2672 /**
Eric Laurent242b3382012-06-15 11:48:50 -07002673 * @param on set <var>true</var> to route A2DP audio to/from Bluetooth
2674 * headset; <var>false</var> disable A2DP audio
Eric Laurenta553c252009-07-17 12:17:14 -07002675 * @deprecated Do not use.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002676 */
Eric Laurenta553c252009-07-17 12:17:14 -07002677 @Deprecated public void setBluetoothA2dpOn(boolean on){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002678 }
2679
2680 /**
Eric Laurentc117bea2017-02-07 11:04:18 -08002681 * Checks whether a Bluetooth A2DP audio peripheral is connected or not.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002682 *
Eric Laurentc117bea2017-02-07 11:04:18 -08002683 * @return true if a Bluetooth A2DP peripheral is connected
Eric Laurent242b3382012-06-15 11:48:50 -07002684 * false if otherwise
Eric Laurentc117bea2017-02-07 11:04:18 -08002685 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002686 */
2687 public boolean isBluetoothA2dpOn() {
Eric Laurent242b3382012-06-15 11:48:50 -07002688 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"")
Eric Laurent9656df22016-04-20 16:42:28 -07002689 == AudioSystem.DEVICE_STATE_AVAILABLE) {
2690 return true;
2691 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"")
2692 == AudioSystem.DEVICE_STATE_AVAILABLE) {
2693 return true;
2694 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,"")
2695 == AudioSystem.DEVICE_STATE_AVAILABLE) {
Eric Laurent242b3382012-06-15 11:48:50 -07002696 return true;
Eric Laurenta553c252009-07-17 12:17:14 -07002697 }
Eric Laurent9656df22016-04-20 16:42:28 -07002698 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002699 }
2700
2701 /**
2702 * Sets audio routing to the wired headset on or off.
2703 *
2704 * @param on set <var>true</var> to route audio to/from wired
2705 * headset; <var>false</var> disable wired headset audio
Eric Laurenta553c252009-07-17 12:17:14 -07002706 * @deprecated Do not use.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002707 */
Eric Laurenta553c252009-07-17 12:17:14 -07002708 @Deprecated public void setWiredHeadsetOn(boolean on){
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002709 }
2710
2711 /**
Eric Laurent497b3fe2011-08-02 17:41:11 -07002712 * Checks whether a wired headset is connected or not.
2713 * <p>This is not a valid indication that audio playback is
2714 * actually over the wired headset as audio routing depends on other conditions.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002715 *
Eric Laurent497b3fe2011-08-02 17:41:11 -07002716 * @return true if a wired headset is connected.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002717 * false if otherwise
Eric Laurentc117bea2017-02-07 11:04:18 -08002718 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002719 */
2720 public boolean isWiredHeadsetOn() {
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08002721 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADSET,"")
Eric Laurent6015a972010-02-12 07:41:14 -08002722 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08002723 AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADPHONE,"")
Paul McLean145c9532017-08-04 11:12:19 -06002724 == AudioSystem.DEVICE_STATE_UNAVAILABLE &&
2725 AudioSystem.getDeviceConnectionState(DEVICE_OUT_USB_HEADSET, "")
2726 == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
Eric Laurenta553c252009-07-17 12:17:14 -07002727 return false;
2728 } else {
2729 return true;
2730 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002731 }
2732
2733 /**
2734 * Sets the microphone mute on or off.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07002735 * <p>
2736 * This method should only be used by applications that replace the platform-wide
2737 * management of audio settings or the main telephony application.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002738 *
2739 * @param on set <var>true</var> to mute the microphone;
2740 * <var>false</var> to turn mute off
2741 */
Kenny Guy70e0c582015-06-30 19:18:28 +01002742 public void setMicrophoneMute(boolean on) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002743 final IAudioService service = getService();
Emily Bernier22c921a2014-05-28 11:01:32 -04002744 try {
Kenny Guy70e0c582015-06-30 19:18:28 +01002745 service.setMicrophoneMute(on, getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00002746 UserHandle.getCallingUserId(), getContext().getAttributionTag());
Emily Bernier22c921a2014-05-28 11:01:32 -04002747 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002748 throw e.rethrowFromSystemServer();
Emily Bernier22c921a2014-05-28 11:01:32 -04002749 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002750 }
2751
2752 /**
Dmitry Shmidt3d233932019-09-20 15:52:03 -07002753 * @hide
2754 * Sets the microphone from switch mute on or off.
2755 * <p>
2756 * This method should only be used by InputManager to notify
2757 * Audio Subsystem about Microphone Mute switch state.
2758 *
2759 * @param on set <var>true</var> to mute the microphone;
2760 * <var>false</var> to turn mute off
2761 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00002762 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Dmitry Shmidt3d233932019-09-20 15:52:03 -07002763 public void setMicrophoneMuteFromSwitch(boolean on) {
2764 final IAudioService service = getService();
2765 try {
2766 service.setMicrophoneMuteFromSwitch(on);
2767 } catch (RemoteException e) {
2768 throw e.rethrowFromSystemServer();
2769 }
2770 }
2771
2772 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002773 * Checks whether the microphone mute is on or off.
2774 *
2775 * @return true if microphone is muted, false if it's not
2776 */
2777 public boolean isMicrophoneMute() {
Dmitry Shmidt3d233932019-09-20 15:52:03 -07002778 final IAudioService service = getService();
2779 try {
2780 return service.isMicrophoneMuted();
2781 } catch (RemoteException e) {
2782 throw e.rethrowFromSystemServer();
2783 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002784 }
2785
2786 /**
Jean-Michel Trivi7be17d22017-12-21 18:09:21 -08002787 * Broadcast Action: microphone muting state changed.
2788 *
2789 * You <em>cannot</em> receive this through components declared
2790 * in manifests, only by explicitly registering for it with
2791 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
2792 * Context.registerReceiver()}.
2793 *
2794 * <p>The intent has no extra values, use {@link #isMicrophoneMute} to check whether the
2795 * microphone is muted.
2796 */
2797 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2798 public static final String ACTION_MICROPHONE_MUTE_CHANGED =
2799 "android.media.action.MICROPHONE_MUTE_CHANGED";
2800
2801 /**
Jean-Michel Trivi90682ff2019-03-18 15:52:00 -07002802 * Broadcast Action: speakerphone state changed.
2803 *
2804 * You <em>cannot</em> receive this through components declared
2805 * in manifests, only by explicitly registering for it with
2806 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
2807 * Context.registerReceiver()}.
2808 *
2809 * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the
2810 * speakerphone functionality is enabled or not.
2811 */
2812 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
2813 public static final String ACTION_SPEAKERPHONE_STATE_CHANGED =
2814 "android.media.action.SPEAKERPHONE_STATE_CHANGED";
2815
2816 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002817 * Sets the audio mode.
Jean-Michel Trivifccb25d2009-09-15 16:06:10 -07002818 * <p>
2819 * The audio mode encompasses audio routing AND the behavior of
2820 * the telephony layer. Therefore this method should only be used by applications that
2821 * replace the platform-wide management of audio settings or the main telephony application.
2822 * In particular, the {@link #MODE_IN_CALL} mode should only be used by the telephony
2823 * application when it places a phone call, as it will cause signals from the radio layer
2824 * to feed the platform mixer.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002825 *
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002826 * @param mode the requested audio mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002827 * Informs the HAL about the current audio state so that
2828 * it can route the audio appropriately.
2829 */
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002830 public void setMode(@AudioMode int mode) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002831 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002832 try {
Marco Nelissena80ac052015-03-12 16:17:45 -07002833 service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002834 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07002835 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002836 }
2837 }
2838
2839 /**
2840 * Returns the current audio mode.
2841 *
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002842 * @return the current audio mode.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002843 */
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002844 @AudioMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002845 public int getMode() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07002846 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002847 try {
Eric Laurent2d7197fc2019-11-06 10:17:06 -08002848 int mode = service.getMode();
2849 int sdk;
2850 try {
2851 sdk = getContext().getApplicationInfo().targetSdkVersion;
2852 } catch (NullPointerException e) {
2853 // some tests don't have a Context
2854 sdk = Build.VERSION.SDK_INT;
2855 }
2856 if (mode == MODE_CALL_SCREENING && sdk <= Build.VERSION_CODES.Q) {
2857 mode = MODE_IN_CALL;
2858 }
2859 return mode;
2860 } catch (RemoteException e) {
2861 throw e.rethrowFromSystemServer();
2862 }
2863 }
2864
2865 /**
Nate Myren08635fe2021-04-20 12:04:39 -07002866 * Interface definition of a callback that is notified when the audio mode changes
2867 */
2868 public interface OnModeChangedListener {
2869 /**
2870 * Called on the listener to indicate that the audio mode has changed
2871 *
2872 * @param mode The current audio mode
2873 */
2874 void onModeChanged(@AudioMode int mode);
2875 }
2876
2877 private final Object mModeListenerLock = new Object();
2878 /**
2879 * List of listeners for audio mode and their associated Executor.
2880 * List is lazy-initialized on first registration
2881 */
2882 @GuardedBy("mModeListenerLock")
2883 private @Nullable ArrayList<ModeListenerInfo> mModeListeners;
2884
2885 @GuardedBy("mModeListenerLock")
2886 private ModeDispatcherStub mModeDispatcherStub;
2887
2888 private final class ModeDispatcherStub
2889 extends IAudioModeDispatcher.Stub {
2890
2891 @Override
2892 public void dispatchAudioModeChanged(int mode) {
2893 // make a shallow copy of listeners so callback is not executed under lock
2894 final ArrayList<ModeListenerInfo> modeListeners;
2895 synchronized (mModeListenerLock) {
2896 if (mModeListeners == null || mModeListeners.size() == 0) {
2897 return;
2898 }
2899 modeListeners = (ArrayList<ModeListenerInfo>) mModeListeners.clone();
2900 }
2901 final long ident = Binder.clearCallingIdentity();
2902 try {
2903 for (ModeListenerInfo info : modeListeners) {
2904 info.mExecutor.execute(() ->
2905 info.mListener.onModeChanged(mode));
2906 }
2907 } finally {
2908 Binder.restoreCallingIdentity(ident);
2909 }
2910 }
2911 }
2912
2913 private static class ModeListenerInfo {
2914 final @NonNull OnModeChangedListener mListener;
2915 final @NonNull Executor mExecutor;
2916
2917 ModeListenerInfo(OnModeChangedListener listener, Executor exe) {
2918 mListener = listener;
2919 mExecutor = exe;
2920 }
2921 }
2922
2923 @GuardedBy("mModeListenerLock")
2924 private boolean hasModeListener(OnModeChangedListener listener) {
2925 return getModeListenerInfo(listener) != null;
2926 }
2927
2928 @GuardedBy("mModeListenerLock")
2929 private @Nullable ModeListenerInfo getModeListenerInfo(
2930 OnModeChangedListener listener) {
2931 if (mModeListeners == null) {
2932 return null;
2933 }
2934 for (ModeListenerInfo info : mModeListeners) {
2935 if (info.mListener == listener) {
2936 return info;
2937 }
2938 }
2939 return null;
2940 }
2941
2942
2943 @GuardedBy("mModeListenerLock")
2944 /**
2945 * @return true if the listener was removed from the list
2946 */
2947 private boolean removeModeListener(OnModeChangedListener listener) {
2948 final ModeListenerInfo infoToRemove = getModeListenerInfo(listener);
2949 if (infoToRemove != null) {
2950 mModeListeners.remove(infoToRemove);
2951 return true;
2952 }
2953 return false;
2954 }
2955
2956 /**
2957 * Adds a listener to be notified of changes to the audio mode.
2958 * See {@link #getMode()}
2959 * @param executor
2960 * @param listener
2961 */
2962 public void addOnModeChangedListener(
2963 @NonNull @CallbackExecutor Executor executor,
2964 @NonNull OnModeChangedListener listener) {
2965 Objects.requireNonNull(executor);
2966 Objects.requireNonNull(listener);
2967 synchronized (mModeListenerLock) {
2968 if (hasModeListener(listener)) {
2969 throw new IllegalArgumentException("attempt to call addOnModeChangedListener() "
2970 + "on a previously registered listener");
2971 }
2972 // lazy initialization of the list of strategy-preferred device listener
2973 if (mModeListeners == null) {
2974 mModeListeners = new ArrayList<>();
2975 }
2976 final int oldCbCount = mModeListeners.size();
2977 mModeListeners.add(new ModeListenerInfo(listener, executor));
2978 if (oldCbCount == 0) {
2979 // register binder for callbacks
2980 if (mModeDispatcherStub == null) {
2981 mModeDispatcherStub = new ModeDispatcherStub();
2982 }
2983 try {
2984 getService().registerModeDispatcher(mModeDispatcherStub);
2985 } catch (RemoteException e) {
2986 throw e.rethrowFromSystemServer();
2987 }
2988 }
2989 }
2990 }
2991
2992 /**
2993 * Removes a previously added listener for changes to audio mode.
2994 * See {@link #getMode()}
2995 * @param listener
2996 */
2997 public void removeOnModeChangedListener(@NonNull OnModeChangedListener listener) {
2998 Objects.requireNonNull(listener);
2999 synchronized (mModeListenerLock) {
3000 if (!removeModeListener(listener)) {
3001 throw new IllegalArgumentException("attempt to call removeOnModeChangedListener() "
3002 + "on an unregistered listener");
3003 }
3004 if (mModeListeners.size() == 0) {
3005 // unregister binder for callbacks
3006 try {
3007 getService().unregisterModeDispatcher(mModeDispatcherStub);
3008 } catch (RemoteException e) {
3009 throw e.rethrowFromSystemServer();
3010 } finally {
3011 mModeDispatcherStub = null;
3012 mModeListeners = null;
3013 }
3014 }
3015 }
3016 }
3017
3018 /**
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003019 * Indicates if the platform supports a special call screening and call monitoring mode.
3020 * <p>
3021 * When this mode is supported, it is possible to perform call screening and monitoring
3022 * functions while other use cases like music or movie playback are active.
3023 * <p>
3024 * Use {@link #setMode(int)} with mode {@link #MODE_CALL_SCREENING} to place the platform in
3025 * call screening mode.
3026 * <p>
3027 * If call screening mode is not supported, setting mode to
3028 * MODE_CALL_SCREENING will be ignored and will not change current mode reported by
3029 * {@link #getMode()}.
3030 * @return true if call screening mode is supported, false otherwise.
3031 */
3032 public boolean isCallScreeningModeSupported() {
3033 final IAudioService service = getService();
3034 try {
3035 return service.isCallScreeningModeSupported();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003036 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003037 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003038 }
3039 }
3040
3041 /* modes for setMode/getMode/setRoute/getRoute */
3042 /**
3043 * Audio harware modes.
3044 */
3045 /**
3046 * Invalid audio mode.
3047 */
3048 public static final int MODE_INVALID = AudioSystem.MODE_INVALID;
3049 /**
3050 * Current audio mode. Used to apply audio routing to current mode.
3051 */
3052 public static final int MODE_CURRENT = AudioSystem.MODE_CURRENT;
3053 /**
3054 * Normal audio mode: not ringing and no call established.
3055 */
3056 public static final int MODE_NORMAL = AudioSystem.MODE_NORMAL;
3057 /**
3058 * Ringing audio mode. An incoming is being signaled.
3059 */
3060 public static final int MODE_RINGTONE = AudioSystem.MODE_RINGTONE;
3061 /**
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003062 * In call audio mode. A telephony call is established.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003063 */
3064 public static final int MODE_IN_CALL = AudioSystem.MODE_IN_CALL;
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003065 /**
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08003066 * In communication audio mode. An audio/video chat or VoIP call is established.
3067 */
3068 public static final int MODE_IN_COMMUNICATION = AudioSystem.MODE_IN_COMMUNICATION;
Eric Laurent2d7197fc2019-11-06 10:17:06 -08003069 /**
3070 * Call screening in progress. Call is connected and audio is accessible to call
3071 * screening applications but other audio use cases are still possible.
3072 */
3073 public static final int MODE_CALL_SCREENING = AudioSystem.MODE_CALL_SCREENING;
3074
3075 /** @hide */
3076 @IntDef(flag = false, prefix = "MODE_", value = {
3077 MODE_NORMAL,
3078 MODE_RINGTONE,
3079 MODE_IN_CALL,
3080 MODE_IN_COMMUNICATION,
3081 MODE_CALL_SCREENING }
3082 )
3083 @Retention(RetentionPolicy.SOURCE)
3084 public @interface AudioMode {}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003085
3086 /* Routing bits for setRouting/getRouting API */
3087 /**
3088 * Routing audio output to earpiece
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003089 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3090 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003091 */
Eric Laurenta553c252009-07-17 12:17:14 -07003092 @Deprecated public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003093 /**
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003094 * Routing audio output to speaker
3095 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3096 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003097 */
Eric Laurenta553c252009-07-17 12:17:14 -07003098 @Deprecated public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003099 /**
3100 * @deprecated use {@link #ROUTE_BLUETOOTH_SCO}
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003101 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3102 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003103 */
3104 @Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO;
3105 /**
3106 * Routing audio output to bluetooth SCO
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003107 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3108 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003109 */
Eric Laurenta553c252009-07-17 12:17:14 -07003110 @Deprecated public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003111 /**
3112 * Routing audio output to headset
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003113 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3114 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003115 */
Eric Laurenta553c252009-07-17 12:17:14 -07003116 @Deprecated public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003117 /**
3118 * Routing audio output to bluetooth A2DP
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003119 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3120 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003121 */
Eric Laurenta553c252009-07-17 12:17:14 -07003122 @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003123 /**
3124 * Used for mask parameter of {@link #setRouting(int,int,int)}.
Dianne Hackborn4a51c202009-08-21 15:14:02 -07003125 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
3126 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003127 */
Eric Laurenta553c252009-07-17 12:17:14 -07003128 @Deprecated public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003129
3130 /**
3131 * Sets the audio routing for a specified mode
3132 *
3133 * @param mode audio mode to change route. E.g., MODE_RINGTONE.
3134 * @param routes bit vector of routes requested, created from one or
3135 * more of ROUTE_xxx types. Set bits indicate that route should be on
3136 * @param mask bit vector of routes to change, created from one or more of
3137 * ROUTE_xxx types. Unset bits indicate the route should be left unchanged
Eric Laurentb9c9d262009-05-06 08:13:20 -07003138 *
3139 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(),
Eric Laurenta553c252009-07-17 12:17:14 -07003140 * setBluetoothScoOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003141 */
Eric Laurenta553c252009-07-17 12:17:14 -07003142 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003143 public void setRouting(int mode, int routes, int mask) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003144 }
3145
3146 /**
3147 * Returns the current audio routing bit vector for a specified mode.
3148 *
3149 * @param mode audio mode to get route (e.g., MODE_RINGTONE)
3150 * @return an audio route bit vector that can be compared with ROUTE_xxx
3151 * bits
Eric Laurentb9c9d262009-05-06 08:13:20 -07003152 * @deprecated Do not query audio routing directly, use isSpeakerphoneOn(),
3153 * isBluetoothScoOn(), isBluetoothA2dpOn() and isWiredHeadsetOn() methods instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003154 */
Eric Laurentb9c9d262009-05-06 08:13:20 -07003155 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003156 public int getRouting(int mode) {
Eric Laurenta553c252009-07-17 12:17:14 -07003157 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003158 }
3159
3160 /**
3161 * Checks whether any music is active.
3162 *
3163 * @return true if any music tracks are active.
3164 */
3165 public boolean isMusicActive() {
Jean-Michel Trivi15e30052020-12-09 11:54:00 -08003166 final IAudioService service = getService();
3167 try {
Eric Laurent89c3a972020-12-16 15:57:56 +01003168 return service.isMusicActive(false /*remotely*/);
Jean-Michel Trivi15e30052020-12-09 11:54:00 -08003169 } catch (RemoteException e) {
3170 throw e.rethrowFromSystemServer();
3171 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003172 }
3173
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003174 /**
3175 * @hide
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003176 * Checks whether any music or media is actively playing on a remote device (e.g. wireless
3177 * display). Note that BT audio sinks are not considered remote devices.
3178 * @return true if {@link AudioManager#STREAM_MUSIC} is active on a remote device
3179 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003180 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003181 public boolean isMusicActiveRemotely() {
Eric Laurent89c3a972020-12-16 15:57:56 +01003182 final IAudioService service = getService();
3183 try {
3184 return service.isMusicActive(true /*remotely*/);
3185 } catch (RemoteException e) {
3186 throw e.rethrowFromSystemServer();
3187 }
Jean-Michel Trivi679d5042013-02-04 16:24:09 -08003188 }
3189
3190 /**
3191 * @hide
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003192 * Checks whether the current audio focus is exclusive.
3193 * @return true if the top of the audio focus stack requested focus
3194 * with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}
3195 */
3196 public boolean isAudioFocusExclusive() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003197 final IAudioService service = getService();
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003198 try {
3199 return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE;
3200 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003201 throw e.rethrowFromSystemServer();
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003202 }
3203 }
3204
3205 /**
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003206 * Return a new audio session identifier not associated with any player or effect.
Jean-Michel Trivi9e477e42014-08-25 17:44:28 -07003207 * An audio session identifier is a system wide unique identifier for a set of audio streams
3208 * (one or more mixed together).
3209 * <p>The primary use of the audio session ID is to associate audio effects to audio players,
3210 * such as {@link MediaPlayer} or {@link AudioTrack}: all audio effects sharing the same audio
3211 * session ID will be applied to the mixed audio content of the players that share the same
3212 * audio session.
3213 * <p>This method can for instance be used when creating one of the
3214 * {@link android.media.audiofx.AudioEffect} objects to define the audio session of the effect,
3215 * or to specify a session for a speech synthesis utterance
3216 * in {@link android.speech.tts.TextToSpeech.Engine}.
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003217 * @return a new unclaimed and unused audio session identifier, or {@link #ERROR} when the
Jean-Michel Trivi9e477e42014-08-25 17:44:28 -07003218 * system failed to generate a new session, a condition in which audio playback or recording
3219 * will subsequently fail as well.
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003220 */
Dichen Zhangf50b2362018-11-26 13:18:58 -08003221 public int generateAudioSessionId() {
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003222 int session = AudioSystem.newAudioSessionId();
3223 if (session > 0) {
3224 return session;
3225 } else {
Jean-Michel Trivi289cc8e2014-07-18 18:45:32 -07003226 Log.e(TAG, "Failure to generate a new audio session ID");
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003227 return ERROR;
3228 }
3229 }
3230
Jean-Michel Trivi289cc8e2014-07-18 18:45:32 -07003231 /**
3232 * A special audio session ID to indicate that the audio session ID isn't known and the
3233 * framework should generate a new value. This can be used when building a new
3234 * {@link AudioTrack} instance with
3235 * {@link AudioTrack#AudioTrack(AudioAttributes, AudioFormat, int, int, int)}.
3236 */
3237 public static final int AUDIO_SESSION_ID_GENERATE = AudioSystem.AUDIO_SESSION_ALLOCATE;
3238
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07003239
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003240 /*
3241 * Sets a generic audio configuration parameter. The use of these parameters
3242 * are platform dependant, see libaudio
3243 *
3244 * ** Temporary interface - DO NOT USE
3245 *
3246 * TODO: Replace with a more generic key:value get/set mechanism
3247 *
3248 * param key name of parameter to set. Must not be null.
3249 * param value value of parameter. Must not be null.
3250 */
3251 /**
3252 * @hide
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07003253 * @deprecated Use {@link #setParameters(String)} instead
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003254 */
Eric Laurenta553c252009-07-17 12:17:14 -07003255 @Deprecated public void setParameter(String key, String value) {
3256 setParameters(key+"="+value);
3257 }
3258
3259 /**
3260 * Sets a variable number of parameter values to audio hardware.
3261 *
3262 * @param keyValuePairs list of parameters key value pairs in the form:
3263 * key1=value1;key2=value2;...
3264 *
3265 */
3266 public void setParameters(String keyValuePairs) {
3267 AudioSystem.setParameters(keyValuePairs);
3268 }
3269
3270 /**
John Spurlockaac753d2013-02-22 16:33:32 -05003271 * Gets a variable number of parameter values from audio hardware.
Eric Laurenta553c252009-07-17 12:17:14 -07003272 *
3273 * @param keys list of parameters
3274 * @return list of parameters key value pairs in the form:
3275 * key1=value1;key2=value2;...
3276 */
3277 public String getParameters(String keys) {
3278 return AudioSystem.getParameters(keys);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003279 }
3280
3281 /* Sound effect identifiers */
3282 /**
3283 * Keyboard and direction pad click sound
3284 * @see #playSoundEffect(int)
3285 */
3286 public static final int FX_KEY_CLICK = 0;
3287 /**
3288 * Focus has moved up
3289 * @see #playSoundEffect(int)
3290 */
3291 public static final int FX_FOCUS_NAVIGATION_UP = 1;
3292 /**
3293 * Focus has moved down
3294 * @see #playSoundEffect(int)
3295 */
3296 public static final int FX_FOCUS_NAVIGATION_DOWN = 2;
3297 /**
3298 * Focus has moved left
3299 * @see #playSoundEffect(int)
3300 */
3301 public static final int FX_FOCUS_NAVIGATION_LEFT = 3;
3302 /**
3303 * Focus has moved right
3304 * @see #playSoundEffect(int)
3305 */
3306 public static final int FX_FOCUS_NAVIGATION_RIGHT = 4;
3307 /**
3308 * IME standard keypress sound
3309 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003310 */
3311 public static final int FX_KEYPRESS_STANDARD = 5;
3312 /**
3313 * IME spacebar keypress sound
3314 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003315 */
3316 public static final int FX_KEYPRESS_SPACEBAR = 6;
3317 /**
3318 * IME delete keypress sound
3319 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003320 */
3321 public static final int FX_KEYPRESS_DELETE = 7;
3322 /**
3323 * IME return_keypress sound
3324 * @see #playSoundEffect(int)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003325 */
3326 public static final int FX_KEYPRESS_RETURN = 8;
Justin Kohcacfe692013-07-11 17:16:53 -07003327
3328 /**
3329 * Invalid keypress sound
3330 * @see #playSoundEffect(int)
3331 */
3332 public static final int FX_KEYPRESS_INVALID = 9;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003333
3334 /**
3335 * Back sound
3336 * @see #playSoundEffect(int)
3337 */
3338 public static final int FX_BACK = 10;
3339
3340 /**
3341 * @hide Home sound
Philip Junker6d9a0962021-02-18 13:55:54 +01003342 * <p>
3343 * To be played by the framework when the home app becomes active if config_enableHomeSound is
3344 * set to true. This is currently only used on TV devices.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003345 * Note that this sound is only available if a sound file is specified in audio_assets.xml.
3346 * @see #playSoundEffect(int)
3347 */
3348 public static final int FX_HOME = 11;
3349
3350 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003351 * @hide Navigation repeat sound 1
3352 * <p>
3353 * To be played by the framework when a focus navigation is repeatedly triggered
3354 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003355 * This is currently only used on TV devices.
3356 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3357 * @see #playSoundEffect(int)
3358 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003359 public static final int FX_FOCUS_NAVIGATION_REPEAT_1 = 12;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003360
3361 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003362 * @hide Navigation repeat sound 2
3363 * <p>
3364 * To be played by the framework when a focus navigation is repeatedly triggered
3365 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003366 * This is currently only used on TV devices.
3367 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3368 * @see #playSoundEffect(int)
3369 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003370 public static final int FX_FOCUS_NAVIGATION_REPEAT_2 = 13;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003371
3372 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003373 * @hide Navigation repeat sound 3
3374 * <p>
3375 * To be played by the framework when a focus navigation is repeatedly triggered
3376 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003377 * This is currently only used on TV devices.
3378 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3379 * @see #playSoundEffect(int)
3380 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003381 public static final int FX_FOCUS_NAVIGATION_REPEAT_3 = 14;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003382
3383 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003384 * @hide Navigation repeat sound 4
3385 * <p>
3386 * To be played by the framework when a focus navigation is repeatedly triggered
3387 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true.
Philip Junker7f1fdff2020-12-03 16:10:41 +01003388 * This is currently only used on TV devices.
3389 * Note that this sound is only available if a sound file is specified in audio_assets.xml
3390 * @see #playSoundEffect(int)
3391 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003392 public static final int FX_FOCUS_NAVIGATION_REPEAT_4 = 15;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003393
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003394 /**
3395 * @hide Number of sound effects
3396 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00003397 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Philip Junker7f1fdff2020-12-03 16:10:41 +01003398 public static final int NUM_SOUND_EFFECTS = 16;
3399
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003400 /** @hide */
3401 @IntDef(prefix = { "FX_" }, value = {
3402 FX_KEY_CLICK,
3403 FX_FOCUS_NAVIGATION_UP,
3404 FX_FOCUS_NAVIGATION_DOWN,
3405 FX_FOCUS_NAVIGATION_LEFT,
3406 FX_FOCUS_NAVIGATION_RIGHT,
3407 FX_KEYPRESS_STANDARD,
3408 FX_KEYPRESS_SPACEBAR,
3409 FX_KEYPRESS_DELETE,
3410 FX_KEYPRESS_RETURN,
3411 FX_KEYPRESS_INVALID,
3412 FX_BACK
3413 })
3414 @Retention(RetentionPolicy.SOURCE)
3415 public @interface SystemSoundEffect {}
3416
Philip Junker7f1fdff2020-12-03 16:10:41 +01003417 /**
Philip Junker6d9a0962021-02-18 13:55:54 +01003418 * @hide Number of FX_FOCUS_NAVIGATION_REPEAT_* sound effects
Philip Junker7f1fdff2020-12-03 16:10:41 +01003419 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003420 public static final int NUM_NAVIGATION_REPEAT_SOUND_EFFECTS = 4;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003421
3422 /**
3423 * @hide
Philip Junker6d9a0962021-02-18 13:55:54 +01003424 * @param n a value in [0, {@link #NUM_NAVIGATION_REPEAT_SOUND_EFFECTS}[
3425 * @return The id of a navigation repeat sound effect or -1 if out of bounds
Philip Junker7f1fdff2020-12-03 16:10:41 +01003426 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003427 public static int getNthNavigationRepeatSoundEffect(int n) {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003428 switch (n) {
3429 case 0:
Philip Junker6d9a0962021-02-18 13:55:54 +01003430 return FX_FOCUS_NAVIGATION_REPEAT_1;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003431 case 1:
Philip Junker6d9a0962021-02-18 13:55:54 +01003432 return FX_FOCUS_NAVIGATION_REPEAT_2;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003433 case 2:
Philip Junker6d9a0962021-02-18 13:55:54 +01003434 return FX_FOCUS_NAVIGATION_REPEAT_3;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003435 case 3:
Philip Junker6d9a0962021-02-18 13:55:54 +01003436 return FX_FOCUS_NAVIGATION_REPEAT_4;
Philip Junker7f1fdff2020-12-03 16:10:41 +01003437 default:
Philip Junker6d9a0962021-02-18 13:55:54 +01003438 Log.w(TAG, "Invalid navigation repeat sound effect id: " + n);
Philip Junker7f1fdff2020-12-03 16:10:41 +01003439 return -1;
3440 }
3441 }
3442
3443 /**
3444 * @hide
3445 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003446 public void setNavigationRepeatSoundEffectsEnabled(boolean enabled) {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003447 try {
Philip Junker6d9a0962021-02-18 13:55:54 +01003448 getService().setNavigationRepeatSoundEffectsEnabled(enabled);
Philip Junker7f1fdff2020-12-03 16:10:41 +01003449 } catch (RemoteException e) {
3450
3451 }
3452 }
3453
3454 /**
3455 * @hide
Philip Junker6d9a0962021-02-18 13:55:54 +01003456 * @return true if the navigation repeat sound effects are enabled
Philip Junker7f1fdff2020-12-03 16:10:41 +01003457 */
Philip Junker6d9a0962021-02-18 13:55:54 +01003458 public boolean areNavigationRepeatSoundEffectsEnabled() {
Philip Junker7f1fdff2020-12-03 16:10:41 +01003459 try {
Philip Junker6d9a0962021-02-18 13:55:54 +01003460 return getService().areNavigationRepeatSoundEffectsEnabled();
Philip Junker7f1fdff2020-12-03 16:10:41 +01003461 } catch (RemoteException e) {
3462 throw e.rethrowFromSystemServer();
3463 }
3464 }
3465
3466 /**
3467 * @hide
3468 * @param enabled
3469 */
3470 public void setHomeSoundEffectEnabled(boolean enabled) {
3471 try {
3472 getService().setHomeSoundEffectEnabled(enabled);
3473 } catch (RemoteException e) {
3474
3475 }
3476 }
3477
3478 /**
3479 * @hide
3480 * @return true if the home sound effect is enabled
3481 */
3482 public boolean isHomeSoundEffectEnabled() {
3483 try {
3484 return getService().isHomeSoundEffectEnabled();
3485 } catch (RemoteException e) {
3486 throw e.rethrowFromSystemServer();
3487 }
3488 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003489
3490 /**
3491 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003492 * @param effectType The type of sound effect.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003493 * NOTE: This version uses the UI settings to determine
3494 * whether sounds are heard or not.
3495 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003496 public void playSoundEffect(@SystemSoundEffect int effectType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003497 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3498 return;
3499 }
3500
Jason Monk0c37ba32014-09-08 15:34:23 -04003501 if (!querySoundEffectsEnabled(Process.myUserHandle().getIdentifier())) {
3502 return;
3503 }
3504
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003505 final IAudioService service = getService();
Jason Monk0c37ba32014-09-08 15:34:23 -04003506 try {
3507 service.playSoundEffect(effectType);
3508 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003509 throw e.rethrowFromSystemServer();
Jason Monk0c37ba32014-09-08 15:34:23 -04003510 }
3511 }
3512
3513 /**
3514 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003515 * @param effectType The type of sound effect.
Jason Monk0c37ba32014-09-08 15:34:23 -04003516 * @param userId The current user to pull sound settings from
3517 * NOTE: This version uses the UI settings to determine
3518 * whether sounds are heard or not.
3519 * @hide
3520 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003521 public void playSoundEffect(@SystemSoundEffect int effectType, int userId) {
Jason Monk0c37ba32014-09-08 15:34:23 -04003522 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3523 return;
3524 }
3525
3526 if (!querySoundEffectsEnabled(userId)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003527 return;
3528 }
3529
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003530 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003531 try {
3532 service.playSoundEffect(effectType);
3533 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003534 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003535 }
3536 }
3537
3538 /**
3539 * Plays a sound effect (Key clicks, lid open/close...)
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003540 * @param effectType The type of sound effect.
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003541 * @param volume Sound effect volume.
3542 * The volume value is a raw scalar so UI controls should be scaled logarithmically.
3543 * If a volume of -1 is specified, the AudioManager.STREAM_MUSIC stream volume minus 3dB will be used.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003544 * NOTE: This version is for applications that have their own
3545 * settings panel for enabling and controlling volume.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003546 */
Philip Junkerdfcb12b2021-03-17 19:38:50 +01003547 public void playSoundEffect(@SystemSoundEffect int effectType, float volume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003548 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) {
3549 return;
3550 }
3551
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003552 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003553 try {
3554 service.playSoundEffectVolume(effectType, volume);
3555 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003556 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003557 }
3558 }
3559
3560 /**
3561 * Settings has an in memory cache, so this is fast.
3562 */
Jason Monk0c37ba32014-09-08 15:34:23 -04003563 private boolean querySoundEffectsEnabled(int user) {
Marco Nelissen29f16932015-04-17 09:50:56 -07003564 return Settings.System.getIntForUser(getContext().getContentResolver(),
Beverlyd6964762018-02-16 14:07:03 -05003565 Settings.System.SOUND_EFFECTS_ENABLED, 0, user) != 0;
Beverlye2d9a232017-11-08 18:14:59 -05003566 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003567
3568 /**
3569 * Load Sound effects.
3570 * This method must be called when sound effects are enabled.
3571 */
3572 public void loadSoundEffects() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003573 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003574 try {
3575 service.loadSoundEffects();
3576 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003577 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003578 }
3579 }
3580
3581 /**
3582 * Unload Sound effects.
3583 * This method can be called to free some memory when
3584 * sound effects are disabled.
3585 */
3586 public void unloadSoundEffects() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003587 final IAudioService service = getService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003588 try {
3589 service.unloadSoundEffects();
3590 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07003591 throw e.rethrowFromSystemServer();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003592 }
3593 }
3594
Eric Laurent4050c932009-07-08 02:52:14 -07003595 /**
Andy Hung69836952020-03-26 01:00:15 -07003596 * @hide
3597 */
3598 public static String audioFocusToString(int focus) {
3599 switch (focus) {
3600 case AUDIOFOCUS_NONE:
3601 return "AUDIOFOCUS_NONE";
3602 case AUDIOFOCUS_GAIN:
3603 return "AUDIOFOCUS_GAIN";
3604 case AUDIOFOCUS_GAIN_TRANSIENT:
3605 return "AUDIOFOCUS_GAIN_TRANSIENT";
3606 case AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK:
3607 return "AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK";
3608 case AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE:
3609 return "AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE";
3610 case AUDIOFOCUS_LOSS:
3611 return "AUDIOFOCUS_LOSS";
3612 case AUDIOFOCUS_LOSS_TRANSIENT:
3613 return "AUDIOFOCUS_LOSS_TRANSIENT";
3614 case AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // Note CAN_DUCK not MAY_DUCK.
3615 return "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK";
3616 default:
3617 return "AUDIO_FOCUS_UNKNOWN(" + focus + ")";
3618 }
3619 }
3620
3621 /**
Jean-Michel Trivi0f49f822017-02-16 14:36:43 -08003622 * Used to indicate no audio focus has been gained or lost, or requested.
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003623 */
3624 public static final int AUDIOFOCUS_NONE = 0;
3625
3626 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003627 * Used to indicate a gain of audio focus, or a request of audio focus, of unknown duration.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003628 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003629 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003630 */
3631 public static final int AUDIOFOCUS_GAIN = 1;
3632 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003633 * Used to indicate a temporary gain or request of audio focus, anticipated to last a short
3634 * amount of time. Examples of temporary changes are the playback of driving directions, or an
3635 * event notification.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003636 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003637 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003638 */
3639 public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2;
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003640 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003641 * Used to indicate a temporary request of audio focus, anticipated to last a short
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003642 * amount of time, and where it is acceptable for other audio applications to keep playing
3643 * after having lowered their output level (also referred to as "ducking").
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003644 * Examples of temporary changes are the playback of driving directions where playback of music
3645 * in the background is acceptable.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003646 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003647 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
3648 */
3649 public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3;
3650 /**
Jean-Michel Trivi23805662013-07-31 14:19:18 -07003651 * Used to indicate a temporary request of audio focus, anticipated to last a short
3652 * amount of time, during which no other applications, or system components, should play
3653 * anything. Examples of exclusive and transient audio focus requests are voice
3654 * memo recording and speech recognition, during which the system shouldn't play any
3655 * notifications, and media playback should have paused.
3656 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int)
3657 */
3658 public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4;
3659 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003660 * Used to indicate a loss of audio focus of unknown duration.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003661 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003662 */
3663 public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN;
3664 /**
3665 * Used to indicate a transient loss of audio focus.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003666 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003667 */
3668 public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT;
3669 /**
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003670 * Used to indicate a transient loss of audio focus where the loser of the audio focus can
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003671 * lower its output volume if it wants to continue playing (also referred to as "ducking"), as
3672 * the new focus owner doesn't require others to be silent.
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003673 * @see OnAudioFocusChangeListener#onAudioFocusChange(int)
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003674 */
3675 public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK =
3676 -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003677
3678 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003679 * Interface definition for a callback to be invoked when the audio focus of the system is
3680 * updated.
3681 */
3682 public interface OnAudioFocusChangeListener {
3683 /**
3684 * Called on the listener to notify it the audio focus for this listener has been changed.
3685 * The focusChange value indicates whether the focus was gained,
3686 * whether the focus was lost, and whether that loss is transient, or whether the new focus
3687 * holder will hold it for an unknown amount of time.
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003688 * When losing focus, listeners can use the focus change information to decide what
3689 * behavior to adopt when losing focus. A music player could for instance elect to lower
3690 * the volume of its music stream (duck) for transient focus losses, and pause otherwise.
3691 * @param focusChange the type of focus change, one of {@link AudioManager#AUDIOFOCUS_GAIN},
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003692 * {@link AudioManager#AUDIOFOCUS_LOSS}, {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003693 * and {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003694 */
Jean-Michel Trivi7f7e67f2010-03-31 11:30:24 -07003695 public void onAudioFocusChange(int focusChange);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003696 }
3697
3698 /**
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003699 * Internal class to hold the AudioFocusRequest as well as the Handler for the callback
3700 */
3701 private static class FocusRequestInfo {
3702 @NonNull final AudioFocusRequest mRequest;
3703 @Nullable final Handler mHandler;
3704 FocusRequestInfo(@NonNull AudioFocusRequest afr, @Nullable Handler handler) {
3705 mRequest = afr;
3706 mHandler = handler;
3707 }
3708 }
3709
3710 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003711 * Map to convert focus event listener IDs, as used in the AudioService audio focus stack,
3712 * to actual listener objects.
3713 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01003714 @UnsupportedAppUsage
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003715 private final ConcurrentHashMap<String, FocusRequestInfo> mAudioFocusIdListenerMap =
3716 new ConcurrentHashMap<String, FocusRequestInfo>();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003717
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003718 private FocusRequestInfo findFocusRequestInfo(String id) {
Jean-Michel Trivid327f212010-03-16 21:44:33 -07003719 return mAudioFocusIdListenerMap.get(id);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003720 }
3721
3722 /**
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003723 * Handler for events (audio focus change, recording config change) coming from the
3724 * audio service.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003725 */
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003726 private final ServiceEventHandlerDelegate mServiceEventHandlerDelegate =
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08003727 new ServiceEventHandlerDelegate(null);
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003728
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003729 /**
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003730 * Event types
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003731 */
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003732 private final static int MSSG_FOCUS_CHANGE = 0;
3733 private final static int MSSG_RECORDING_CONFIG_CHANGE = 1;
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003734 private final static int MSSG_PLAYBACK_CONFIG_CHANGE = 2;
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003735
3736 /**
3737 * Helper class to handle the forwarding of audio service events to the appropriate listener
3738 */
3739 private class ServiceEventHandlerDelegate {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003740 private final Handler mHandler;
3741
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08003742 ServiceEventHandlerDelegate(Handler handler) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003743 Looper looper;
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08003744 if (handler == null) {
3745 if ((looper = Looper.myLooper()) == null) {
3746 looper = Looper.getMainLooper();
3747 }
3748 } else {
3749 looper = handler.getLooper();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003750 }
3751
3752 if (looper != null) {
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003753 // implement the event handler delegate to receive events from audio service
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003754 mHandler = new Handler(looper) {
3755 @Override
3756 public void handleMessage(Message msg) {
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003757 switch (msg.what) {
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003758 case MSSG_FOCUS_CHANGE: {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003759 final FocusRequestInfo fri = findFocusRequestInfo((String)msg.obj);
3760 if (fri != null) {
3761 final OnAudioFocusChangeListener listener =
3762 fri.mRequest.getOnAudioFocusChangeListener();
3763 if (listener != null) {
3764 Log.d(TAG, "dispatching onAudioFocusChange("
3765 + msg.arg1 + ") to " + msg.obj);
3766 listener.onAudioFocusChange(msg.arg1);
3767 }
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003768 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003769 } break;
3770 case MSSG_RECORDING_CONFIG_CHANGE: {
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08003771 final RecordConfigChangeCallbackData cbData =
3772 (RecordConfigChangeCallbackData) msg.obj;
3773 if (cbData.mCb != null) {
Jean-Michel Trivie6a505b2016-04-01 09:56:28 -07003774 cbData.mCb.onRecordingConfigChanged(cbData.mConfigs);
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08003775 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08003776 } break;
3777 case MSSG_PLAYBACK_CONFIG_CHANGE: {
3778 final PlaybackConfigChangeCallbackData cbData =
3779 (PlaybackConfigChangeCallbackData) msg.obj;
3780 if (cbData.mCb != null) {
3781 if (DEBUG) {
3782 Log.d(TAG, "dispatching onPlaybackConfigChanged()");
3783 }
3784 cbData.mCb.onPlaybackConfigChanged(cbData.mConfigs);
3785 }
3786 } break;
Jean-Michel Trivi3b61d2d2016-01-07 10:50:09 -08003787 default:
3788 Log.e(TAG, "Unknown event " + msg.what);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003789 }
3790 }
3791 };
3792 } else {
3793 mHandler = null;
3794 }
3795 }
3796
3797 Handler getHandler() {
3798 return mHandler;
3799 }
3800 }
3801
Glenn Kasten30c918c2011-11-10 17:56:41 -08003802 private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003803 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003804 public void dispatchAudioFocusChange(int focusChange, String id) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003805 final FocusRequestInfo fri = findFocusRequestInfo(id);
3806 if (fri != null) {
3807 final OnAudioFocusChangeListener listener =
3808 fri.mRequest.getOnAudioFocusChangeListener();
3809 if (listener != null) {
3810 final Handler h = (fri.mHandler == null) ?
3811 mServiceEventHandlerDelegate.getHandler() : fri.mHandler;
3812 final Message m = h.obtainMessage(
3813 MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/,
3814 id/*obj*/);
3815 h.sendMessage(m);
3816 }
3817 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003818 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08003819
3820 @Override
3821 public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) {
3822 synchronized (mFocusRequestsLock) {
3823 // TODO use generation counter as the key instead
3824 final BlockingFocusResultReceiver focusReceiver =
3825 mFocusRequestsAwaitingResult.remove(clientId);
3826 if (focusReceiver != null) {
3827 focusReceiver.notifyResult(requestResult);
3828 } else {
3829 Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver");
3830 }
3831 }
3832 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003833 };
3834
Jean-Michel Trivid327f212010-03-16 21:44:33 -07003835 private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003836 if (l == null) {
Jean-Michel Trivi308e9a52010-03-17 15:04:20 -07003837 return new String(this.toString());
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003838 } else {
3839 return new String(this.toString() + l.toString());
3840 }
3841 }
3842
3843 /**
Xavier Ducrohet5f53f082010-05-11 14:19:40 -07003844 * @hide
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003845 * Registers a listener to be called when audio focus changes and keeps track of the associated
3846 * focus request (including Handler to use for the listener).
3847 * @param afr the full request parameters
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003848 */
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003849 public void registerAudioFocusRequest(@NonNull AudioFocusRequest afr) {
3850 final Handler h = afr.getOnAudioFocusChangeListenerHandler();
3851 final FocusRequestInfo fri = new FocusRequestInfo(afr, (h == null) ? null :
3852 new ServiceEventHandlerDelegate(h).getHandler());
3853 final String key = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
3854 mAudioFocusIdListenerMap.put(key, fri);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003855 }
3856
3857 /**
Xavier Ducrohet5f53f082010-05-11 14:19:40 -07003858 * @hide
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003859 * Causes the specified listener to not be called anymore when focus is gained or lost.
3860 * @param l the listener to unregister.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003861 */
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003862 public void unregisterAudioFocusRequest(OnAudioFocusChangeListener l) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003863 // remove locally
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07003864 mAudioFocusIdListenerMap.remove(getIdForAudioFocusListener(l));
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003865 }
3866
3867
3868 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003869 * A failed focus change request.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003870 */
3871 public static final int AUDIOFOCUS_REQUEST_FAILED = 0;
3872 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003873 * A successful focus change request.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003874 */
3875 public static final int AUDIOFOCUS_REQUEST_GRANTED = 1;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003876 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003877 * A focus change request whose granting is delayed: the request was successful, but the
3878 * requester will only be granted audio focus once the condition that prevented immediate
3879 * granting has ended.
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08003880 * See {@link #requestAudioFocus(AudioFocusRequest)} and
3881 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)}
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003882 */
3883 public static final int AUDIOFOCUS_REQUEST_DELAYED = 2;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003884
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08003885 /** @hide */
3886 @IntDef(flag = false, prefix = "AUDIOFOCUS_REQUEST", value = {
3887 AUDIOFOCUS_REQUEST_FAILED,
3888 AUDIOFOCUS_REQUEST_GRANTED,
3889 AUDIOFOCUS_REQUEST_DELAYED }
3890 )
3891 @Retention(RetentionPolicy.SOURCE)
3892 public @interface FocusRequestResult {}
3893
3894 /**
3895 * @hide
3896 * code returned when a synchronous focus request on the client-side is to be blocked
3897 * until the external audio focus policy decides on the response for the client
3898 */
3899 public static final int AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY = 100;
3900
3901 /**
3902 * Timeout duration in ms when waiting on an external focus policy for the result for a
3903 * focus request
3904 */
3905 private static final int EXT_FOCUS_POLICY_TIMEOUT_MS = 200;
3906
3907 private static final String FOCUS_CLIENT_ID_STRING = "android_audio_focus_client_id";
3908
3909 private final Object mFocusRequestsLock = new Object();
3910 /**
3911 * Map of all receivers of focus request results, one per unresolved focus request.
3912 * Receivers are added before sending the request to the external focus policy,
3913 * and are removed either after receiving the result, or after the timeout.
3914 * This variable is lazily initialized.
3915 */
3916 @GuardedBy("mFocusRequestsLock")
3917 private HashMap<String, BlockingFocusResultReceiver> mFocusRequestsAwaitingResult;
3918
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003919
3920 /**
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003921 * Request audio focus.
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07003922 * Send a request to obtain the audio focus
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003923 * @param l the listener to be notified of audio focus changes
3924 * @param streamType the main audio stream type affected by the focus request
3925 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
3926 * is temporary, and focus will be abandonned shortly. Examples of transient requests are
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003927 * for the playback of driving directions, or notifications sounds.
Jean-Michel Trivi983ac2b2010-03-19 12:09:25 -07003928 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
3929 * the previous focus owner to keep playing if it ducks its audio output.
Jean-Michel Trivi9171db22013-07-31 17:11:12 -07003930 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
3931 * that benefits from the system not playing disruptive sounds like notifications, for
3932 * usecases such as voice memo recording, or speech recognition.
Jean-Michel Trivi078fd472010-03-18 16:51:04 -07003933 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003934 * as the playback of a song or a video.
3935 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08003936 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest)}
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003937 */
3938 public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) {
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08003939 PlayerBase.deprecateStreamTypeForPlayback(streamType,
3940 "AudioManager", "requestAudioFocus()");
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08003941 int status = AUDIOFOCUS_REQUEST_FAILED;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003942
3943 try {
3944 // status is guaranteed to be either AUDIOFOCUS_REQUEST_FAILED or
3945 // AUDIOFOCUS_REQUEST_GRANTED as focus is requested without the
3946 // AUDIOFOCUS_FLAG_DELAY_OK flag
3947 status = requestAudioFocus(l,
3948 new AudioAttributes.Builder()
3949 .setInternalLegacyStreamType(streamType).build(),
3950 durationHint,
3951 0 /* flags, legacy behavior */);
3952 } catch (IllegalArgumentException e) {
3953 Log.e(TAG, "Audio focus request denied due to ", e);
3954 }
3955
3956 return status;
3957 }
3958
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08003959 // when adding new flags, add them to the relevant AUDIOFOCUS_FLAGS_APPS or SYSTEM masks
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08003960 /**
3961 * @hide
3962 * Use this flag when requesting audio focus to indicate it is ok for the requester to not be
3963 * granted audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when
3964 * the system is in a state where focus cannot change, but be granted focus later when
3965 * this condition ends.
3966 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08003967 @SystemApi
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08003968 public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08003969 /**
3970 * @hide
3971 * Use this flag when requesting audio focus to indicate that the requester
3972 * will pause its media playback (if applicable) when losing audio focus with
3973 * {@link #AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}, rather than ducking.
3974 * <br>On some platforms, the ducking may be handled without the application being aware of it
3975 * (i.e. it will not transiently lose focus). For applications that for instance play spoken
3976 * content, such as audio book or podcast players, ducking may never be acceptable, and will
3977 * thus always pause. This flag enables them to be declared as such whenever they request focus.
3978 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08003979 @SystemApi
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08003980 public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 0x1 << 1;
3981 /**
3982 * @hide
3983 * Use this flag to lock audio focus so granting is temporarily disabled.
3984 * <br>This flag can only be used by owners of a registered
3985 * {@link android.media.audiopolicy.AudioPolicy} in
3986 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int, AudioPolicy)}
3987 */
3988 @SystemApi
3989 public static final int AUDIOFOCUS_FLAG_LOCK = 0x1 << 2;
Jean-Michel Trivi28602092021-03-24 11:14:47 -07003990
3991 /**
3992 * @hide
3993 * flag set on test API calls,
3994 * see {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)},
3995 * note that it isn't used in conjunction with other flags, it is passed as the single
3996 * value for flags */
3997 public static final int AUDIOFOCUS_FLAG_TEST = 0x1 << 3;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08003998 /** @hide */
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08003999 public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK
4000 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004001 /** @hide */
4002 public static final int AUDIOFOCUS_FLAGS_SYSTEM = AUDIOFOCUS_FLAG_DELAY_OK
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004003 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS | AUDIOFOCUS_FLAG_LOCK;
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004004
4005 /**
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004006 * Request audio focus.
4007 * See the {@link AudioFocusRequest} for information about the options available to configure
4008 * your request, and notification of focus gain and loss.
4009 * @param focusRequest a {@link AudioFocusRequest} instance used to configure how focus is
4010 * requested.
4011 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4012 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4013 * <br>Note that the return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus
4014 * is requested without building the {@link AudioFocusRequest} with
4015 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} set to
4016 * {@code true}.
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004017 * @throws NullPointerException if passed a null argument
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004018 */
4019 public int requestAudioFocus(@NonNull AudioFocusRequest focusRequest) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004020 return requestAudioFocus(focusRequest, null /* no AudioPolicy*/);
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004021 }
4022
4023 /**
4024 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4025 * @param focusRequest the {@link AudioFocusRequest} that was used when requesting focus
4026 * with {@link #requestAudioFocus(AudioFocusRequest)}.
4027 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
4028 * @throws IllegalArgumentException if passed a null argument
4029 */
4030 public int abandonAudioFocusRequest(@NonNull AudioFocusRequest focusRequest) {
4031 if (focusRequest == null) {
4032 throw new IllegalArgumentException("Illegal null AudioFocusRequest");
4033 }
4034 return abandonAudioFocus(focusRequest.getOnAudioFocusChangeListener(),
4035 focusRequest.getAudioAttributes());
4036 }
4037
4038 /**
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004039 * @hide
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004040 * Request audio focus.
4041 * Send a request to obtain the audio focus. This method differs from
4042 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)} in that it can express
4043 * that the requester accepts delayed grants of audio focus.
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004044 * @param l the listener to be notified of audio focus changes. It is not allowed to be null
4045 * when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}.
4046 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4047 * requesting audio focus.
4048 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request
4049 * is temporary, and focus will be abandonned shortly. Examples of transient requests are
4050 * for the playback of driving directions, or notifications sounds.
4051 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for
4052 * the previous focus owner to keep playing if it ducks its audio output.
4053 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request
4054 * that benefits from the system not playing disruptive sounds like notifications, for
4055 * usecases such as voice memo recording, or speech recognition.
4056 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such
4057 * as the playback of a song or a video.
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004058 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
4059 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS} and {@link #AUDIOFOCUS_FLAG_LOCK}.
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004060 * <br>Use 0 when not using any flags for the request, which behaves like
4061 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4062 * focus is granted immediately, or the grant request fails because the system is in a
4063 * state where focus cannot change (e.g. a phone call).
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004064 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4065 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4066 * The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested
4067 * without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag.
4068 * @throws IllegalArgumentException
4069 */
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004070 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004071 @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004072 public int requestAudioFocus(OnAudioFocusChangeListener l,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004073 @NonNull AudioAttributes requestAttributes,
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004074 int durationHint,
4075 int flags) throws IllegalArgumentException {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004076 if (flags != (flags & AUDIOFOCUS_FLAGS_APPS)) {
4077 throw new IllegalArgumentException("Invalid flags 0x"
4078 + Integer.toHexString(flags).toUpperCase());
4079 }
4080 return requestAudioFocus(l, requestAttributes, durationHint,
4081 flags & AUDIOFOCUS_FLAGS_APPS,
4082 null /* no AudioPolicy*/);
4083 }
4084
4085 /**
4086 * @hide
4087 * Request or lock audio focus.
4088 * This method is to be used by system components that have registered an
4089 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4090 * so focus granting is temporarily disabled.
4091 * @param l see the description of the same parameter in
4092 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4093 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for
4094 * requesting audio focus.
4095 * @param durationHint see the description of the same parameter in
4096 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4097 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK},
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004098 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS}, and {@link #AUDIOFOCUS_FLAG_LOCK}.
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004099 * <br>Use 0 when not using any flags for the request, which behaves like
4100 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio
4101 * focus is granted immediately, or the grant request fails because the system is in a
4102 * state where focus cannot change (e.g. a phone call).
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004103 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4104 * focus, or null.
4105 * @return see the description of the same return value in
4106 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)}
4107 * @throws IllegalArgumentException
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004108 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest, AudioPolicy)}
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004109 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004110 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004111 @RequiresPermission(anyOf= {
4112 android.Manifest.permission.MODIFY_PHONE_STATE,
4113 android.Manifest.permission.MODIFY_AUDIO_ROUTING
4114 })
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004115 public int requestAudioFocus(OnAudioFocusChangeListener l,
4116 @NonNull AudioAttributes requestAttributes,
4117 int durationHint,
4118 int flags,
4119 AudioPolicy ap) throws IllegalArgumentException {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004120 // parameter checking
4121 if (requestAttributes == null) {
4122 throw new IllegalArgumentException("Illegal null AudioAttributes argument");
4123 }
Jean-Michel Trivi3db31ac2017-02-24 11:40:37 -08004124 if (!AudioFocusRequest.isValidFocusGain(durationHint)) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004125 throw new IllegalArgumentException("Invalid duration hint");
Jean-Michel Trivi55d1bb32010-04-01 17:40:58 -07004126 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004127 if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004128 throw new IllegalArgumentException("Illegal flags 0x"
4129 + Integer.toHexString(flags).toUpperCase());
4130 }
4131 if (((flags & AUDIOFOCUS_FLAG_DELAY_OK) == AUDIOFOCUS_FLAG_DELAY_OK) && (l == null)) {
4132 throw new IllegalArgumentException(
4133 "Illegal null focus listener when flagged as accepting delayed focus grant");
4134 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004135 if (((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4136 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) && (l == null)) {
4137 throw new IllegalArgumentException(
4138 "Illegal null focus listener when flagged as pausing instead of ducking");
4139 }
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004140 if (((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) && (ap == null)) {
4141 throw new IllegalArgumentException(
4142 "Illegal null audio policy when locking audio focus");
4143 }
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004144
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004145 final AudioFocusRequest afr = new AudioFocusRequest.Builder(durationHint)
Jean-Michel Trivi36728ce2017-05-01 12:33:40 -07004146 .setOnAudioFocusChangeListenerInt(l, null /* no Handler for this legacy API */)
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004147 .setAudioAttributes(requestAttributes)
4148 .setAcceptsDelayedFocusGain((flags & AUDIOFOCUS_FLAG_DELAY_OK)
4149 == AUDIOFOCUS_FLAG_DELAY_OK)
4150 .setWillPauseWhenDucked((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4151 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS)
4152 .setLocksFocus((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK)
4153 .build();
4154 return requestAudioFocus(afr, ap);
4155 }
4156
4157 /**
4158 * @hide
Jean-Michel Trivi28602092021-03-24 11:14:47 -07004159 * Test API to request audio focus for an arbitrary client operating from a (fake) given UID.
4160 * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4161 * @param afr the parameters of the request
4162 * @param clientFakeId the identifier of the AudioManager the client would be requesting from
4163 * @param clientFakeUid the UID of the client, here an arbitrary int,
4164 * doesn't have to be a real UID
4165 * @param clientTargetSdk the target SDK used by the client
4166 * @return return code indicating status of the request
4167 */
4168 @TestApi
4169 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4170 public @FocusRequestResult int requestAudioFocusForTest(@NonNull AudioFocusRequest afr,
4171 @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk) {
4172 Objects.requireNonNull(afr);
4173 Objects.requireNonNull(clientFakeId);
4174 try {
4175 return getService().requestAudioFocusForTest(afr.getAudioAttributes(),
4176 afr.getFocusGain(),
4177 mICallBack,
4178 mAudioFocusDispatcher,
4179 clientFakeId, "com.android.test.fakeclient", clientFakeUid, clientTargetSdk);
4180 } catch (RemoteException e) {
4181 throw e.rethrowFromSystemServer();
4182 }
4183 }
4184
4185 /**
4186 * @hide
4187 * Test API to abandon audio focus for an arbitrary client.
4188 * Used to simulate conditions of the test, not the behavior of the focus requester under test.
4189 * @param afr the parameters used for the request
4190 * @param clientFakeId clientFakeId the identifier of the AudioManager from which the client
4191 * would be requesting
4192 * @return return code indicating status of the request
4193 */
4194 @TestApi
4195 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4196 public @FocusRequestResult int abandonAudioFocusForTest(@NonNull AudioFocusRequest afr,
4197 @NonNull String clientFakeId) {
4198 Objects.requireNonNull(afr);
4199 Objects.requireNonNull(clientFakeId);
4200 try {
4201 return getService().abandonAudioFocusForTest(mAudioFocusDispatcher,
4202 clientFakeId, afr.getAudioAttributes(), "com.android.test.fakeclient");
4203 } catch (RemoteException e) {
4204 throw e.rethrowFromSystemServer();
4205 }
4206 }
4207
4208 /**
4209 * @hide
4210 * Return the duration of the fade out applied when a player of the given AudioAttributes
4211 * is losing audio focus
4212 * @param aa the AudioAttributes of the player losing focus with {@link #AUDIOFOCUS_LOSS}
4213 * @return a duration in ms, 0 indicates no fade out is applied
4214 */
4215 @TestApi
4216 @RequiresPermission("android.permission.QUERY_AUDIO_STATE")
4217 public @IntRange(from = 0) long getFadeOutDurationOnFocusLossMillis(@NonNull AudioAttributes aa)
4218 {
4219 Objects.requireNonNull(aa);
4220 try {
4221 return getService().getFadeOutDurationOnFocusLossMillis(aa);
4222 } catch (RemoteException e) {
4223 throw e.rethrowFromSystemServer();
4224 }
4225 }
4226
4227 /**
4228 * @hide
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004229 * Request or lock audio focus.
4230 * This method is to be used by system components that have registered an
4231 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it
4232 * so focus granting is temporarily disabled.
4233 * @param afr see the description of the same parameter in
4234 * {@link #requestAudioFocus(AudioFocusRequest)}
4235 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking
4236 * focus, or null.
4237 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED}
4238 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}.
4239 * @throws NullPointerException if the AudioFocusRequest is null
4240 * @throws IllegalArgumentException when trying to lock focus without an AudioPolicy
4241 */
4242 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004243 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004244 public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) {
4245 if (afr == null) {
4246 throw new NullPointerException("Illegal null AudioFocusRequest");
4247 }
4248 // this can only be checked now, not during the creation of the AudioFocusRequest instance
4249 if (afr.locksFocus() && ap == null) {
4250 throw new IllegalArgumentException(
4251 "Illegal null audio policy when locking audio focus");
4252 }
4253 registerAudioFocusRequest(afr);
4254 final IAudioService service = getService();
4255 final int status;
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07004256 int sdk;
4257 try {
4258 sdk = getContext().getApplicationInfo().targetSdkVersion;
4259 } catch (NullPointerException e) {
4260 // some tests don't have a Context
4261 sdk = Build.VERSION.SDK_INT;
4262 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004263
4264 final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener());
4265 final BlockingFocusResultReceiver focusReceiver;
4266 synchronized (mFocusRequestsLock) {
4267 try {
4268 // TODO status contains result and generation counter for ext policy
4269 status = service.requestAudioFocus(afr.getAudioAttributes(),
4270 afr.getFocusGain(), mICallBack,
4271 mAudioFocusDispatcher,
4272 clientId,
John Wu4f7e5102021-06-22 17:29:11 +00004273 getContext().getOpPackageName() /* package name */,
4274 getContext().getAttributionTag(),
4275 afr.getFlags(),
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004276 ap != null ? ap.cb() : null,
4277 sdk);
4278 } catch (RemoteException e) {
4279 throw e.rethrowFromSystemServer();
4280 }
4281 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) {
4282 // default path with no external focus policy
4283 return status;
4284 }
4285 if (mFocusRequestsAwaitingResult == null) {
4286 mFocusRequestsAwaitingResult =
4287 new HashMap<String, BlockingFocusResultReceiver>(1);
4288 }
4289 focusReceiver = new BlockingFocusResultReceiver(clientId);
4290 mFocusRequestsAwaitingResult.put(clientId, focusReceiver);
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004291 }
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004292 focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS);
4293 if (DEBUG && !focusReceiver.receivedResult()) {
4294 Log.e(TAG, "requestAudio response from ext policy timed out, denying request");
4295 }
4296 synchronized (mFocusRequestsLock) {
4297 mFocusRequestsAwaitingResult.remove(clientId);
4298 }
4299 return focusReceiver.requestResult();
4300 }
4301
4302 // helper class that abstracts out the handling of spurious wakeups in Object.wait()
4303 private static final class SafeWaitObject {
4304 private boolean mQuit = false;
4305
4306 public void safeNotify() {
4307 synchronized (this) {
4308 mQuit = true;
4309 this.notify();
4310 }
4311 }
4312
4313 public void safeWait(long millis) throws InterruptedException {
4314 final long timeOutTime = java.lang.System.currentTimeMillis() + millis;
4315 synchronized (this) {
4316 while (!mQuit) {
4317 final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis();
4318 if (timeToWait < 0) { break; }
4319 this.wait(timeToWait);
4320 }
4321 }
4322 }
4323 }
4324
4325 private static final class BlockingFocusResultReceiver {
4326 private final SafeWaitObject mLock = new SafeWaitObject();
4327 @GuardedBy("mLock")
4328 private boolean mResultReceived = false;
4329 // request denied by default (e.g. timeout)
4330 private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4331 private final String mFocusClientId;
4332
4333 BlockingFocusResultReceiver(String clientId) {
4334 mFocusClientId = clientId;
4335 }
4336
4337 boolean receivedResult() { return mResultReceived; }
4338 int requestResult() { return mFocusRequestResult; }
4339
4340 void notifyResult(int requestResult) {
4341 synchronized (mLock) {
4342 mResultReceived = true;
4343 mFocusRequestResult = requestResult;
4344 mLock.safeNotify();
4345 }
4346 }
4347
4348 public void waitForResult(long timeOutMs) {
4349 synchronized (mLock) {
4350 if (mResultReceived) {
4351 // the result was received before waiting
4352 return;
4353 }
4354 try {
4355 mLock.safeWait(timeOutMs);
4356 } catch (InterruptedException e) { }
4357 }
4358 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004359 }
4360
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004361 /**
4362 * @hide
4363 * Used internally by telephony package to request audio focus. Will cause the focus request
4364 * to be associated with the "voice communication" identifier only used in AudioService
4365 * to identify this use case.
4366 * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for
4367 * the establishment of the call
4368 * @param durationHint the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so
4369 * media applications resume after a call
4370 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00004371 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004372 public void requestAudioFocusForCall(int streamType, int durationHint) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004373 final IAudioService service = getService();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004374 try {
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004375 service.requestAudioFocus(new AudioAttributes.Builder()
4376 .setInternalLegacyStreamType(streamType).build(),
4377 durationHint, mICallBack, null,
John Spurlock61560172015-02-06 19:46:04 -05004378 AudioSystem.IN_VOICE_COMM_FOCUS_ID,
Marco Nelissen29f16932015-04-17 09:50:56 -07004379 getContext().getOpPackageName(),
John Wu4f7e5102021-06-22 17:29:11 +00004380 getContext().getAttributionTag(),
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004381 AUDIOFOCUS_FLAG_LOCK,
Jean-Michel Trivi461922f2017-04-25 15:23:17 -07004382 null /* policy token */, 0 /* sdk n/a here*/);
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004383 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004384 throw e.rethrowFromSystemServer();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004385 }
4386 }
4387
4388 /**
4389 * @hide
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08004390 * Return the volume ramping time for a sound to be played after the given focus request,
4391 * and to play a sound of the given attributes
4392 * @param focusGain
4393 * @param attr
4394 * @return
4395 */
4396 public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004397 final IAudioService service = getService();
Jean-Michel Trivi99489cc2017-01-25 19:08:49 -08004398 try {
4399 return service.getFocusRampTimeMs(focusGain, attr);
4400 } catch (RemoteException e) {
4401 throw e.rethrowFromSystemServer();
4402 }
4403 }
4404
4405 /**
4406 * @hide
Jean-Michel Trivie2d8aae2018-01-30 15:09:47 -08004407 * Set the result to the audio focus request received through
4408 * {@link AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
4409 * @param afi the information about the focus requester
4410 * @param requestResult the result to the focus request to be passed to the requester
4411 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
4412 */
4413 @SystemApi
4414 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
4415 public void setFocusRequestResult(@NonNull AudioFocusInfo afi,
4416 @FocusRequestResult int requestResult, @NonNull AudioPolicy ap) {
4417 if (afi == null) {
4418 throw new IllegalArgumentException("Illegal null AudioFocusInfo");
4419 }
4420 if (ap == null) {
4421 throw new IllegalArgumentException("Illegal null AudioPolicy");
4422 }
4423 final IAudioService service = getService();
4424 try {
4425 service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb());
4426 } catch (RemoteException e) {
4427 throw e.rethrowFromSystemServer();
4428 }
4429 }
4430
4431 /**
4432 * @hide
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004433 * Notifies an application with a focus listener of gain or loss of audio focus.
4434 * This method can only be used by owners of an {@link AudioPolicy} configured with
4435 * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true.
4436 * @param afi the recipient of the focus change, that has previously requested audio focus, and
4437 * that was received by the {@code AudioPolicy} through
4438 * {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}.
4439 * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN},
4440 * {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or
4441 * {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE})
4442 * or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS},
4443 * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT},
4444 * or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}).
4445 * <br>For the focus gain, the change type should be the same as the app requested.
4446 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy.
4447 * @return {@link #AUDIOFOCUS_REQUEST_GRANTED} if the dispatch was successfully sent, or
4448 * {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener, or
4449 * if there was an error sending the request.
4450 * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null.
4451 */
4452 @SystemApi
Jean-Michel Trivi26ae15f2017-08-25 19:20:49 -07004453 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004454 public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange,
4455 @NonNull AudioPolicy ap) {
4456 if (afi == null) {
4457 throw new NullPointerException("Illegal null AudioFocusInfo");
4458 }
4459 if (ap == null) {
4460 throw new NullPointerException("Illegal null AudioPolicy");
4461 }
4462 final IAudioService service = getService();
4463 try {
4464 return service.dispatchFocusChange(afi, focusChange, ap.cb());
4465 } catch (RemoteException e) {
4466 throw e.rethrowFromSystemServer();
4467 }
4468 }
4469
4470 /**
4471 * @hide
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004472 * Used internally by telephony package to abandon audio focus, typically after a call or
4473 * when ringing ends and the call is rejected or not answered.
4474 * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}.
4475 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00004476 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004477 public void abandonAudioFocusForCall() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004478 final IAudioService service = getService();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004479 try {
John Spurlock61560172015-02-06 19:46:04 -05004480 service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004481 null /*AudioAttributes, legacy behavior*/, getContext().getOpPackageName());
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004482 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004483 throw e.rethrowFromSystemServer();
Jean-Michel Trivi4dd36742012-01-24 09:52:39 -08004484 }
4485 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004486
4487 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004488 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4489 * @param l the listener with which focus was requested.
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004490 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi36bdb662017-03-09 11:56:51 -08004491 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004492 */
4493 public int abandonAudioFocus(OnAudioFocusChangeListener l) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004494 return abandonAudioFocus(l, null /*AudioAttributes, legacy behavior*/);
4495 }
4496
4497 /**
4498 * @hide
4499 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus.
4500 * @param l the listener with which focus was requested.
4501 * @param aa the {@link AudioAttributes} with which audio focus was requested
4502 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED}
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004503 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)}
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004504 */
4505 @SystemApi
Aurimas Liutikas1394a012020-11-12 18:26:09 -08004506 @SuppressLint("RequiresPermission") // no permission enforcement, but only "undoes" what would
4507 // have been done by a matching requestAudioFocus
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004508 public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) {
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004509 int status = AUDIOFOCUS_REQUEST_FAILED;
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004510 unregisterAudioFocusRequest(l);
4511 final IAudioService service = getService();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004512 try {
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004513 status = service.abandonAudioFocus(mAudioFocusDispatcher,
Jean-Michel Trivi126cf032017-04-02 23:19:02 -07004514 getIdForAudioFocusListener(l), aa, getContext().getOpPackageName());
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004515 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004516 throw e.rethrowFromSystemServer();
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004517 }
4518 return status;
4519 }
4520
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004521 //====================================================================
4522 // Remote Control
4523 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004524 * Register a component to be the sole receiver of MEDIA_BUTTON intents.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004525 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
4526 * that will receive the media button intent. This broadcast receiver must be declared
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004527 * in the application manifest. The package of the component must match that of
4528 * the context you're registering from.
RoboErikb214efb2014-07-24 13:20:30 -07004529 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004530 */
RoboErikb214efb2014-07-24 13:20:30 -07004531 @Deprecated
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004532 public void registerMediaButtonEventReceiver(ComponentName eventReceiver) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004533 if (eventReceiver == null) {
4534 return;
4535 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004536 if (!eventReceiver.getPackageName().equals(getContext().getPackageName())) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004537 Log.e(TAG, "registerMediaButtonEventReceiver() error: " +
4538 "receiver and context package names don't match");
4539 return;
4540 }
4541 // construct a PendingIntent for the media button and register it
4542 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4543 // the associated intent will be handled by the component being registered
4544 mediaButtonIntent.setComponent(eventReceiver);
Marco Nelissen29f16932015-04-17 09:50:56 -07004545 PendingIntent pi = PendingIntent.getBroadcast(getContext(),
Jean-Michel Triviec84dae2020-10-22 17:12:37 -07004546 0/*requestCode, ignored*/, mediaButtonIntent,
4547 PendingIntent.FLAG_IMMUTABLE);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004548 registerMediaButtonIntent(pi, eventReceiver);
4549 }
4550
4551 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -07004552 * Register a component to be the sole receiver of MEDIA_BUTTON intents. This is like
4553 * {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows
4554 * the buttons to go to any PendingIntent. Note that you should only use this form if
4555 * you know you will continue running for the full time until unregistering the
4556 * PendingIntent.
4557 * @param eventReceiver target that will receive media button intents. The PendingIntent
RoboErikb214efb2014-07-24 13:20:30 -07004558 * will be sent an {@link Intent#ACTION_MEDIA_BUTTON} event when a media button action
4559 * occurs, with {@link Intent#EXTRA_KEY_EVENT} added and holding the key code of the
4560 * media button that was pressed.
4561 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead.
Dianne Hackborn961cae92013-03-20 14:59:43 -07004562 */
RoboErikb214efb2014-07-24 13:20:30 -07004563 @Deprecated
Dianne Hackborn961cae92013-03-20 14:59:43 -07004564 public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) {
4565 if (eventReceiver == null) {
4566 return;
4567 }
4568 registerMediaButtonIntent(eventReceiver, null);
4569 }
4570
4571 /**
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004572 * @hide
4573 * no-op if (pi == null) or (eventReceiver == null)
4574 */
4575 public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) {
Dianne Hackborn961cae92013-03-20 14:59:43 -07004576 if (pi == null) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004577 Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter");
4578 return;
4579 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004580 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
4581 helper.addMediaButtonListener(pi, eventReceiver, getContext());
Jean-Michel Trivi722b8082012-05-15 15:18:33 -07004582 }
4583
4584 /**
Jean-Michel Trivi46b3a182010-05-11 11:22:54 -07004585 * Unregister the receiver of MEDIA_BUTTON intents.
4586 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver}
4587 * that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}.
RoboErikb214efb2014-07-24 13:20:30 -07004588 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004589 */
RoboErikb214efb2014-07-24 13:20:30 -07004590 @Deprecated
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004591 public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004592 if (eventReceiver == null) {
4593 return;
4594 }
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004595 // construct a PendingIntent for the media button and unregister it
4596 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4597 // the associated intent will be handled by the component being registered
4598 mediaButtonIntent.setComponent(eventReceiver);
Marco Nelissen29f16932015-04-17 09:50:56 -07004599 PendingIntent pi = PendingIntent.getBroadcast(getContext(),
Jean-Michel Triviec84dae2020-10-22 17:12:37 -07004600 0/*requestCode, ignored*/, mediaButtonIntent,
4601 PendingIntent.FLAG_IMMUTABLE);
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004602 unregisterMediaButtonIntent(pi);
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004603 }
4604
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004605 /**
Dianne Hackborn961cae92013-03-20 14:59:43 -07004606 * Unregister the receiver of MEDIA_BUTTON intents.
4607 * @param eventReceiver same PendingIntent that was registed with
4608 * {@link #registerMediaButtonEventReceiver(PendingIntent)}.
RoboErikb214efb2014-07-24 13:20:30 -07004609 * @deprecated Use {@link MediaSession} instead.
Dianne Hackborn961cae92013-03-20 14:59:43 -07004610 */
RoboErikb214efb2014-07-24 13:20:30 -07004611 @Deprecated
Dianne Hackborn961cae92013-03-20 14:59:43 -07004612 public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) {
4613 if (eventReceiver == null) {
4614 return;
4615 }
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004616 unregisterMediaButtonIntent(eventReceiver);
Dianne Hackborn961cae92013-03-20 14:59:43 -07004617 }
4618
4619 /**
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004620 * @hide
4621 */
Jean-Michel Trivib839b832013-03-30 14:17:45 -07004622 public void unregisterMediaButtonIntent(PendingIntent pi) {
Marco Nelissen29f16932015-04-17 09:50:56 -07004623 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext());
RoboErik430fc482014-06-12 15:49:20 -07004624 helper.removeMediaButtonListener(pi);
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004625 }
Jean-Michel Trivi178889e2011-08-15 17:17:52 -07004626
4627 /**
Jean-Michel Trivi178889e2011-08-15 17:17:52 -07004628 * Registers the remote control client for providing information to display on the remote
4629 * controls.
Jean-Michel Trivi466ade52011-09-01 10:02:30 -07004630 * @param rcClient The remote control client from which remote controls will receive
4631 * information to display.
4632 * @see RemoteControlClient
RoboErikb214efb2014-07-24 13:20:30 -07004633 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004634 */
RoboErikb214efb2014-07-24 13:20:30 -07004635 @Deprecated
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004636 public void registerRemoteControlClient(RemoteControlClient rcClient) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004637 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004638 return;
4639 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004640 rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004641 }
4642
4643 /**
Jean-Michel Trivifcd693a2011-08-11 13:53:55 -07004644 * Unregisters the remote control client that was providing information to display on the
Jean-Michel Trivi466ade52011-09-01 10:02:30 -07004645 * remote controls.
4646 * @param rcClient The remote control client to unregister.
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004647 * @see #registerRemoteControlClient(RemoteControlClient)
RoboErikb214efb2014-07-24 13:20:30 -07004648 * @deprecated Use {@link MediaSession} instead.
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004649 */
RoboErikb214efb2014-07-24 13:20:30 -07004650 @Deprecated
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004651 public void unregisterRemoteControlClient(RemoteControlClient rcClient) {
Jean-Michel Trivif0cff042011-09-14 18:11:09 -07004652 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) {
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004653 return;
4654 }
Marco Nelissen29f16932015-04-17 09:50:56 -07004655 rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(getContext()));
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004656 }
4657
Jean-Michel Trivi44413e52011-08-23 18:20:03 -07004658 /**
RoboErika66c40b2014-08-15 15:21:41 -07004659 * Registers a {@link RemoteController} instance for it to receive media
4660 * metadata updates and playback state information from applications using
4661 * {@link RemoteControlClient}, and control their playback.
4662 * <p>
John Spurlockee5ad722015-03-03 16:17:21 -05004663 * Registration requires the {@link RemoteController.OnClientUpdateListener} listener to be
RoboErika66c40b2014-08-15 15:21:41 -07004664 * one of the enabled notification listeners (see
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004665 * {@link android.service.notification.NotificationListenerService}).
RoboErika66c40b2014-08-15 15:21:41 -07004666 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -07004667 * @param rctlr the object to register.
RoboErika66c40b2014-08-15 15:21:41 -07004668 * @return true if the {@link RemoteController} was successfully registered,
4669 * false if an error occurred, due to an internal system error, or
4670 * insufficient permissions.
RoboErikb214efb2014-07-24 13:20:30 -07004671 * @deprecated Use
RoboErika66c40b2014-08-15 15:21:41 -07004672 * {@link MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, ComponentName)}
4673 * and {@link MediaController} instead.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004674 */
RoboErikb214efb2014-07-24 13:20:30 -07004675 @Deprecated
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004676 public boolean registerRemoteController(RemoteController rctlr) {
4677 if (rctlr == null) {
4678 return false;
4679 }
RoboErik430fc482014-06-12 15:49:20 -07004680 rctlr.startListeningToSessions();
4681 return true;
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004682 }
4683
4684 /**
RoboErika66c40b2014-08-15 15:21:41 -07004685 * Unregisters a {@link RemoteController}, causing it to no longer receive
4686 * media metadata and playback state information, and no longer be capable
4687 * of controlling playback.
4688 *
Jean-Michel Trivia83487e2013-09-17 21:19:30 -07004689 * @param rctlr the object to unregister.
RoboErikb214efb2014-07-24 13:20:30 -07004690 * @deprecated Use
RoboErika66c40b2014-08-15 15:21:41 -07004691 * {@link MediaSessionManager#removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener)}
4692 * instead.
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004693 */
RoboErikb214efb2014-07-24 13:20:30 -07004694 @Deprecated
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004695 public void unregisterRemoteController(RemoteController rctlr) {
4696 if (rctlr == null) {
4697 return;
4698 }
RoboErik430fc482014-06-12 15:49:20 -07004699 rctlr.stopListeningToSessions();
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004700 }
4701
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07004702
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08004703 //====================================================================
4704 // Audio policy
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07004705 /**
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004706 * @hide
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004707 * Register the given {@link AudioPolicy}.
4708 * This call is synchronous and blocks until the registration process successfully completed
4709 * or failed to complete.
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004710 * @param policy the non-null {@link AudioPolicy} to register.
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004711 * @return {@link #ERROR} if there was an error communicating with the registration service
4712 * or if the user doesn't have the required
4713 * {@link android.Manifest.permission#MODIFY_AUDIO_ROUTING} permission,
4714 * {@link #SUCCESS} otherwise.
4715 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004716 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06004717 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004718 public int registerAudioPolicy(@NonNull AudioPolicy policy) {
Robert Berry669be042019-01-22 18:48:35 -05004719 return registerAudioPolicyStatic(policy);
4720 }
4721
4722 static int registerAudioPolicyStatic(@NonNull AudioPolicy policy) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004723 if (policy == null) {
4724 throw new IllegalArgumentException("Illegal null AudioPolicy argument");
4725 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004726 final IAudioService service = getService();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004727 try {
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -08004728 MediaProjection projection = policy.getMediaProjection();
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004729 String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(),
Jean-Michel Triviee7d2452019-03-19 12:29:27 -07004730 policy.hasFocusListener(), policy.isFocusPolicy(), policy.isTestFocusPolicy(),
4731 policy.isVolumeController(),
Kevin Rocard2fe8b8b2019-02-20 11:25:23 -08004732 projection == null ? null : projection.getProjection());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07004733 if (regId == null) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004734 return ERROR;
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07004735 } else {
4736 policy.setRegistration(regId);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004737 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07004738 // successful registration
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004739 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004740 throw e.rethrowFromSystemServer();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004741 }
4742 return SUCCESS;
4743 }
4744
4745 /**
4746 * @hide
Jean-Michel Trivicada3722019-03-02 16:14:12 -08004747 * Unregisters an {@link AudioPolicy} asynchronously.
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004748 * @param policy the non-null {@link AudioPolicy} to unregister.
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004749 */
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004750 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06004751 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08004752 public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) {
Robert Berry669be042019-01-22 18:48:35 -05004753 unregisterAudioPolicyAsyncStatic(policy);
4754 }
4755
4756 static void unregisterAudioPolicyAsyncStatic(@NonNull AudioPolicy policy) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004757 if (policy == null) {
4758 throw new IllegalArgumentException("Illegal null AudioPolicy argument");
4759 }
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004760 final IAudioService service = getService();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004761 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004762 service.unregisterAudioPolicyAsync(policy.cb());
Jean-Michel Trivif5f3e682020-07-29 15:45:48 -07004763 policy.reset();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004764 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07004765 throw e.rethrowFromSystemServer();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004766 }
4767 }
4768
Jean-Michel Trivicada3722019-03-02 16:14:12 -08004769 /**
4770 * @hide
4771 * Unregisters an {@link AudioPolicy} synchronously.
4772 * This method also invalidates all {@link AudioRecord} and {@link AudioTrack} objects
4773 * associated with mixes of this policy.
4774 * @param policy the non-null {@link AudioPolicy} to unregister.
4775 */
4776 @SystemApi
4777 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
4778 public void unregisterAudioPolicy(@NonNull AudioPolicy policy) {
4779 Preconditions.checkNotNull(policy, "Illegal null AudioPolicy argument");
4780 final IAudioService service = getService();
4781 try {
4782 policy.invalidateCaptorsAndInjectors();
4783 service.unregisterAudioPolicy(policy.cb());
Jean-Michel Trivif5f3e682020-07-29 15:45:48 -07004784 policy.reset();
Jean-Michel Trivicada3722019-03-02 16:14:12 -08004785 } catch (RemoteException e) {
4786 throw e.rethrowFromSystemServer();
4787 }
4788 }
4789
Jean-Michel Trivi0c88f492019-04-12 15:43:56 -07004790 /**
4791 * @hide
4792 * @return true if an AudioPolicy was previously registered
4793 */
4794 @TestApi
4795 public boolean hasRegisteredDynamicPolicy() {
4796 final IAudioService service = getService();
4797 try {
4798 return service.hasRegisteredDynamicPolicy();
4799 } catch (RemoteException e) {
4800 throw e.rethrowFromSystemServer();
4801 }
4802 }
4803
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004804 //====================================================================
4805 // Notification of playback activity & playback configuration
4806 /**
4807 * Interface for receiving update notifications about the playback activity on the system.
4808 * Extend this abstract class and register it with
4809 * {@link AudioManager#registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}
4810 * to be notified.
4811 * Use {@link AudioManager#getActivePlaybackConfigurations()} to query the current
4812 * configuration.
4813 * @see AudioPlaybackConfiguration
4814 */
4815 public static abstract class AudioPlaybackCallback {
4816 /**
4817 * Called whenever the playback activity and configuration has changed.
4818 * @param configs list containing the results of
4819 * {@link AudioManager#getActivePlaybackConfigurations()}.
4820 */
4821 public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {}
4822 }
4823
4824 private static class AudioPlaybackCallbackInfo {
4825 final AudioPlaybackCallback mCb;
4826 final Handler mHandler;
4827 AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler) {
4828 mCb = cb;
4829 mHandler = handler;
4830 }
4831 }
4832
4833 private final static class PlaybackConfigChangeCallbackData {
4834 final AudioPlaybackCallback mCb;
4835 final List<AudioPlaybackConfiguration> mConfigs;
4836
4837 PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb,
4838 List<AudioPlaybackConfiguration> configs) {
4839 mCb = cb;
4840 mConfigs = configs;
4841 }
4842 }
4843
4844 /**
4845 * Register a callback to be notified of audio playback changes through
4846 * {@link AudioPlaybackCallback}
4847 * @param cb non-null callback to register
4848 * @param handler the {@link Handler} object for the thread on which to execute
4849 * the callback. If <code>null</code>, the {@link Handler} associated with the main
4850 * {@link Looper} will be used.
4851 */
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08004852 public void registerAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb,
4853 @Nullable Handler handler)
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004854 {
4855 if (cb == null) {
4856 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
4857 }
4858
4859 synchronized(mPlaybackCallbackLock) {
4860 // lazy initialization of the list of playback callbacks
4861 if (mPlaybackCallbackList == null) {
4862 mPlaybackCallbackList = new ArrayList<AudioPlaybackCallbackInfo>();
4863 }
4864 final int oldCbCount = mPlaybackCallbackList.size();
4865 if (!hasPlaybackCallback_sync(cb)) {
4866 mPlaybackCallbackList.add(new AudioPlaybackCallbackInfo(cb,
4867 new ServiceEventHandlerDelegate(handler).getHandler()));
4868 final int newCbCount = mPlaybackCallbackList.size();
4869 if ((oldCbCount == 0) && (newCbCount > 0)) {
4870 // register binder for callbacks
4871 try {
4872 getService().registerPlaybackCallback(mPlayCb);
4873 } catch (RemoteException e) {
4874 throw e.rethrowFromSystemServer();
4875 }
4876 }
4877 } else {
4878 Log.w(TAG, "attempt to call registerAudioPlaybackCallback() on a previously"
4879 + "registered callback");
4880 }
4881 }
4882 }
4883
4884 /**
4885 * Unregister an audio playback callback previously registered with
4886 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
4887 * @param cb non-null callback to unregister
4888 */
4889 public void unregisterAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb) {
4890 if (cb == null) {
4891 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument");
4892 }
4893 synchronized(mPlaybackCallbackLock) {
4894 if (mPlaybackCallbackList == null) {
4895 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
4896 + " that was never registered");
4897 return;
4898 }
4899 final int oldCbCount = mPlaybackCallbackList.size();
4900 if (removePlaybackCallback_sync(cb)) {
4901 final int newCbCount = mPlaybackCallbackList.size();
4902 if ((oldCbCount > 0) && (newCbCount == 0)) {
4903 // unregister binder for callbacks
4904 try {
4905 getService().unregisterPlaybackCallback(mPlayCb);
4906 } catch (RemoteException e) {
4907 throw e.rethrowFromSystemServer();
4908 }
4909 }
4910 } else {
4911 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback"
4912 + " already unregistered or never registered");
4913 }
4914 }
4915 }
4916
4917 /**
4918 * Returns the current active audio playback configurations of the device
4919 * @return a non-null list of playback configurations. An empty list indicates there is no
4920 * playback active when queried.
4921 * @see AudioPlaybackConfiguration
4922 */
4923 public @NonNull List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() {
4924 final IAudioService service = getService();
4925 try {
4926 return service.getActivePlaybackConfigurations();
4927 } catch (RemoteException e) {
4928 throw e.rethrowFromSystemServer();
4929 }
4930 }
4931
4932 /**
4933 * All operations on this list are sync'd on mPlaybackCallbackLock.
4934 * List is lazy-initialized in
4935 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}.
4936 * List can be null.
4937 */
4938 private List<AudioPlaybackCallbackInfo> mPlaybackCallbackList;
4939 private final Object mPlaybackCallbackLock = new Object();
4940
4941 /**
4942 * Must be called synchronized on mPlaybackCallbackLock
4943 */
4944 private boolean hasPlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
4945 if (mPlaybackCallbackList != null) {
4946 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
4947 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
4948 return true;
4949 }
4950 }
4951 }
4952 return false;
4953 }
4954
4955 /**
4956 * Must be called synchronized on mPlaybackCallbackLock
4957 */
4958 private boolean removePlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) {
4959 if (mPlaybackCallbackList != null) {
4960 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
4961 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) {
4962 mPlaybackCallbackList.remove(i);
4963 return true;
4964 }
4965 }
4966 }
4967 return false;
4968 }
4969
4970 private final IPlaybackConfigDispatcher mPlayCb = new IPlaybackConfigDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07004971 @Override
Jean-Michel Trivi776a3992017-09-12 16:45:34 -07004972 public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
4973 boolean flush) {
4974 if (flush) {
4975 Binder.flushPendingCommands();
4976 }
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004977 synchronized(mPlaybackCallbackLock) {
4978 if (mPlaybackCallbackList != null) {
4979 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) {
4980 final AudioPlaybackCallbackInfo arci = mPlaybackCallbackList.get(i);
4981 if (arci.mHandler != null) {
4982 final Message m = arci.mHandler.obtainMessage(
4983 MSSG_PLAYBACK_CONFIG_CHANGE/*what*/,
4984 new PlaybackConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
4985 arci.mHandler.sendMessage(m);
4986 }
4987 }
4988 }
4989 }
4990 }
4991
4992 };
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07004993
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08004994 //====================================================================
Jean-Michel Trivi292a6a42016-12-01 08:32:15 -08004995 // Notification of recording activity & recording configuration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08004996 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08004997 * Interface for receiving update notifications about the recording configuration. Extend
4998 * this abstract class and register it with
4999 * {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)}
5000 * to be notified.
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005001 * Use {@link AudioManager#getActiveRecordingConfigurations()} to query the current
5002 * configuration.
Jean-Michel Trivi7872aff2016-07-06 14:34:52 -07005003 * @see AudioRecordingConfiguration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005004 */
5005 public static abstract class AudioRecordingCallback {
5006 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005007 * Called whenever the device recording configuration has changed.
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005008 * @param configs list containing the results of
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005009 * {@link AudioManager#getActiveRecordingConfigurations()}.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005010 */
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005011 public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {}
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005012 }
5013
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005014 private static class AudioRecordingCallbackInfo {
5015 final AudioRecordingCallback mCb;
5016 final Handler mHandler;
5017 AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler) {
5018 mCb = cb;
5019 mHandler = handler;
5020 }
5021 }
5022
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005023 private final static class RecordConfigChangeCallbackData {
5024 final AudioRecordingCallback mCb;
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005025 final List<AudioRecordingConfiguration> mConfigs;
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005026
5027 RecordConfigChangeCallbackData(AudioRecordingCallback cb,
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005028 List<AudioRecordingConfiguration> configs) {
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005029 mCb = cb;
5030 mConfigs = configs;
5031 }
5032 }
5033
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005034 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005035 * Register a callback to be notified of audio recording changes through
5036 * {@link AudioRecordingCallback}
5037 * @param cb non-null callback to register
5038 * @param handler the {@link Handler} object for the thread on which to execute
5039 * the callback. If <code>null</code>, the {@link Handler} associated with the main
5040 * {@link Looper} will be used.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005041 */
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08005042 public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb,
5043 @Nullable Handler handler)
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005044 {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005045 if (cb == null) {
5046 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5047 }
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005048
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005049 synchronized(mRecordCallbackLock) {
5050 // lazy initialization of the list of recording callbacks
5051 if (mRecordCallbackList == null) {
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005052 mRecordCallbackList = new ArrayList<AudioRecordingCallbackInfo>();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005053 }
5054 final int oldCbCount = mRecordCallbackList.size();
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005055 if (!hasRecordCallback_sync(cb)) {
5056 mRecordCallbackList.add(new AudioRecordingCallbackInfo(cb,
5057 new ServiceEventHandlerDelegate(handler).getHandler()));
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005058 final int newCbCount = mRecordCallbackList.size();
5059 if ((oldCbCount == 0) && (newCbCount > 0)) {
5060 // register binder for callbacks
5061 final IAudioService service = getService();
5062 try {
5063 service.registerRecordingCallback(mRecCb);
5064 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005065 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005066 }
5067 }
5068 } else {
5069 Log.w(TAG, "attempt to call registerAudioRecordingCallback() on a previously"
5070 + "registered callback");
5071 }
5072 }
5073 }
5074
5075 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005076 * Unregister an audio recording callback previously registered with
5077 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
5078 * @param cb non-null callback to unregister
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005079 */
5080 public void unregisterAudioRecordingCallback(@NonNull AudioRecordingCallback cb) {
5081 if (cb == null) {
5082 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument");
5083 }
5084 synchronized(mRecordCallbackLock) {
5085 if (mRecordCallbackList == null) {
5086 return;
5087 }
5088 final int oldCbCount = mRecordCallbackList.size();
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005089 if (removeRecordCallback_sync(cb)) {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005090 final int newCbCount = mRecordCallbackList.size();
5091 if ((oldCbCount > 0) && (newCbCount == 0)) {
5092 // unregister binder for callbacks
5093 final IAudioService service = getService();
5094 try {
5095 service.unregisterRecordingCallback(mRecCb);
5096 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005097 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005098 }
5099 }
5100 } else {
5101 Log.w(TAG, "attempt to call unregisterAudioRecordingCallback() on a callback"
5102 + " already unregistered or never registered");
5103 }
5104 }
5105 }
5106
5107 /**
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005108 * Returns the current active audio recording configurations of the device.
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005109 * @return a non-null list of recording configurations. An empty list indicates there is
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005110 * no recording active when queried.
Jean-Michel Trivi7872aff2016-07-06 14:34:52 -07005111 * @see AudioRecordingConfiguration
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005112 */
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005113 public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() {
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005114 final IAudioService service = getService();
5115 try {
Jean-Michel Trivi598c0c92016-03-07 14:13:03 -08005116 return service.getActiveRecordingConfigurations();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005117 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005118 throw e.rethrowFromSystemServer();
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005119 }
5120 }
5121
5122 /**
5123 * constants for the recording events, to keep in sync
5124 * with frameworks/av/include/media/AudioPolicy.h
5125 */
5126 /** @hide */
Mikhail Naganova00883d2019-04-18 12:36:27 -07005127 public static final int RECORD_CONFIG_EVENT_NONE = -1;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005128 /** @hide */
Mikhail Naganova00883d2019-04-18 12:36:27 -07005129 public static final int RECORD_CONFIG_EVENT_START = 0;
5130 /** @hide */
5131 public static final int RECORD_CONFIG_EVENT_STOP = 1;
5132 /** @hide */
5133 public static final int RECORD_CONFIG_EVENT_UPDATE = 2;
5134 /** @hide */
Mikhail Naganovcfe4c262019-05-09 09:02:47 -07005135 public static final int RECORD_CONFIG_EVENT_RELEASE = 3;
Mikhail Naganova00883d2019-04-18 12:36:27 -07005136 /**
5137 * keep in sync with frameworks/native/include/audiomanager/AudioManager.h
5138 */
5139 /** @hide */
5140 public static final int RECORD_RIID_INVALID = -1;
5141 /** @hide */
5142 public static final int RECORDER_STATE_STARTED = 0;
5143 /** @hide */
5144 public static final int RECORDER_STATE_STOPPED = 1;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005145
5146 /**
5147 * All operations on this list are sync'd on mRecordCallbackLock.
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005148 * List is lazy-initialized in
5149 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}.
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005150 * List can be null.
5151 */
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005152 private List<AudioRecordingCallbackInfo> mRecordCallbackList;
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005153 private final Object mRecordCallbackLock = new Object();
5154
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005155 /**
5156 * Must be called synchronized on mRecordCallbackLock
5157 */
5158 private boolean hasRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5159 if (mRecordCallbackList != null) {
5160 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5161 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5162 return true;
5163 }
5164 }
5165 }
5166 return false;
5167 }
5168
5169 /**
5170 * Must be called synchronized on mRecordCallbackLock
5171 */
5172 private boolean removeRecordCallback_sync(@NonNull AudioRecordingCallback cb) {
5173 if (mRecordCallbackList != null) {
5174 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5175 if (cb.equals(mRecordCallbackList.get(i).mCb)) {
5176 mRecordCallbackList.remove(i);
5177 return true;
5178 }
5179 }
5180 }
5181 return false;
5182 }
5183
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005184 private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005185 @Override
Jean-Michel Trivif04fab12016-05-19 10:42:35 -07005186 public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) {
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005187 synchronized(mRecordCallbackLock) {
5188 if (mRecordCallbackList != null) {
5189 for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
5190 final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i);
5191 if (arci.mHandler != null) {
5192 final Message m = arci.mHandler.obtainMessage(
Jean-Michel Trivi28ff76b2016-03-02 09:36:30 -08005193 MSSG_RECORDING_CONFIG_CHANGE/*what*/,
5194 new RecordConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
Jean-Michel Trivib919f6f2016-01-12 18:27:17 -08005195 arci.mHandler.sendMessage(m);
5196 }
5197 }
5198 }
5199 }
Jean-Michel Trivid3c71f02015-12-07 11:59:31 -08005200 }
5201
5202 };
5203
5204 //=====================================================================
5205
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005206 /**
Eric Laurent4050c932009-07-08 02:52:14 -07005207 * @hide
5208 * Reload audio settings. This method is called by Settings backup
5209 * agent when audio settings are restored and causes the AudioService
5210 * to read and apply restored settings.
5211 */
Mathew Inwood8e742f92020-10-27 11:47:29 +00005212 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
Eric Laurent4050c932009-07-08 02:52:14 -07005213 public void reloadAudioSettings() {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005214 final IAudioService service = getService();
Eric Laurent4050c932009-07-08 02:52:14 -07005215 try {
5216 service.reloadAudioSettings();
5217 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005218 throw e.rethrowFromSystemServer();
Eric Laurent4050c932009-07-08 02:52:14 -07005219 }
5220 }
5221
John Du5a0cf7a2013-07-19 11:30:34 -07005222 /**
5223 * @hide
5224 * Notifies AudioService that it is connected to an A2DP device that supports absolute volume,
5225 * so that AudioService can send volume change events to the A2DP device, rather than handling
5226 * them.
5227 */
5228 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005229 final IAudioService service = getService();
John Du5a0cf7a2013-07-19 11:30:34 -07005230 try {
5231 service.avrcpSupportsAbsoluteVolume(address, support);
5232 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005233 throw e.rethrowFromSystemServer();
John Du5a0cf7a2013-07-19 11:30:34 -07005234 }
5235 }
5236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005237 /**
5238 * {@hide}
5239 */
Glenn Kasten30c918c2011-11-10 17:56:41 -08005240 private final IBinder mICallBack = new Binder();
Glenn Kasten7f9b1fa2010-03-31 11:11:36 -07005241
5242 /**
5243 * Checks whether the phone is in silent mode, with or without vibrate.
5244 *
5245 * @return true if phone is in silent mode, with or without vibrate.
5246 *
5247 * @see #getRingerMode()
5248 *
5249 * @hide pending API Council approval
5250 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005251 @UnsupportedAppUsage
Glenn Kasten7f9b1fa2010-03-31 11:11:36 -07005252 public boolean isSilentMode() {
5253 int ringerMode = getRingerMode();
5254 boolean silentMode =
5255 (ringerMode == RINGER_MODE_SILENT) ||
5256 (ringerMode == RINGER_MODE_VIBRATE);
5257 return silentMode;
5258 }
5259
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005260 // This section re-defines new output device constants from AudioSystem, because the AudioSystem
5261 // class is not used by other parts of the framework, which instead use definitions and methods
5262 // from AudioManager. AudioSystem is an internal class used by AudioManager and AudioService.
5263
Eric Laurent948d3272014-05-16 15:18:45 -07005264 /** @hide
Wonsik Kimd7c29182014-05-27 10:38:21 +09005265 * The audio device code for representing "no device." */
5266 public static final int DEVICE_NONE = AudioSystem.DEVICE_NONE;
5267 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005268 * The audio output device code for the small speaker at the front of the device used
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005269 * when placing calls. Does not refer to an in-ear headphone without attached microphone,
5270 * such as earbuds, earphones, or in-ear monitors (IEM). Those would be handled as a
5271 * {@link #DEVICE_OUT_WIRED_HEADPHONE}.
5272 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005273 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005274 public static final int DEVICE_OUT_EARPIECE = AudioSystem.DEVICE_OUT_EARPIECE;
Eric Laurent948d3272014-05-16 15:18:45 -07005275 /** @hide
5276 * The audio output device code for the built-in speaker */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005277 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005278 public static final int DEVICE_OUT_SPEAKER = AudioSystem.DEVICE_OUT_SPEAKER;
Eric Laurent948d3272014-05-16 15:18:45 -07005279 /** @hide
5280 * The audio output device code for a wired headset with attached microphone */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005281 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005282 public static final int DEVICE_OUT_WIRED_HEADSET = AudioSystem.DEVICE_OUT_WIRED_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005283 /** @hide
5284 * The audio output device code for a wired headphone without attached microphone */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005285 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005286 public static final int DEVICE_OUT_WIRED_HEADPHONE = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
Eric Laurent948d3272014-05-16 15:18:45 -07005287 /** @hide
Paul McLean145c9532017-08-04 11:12:19 -06005288 * The audio output device code for a USB headphone with attached microphone */
5289 public static final int DEVICE_OUT_USB_HEADSET = AudioSystem.DEVICE_OUT_USB_HEADSET;
5290 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005291 * The audio output device code for generic Bluetooth SCO, for voice */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005292 public static final int DEVICE_OUT_BLUETOOTH_SCO = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
Eric Laurent948d3272014-05-16 15:18:45 -07005293 /** @hide
5294 * The audio output device code for Bluetooth SCO Headset Profile (HSP) and
5295 * Hands-Free Profile (HFP), for voice
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005296 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005297 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005298 public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET =
5299 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005300 /** @hide
5301 * The audio output device code for Bluetooth SCO car audio, for voice */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005302 public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT =
5303 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurent948d3272014-05-16 15:18:45 -07005304 /** @hide
5305 * The audio output device code for generic Bluetooth A2DP, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005306 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005307 public static final int DEVICE_OUT_BLUETOOTH_A2DP = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
Eric Laurent948d3272014-05-16 15:18:45 -07005308 /** @hide
5309 * The audio output device code for Bluetooth A2DP headphones, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005310 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005311 public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES =
5312 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
Eric Laurent948d3272014-05-16 15:18:45 -07005313 /** @hide
5314 * The audio output device code for Bluetooth A2DP external speaker, for music */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005315 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005316 public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER =
5317 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
Eric Laurent948d3272014-05-16 15:18:45 -07005318 /** @hide
5319 * The audio output device code for S/PDIF (legacy) or HDMI
5320 * Deprecated: replaced by {@link #DEVICE_OUT_HDMI} */
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005321 public static final int DEVICE_OUT_AUX_DIGITAL = AudioSystem.DEVICE_OUT_AUX_DIGITAL;
Eric Laurent948d3272014-05-16 15:18:45 -07005322 /** @hide
5323 * The audio output device code for HDMI */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005324 @UnsupportedAppUsage
Eric Laurent948d3272014-05-16 15:18:45 -07005325 public static final int DEVICE_OUT_HDMI = AudioSystem.DEVICE_OUT_HDMI;
5326 /** @hide
5327 * The audio output device code for an analog wired headset attached via a
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005328 * docking station
5329 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005330 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005331 public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005332 /** @hide
5333 * The audio output device code for a digital wired headset attached via a
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005334 * docking station
5335 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005336 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005337 public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005338 /** @hide
5339 * The audio output device code for a USB audio accessory. The accessory is in USB host
Eric Laurent59f48272012-04-05 19:42:21 -07005340 * mode and the Android device in USB device mode
5341 */
5342 public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
Eric Laurent948d3272014-05-16 15:18:45 -07005343 /** @hide
5344 * The audio output device code for a USB audio device. The device is in USB device
Eric Laurent59f48272012-04-05 19:42:21 -07005345 * mode and the Android device in USB host mode
5346 */
5347 public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE;
Eric Laurent948d3272014-05-16 15:18:45 -07005348 /** @hide
5349 * The audio output device code for projection output.
5350 */
5351 public static final int DEVICE_OUT_REMOTE_SUBMIX = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
5352 /** @hide
5353 * The audio output device code the telephony voice TX path.
5354 */
5355 public static final int DEVICE_OUT_TELEPHONY_TX = AudioSystem.DEVICE_OUT_TELEPHONY_TX;
5356 /** @hide
5357 * The audio output device code for an analog jack with line impedance detected.
5358 */
5359 public static final int DEVICE_OUT_LINE = AudioSystem.DEVICE_OUT_LINE;
5360 /** @hide
5361 * The audio output device code for HDMI Audio Return Channel.
5362 */
5363 public static final int DEVICE_OUT_HDMI_ARC = AudioSystem.DEVICE_OUT_HDMI_ARC;
5364 /** @hide
Kuowei Lif898eae2020-10-27 16:41:18 +08005365 * The audio output device code for HDMI enhanced Audio Return Channel.
5366 */
5367 public static final int DEVICE_OUT_HDMI_EARC = AudioSystem.DEVICE_OUT_HDMI_EARC;
5368 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005369 * The audio output device code for S/PDIF digital connection.
5370 */
5371 public static final int DEVICE_OUT_SPDIF = AudioSystem.DEVICE_OUT_SPDIF;
5372 /** @hide
5373 * The audio output device code for built-in FM transmitter.
5374 */
5375 public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM;
5376 /** @hide
Eric Laurentca94af02020-08-07 12:30:44 -07005377 * The audio output device code for echo reference injection point.
5378 */
5379 public static final int DEVICE_OUT_ECHO_CANCELLER = AudioSystem.DEVICE_OUT_ECHO_CANCELLER;
5380 /** @hide
Eric Laurent6239d7e2020-08-07 10:58:14 -07005381 * The audio output device code for a BLE audio headset.
5382 */
5383 public static final int DEVICE_OUT_BLE_HEADSET = AudioSystem.DEVICE_OUT_BLE_HEADSET;
5384 /** @hide
5385 * The audio output device code for a BLE audio speaker.
5386 */
5387 public static final int DEVICE_OUT_BLE_SPEAKER = AudioSystem.DEVICE_OUT_BLE_SPEAKER;
5388 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005389 * This is not used as a returned value from {@link #getDevicesForStream}, but could be
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005390 * used in the future in a set method to select whatever default device is chosen by the
5391 * platform-specific implementation.
5392 */
5393 public static final int DEVICE_OUT_DEFAULT = AudioSystem.DEVICE_OUT_DEFAULT;
5394
Eric Laurent948d3272014-05-16 15:18:45 -07005395 /** @hide
5396 * The audio input device code for default built-in microphone
5397 */
5398 public static final int DEVICE_IN_BUILTIN_MIC = AudioSystem.DEVICE_IN_BUILTIN_MIC;
5399 /** @hide
5400 * The audio input device code for a Bluetooth SCO headset
5401 */
5402 public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET =
5403 AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
5404 /** @hide
5405 * The audio input device code for wired headset microphone
5406 */
5407 public static final int DEVICE_IN_WIRED_HEADSET =
5408 AudioSystem.DEVICE_IN_WIRED_HEADSET;
5409 /** @hide
5410 * The audio input device code for HDMI
5411 */
5412 public static final int DEVICE_IN_HDMI =
5413 AudioSystem.DEVICE_IN_HDMI;
5414 /** @hide
Nick Chalko2e1f76a2018-10-25 10:19:10 -07005415 * The audio input device code for HDMI ARC
5416 */
5417 public static final int DEVICE_IN_HDMI_ARC =
5418 AudioSystem.DEVICE_IN_HDMI_ARC;
5419
5420 /** @hide
Kuowei Lif898eae2020-10-27 16:41:18 +08005421 * The audio input device code for HDMI EARC
5422 */
5423 public static final int DEVICE_IN_HDMI_EARC =
5424 AudioSystem.DEVICE_IN_HDMI_EARC;
5425
5426 /** @hide
Eric Laurent948d3272014-05-16 15:18:45 -07005427 * The audio input device code for telephony voice RX path
5428 */
5429 public static final int DEVICE_IN_TELEPHONY_RX =
5430 AudioSystem.DEVICE_IN_TELEPHONY_RX;
5431 /** @hide
5432 * The audio input device code for built-in microphone pointing to the back
5433 */
5434 public static final int DEVICE_IN_BACK_MIC =
5435 AudioSystem.DEVICE_IN_BACK_MIC;
5436 /** @hide
5437 * The audio input device code for analog from a docking station
5438 */
5439 public static final int DEVICE_IN_ANLG_DOCK_HEADSET =
5440 AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET;
5441 /** @hide
5442 * The audio input device code for digital from a docking station
5443 */
5444 public static final int DEVICE_IN_DGTL_DOCK_HEADSET =
5445 AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET;
5446 /** @hide
5447 * The audio input device code for a USB audio accessory. The accessory is in USB host
5448 * mode and the Android device in USB device mode
5449 */
5450 public static final int DEVICE_IN_USB_ACCESSORY =
5451 AudioSystem.DEVICE_IN_USB_ACCESSORY;
5452 /** @hide
5453 * The audio input device code for a USB audio device. The device is in USB device
5454 * mode and the Android device in USB host mode
5455 */
5456 public static final int DEVICE_IN_USB_DEVICE =
5457 AudioSystem.DEVICE_IN_USB_DEVICE;
5458 /** @hide
5459 * The audio input device code for a FM radio tuner
5460 */
5461 public static final int DEVICE_IN_FM_TUNER = AudioSystem.DEVICE_IN_FM_TUNER;
5462 /** @hide
5463 * The audio input device code for a TV tuner
5464 */
5465 public static final int DEVICE_IN_TV_TUNER = AudioSystem.DEVICE_IN_TV_TUNER;
5466 /** @hide
5467 * The audio input device code for an analog jack with line impedance detected
5468 */
5469 public static final int DEVICE_IN_LINE = AudioSystem.DEVICE_IN_LINE;
5470 /** @hide
5471 * The audio input device code for a S/PDIF digital connection
5472 */
5473 public static final int DEVICE_IN_SPDIF = AudioSystem.DEVICE_IN_SPDIF;
Terry Heo112c19e2014-07-07 10:25:38 +09005474 /** @hide
5475 * The audio input device code for audio loopback
5476 */
5477 public static final int DEVICE_IN_LOOPBACK = AudioSystem.DEVICE_IN_LOOPBACK;
Eric Laurent6239d7e2020-08-07 10:58:14 -07005478 /** @hide
Eric Laurentca94af02020-08-07 12:30:44 -07005479 * The audio input device code for an echo reference capture point.
5480 */
5481 public static final int DEVICE_IN_ECHO_REFERENCE = AudioSystem.DEVICE_IN_ECHO_REFERENCE;
5482 /** @hide
Eric Laurent6239d7e2020-08-07 10:58:14 -07005483 * The audio input device code for a BLE audio headset.
5484 */
5485 public static final int DEVICE_IN_BLE_HEADSET = AudioSystem.DEVICE_IN_BLE_HEADSET;
Eric Laurent948d3272014-05-16 15:18:45 -07005486
5487 /**
5488 * Return true if the device code corresponds to an output device.
5489 * @hide
5490 */
5491 public static boolean isOutputDevice(int device)
5492 {
5493 return (device & AudioSystem.DEVICE_BIT_IN) == 0;
5494 }
5495
5496 /**
5497 * Return true if the device code corresponds to an input device.
5498 * @hide
5499 */
5500 public static boolean isInputDevice(int device)
5501 {
5502 return (device & AudioSystem.DEVICE_BIT_IN) == AudioSystem.DEVICE_BIT_IN;
5503 }
5504
5505
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005506 /**
5507 * Return the enabled devices for the specified output stream type.
5508 *
5509 * @param streamType The stream type to query. One of
5510 * {@link #STREAM_VOICE_CALL},
5511 * {@link #STREAM_SYSTEM},
5512 * {@link #STREAM_RING},
5513 * {@link #STREAM_MUSIC},
5514 * {@link #STREAM_ALARM},
5515 * {@link #STREAM_NOTIFICATION},
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -08005516 * {@link #STREAM_DTMF},
5517 * {@link #STREAM_ACCESSIBILITY}.
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005518 *
5519 * @return The bit-mask "or" of audio output device codes for all enabled devices on this
5520 * stream. Zero or more of
5521 * {@link #DEVICE_OUT_EARPIECE},
5522 * {@link #DEVICE_OUT_SPEAKER},
5523 * {@link #DEVICE_OUT_WIRED_HEADSET},
5524 * {@link #DEVICE_OUT_WIRED_HEADPHONE},
5525 * {@link #DEVICE_OUT_BLUETOOTH_SCO},
5526 * {@link #DEVICE_OUT_BLUETOOTH_SCO_HEADSET},
5527 * {@link #DEVICE_OUT_BLUETOOTH_SCO_CARKIT},
5528 * {@link #DEVICE_OUT_BLUETOOTH_A2DP},
5529 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES},
5530 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER},
Eric Laurent948d3272014-05-16 15:18:45 -07005531 * {@link #DEVICE_OUT_HDMI},
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005532 * {@link #DEVICE_OUT_ANLG_DOCK_HEADSET},
5533 * {@link #DEVICE_OUT_DGTL_DOCK_HEADSET}.
Eric Laurent948d3272014-05-16 15:18:45 -07005534 * {@link #DEVICE_OUT_USB_ACCESSORY}.
5535 * {@link #DEVICE_OUT_USB_DEVICE}.
5536 * {@link #DEVICE_OUT_REMOTE_SUBMIX}.
5537 * {@link #DEVICE_OUT_TELEPHONY_TX}.
5538 * {@link #DEVICE_OUT_LINE}.
5539 * {@link #DEVICE_OUT_HDMI_ARC}.
Kuowei Lif898eae2020-10-27 16:41:18 +08005540 * {@link #DEVICE_OUT_HDMI_EARC}.
Eric Laurent948d3272014-05-16 15:18:45 -07005541 * {@link #DEVICE_OUT_SPDIF}.
5542 * {@link #DEVICE_OUT_FM}.
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005543 * {@link #DEVICE_OUT_DEFAULT} is not used here.
5544 *
5545 * The implementation may support additional device codes beyond those listed, so
5546 * the application should ignore any bits which it does not recognize.
5547 * Note that the information may be imprecise when the implementation
5548 * cannot distinguish whether a particular device is enabled.
5549 *
5550 * {@hide}
5551 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005552 @UnsupportedAppUsage
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005553 public int getDevicesForStream(int streamType) {
5554 switch (streamType) {
5555 case STREAM_VOICE_CALL:
5556 case STREAM_SYSTEM:
5557 case STREAM_RING:
5558 case STREAM_MUSIC:
5559 case STREAM_ALARM:
5560 case STREAM_NOTIFICATION:
5561 case STREAM_DTMF:
Jean-Michel Trivi8e0bc782016-11-25 10:22:23 -08005562 case STREAM_ACCESSIBILITY:
Eric Laurent89c3a972020-12-16 15:57:56 +01005563 final IAudioService service = getService();
5564 try {
5565 return service.getDevicesForStream(streamType);
5566 } catch (RemoteException e) {
5567 throw e.rethrowFromSystemServer();
5568 }
Glenn Kasten8b4b97a2011-02-04 13:54:26 -08005569 default:
5570 return 0;
5571 }
5572 }
5573
Jean-Michel Trivi56b97b72020-01-07 14:18:05 -08005574 /**
5575 * @hide
5576 * Get the audio devices that would be used for the routing of the given audio attributes.
5577 * @param attributes the {@link AudioAttributes} for which the routing is being queried
5578 * @return an empty list if there was an issue with the request, a list of audio devices
5579 * otherwise (typically one device, except for duplicated paths).
5580 */
5581 @SystemApi
kholoud mohamed37839212021-03-15 16:49:06 +00005582 @RequiresPermission(anyOf = {
5583 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5584 android.Manifest.permission.QUERY_AUDIO_STATE
5585 })
Jean-Michel Trivi0e87bca2020-02-18 14:30:29 -08005586 public @NonNull List<AudioDeviceAttributes> getDevicesForAttributes(
Jean-Michel Trivi56b97b72020-01-07 14:18:05 -08005587 @NonNull AudioAttributes attributes) {
5588 Objects.requireNonNull(attributes);
5589 final IAudioService service = getService();
5590 try {
5591 return service.getDevicesForAttributes(attributes);
5592 } catch (RemoteException e) {
5593 throw e.rethrowFromSystemServer();
5594 }
5595 }
5596
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005597 /**
5598 * @hide
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00005599 * Volume behavior for an audio device that has no particular volume behavior set. Invalid as
Marvin Ramin5495cc92020-07-23 11:58:33 +02005600 * an argument to {@link #setDeviceVolumeBehavior(AudioDeviceAttributes, int)} and should not
5601 * be returned by {@link #getDeviceVolumeBehavior(AudioDeviceAttributes)}.
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00005602 */
5603 public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1;
5604 /**
5605 * @hide
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005606 * Volume behavior for an audio device where a software attenuation is applied
Marvin Ramin5495cc92020-07-23 11:58:33 +02005607 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005608 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005609 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005610 public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0;
5611 /**
5612 * @hide
5613 * Volume behavior for an audio device where the volume is always set to provide no attenuation
5614 * nor gain (e.g. unit gain).
Marvin Ramin5495cc92020-07-23 11:58:33 +02005615 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005616 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005617 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005618 public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1;
5619 /**
5620 * @hide
5621 * Volume behavior for an audio device where the volume is either set to muted, or to provide
5622 * no attenuation nor gain (e.g. unit gain).
Marvin Ramin5495cc92020-07-23 11:58:33 +02005623 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005624 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005625 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005626 public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2;
5627 /**
5628 * @hide
5629 * Volume behavior for an audio device where no software attenuation is applied, and
5630 * the volume is kept synchronized between the host and the device itself through a
5631 * device-specific protocol such as BT AVRCP.
Marvin Ramin5495cc92020-07-23 11:58:33 +02005632 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005633 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005634 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005635 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3;
5636 /**
5637 * @hide
5638 * Volume behavior for an audio device where no software attenuation is applied, and
5639 * the volume is kept synchronized between the host and the device itself through a
5640 * device-specific protocol (such as for hearing aids), based on the audio mode (e.g.
5641 * normal vs in phone call).
5642 * @see #setMode(int)
Marvin Ramin5495cc92020-07-23 11:58:33 +02005643 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int)
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005644 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005645 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005646 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4;
5647
5648 /** @hide */
5649 @IntDef({
5650 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
5651 DEVICE_VOLUME_BEHAVIOR_FULL,
5652 DEVICE_VOLUME_BEHAVIOR_FIXED,
5653 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
5654 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
5655 })
5656 @Retention(RetentionPolicy.SOURCE)
5657 public @interface DeviceVolumeBehavior {}
5658
Madhava Srinivasanb5ed6002020-06-11 21:49:24 +00005659 /** @hide */
5660 @IntDef({
5661 DEVICE_VOLUME_BEHAVIOR_UNSET,
5662 DEVICE_VOLUME_BEHAVIOR_VARIABLE,
5663 DEVICE_VOLUME_BEHAVIOR_FULL,
5664 DEVICE_VOLUME_BEHAVIOR_FIXED,
5665 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE,
5666 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE,
5667 })
5668 @Retention(RetentionPolicy.SOURCE)
5669 public @interface DeviceVolumeBehaviorState {}
5670
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005671 /**
5672 * @hide
5673 * Throws IAE on an invalid volume behavior value
5674 * @param volumeBehavior behavior value to check
5675 */
5676 public static void enforceValidVolumeBehavior(int volumeBehavior) {
5677 switch (volumeBehavior) {
5678 case DEVICE_VOLUME_BEHAVIOR_VARIABLE:
5679 case DEVICE_VOLUME_BEHAVIOR_FULL:
5680 case DEVICE_VOLUME_BEHAVIOR_FIXED:
5681 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE:
5682 case DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE:
5683 return;
5684 default:
5685 throw new IllegalArgumentException("Illegal volume behavior " + volumeBehavior);
5686 }
5687 }
5688
5689 /**
5690 * @hide
5691 * Sets the volume behavior for an audio output device.
Marvin Ramin5495cc92020-07-23 11:58:33 +02005692 * @see #DEVICE_VOLUME_BEHAVIOR_VARIABLE
5693 * @see #DEVICE_VOLUME_BEHAVIOR_FULL
5694 * @see #DEVICE_VOLUME_BEHAVIOR_FIXED
5695 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE
5696 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE
5697 * @param device the device to be affected
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005698 * @param deviceVolumeBehavior one of the device behaviors
5699 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005700 @SystemApi
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005701 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
5702 public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device,
5703 @DeviceVolumeBehavior int deviceVolumeBehavior) {
5704 // verify arguments (validity of device type is enforced in server)
5705 Objects.requireNonNull(device);
5706 enforceValidVolumeBehavior(deviceVolumeBehavior);
5707 // communicate with service
5708 final IAudioService service = getService();
5709 try {
5710 service.setDeviceVolumeBehavior(device, deviceVolumeBehavior,
5711 mApplicationContext.getOpPackageName());
5712 } catch (RemoteException e) {
5713 throw e.rethrowFromSystemServer();
5714 }
5715 }
5716
5717 /**
5718 * @hide
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005719 * Returns the volume device behavior for the given audio device
5720 * @param device the audio device
5721 * @return the volume behavior for the device
5722 */
Marvin Ramin5495cc92020-07-23 11:58:33 +02005723 @SystemApi
kholoud mohamed37839212021-03-15 16:49:06 +00005724 @RequiresPermission(anyOf = {
5725 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5726 android.Manifest.permission.QUERY_AUDIO_STATE
5727 })
Marvin Ramin5495cc92020-07-23 11:58:33 +02005728 public @DeviceVolumeBehavior
5729 int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) {
Jean-Michel Trivi005c6012020-03-15 20:33:15 -07005730 // verify arguments (validity of device type is enforced in server)
5731 Objects.requireNonNull(device);
5732 // communicate with service
5733 final IAudioService service = getService();
5734 try {
5735 return service.getDeviceVolumeBehavior(device);
5736 } catch (RemoteException e) {
5737 throw e.rethrowFromSystemServer();
5738 }
5739 }
5740
kholoud mohamed37839212021-03-15 16:49:06 +00005741 /**
5742 * @hide
5743 * Returns {@code true} if the volume device behavior is {@link #DEVICE_VOLUME_BEHAVIOR_FULL}.
5744 */
5745 @TestApi
5746 @RequiresPermission(anyOf = {
5747 android.Manifest.permission.MODIFY_AUDIO_ROUTING,
5748 android.Manifest.permission.QUERY_AUDIO_STATE
5749 })
5750 public boolean isFullVolumeDevice() {
5751 final AudioAttributes attributes = new AudioAttributes.Builder()
5752 .setUsage(AudioAttributes.USAGE_MEDIA)
5753 .build();
5754 final List<AudioDeviceAttributes> devices = getDevicesForAttributes(attributes);
5755 for (AudioDeviceAttributes device : devices) {
5756 if (getDeviceVolumeBehavior(device) == DEVICE_VOLUME_BEHAVIOR_FULL) {
5757 return true;
5758 }
5759 }
5760 return false;
5761 }
5762
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005763 /**
5764 * Indicate wired accessory connection state change.
5765 * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx)
5766 * @param state new connection state: 1 connected, 0 disconnected
5767 * @param name device name
5768 * {@hide}
5769 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01005770 @UnsupportedAppUsage
Jean-Michel Trivif0491972020-03-24 09:20:50 -07005771 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Paul McLean10804eb2015-01-28 11:16:35 -08005772 public void setWiredDeviceConnectionState(int type, int state, String address, String name) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005773 final IAudioService service = getService();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005774 try {
John Spurlock90874332015-03-10 16:00:54 -04005775 service.setWiredDeviceConnectionState(type, state, address, name,
Marco Nelissena80ac052015-03-12 16:17:45 -07005776 mApplicationContext.getOpPackageName());
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005777 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005778 throw e.rethrowFromSystemServer();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07005779 }
5780 }
5781
5782 /**
weichinwengc30a3e82018-10-09 18:02:17 +08005783 * Indicate Hearing Aid connection state change and eventually suppress
5784 * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
Jean-Michel Trivifc86cfa2019-03-01 10:15:47 -08005785 * This operation is asynchronous but its execution will still be sequentially scheduled
5786 * relative to calls to {@link #setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
5787 * * BluetoothDevice, int, int, boolean, int)} and
5788 * and {@link #handleBluetoothA2dpDeviceConfigChange(BluetoothDevice)}.
Jakub Pawlowski10c90612018-02-21 13:28:46 -08005789 * @param device Bluetooth device connected/disconnected
5790 * @param state new connection state (BluetoothProfile.STATE_xxx)
weichinwengc30a3e82018-10-09 18:02:17 +08005791 * @param musicDevice Default get system volume for the connecting device.
5792 * (either {@link android.bluetooth.BluetoothProfile.hearingaid} or
5793 * {@link android.bluetooth.BluetoothProfile.HEARING_AID})
5794 * @param suppressNoisyIntent if true the
5795 * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
Jakub Pawlowski10c90612018-02-21 13:28:46 -08005796 * {@hide}
5797 */
Jean-Michel Trivifc86cfa2019-03-01 10:15:47 -08005798 public void setBluetoothHearingAidDeviceConnectionState(
weichinwengc30a3e82018-10-09 18:02:17 +08005799 BluetoothDevice device, int state, boolean suppressNoisyIntent,
5800 int musicDevice) {
Jakub Pawlowski10c90612018-02-21 13:28:46 -08005801 final IAudioService service = getService();
5802 try {
Jean-Michel Trivifc86cfa2019-03-01 10:15:47 -08005803 service.setBluetoothHearingAidDeviceConnectionState(device,
weichinwengc30a3e82018-10-09 18:02:17 +08005804 state, suppressNoisyIntent, musicDevice);
Jakub Pawlowski10c90612018-02-21 13:28:46 -08005805 } catch (RemoteException e) {
5806 throw e.rethrowFromSystemServer();
5807 }
5808 }
5809
5810 /**
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005811 * Indicate A2DP source or sink connection state change and eventually suppress
5812 * the {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent.
Jean-Michel Trivifc86cfa2019-03-01 10:15:47 -08005813 * This operation is asynchronous but its execution will still be sequentially scheduled
5814 * relative to calls to {@link #setBluetoothHearingAidDeviceConnectionState(BluetoothDevice,
5815 * int, boolean, int)} and
5816 * {@link #handleBluetoothA2dpDeviceConfigChange(BluetoothDevice)}.
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005817 * @param device Bluetooth device connected/disconnected
Jean-Michel Trivi58850372018-09-14 16:01:28 -07005818 * @param state new connection state, {@link BluetoothProfile#STATE_CONNECTED}
5819 * or {@link BluetoothProfile#STATE_DISCONNECTED}
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005820 * @param profile profile for the A2DP device
Eric Laurent3e6fb632018-05-21 09:28:46 -07005821 * @param a2dpVolume New volume for the connecting device. Does nothing if disconnecting.
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005822 * (either {@link android.bluetooth.BluetoothProfile.A2DP} or
5823 * {@link android.bluetooth.BluetoothProfile.A2DP_SINK})
5824 * @param suppressNoisyIntent if true the
5825 * {@link AudioManager.ACTION_AUDIO_BECOMING_NOISY} intent will not be sent.
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005826 * {@hide}
5827 */
Jean-Michel Trivifc86cfa2019-03-01 10:15:47 -08005828 public void setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
Jean-Michel Trivi58850372018-09-14 16:01:28 -07005829 BluetoothDevice device, int state,
5830 int profile, boolean suppressNoisyIntent, int a2dpVolume) {
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005831 final IAudioService service = getService();
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005832 try {
Jean-Michel Trivifc86cfa2019-03-01 10:15:47 -08005833 service.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device,
Eric Laurent3e6fb632018-05-21 09:28:46 -07005834 state, profile, suppressNoisyIntent, a2dpVolume);
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005835 } catch (RemoteException e) {
5836 throw e.rethrowFromSystemServer();
5837 }
Pavlin Radoslavov82e06462018-01-19 18:20:04 -08005838 }
5839
5840 /**
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005841 * Indicate A2DP device configuration has changed.
Jean-Michel Trivifc86cfa2019-03-01 10:15:47 -08005842 * This operation is asynchronous but its execution will still be sequentially scheduled
5843 * relative to calls to
5844 * {@link #setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice, int, int,
5845 * boolean, int)} and
5846 * {@link #setBluetoothHearingAidDeviceConnectionState(BluetoothDevice, int, boolean, int)}
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005847 * @param device Bluetooth device whose configuration has changed.
5848 * {@hide}
5849 */
5850 public void handleBluetoothA2dpDeviceConfigChange(BluetoothDevice device) {
Jean-Michel Trivi50750ff2017-03-21 11:18:24 -07005851 final IAudioService service = getService();
Pavlin Radoslavov44a4ef02016-12-21 12:05:51 -08005852 try {
5853 service.handleBluetoothA2dpDeviceConfigChange(device);
5854 } catch (RemoteException e) {
5855 throw e.rethrowFromSystemServer();
5856 }
5857 }
5858
Jeff Sharkey098d5802012-04-26 17:30:34 -07005859 /** {@hide} */
5860 public IRingtonePlayer getRingtonePlayer() {
5861 try {
5862 return getService().getRingtonePlayer();
5863 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07005864 throw e.rethrowFromSystemServer();
Jeff Sharkey098d5802012-04-26 17:30:34 -07005865 }
5866 }
Glenn Kasten228c9842012-09-14 08:48:47 -07005867
5868 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07005869 * Used as a key for {@link #getProperty} to request the native or optimal output sample rate
Glenn Kastenc3de5142016-07-15 12:14:24 -07005870 * for this device's low latency output stream, in decimal Hz. Latency-sensitive apps
5871 * should use this value as a default, and offer the user the option to override it.
5872 * The low latency output stream is typically either the device's primary output stream,
5873 * or another output stream with smaller buffers.
Glenn Kasten228c9842012-09-14 08:48:47 -07005874 */
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08005875 // FIXME Deprecate
Glenn Kasten228c9842012-09-14 08:48:47 -07005876 public static final String PROPERTY_OUTPUT_SAMPLE_RATE =
5877 "android.media.property.OUTPUT_SAMPLE_RATE";
5878
5879 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07005880 * Used as a key for {@link #getProperty} to request the native or optimal output buffer size
Glenn Kastenc3de5142016-07-15 12:14:24 -07005881 * for this device's low latency output stream, in decimal PCM frames. Latency-sensitive apps
5882 * should use this value as a minimum, and offer the user the option to override it.
5883 * The low latency output stream is typically either the device's primary output stream,
5884 * or another output stream with smaller buffers.
Glenn Kasten228c9842012-09-14 08:48:47 -07005885 */
Glenn Kasten1cbf9b32016-02-02 12:04:09 -08005886 // FIXME Deprecate
Glenn Kasten228c9842012-09-14 08:48:47 -07005887 public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER =
5888 "android.media.property.OUTPUT_FRAMES_PER_BUFFER";
5889
5890 /**
Arunesh Mishrad08715e52015-04-23 22:39:40 -07005891 * Used as a key for {@link #getProperty} to determine if the default microphone audio source
5892 * supports near-ultrasound frequencies (range of 18 - 21 kHz).
5893 */
5894 public static final String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND =
5895 "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND";
5896
5897 /**
5898 * Used as a key for {@link #getProperty} to determine if the default speaker audio path
5899 * supports near-ultrasound frequencies (range of 18 - 21 kHz).
5900 */
5901 public static final String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND =
5902 "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND";
5903
5904 /**
ragoa7cc59c2015-12-02 11:31:15 -08005905 * Used as a key for {@link #getProperty} to determine if the unprocessed audio source is
5906 * available and supported with the expected frequency range and level response.
5907 */
5908 public static final String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED =
5909 "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED";
5910 /**
Glenn Kasten62796aa2012-09-20 08:08:07 -07005911 * Returns the value of the property with the specified key.
Glenn Kasten228c9842012-09-14 08:48:47 -07005912 * @param key One of the strings corresponding to a property key: either
Glenn Kasten0b986af2015-10-30 18:24:04 -07005913 * {@link #PROPERTY_OUTPUT_SAMPLE_RATE},
5914 * {@link #PROPERTY_OUTPUT_FRAMES_PER_BUFFER},
ragoa7cc59c2015-12-02 11:31:15 -08005915 * {@link #PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND},
5916 * {@link #PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND}, or
5917 * {@link #PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED}.
Glenn Kasten228c9842012-09-14 08:48:47 -07005918 * @return A string representing the associated value for that property key,
5919 * or null if there is no value for that key.
Glenn Kasten228c9842012-09-14 08:48:47 -07005920 */
5921 public String getProperty(String key) {
Glenn Kastenc6c43652012-09-24 17:32:30 -07005922 if (PROPERTY_OUTPUT_SAMPLE_RATE.equals(key)) {
5923 int outputSampleRate = AudioSystem.getPrimaryOutputSamplingRate();
5924 return outputSampleRate > 0 ? Integer.toString(outputSampleRate) : null;
5925 } else if (PROPERTY_OUTPUT_FRAMES_PER_BUFFER.equals(key)) {
5926 int outputFramesPerBuffer = AudioSystem.getPrimaryOutputFrameCount();
5927 return outputFramesPerBuffer > 0 ? Integer.toString(outputFramesPerBuffer) : null;
Arunesh Mishrabc922272015-04-27 09:39:00 -07005928 } else if (PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND.equals(key)) {
Arunesh Mishra6e4fb342015-06-02 13:23:41 -07005929 // Will throw a RuntimeException Resources.NotFoundException if this config value is
5930 // not found.
5931 return String.valueOf(getContext().getResources().getBoolean(
5932 com.android.internal.R.bool.config_supportMicNearUltrasound));
Arunesh Mishrabc922272015-04-27 09:39:00 -07005933 } else if (PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND.equals(key)) {
Arunesh Mishra6e4fb342015-06-02 13:23:41 -07005934 return String.valueOf(getContext().getResources().getBoolean(
5935 com.android.internal.R.bool.config_supportSpeakerNearUltrasound));
ragoa7cc59c2015-12-02 11:31:15 -08005936 } else if (PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED.equals(key)) {
5937 return String.valueOf(getContext().getResources().getBoolean(
5938 com.android.internal.R.bool.config_supportAudioSourceUnprocessed));
Glenn Kastenc6c43652012-09-24 17:32:30 -07005939 } else {
5940 // null or unknown key
5941 return null;
5942 }
Glenn Kasten228c9842012-09-14 08:48:47 -07005943 }
5944
Oliver Woodman61dcdf32013-06-26 12:43:36 +01005945 /**
Andy Hung97aa07f82020-01-17 14:05:06 -08005946 * @hide
5947 * Sets an additional audio output device delay in milliseconds.
5948 *
5949 * The additional output delay is a request to the output device to
5950 * delay audio presentation (generally with respect to video presentation for better
5951 * synchronization).
5952 * It may not be supported by all output devices,
5953 * and typically increases the audio latency by the amount of additional
5954 * audio delay requested.
5955 *
5956 * If additional audio delay is supported by an audio output device,
5957 * it is expected to be supported for all output streams (and configurations)
5958 * opened on that device.
5959 *
5960 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
Andy Hung120c1c42020-03-26 12:01:33 -07005961 * @param delayMillis delay in milliseconds desired. This should be in range of {@code 0}
Andy Hung97aa07f82020-01-17 14:05:06 -08005962 * to the value returned by {@link #getMaxAdditionalOutputDeviceDelay()}.
5963 * @return true if successful, false if the device does not support output device delay
5964 * or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}.
5965 */
5966 @SystemApi
5967 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
5968 public boolean setAdditionalOutputDeviceDelay(
Andy Hung120c1c42020-03-26 12:01:33 -07005969 @NonNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis) {
Andy Hung97aa07f82020-01-17 14:05:06 -08005970 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08005971 try {
5972 return getService().setAdditionalOutputDeviceDelay(
5973 new AudioDeviceAttributes(device), delayMillis);
5974 } catch (RemoteException e) {
5975 throw e.rethrowFromSystemServer();
5976 }
Andy Hung97aa07f82020-01-17 14:05:06 -08005977 }
5978
5979 /**
5980 * @hide
5981 * Returns the current additional audio output device delay in milliseconds.
5982 *
5983 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
5984 * @return the additional output device delay. This is a non-negative number.
5985 * {@code 0} is returned if unsupported.
5986 */
5987 @SystemApi
5988 @IntRange(from = 0)
Andy Hung120c1c42020-03-26 12:01:33 -07005989 public long getAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Andy Hung97aa07f82020-01-17 14:05:06 -08005990 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08005991 try {
5992 return getService().getAdditionalOutputDeviceDelay(new AudioDeviceAttributes(device));
5993 } catch (RemoteException e) {
5994 throw e.rethrowFromSystemServer();
5995 }
Andy Hung97aa07f82020-01-17 14:05:06 -08005996 }
5997
5998 /**
5999 * @hide
6000 * Returns the maximum additional audio output device delay in milliseconds.
6001 *
6002 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}.
6003 * @return the maximum output device delay in milliseconds that can be set.
6004 * This is a non-negative number
6005 * representing the additional audio delay supported for the device.
6006 * {@code 0} is returned if unsupported.
6007 */
6008 @SystemApi
6009 @IntRange(from = 0)
Andy Hung120c1c42020-03-26 12:01:33 -07006010 public long getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) {
Andy Hung97aa07f82020-01-17 14:05:06 -08006011 Objects.requireNonNull(device);
Kuowei Lif50ac2e32020-08-13 14:34:17 +08006012 try {
6013 return getService().getMaxAdditionalOutputDeviceDelay(
6014 new AudioDeviceAttributes(device));
6015 } catch (RemoteException e) {
6016 throw e.rethrowFromSystemServer();
6017 }
Andy Hung97aa07f82020-01-17 14:05:06 -08006018 }
6019
6020 /**
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006021 * Returns the estimated latency for the given stream type in milliseconds.
6022 *
6023 * DO NOT UNHIDE. The existing approach for doing A/V sync has too many problems. We need
6024 * a better solution.
6025 * @hide
6026 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006027 @UnsupportedAppUsage
Oliver Woodman61dcdf32013-06-26 12:43:36 +01006028 public int getOutputLatency(int streamType) {
6029 return AudioSystem.getOutputLatency(streamType);
6030 }
6031
John Spurlock3346a802014-05-20 16:25:37 -04006032 /**
6033 * Registers a global volume controller interface. Currently limited to SystemUI.
6034 *
6035 * @hide
6036 */
6037 public void setVolumeController(IVolumeController controller) {
6038 try {
6039 getService().setVolumeController(controller);
6040 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006041 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006042 }
6043 }
6044
6045 /**
John Spurlock33f4e042014-07-11 13:10:58 -04006046 * Notify audio manager about volume controller visibility changes.
6047 * Currently limited to SystemUI.
6048 *
6049 * @hide
6050 */
6051 public void notifyVolumeControllerVisible(IVolumeController controller, boolean visible) {
6052 try {
6053 getService().notifyVolumeControllerVisible(controller, visible);
6054 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006055 throw e.rethrowFromSystemServer();
John Spurlock33f4e042014-07-11 13:10:58 -04006056 }
6057 }
6058
6059 /**
John Spurlock3346a802014-05-20 16:25:37 -04006060 * Only useful for volume controllers.
6061 * @hide
6062 */
John Spurlock3346a802014-05-20 16:25:37 -04006063 public boolean isStreamAffectedByRingerMode(int streamType) {
6064 try {
6065 return getService().isStreamAffectedByRingerMode(streamType);
6066 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006067 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006068 }
6069 }
6070
6071 /**
6072 * Only useful for volume controllers.
6073 * @hide
6074 */
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05006075 public boolean isStreamAffectedByMute(int streamType) {
6076 try {
6077 return getService().isStreamAffectedByMute(streamType);
6078 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006079 throw e.rethrowFromSystemServer();
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05006080 }
6081 }
6082
6083 /**
6084 * Only useful for volume controllers.
6085 * @hide
6086 */
John Spurlock3346a802014-05-20 16:25:37 -04006087 public void disableSafeMediaVolume() {
6088 try {
Marco Nelissena80ac052015-03-12 16:17:45 -07006089 getService().disableSafeMediaVolume(mApplicationContext.getOpPackageName());
John Spurlock3346a802014-05-20 16:25:37 -04006090 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006091 throw e.rethrowFromSystemServer();
John Spurlock3346a802014-05-20 16:25:37 -04006092 }
6093 }
Eric Laurenta198a292014-02-18 16:26:17 -08006094
6095 /**
John Spurlock661f2cf42014-11-17 10:29:10 -05006096 * Only useful for volume controllers.
6097 * @hide
6098 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006099 @UnsupportedAppUsage
John Spurlock661f2cf42014-11-17 10:29:10 -05006100 public void setRingerModeInternal(int ringerMode) {
6101 try {
Marco Nelissen29f16932015-04-17 09:50:56 -07006102 getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName());
John Spurlock661f2cf42014-11-17 10:29:10 -05006103 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006104 throw e.rethrowFromSystemServer();
John Spurlock661f2cf42014-11-17 10:29:10 -05006105 }
6106 }
6107
6108 /**
6109 * Only useful for volume controllers.
6110 * @hide
6111 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006112 @UnsupportedAppUsage
John Spurlock661f2cf42014-11-17 10:29:10 -05006113 public int getRingerModeInternal() {
6114 try {
6115 return getService().getRingerModeInternal();
6116 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006117 throw e.rethrowFromSystemServer();
John Spurlock661f2cf42014-11-17 10:29:10 -05006118 }
6119 }
6120
6121 /**
John Spurlocka48d7792015-03-03 17:35:57 -05006122 * Only useful for volume controllers.
6123 * @hide
6124 */
6125 public void setVolumePolicy(VolumePolicy policy) {
6126 try {
6127 getService().setVolumePolicy(policy);
6128 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006129 throw e.rethrowFromSystemServer();
John Spurlocka48d7792015-03-03 17:35:57 -05006130 }
6131 }
6132
6133 /**
Jungshik Jang41d97462014-06-30 22:26:29 +09006134 * Set Hdmi Cec system audio mode.
6135 *
6136 * @param on whether to be on system audio mode
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09006137 * @return output device type. 0 (DEVICE_NONE) if failed to set device.
Jungshik Jang41d97462014-06-30 22:26:29 +09006138 * @hide
6139 */
Jungshik Jang12307ca2014-07-15 19:27:56 +09006140 public int setHdmiSystemAudioSupported(boolean on) {
Jungshik Jang41d97462014-06-30 22:26:29 +09006141 try {
Jungshik Jang12307ca2014-07-15 19:27:56 +09006142 return getService().setHdmiSystemAudioSupported(on);
Jungshik Jang41d97462014-06-30 22:26:29 +09006143 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006144 throw e.rethrowFromSystemServer();
Jungshik Jang41d97462014-06-30 22:26:29 +09006145 }
6146 }
6147
6148 /**
Terry Heoe7d6d972014-09-04 21:05:28 +09006149 * Returns true if Hdmi Cec system audio mode is supported.
6150 *
6151 * @hide
6152 */
6153 @SystemApi
Aurimas Liutikas1394a012020-11-12 18:26:09 -08006154 @SuppressLint("RequiresPermission") // FIXME is this still used?
Terry Heoe7d6d972014-09-04 21:05:28 +09006155 public boolean isHdmiSystemAudioSupported() {
6156 try {
6157 return getService().isHdmiSystemAudioSupported();
6158 } catch (RemoteException e) {
Jeff Sharkeyf8880562016-02-26 13:03:01 -07006159 throw e.rethrowFromSystemServer();
Terry Heoe7d6d972014-09-04 21:05:28 +09006160 }
6161 }
6162
6163 /**
Eric Laurenta198a292014-02-18 16:26:17 -08006164 * Return codes for listAudioPorts(), createAudioPatch() ...
6165 */
6166
Jean-Michel Trivid6f65de2018-12-18 18:49:14 -08006167 /** @hide */
6168 @SystemApi
Eric Laurenta198a292014-02-18 16:26:17 -08006169 public static final int SUCCESS = AudioSystem.SUCCESS;
Jean-Michel Trivi8a21f5d2014-06-05 15:03:52 -07006170 /**
6171 * A default error code.
Eric Laurenta198a292014-02-18 16:26:17 -08006172 */
6173 public static final int ERROR = AudioSystem.ERROR;
6174 /** @hide
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07006175 * CANDIDATE FOR PUBLIC API
Eric Laurenta198a292014-02-18 16:26:17 -08006176 */
6177 public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE;
6178 /** @hide
6179 */
6180 public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION;
6181 /** @hide
6182 */
6183 public static final int ERROR_PERMISSION_DENIED = AudioSystem.PERMISSION_DENIED;
6184 /** @hide
6185 */
6186 public static final int ERROR_NO_INIT = AudioSystem.NO_INIT;
Eric Laurentff0d9f02014-06-09 17:23:02 -07006187 /**
6188 * An error code indicating that the object reporting it is no longer valid and needs to
6189 * be recreated.
Eric Laurenta198a292014-02-18 16:26:17 -08006190 */
6191 public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT;
6192
6193 /**
6194 * Returns a list of descriptors for all audio ports managed by the audio framework.
6195 * Audio ports are nodes in the audio framework or audio hardware that can be configured
6196 * or connected and disconnected with createAudioPatch() or releaseAudioPatch().
6197 * See AudioPort for a list of attributes of each audio port.
6198 * @param ports An AudioPort ArrayList where the list will be returned.
6199 * @hide
6200 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006201 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006202 public static int listAudioPorts(ArrayList<AudioPort> ports) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006203 return updateAudioPortCache(ports, null, null);
6204 }
6205
6206 /**
6207 * Returns a list of descriptors for all audio ports managed by the audio framework as
6208 * it was before the last update calback.
6209 * @param ports An AudioPort ArrayList where the list will be returned.
6210 * @hide
6211 */
6212 public static int listPreviousAudioPorts(ArrayList<AudioPort> ports) {
6213 return updateAudioPortCache(null, null, ports);
Eric Laurenta198a292014-02-18 16:26:17 -08006214 }
6215
6216 /**
6217 * Specialized version of listAudioPorts() listing only audio devices (AudioDevicePort)
6218 * @see listAudioPorts(ArrayList<AudioPort>)
6219 * @hide
6220 */
Eric Laurent4bcdba82015-05-01 11:37:49 -07006221 public static int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006222 if (devices == null) {
6223 return ERROR_BAD_VALUE;
6224 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006225 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006226 int status = updateAudioPortCache(ports, null, null);
Eric Laurentb69681c2014-05-19 19:02:51 -07006227 if (status == SUCCESS) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006228 filterDevicePorts(ports, devices);
Eric Laurentb69681c2014-05-19 19:02:51 -07006229 }
6230 return status;
Eric Laurenta198a292014-02-18 16:26:17 -08006231 }
6232
6233 /**
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006234 * Specialized version of listPreviousAudioPorts() listing only audio devices (AudioDevicePort)
6235 * @see listPreviousAudioPorts(ArrayList<AudioPort>)
6236 * @hide
6237 */
6238 public static int listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
6239 if (devices == null) {
6240 return ERROR_BAD_VALUE;
6241 }
6242 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
6243 int status = updateAudioPortCache(null, null, ports);
6244 if (status == SUCCESS) {
6245 filterDevicePorts(ports, devices);
6246 }
6247 return status;
6248 }
6249
6250 private static void filterDevicePorts(ArrayList<AudioPort> ports,
6251 ArrayList<AudioDevicePort> devices) {
6252 devices.clear();
6253 for (int i = 0; i < ports.size(); i++) {
6254 if (ports.get(i) instanceof AudioDevicePort) {
6255 devices.add((AudioDevicePort)ports.get(i));
6256 }
6257 }
6258 }
6259
6260 /**
Eric Laurenta198a292014-02-18 16:26:17 -08006261 * Create a connection between two or more devices. The framework will reject the request if
6262 * device types are not compatible or the implementation does not support the requested
6263 * configuration.
6264 * NOTE: current implementation is limited to one source and one sink per patch.
6265 * @param patch AudioPatch array where the newly created patch will be returned.
6266 * As input, if patch[0] is not null, the specified patch will be replaced by the
6267 * new patch created. This avoids calling releaseAudioPatch() when modifying a
6268 * patch and allows the implementation to optimize transitions.
6269 * @param sources List of source audio ports. All must be AudioPort.ROLE_SOURCE.
6270 * @param sinks List of sink audio ports. All must be AudioPort.ROLE_SINK.
6271 *
6272 * @return - {@link #SUCCESS} if connection is successful.
6273 * - {@link #ERROR_BAD_VALUE} if incompatible device types are passed.
6274 * - {@link #ERROR_INVALID_OPERATION} if the requested connection is not supported.
6275 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to create
6276 * a patch.
6277 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead
6278 * - {@link #ERROR} if patch cannot be connected for any other reason.
6279 *
6280 * patch[0] contains the newly created patch
6281 * @hide
6282 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006283 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006284 public static int createAudioPatch(AudioPatch[] patch,
Eric Laurenta198a292014-02-18 16:26:17 -08006285 AudioPortConfig[] sources,
6286 AudioPortConfig[] sinks) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006287 return AudioSystem.createAudioPatch(patch, sources, sinks);
Eric Laurenta198a292014-02-18 16:26:17 -08006288 }
6289
6290 /**
6291 * Releases an existing audio patch connection.
6292 * @param patch The audio patch to disconnect.
6293 * @return - {@link #SUCCESS} if disconnection is successful.
6294 * - {@link #ERROR_BAD_VALUE} if the specified patch does not exist.
6295 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to release
6296 * a patch.
6297 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead
6298 * - {@link #ERROR} if patch cannot be released for any other reason.
6299 * @hide
6300 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006301 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006302 public static int releaseAudioPatch(AudioPatch patch) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006303 return AudioSystem.releaseAudioPatch(patch);
Eric Laurenta198a292014-02-18 16:26:17 -08006304 }
6305
6306 /**
6307 * List all existing connections between audio ports.
6308 * @param patches An AudioPatch array where the list will be returned.
6309 * @hide
6310 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006311 @UnsupportedAppUsage
Eric Laurent4bcdba82015-05-01 11:37:49 -07006312 public static int listAudioPatches(ArrayList<AudioPatch> patches) {
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006313 return updateAudioPortCache(null, patches, null);
Eric Laurenta198a292014-02-18 16:26:17 -08006314 }
6315
6316 /**
6317 * Set the gain on the specified AudioPort. The AudioGainConfig config is build by
6318 * AudioGain.buildConfig()
6319 * @hide
6320 */
Eric Laurent4bcdba82015-05-01 11:37:49 -07006321 public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) {
Eric Laurent3a241992014-05-19 19:33:26 -07006322 if (port == null || gain == null) {
6323 return ERROR_BAD_VALUE;
6324 }
6325 AudioPortConfig activeConfig = port.activeConfig();
6326 AudioPortConfig config = new AudioPortConfig(port, activeConfig.samplingRate(),
6327 activeConfig.channelMask(), activeConfig.format(), gain);
6328 config.mConfigMask = AudioPortConfig.GAIN;
6329 return AudioSystem.setAudioPortConfig(config);
Eric Laurenta198a292014-02-18 16:26:17 -08006330 }
6331
6332 /**
6333 * Listener registered by client to be notified upon new audio port connections,
6334 * disconnections or attributes update.
6335 * @hide
6336 */
6337 public interface OnAudioPortUpdateListener {
6338 /**
6339 * Callback method called upon audio port list update.
6340 * @param portList the updated list of audio ports
6341 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006342 public void onAudioPortListUpdate(AudioPort[] portList);
Eric Laurenta198a292014-02-18 16:26:17 -08006343
6344 /**
6345 * Callback method called upon audio patch list update.
6346 * @param patchList the updated list of audio patches
6347 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006348 public void onAudioPatchListUpdate(AudioPatch[] patchList);
Eric Laurenta198a292014-02-18 16:26:17 -08006349
6350 /**
6351 * Callback method called when the mediaserver dies
6352 */
Eric Laurentfdaed9d2014-07-29 09:29:30 -07006353 public void onServiceDied();
Eric Laurenta198a292014-02-18 16:26:17 -08006354 }
6355
6356 /**
Eric Laurent700e7342014-05-02 18:33:15 -07006357 * Register an audio port list update listener.
Eric Laurenta198a292014-02-18 16:26:17 -08006358 * @hide
6359 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006360 @UnsupportedAppUsage
Eric Laurenta198a292014-02-18 16:26:17 -08006361 public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) {
Eric Laurentc573bc52015-06-26 10:01:12 -07006362 sAudioPortEventHandler.init();
Eric Laurentf076db42015-01-14 13:23:27 -08006363 sAudioPortEventHandler.registerListener(l);
Eric Laurenta198a292014-02-18 16:26:17 -08006364 }
6365
6366 /**
Eric Laurent700e7342014-05-02 18:33:15 -07006367 * Unregister an audio port list update listener.
Eric Laurenta198a292014-02-18 16:26:17 -08006368 * @hide
6369 */
Mathew Inwood31a792a2018-08-17 08:54:26 +01006370 @UnsupportedAppUsage
Eric Laurenta198a292014-02-18 16:26:17 -08006371 public void unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l) {
Eric Laurentf076db42015-01-14 13:23:27 -08006372 sAudioPortEventHandler.unregisterListener(l);
Eric Laurenta198a292014-02-18 16:26:17 -08006373 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006374
6375 //
6376 // AudioPort implementation
6377 //
6378
6379 static final int AUDIOPORT_GENERATION_INIT = 0;
Eric Laurentf076db42015-01-14 13:23:27 -08006380 static Integer sAudioPortGeneration = new Integer(AUDIOPORT_GENERATION_INIT);
6381 static ArrayList<AudioPort> sAudioPortsCached = new ArrayList<AudioPort>();
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006382 static ArrayList<AudioPort> sPreviousAudioPortsCached = new ArrayList<AudioPort>();
Eric Laurentf076db42015-01-14 13:23:27 -08006383 static ArrayList<AudioPatch> sAudioPatchesCached = new ArrayList<AudioPatch>();
Eric Laurentb69681c2014-05-19 19:02:51 -07006384
Eric Laurentf076db42015-01-14 13:23:27 -08006385 static int resetAudioPortGeneration() {
Eric Laurentb69681c2014-05-19 19:02:51 -07006386 int generation;
Eric Laurentf076db42015-01-14 13:23:27 -08006387 synchronized (sAudioPortGeneration) {
6388 generation = sAudioPortGeneration;
6389 sAudioPortGeneration = AUDIOPORT_GENERATION_INIT;
Eric Laurentb69681c2014-05-19 19:02:51 -07006390 }
6391 return generation;
6392 }
6393
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006394 static int updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches,
6395 ArrayList<AudioPort> previousPorts) {
Eric Laurentc573bc52015-06-26 10:01:12 -07006396 sAudioPortEventHandler.init();
Eric Laurentf076db42015-01-14 13:23:27 -08006397 synchronized (sAudioPortGeneration) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006398
Eric Laurentf076db42015-01-14 13:23:27 -08006399 if (sAudioPortGeneration == AUDIOPORT_GENERATION_INIT) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006400 int[] patchGeneration = new int[1];
6401 int[] portGeneration = new int[1];
6402 int status;
6403 ArrayList<AudioPort> newPorts = new ArrayList<AudioPort>();
6404 ArrayList<AudioPatch> newPatches = new ArrayList<AudioPatch>();
6405
6406 do {
6407 newPorts.clear();
6408 status = AudioSystem.listAudioPorts(newPorts, portGeneration);
Eric Laurentb69681c2014-05-19 19:02:51 -07006409 if (status != SUCCESS) {
Wonsik Kimb561cce2015-01-30 17:48:51 +09006410 Log.w(TAG, "updateAudioPortCache: listAudioPorts failed");
Eric Laurentb69681c2014-05-19 19:02:51 -07006411 return status;
6412 }
6413 newPatches.clear();
6414 status = AudioSystem.listAudioPatches(newPatches, patchGeneration);
Eric Laurentb69681c2014-05-19 19:02:51 -07006415 if (status != SUCCESS) {
Wonsik Kimb561cce2015-01-30 17:48:51 +09006416 Log.w(TAG, "updateAudioPortCache: listAudioPatches failed");
Eric Laurentb69681c2014-05-19 19:02:51 -07006417 return status;
6418 }
jiabinc4ecaa52017-09-26 14:28:41 -07006419 // Loop until patch generation is the same as port generation unless audio ports
6420 // and audio patches are not null.
6421 } while (patchGeneration[0] != portGeneration[0]
6422 && (ports == null || patches == null));
6423 // If the patch generation doesn't equal port generation, return ERROR here in case
6424 // of mismatch between audio ports and audio patches.
6425 if (patchGeneration[0] != portGeneration[0]) {
6426 return ERROR;
6427 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006428
6429 for (int i = 0; i < newPatches.size(); i++) {
6430 for (int j = 0; j < newPatches.get(i).sources().length; j++) {
Eric Laurentb4e09092014-06-02 19:18:43 -07006431 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sources()[j],
6432 newPorts);
Eric Laurentb69681c2014-05-19 19:02:51 -07006433 newPatches.get(i).sources()[j] = portCfg;
6434 }
6435 for (int j = 0; j < newPatches.get(i).sinks().length; j++) {
Eric Laurentb4e09092014-06-02 19:18:43 -07006436 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sinks()[j],
6437 newPorts);
Eric Laurentb69681c2014-05-19 19:02:51 -07006438 newPatches.get(i).sinks()[j] = portCfg;
6439 }
6440 }
Wonsik Kimb561cce2015-01-30 17:48:51 +09006441 for (Iterator<AudioPatch> i = newPatches.iterator(); i.hasNext(); ) {
6442 AudioPatch newPatch = i.next();
6443 boolean hasInvalidPort = false;
6444 for (AudioPortConfig portCfg : newPatch.sources()) {
6445 if (portCfg == null) {
6446 hasInvalidPort = true;
6447 break;
6448 }
6449 }
6450 for (AudioPortConfig portCfg : newPatch.sinks()) {
6451 if (portCfg == null) {
6452 hasInvalidPort = true;
6453 break;
6454 }
6455 }
6456 if (hasInvalidPort) {
6457 // Temporarily remove patches with invalid ports. One who created the patch
6458 // is responsible for dealing with the port change.
6459 i.remove();
6460 }
6461 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006462
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006463 sPreviousAudioPortsCached = sAudioPortsCached;
Eric Laurentf076db42015-01-14 13:23:27 -08006464 sAudioPortsCached = newPorts;
6465 sAudioPatchesCached = newPatches;
6466 sAudioPortGeneration = portGeneration[0];
Eric Laurentb69681c2014-05-19 19:02:51 -07006467 }
6468 if (ports != null) {
6469 ports.clear();
Eric Laurentf076db42015-01-14 13:23:27 -08006470 ports.addAll(sAudioPortsCached);
Eric Laurentb69681c2014-05-19 19:02:51 -07006471 }
6472 if (patches != null) {
6473 patches.clear();
Eric Laurentf076db42015-01-14 13:23:27 -08006474 patches.addAll(sAudioPatchesCached);
Eric Laurentb69681c2014-05-19 19:02:51 -07006475 }
Eric Laurent8a1e7a82015-05-08 11:43:05 -07006476 if (previousPorts != null) {
6477 previousPorts.clear();
6478 previousPorts.addAll(sPreviousAudioPortsCached);
6479 }
Eric Laurentb69681c2014-05-19 19:02:51 -07006480 }
6481 return SUCCESS;
6482 }
6483
Eric Laurentf076db42015-01-14 13:23:27 -08006484 static AudioPortConfig updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006485 AudioPort port = portCfg.port();
6486 int k;
6487 for (k = 0; k < ports.size(); k++) {
6488 // compare handles because the port returned by JNI is not of the correct
6489 // subclass
6490 if (ports.get(k).handle().equals(port.handle())) {
Eric Laurentb69681c2014-05-19 19:02:51 -07006491 port = ports.get(k);
6492 break;
6493 }
6494 }
6495 if (k == ports.size()) {
6496 // this hould never happen
6497 Log.e(TAG, "updatePortConfig port not found for handle: "+port.handle().id());
6498 return null;
6499 }
6500 AudioGainConfig gainCfg = portCfg.gain();
6501 if (gainCfg != null) {
6502 AudioGain gain = port.gain(gainCfg.index());
6503 gainCfg = gain.buildConfig(gainCfg.mode(),
6504 gainCfg.channelMask(),
6505 gainCfg.values(),
6506 gainCfg.rampDurationMs());
6507 }
6508 return port.buildConfig(portCfg.samplingRate(),
6509 portCfg.channelMask(),
6510 portCfg.format(),
6511 gainCfg);
6512 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006513
6514 private OnAmPortUpdateListener mPortListener = null;
6515
6516 /**
6517 * The message sent to apps when the contents of the device list changes if they provide
Andrew Solovay5c05ded2018-10-02 14:14:42 -07006518 * a {@link Handler} object to addOnAudioDeviceConnectionListener().
Paul McLeane3383cc2015-05-08 11:41:20 -07006519 */
Paul McLeancbeb8a22015-06-10 08:21:27 -07006520 private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0;
6521 private final static int MSG_DEVICES_DEVICES_ADDED = 1;
6522 private final static int MSG_DEVICES_DEVICES_REMOVED = 2;
Paul McLeane3383cc2015-05-08 11:41:20 -07006523
Paul McLean8e6c9f42015-05-19 11:13:41 -07006524 /**
6525 * The list of {@link AudioDeviceCallback} objects to receive add/remove notifications.
6526 */
Jack He89f97982018-05-02 19:10:56 -07006527 private final ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate> mDeviceCallbacks =
Paul McLean03346882015-05-12 15:36:56 -07006528 new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>();
Paul McLeane3383cc2015-05-08 11:41:20 -07006529
6530 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006531 * The following are flags to allow users of {@link AudioManager#getDevices(int)} to filter
6532 * the results list to only those device types they are interested in.
6533 */
6534 /**
Paul McLeane3383cc2015-05-08 11:41:20 -07006535 * Specifies to the {@link AudioManager#getDevices(int)} method to include
6536 * source (i.e. input) audio devices.
6537 */
6538 public static final int GET_DEVICES_INPUTS = 0x0001;
6539
6540 /**
6541 * Specifies to the {@link AudioManager#getDevices(int)} method to include
6542 * sink (i.e. output) audio devices.
6543 */
6544 public static final int GET_DEVICES_OUTPUTS = 0x0002;
6545
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07006546 /** @hide */
6547 @IntDef(flag = true, prefix = "GET_DEVICES", value = {
6548 GET_DEVICES_INPUTS,
6549 GET_DEVICES_OUTPUTS }
6550 )
6551 @Retention(RetentionPolicy.SOURCE)
6552 public @interface AudioDeviceRole {}
6553
Paul McLeane3383cc2015-05-08 11:41:20 -07006554 /**
6555 * Specifies to the {@link AudioManager#getDevices(int)} method to include both
6556 * source and sink devices.
6557 */
6558 public static final int GET_DEVICES_ALL = GET_DEVICES_OUTPUTS | GET_DEVICES_INPUTS;
6559
6560 /**
6561 * Determines if a given AudioDevicePort meets the specified filter criteria.
6562 * @param port The port to test.
6563 * @param flags A set of bitflags specifying the criteria to test.
6564 * @see {@link GET_DEVICES_OUTPUTS} and {@link GET_DEVICES_INPUTS}
6565 **/
6566 private static boolean checkFlags(AudioDevicePort port, int flags) {
6567 return port.role() == AudioPort.ROLE_SINK && (flags & GET_DEVICES_OUTPUTS) != 0 ||
6568 port.role() == AudioPort.ROLE_SOURCE && (flags & GET_DEVICES_INPUTS) != 0;
6569 }
6570
Paul McLean11354572015-08-07 12:50:48 -06006571 private static boolean checkTypes(AudioDevicePort port) {
6572 return AudioDeviceInfo.convertInternalDeviceToDeviceType(port.type()) !=
jiabin9697c6c2018-03-20 17:13:04 -07006573 AudioDeviceInfo.TYPE_UNKNOWN;
Paul McLean11354572015-08-07 12:50:48 -06006574 }
6575
Paul McLeane3383cc2015-05-08 11:41:20 -07006576 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006577 * Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices
6578 * currently connected to the system and meeting the criteria specified in the
6579 * <code>flags</code> parameter.
Paul McLeane3383cc2015-05-08 11:41:20 -07006580 * @param flags A set of bitflags specifying the criteria to test.
Elliot Waite54de77472017-01-11 15:30:35 -08006581 * @see #GET_DEVICES_OUTPUTS
6582 * @see #GET_DEVICES_INPUTS
6583 * @see #GET_DEVICES_ALL
Paul McLeane3383cc2015-05-08 11:41:20 -07006584 * @return A (possibly zero-length) array of AudioDeviceInfo objects.
6585 */
Jean-Michel Trivi21cd5412019-10-30 08:16:51 -07006586 public AudioDeviceInfo[] getDevices(@AudioDeviceRole int flags) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006587 return getDevicesStatic(flags);
6588 }
6589
Paul McLean8e6c9f42015-05-19 11:13:41 -07006590 /**
6591 * Does the actual computation to generate an array of (externally-visible) AudioDeviceInfo
6592 * objects from the current (internal) AudioDevicePort list.
6593 */
Paul McLean03346882015-05-12 15:36:56 -07006594 private static AudioDeviceInfo[]
6595 infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006596
Paul McLean8e6c9f42015-05-19 11:13:41 -07006597 // figure out how many AudioDeviceInfo we need space for...
Paul McLeane3383cc2015-05-08 11:41:20 -07006598 int numRecs = 0;
6599 for (AudioDevicePort port : ports) {
Paul McLean11354572015-08-07 12:50:48 -06006600 if (checkTypes(port) && checkFlags(port, flags)) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006601 numRecs++;
6602 }
6603 }
6604
Paul McLean8e6c9f42015-05-19 11:13:41 -07006605 // Now load them up...
Paul McLeane3383cc2015-05-08 11:41:20 -07006606 AudioDeviceInfo[] deviceList = new AudioDeviceInfo[numRecs];
6607 int slot = 0;
6608 for (AudioDevicePort port : ports) {
Paul McLean11354572015-08-07 12:50:48 -06006609 if (checkTypes(port) && checkFlags(port, flags)) {
Paul McLeane3383cc2015-05-08 11:41:20 -07006610 deviceList[slot++] = new AudioDeviceInfo(port);
6611 }
6612 }
6613
6614 return deviceList;
6615 }
6616
Paul McLean03346882015-05-12 15:36:56 -07006617 /*
Paul McLean8e6c9f42015-05-19 11:13:41 -07006618 * Calculate the list of ports that are in ports_B, but not in ports_A. This is used by
6619 * the add/remove callback mechanism to provide a list of the newly added or removed devices
6620 * rather than the whole list and make the app figure it out.
6621 * Note that calling this method with:
6622 * ports_A == PREVIOUS_ports and ports_B == CURRENT_ports will calculated ADDED ports.
6623 * ports_A == CURRENT_ports and ports_B == PREVIOUS_ports will calculated REMOVED ports.
Paul McLean03346882015-05-12 15:36:56 -07006624 */
6625 private static AudioDeviceInfo[] calcListDeltas(
6626 ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags) {
6627
6628 ArrayList<AudioDevicePort> delta_ports = new ArrayList<AudioDevicePort>();
6629
6630 AudioDevicePort cur_port = null;
6631 for (int cur_index = 0; cur_index < ports_B.size(); cur_index++) {
6632 boolean cur_port_found = false;
6633 cur_port = ports_B.get(cur_index);
6634 for (int prev_index = 0;
6635 prev_index < ports_A.size() && !cur_port_found;
6636 prev_index++) {
6637 cur_port_found = (cur_port.id() == ports_A.get(prev_index).id());
6638 }
6639
6640 if (!cur_port_found) {
6641 delta_ports.add(cur_port);
6642 }
6643 }
6644
6645 return infoListFromPortList(delta_ports, flags);
6646 }
6647
Paul McLeane3383cc2015-05-08 11:41:20 -07006648 /**
Paul McLean03346882015-05-12 15:36:56 -07006649 * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently
6650 * connected to the system and meeting the criteria specified in the <code>flags</code>
6651 * parameter.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006652 * This is an internal function. The public API front is getDevices(int).
Paul McLean03346882015-05-12 15:36:56 -07006653 * @param flags A set of bitflags specifying the criteria to test.
Elliot Waite54de77472017-01-11 15:30:35 -08006654 * @see #GET_DEVICES_OUTPUTS
6655 * @see #GET_DEVICES_INPUTS
6656 * @see #GET_DEVICES_ALL
Paul McLean03346882015-05-12 15:36:56 -07006657 * @return A (possibly zero-length) array of AudioDeviceInfo objects.
6658 * @hide
6659 */
6660 public static AudioDeviceInfo[] getDevicesStatic(int flags) {
6661 ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>();
6662 int status = AudioManager.listAudioDevicePorts(ports);
6663 if (status != AudioManager.SUCCESS) {
6664 // fail and bail!
Paul McLean8e6c9f42015-05-19 11:13:41 -07006665 return new AudioDeviceInfo[0]; // Always return an array.
Paul McLean03346882015-05-12 15:36:56 -07006666 }
6667
6668 return infoListFromPortList(ports, flags);
6669 }
6670
6671 /**
Eric Laurentb36d4a12020-10-09 09:52:49 -07006672 * Returns an {@link AudioDeviceInfo} corresponding to the specified {@link AudioPort} ID.
6673 * @param portId The audio port ID to look up for.
6674 * @param flags A set of bitflags specifying the criteria to test.
6675 * @see #GET_DEVICES_OUTPUTS
6676 * @see #GET_DEVICES_INPUTS
6677 * @see #GET_DEVICES_ALL
6678 * @return An AudioDeviceInfo or null if no device with matching port ID is found.
6679 * @hide
6680 */
6681 public static AudioDeviceInfo getDeviceForPortId(int portId, int flags) {
6682 if (portId == 0) {
6683 return null;
6684 }
6685 AudioDeviceInfo[] devices = getDevicesStatic(flags);
6686 for (AudioDeviceInfo device : devices) {
6687 if (device.getId() == portId) {
6688 return device;
6689 }
6690 }
6691 return null;
6692 }
6693
6694 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006695 * Registers an {@link AudioDeviceCallback} object to receive notifications of changes
Paul McLeane3383cc2015-05-08 11:41:20 -07006696 * to the set of connected audio devices.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006697 * @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect
6698 * notifications.
6699 * @param handler Specifies the {@link Handler} object for the thread on which to execute
6700 * the callback. If <code>null</code>, the {@link Handler} associated with the main
6701 * {@link Looper} will be used.
Paul McLeane3383cc2015-05-08 11:41:20 -07006702 */
Paul McLean03346882015-05-12 15:36:56 -07006703 public void registerAudioDeviceCallback(AudioDeviceCallback callback,
Jean-Michel Trivi1ec66182019-12-30 09:53:04 -08006704 @Nullable Handler handler) {
Eric Laurent1691f732015-07-14 16:27:54 -07006705 synchronized (mDeviceCallbacks) {
6706 if (callback != null && !mDeviceCallbacks.containsKey(callback)) {
Eric Laurentc573bc52015-06-26 10:01:12 -07006707 if (mDeviceCallbacks.size() == 0) {
6708 if (mPortListener == null) {
6709 mPortListener = new OnAmPortUpdateListener();
6710 }
6711 registerAudioPortUpdateListener(mPortListener);
6712 }
Paul McLeancbeb8a22015-06-10 08:21:27 -07006713 NativeEventHandlerDelegate delegate =
6714 new NativeEventHandlerDelegate(callback, handler);
6715 mDeviceCallbacks.put(callback, delegate);
jiabin8c3a7672018-05-22 15:44:21 -07006716 broadcastDeviceListChange_sync(delegate.getHandler());
Paul McLeane3383cc2015-05-08 11:41:20 -07006717 }
6718 }
6719 }
6720
6721 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006722 * Unregisters an {@link AudioDeviceCallback} object which has been previously registered
Paul McLeane3383cc2015-05-08 11:41:20 -07006723 * to receive notifications of changes to the set of connected audio devices.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006724 * @param callback The {@link AudioDeviceCallback} object that was previously registered
Elliot Waite54de77472017-01-11 15:30:35 -08006725 * with {@link AudioManager#registerAudioDeviceCallback} to be unregistered.
Paul McLeane3383cc2015-05-08 11:41:20 -07006726 */
Paul McLean03346882015-05-12 15:36:56 -07006727 public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) {
6728 synchronized (mDeviceCallbacks) {
6729 if (mDeviceCallbacks.containsKey(callback)) {
6730 mDeviceCallbacks.remove(callback);
Eric Laurentc573bc52015-06-26 10:01:12 -07006731 if (mDeviceCallbacks.size() == 0) {
6732 unregisterAudioPortUpdateListener(mPortListener);
6733 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006734 }
6735 }
6736 }
6737
jiabinc0f49442018-01-05 10:23:50 -08006738 /**
6739 * Set port id for microphones by matching device type and address.
6740 * @hide
6741 */
6742 public static void setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones) {
6743 AudioDeviceInfo[] devices = getDevicesStatic(AudioManager.GET_DEVICES_INPUTS);
6744 for (int i = microphones.size() - 1; i >= 0; i--) {
6745 boolean foundPortId = false;
6746 for (AudioDeviceInfo device : devices) {
6747 if (device.getPort().type() == microphones.get(i).getInternalDeviceType()
6748 && TextUtils.equals(device.getAddress(), microphones.get(i).getAddress())) {
6749 microphones.get(i).setId(device.getId());
6750 foundPortId = true;
6751 break;
6752 }
6753 }
6754 if (!foundPortId) {
6755 Log.i(TAG, "Failed to find port id for device with type:"
6756 + microphones.get(i).getType() + " address:"
6757 + microphones.get(i).getAddress());
6758 microphones.remove(i);
6759 }
6760 }
6761 }
6762
6763 /**
jiabin589a2362018-02-22 16:21:53 -08006764 * Convert {@link AudioDeviceInfo} to {@link MicrophoneInfo}.
6765 * @hide
6766 */
6767 public static MicrophoneInfo microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo) {
6768 int deviceType = deviceInfo.getType();
6769 int micLocation = (deviceType == AudioDeviceInfo.TYPE_BUILTIN_MIC
6770 || deviceType == AudioDeviceInfo.TYPE_TELEPHONY) ? MicrophoneInfo.LOCATION_MAINBODY
6771 : deviceType == AudioDeviceInfo.TYPE_UNKNOWN ? MicrophoneInfo.LOCATION_UNKNOWN
6772 : MicrophoneInfo.LOCATION_PERIPHERAL;
6773 MicrophoneInfo microphone = new MicrophoneInfo(
6774 deviceInfo.getPort().name() + deviceInfo.getId(),
6775 deviceInfo.getPort().type(), deviceInfo.getAddress(), micLocation,
6776 MicrophoneInfo.GROUP_UNKNOWN, MicrophoneInfo.INDEX_IN_THE_GROUP_UNKNOWN,
6777 MicrophoneInfo.POSITION_UNKNOWN, MicrophoneInfo.ORIENTATION_UNKNOWN,
6778 new ArrayList<Pair<Float, Float>>(), new ArrayList<Pair<Integer, Integer>>(),
6779 MicrophoneInfo.SENSITIVITY_UNKNOWN, MicrophoneInfo.SPL_UNKNOWN,
6780 MicrophoneInfo.SPL_UNKNOWN, MicrophoneInfo.DIRECTIONALITY_UNKNOWN);
6781 microphone.setId(deviceInfo.getId());
6782 return microphone;
6783 }
6784
6785 /**
jiabind0be5b22018-04-10 14:10:04 -07006786 * Add {@link MicrophoneInfo} by device information while filtering certain types.
6787 */
6788 private void addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones,
6789 HashSet<Integer> filterTypes) {
6790 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_INPUTS);
6791 for (AudioDeviceInfo device : devices) {
6792 if (filterTypes.contains(device.getType())) {
6793 continue;
6794 }
6795 MicrophoneInfo microphone = microphoneInfoFromAudioDeviceInfo(device);
6796 microphones.add(microphone);
6797 }
6798 }
6799
6800 /**
jiabinc0f49442018-01-05 10:23:50 -08006801 * Returns a list of {@link MicrophoneInfo} that corresponds to the characteristics
6802 * of all available microphones. The list is empty when no microphones are available
6803 * on the device. An error during the query will result in an IOException being thrown.
6804 *
6805 * @return a list that contains all microphones' characteristics
6806 * @throws IOException if an error occurs.
6807 */
6808 public List<MicrophoneInfo> getMicrophones() throws IOException {
6809 ArrayList<MicrophoneInfo> microphones = new ArrayList<MicrophoneInfo>();
6810 int status = AudioSystem.getMicrophones(microphones);
jiabind0be5b22018-04-10 14:10:04 -07006811 HashSet<Integer> filterTypes = new HashSet<>();
6812 filterTypes.add(AudioDeviceInfo.TYPE_TELEPHONY);
jiabinc0f49442018-01-05 10:23:50 -08006813 if (status != AudioManager.SUCCESS) {
jiabind0be5b22018-04-10 14:10:04 -07006814 // fail and populate microphones with unknown characteristics by device information.
jiabina26a7622018-04-11 15:38:46 -07006815 if (status != AudioManager.ERROR_INVALID_OPERATION) {
6816 Log.e(TAG, "getMicrophones failed:" + status);
6817 }
6818 Log.i(TAG, "fallback on device info");
jiabind0be5b22018-04-10 14:10:04 -07006819 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
6820 return microphones;
jiabinc0f49442018-01-05 10:23:50 -08006821 }
6822 setPortIdForMicrophones(microphones);
jiabind0be5b22018-04-10 14:10:04 -07006823 filterTypes.add(AudioDeviceInfo.TYPE_BUILTIN_MIC);
6824 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes);
jiabinc0f49442018-01-05 10:23:50 -08006825 return microphones;
6826 }
6827
Arun Mirpuricb102fa2019-01-11 18:39:21 -08006828 /**
6829 * Returns a list of audio formats that corresponds to encoding formats
6830 * supported on offload path for A2DP playback.
6831 *
6832 * @return a list of {@link BluetoothCodecConfig} objects containing encoding formats
6833 * supported for offload A2DP playback
6834 * @hide
6835 */
6836 public List<BluetoothCodecConfig> getHwOffloadEncodingFormatsSupportedForA2DP() {
6837 ArrayList<Integer> formatsList = new ArrayList<Integer>();
6838 ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<BluetoothCodecConfig>();
6839
6840 int status = AudioSystem.getHwOffloadEncodingFormatsSupportedForA2DP(formatsList);
6841 if (status != AudioManager.SUCCESS) {
6842 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status);
6843 return codecConfigList;
6844 }
6845
6846 for (Integer format : formatsList) {
6847 int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format);
6848 if (btSourceCodec
6849 != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
6850 codecConfigList.add(new BluetoothCodecConfig(btSourceCodec));
6851 }
6852 }
6853 return codecConfigList;
6854 }
6855
Paul McLeancbeb8a22015-06-10 08:21:27 -07006856 // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the
6857 // (unpredictable) last time updateAudioPortCache() was called by someone, keep a list
6858 // of the ports that exist at the time of the last notification.
6859 private ArrayList<AudioDevicePort> mPreviousPorts = new ArrayList<AudioDevicePort>();
6860
Paul McLeane3383cc2015-05-08 11:41:20 -07006861 /**
Paul McLean8e6c9f42015-05-19 11:13:41 -07006862 * Internal method to compute and generate add/remove messages and then send to any
jiabin8c3a7672018-05-22 15:44:21 -07006863 * registered callbacks. Must be called synchronized on mDeviceCallbacks.
Paul McLeane3383cc2015-05-08 11:41:20 -07006864 */
jiabin8c3a7672018-05-22 15:44:21 -07006865 private void broadcastDeviceListChange_sync(Handler handler) {
Paul McLean03346882015-05-12 15:36:56 -07006866 int status;
6867
Paul McLeancbeb8a22015-06-10 08:21:27 -07006868 // Get the new current set of ports
Paul McLean03346882015-05-12 15:36:56 -07006869 ArrayList<AudioDevicePort> current_ports = new ArrayList<AudioDevicePort>();
6870 status = AudioManager.listAudioDevicePorts(current_ports);
6871 if (status != AudioManager.SUCCESS) {
6872 return;
6873 }
6874
Paul McLeancbeb8a22015-06-10 08:21:27 -07006875 if (handler != null) {
6876 // This is the callback for the registration, so send the current list
6877 AudioDeviceInfo[] deviceList =
6878 infoListFromPortList(current_ports, GET_DEVICES_ALL);
6879 handler.sendMessage(
6880 Message.obtain(handler, MSG_DEVICES_CALLBACK_REGISTERED, deviceList));
6881 } else {
6882 AudioDeviceInfo[] added_devices =
6883 calcListDeltas(mPreviousPorts, current_ports, GET_DEVICES_ALL);
6884 AudioDeviceInfo[] removed_devices =
6885 calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL);
Paul McLeancbeb8a22015-06-10 08:21:27 -07006886 if (added_devices.length != 0 || removed_devices.length != 0) {
jiabin8c3a7672018-05-22 15:44:21 -07006887 for (int i = 0; i < mDeviceCallbacks.size(); i++) {
6888 handler = mDeviceCallbacks.valueAt(i).getHandler();
6889 if (handler != null) {
6890 if (removed_devices.length != 0) {
6891 handler.sendMessage(Message.obtain(handler,
6892 MSG_DEVICES_DEVICES_REMOVED,
6893 removed_devices));
6894 }
6895 if (added_devices.length != 0) {
6896 handler.sendMessage(Message.obtain(handler,
6897 MSG_DEVICES_DEVICES_ADDED,
6898 added_devices));
Paul McLeancbeb8a22015-06-10 08:21:27 -07006899 }
Paul McLean03346882015-05-12 15:36:56 -07006900 }
6901 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006902 }
6903 }
Paul McLeancbeb8a22015-06-10 08:21:27 -07006904
6905 mPreviousPorts = current_ports;
Paul McLeane3383cc2015-05-08 11:41:20 -07006906 }
6907
6908 /**
6909 * Handles Port list update notifications from the AudioManager
6910 */
6911 private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener {
6912 static final String TAG = "OnAmPortUpdateListener";
6913 public void onAudioPortListUpdate(AudioPort[] portList) {
jiabin8c3a7672018-05-22 15:44:21 -07006914 synchronized (mDeviceCallbacks) {
6915 broadcastDeviceListChange_sync(null);
6916 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006917 }
6918
6919 /**
6920 * Callback method called upon audio patch list update.
Paul McLean8e6c9f42015-05-19 11:13:41 -07006921 * Note: We don't do anything with Patches at this time, so ignore this notification.
6922 * @param patchList the updated list of audio patches.
Paul McLeane3383cc2015-05-08 11:41:20 -07006923 */
6924 public void onAudioPatchListUpdate(AudioPatch[] patchList) {}
6925
6926 /**
6927 * Callback method called when the mediaserver dies
6928 */
6929 public void onServiceDied() {
jiabin8c3a7672018-05-22 15:44:21 -07006930 synchronized (mDeviceCallbacks) {
6931 broadcastDeviceListChange_sync(null);
6932 }
Paul McLeane3383cc2015-05-08 11:41:20 -07006933 }
6934 }
6935
Eric Laurent1d3cdce2018-01-20 10:31:21 -08006936
6937 /**
6938 * @hide
6939 * Abstract class to receive event notification about audioserver process state.
6940 */
6941 @SystemApi
6942 public abstract static class AudioServerStateCallback {
6943 public void onAudioServerDown() { }
6944 public void onAudioServerUp() { }
6945 }
6946
6947 private Executor mAudioServerStateExec;
6948 private AudioServerStateCallback mAudioServerStateCb;
6949 private final Object mAudioServerStateCbLock = new Object();
6950
6951 private final IAudioServerStateDispatcher mAudioServerStateDispatcher =
6952 new IAudioServerStateDispatcher.Stub() {
6953 @Override
6954 public void dispatchAudioServerStateChange(boolean state) {
6955 Executor exec;
6956 AudioServerStateCallback cb;
6957
6958 synchronized (mAudioServerStateCbLock) {
6959 exec = mAudioServerStateExec;
6960 cb = mAudioServerStateCb;
6961 }
6962
6963 if ((exec == null) || (cb == null)) {
6964 return;
6965 }
6966 if (state) {
6967 exec.execute(() -> cb.onAudioServerUp());
6968 } else {
6969 exec.execute(() -> cb.onAudioServerDown());
6970 }
6971 }
6972 };
6973
6974 /**
6975 * @hide
6976 * Registers a callback for notification of audio server state changes.
6977 * @param executor {@link Executor} to handle the callbacks
6978 * @param stateCallback the callback to receive the audio server state changes
6979 * To remove the callabck, pass a null reference for both executor and stateCallback.
6980 */
6981 @SystemApi
6982 public void setAudioServerStateCallback(@NonNull Executor executor,
6983 @NonNull AudioServerStateCallback stateCallback) {
6984 if (stateCallback == null) {
6985 throw new IllegalArgumentException("Illegal null AudioServerStateCallback");
6986 }
6987 if (executor == null) {
6988 throw new IllegalArgumentException(
6989 "Illegal null Executor for the AudioServerStateCallback");
6990 }
6991
6992 synchronized (mAudioServerStateCbLock) {
6993 if (mAudioServerStateCb != null) {
6994 throw new IllegalStateException(
6995 "setAudioServerStateCallback called with already registered callabck");
6996 }
6997 final IAudioService service = getService();
6998 try {
6999 service.registerAudioServerStateDispatcher(mAudioServerStateDispatcher);
7000 } catch (RemoteException e) {
7001 throw e.rethrowFromSystemServer();
7002 }
7003 mAudioServerStateExec = executor;
7004 mAudioServerStateCb = stateCallback;
7005 }
7006 }
7007
7008 /**
7009 * @hide
7010 * Unregisters the callback for notification of audio server state changes.
7011 */
7012 @SystemApi
7013 public void clearAudioServerStateCallback() {
7014 synchronized (mAudioServerStateCbLock) {
7015 if (mAudioServerStateCb != null) {
7016 final IAudioService service = getService();
7017 try {
7018 service.unregisterAudioServerStateDispatcher(
7019 mAudioServerStateDispatcher);
7020 } catch (RemoteException e) {
7021 throw e.rethrowFromSystemServer();
7022 }
7023 }
7024 mAudioServerStateExec = null;
7025 mAudioServerStateCb = null;
7026 }
7027 }
7028
7029 /**
7030 * @hide
7031 * Checks if native audioservice is running or not.
7032 * @return true if native audioservice runs, false otherwise.
7033 */
7034 @SystemApi
7035 public boolean isAudioServerRunning() {
7036 final IAudioService service = getService();
7037 try {
7038 return service.isAudioServerRunning();
7039 } catch (RemoteException e) {
7040 throw e.rethrowFromSystemServer();
7041 }
7042 }
7043
jiabin39940752018-04-02 18:18:45 -07007044 /**
Kriti Dang527e66c2021-03-04 10:37:22 +01007045 * Sets the surround sound mode.
7046 *
7047 * @return true if successful, otherwise false
7048 */
7049 @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
7050 public boolean setEncodedSurroundMode(@EncodedSurroundOutputMode int mode) {
7051 try {
7052 return getService().setEncodedSurroundMode(mode);
7053 } catch (RemoteException e) {
7054 throw e.rethrowFromSystemServer();
7055 }
7056 }
7057
7058 /**
7059 * Gets the surround sound mode.
7060 *
7061 * @return true if successful, otherwise false
7062 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007063 public @EncodedSurroundOutputMode int getEncodedSurroundMode() {
7064 try {
Kriti Dang98fdb262021-04-01 13:26:00 +02007065 return getService().getEncodedSurroundMode(
7066 getContext().getApplicationInfo().targetSdkVersion);
Kriti Dang527e66c2021-03-04 10:37:22 +01007067 } catch (RemoteException e) {
7068 throw e.rethrowFromSystemServer();
7069 }
7070 }
7071
7072 /**
jiabin39940752018-04-02 18:18:45 -07007073 * @hide
7074 * Returns all surround formats.
7075 * @return a map where the key is a surround format and
7076 * the value indicates the surround format is enabled or not
7077 */
Marin Shalamanov49e778e2021-06-02 14:12:41 +02007078 @TestApi
7079 @NonNull
jiabin39940752018-04-02 18:18:45 -07007080 public Map<Integer, Boolean> getSurroundFormats() {
Kriti Dang1380c0e2021-06-04 14:51:48 +02007081 try {
7082 return getService().getSurroundFormats();
7083 } catch (RemoteException e) {
7084 throw e.rethrowFromSystemServer();
jiabin39940752018-04-02 18:18:45 -07007085 }
jiabin39940752018-04-02 18:18:45 -07007086 }
7087
7088 /**
Kriti Dang3f296bd2021-05-31 15:54:44 +02007089 * Sets and persists a certain surround format as enabled or not.
7090 * <p>
7091 * This API is called by TvSettings surround sound menu when user enables or disables a
7092 * surround sound format. This setting is persisted as global user setting.
7093 * Applications should revert their changes to surround sound settings unless they intend to
7094 * modify the global user settings across all apps. The framework does not auto-revert an
7095 * application's settings after a lifecycle event. Audio focus is not required to apply these
7096 * settings.
Kriti Dang1985c452021-05-10 17:06:44 +02007097 *
jiabin39940752018-04-02 18:18:45 -07007098 * @param enabled the required surround format state, true for enabled, false for disabled
7099 * @return true if successful, otherwise false
7100 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007101 @RequiresPermission(android.Manifest.permission.WRITE_SETTINGS)
jiabin39940752018-04-02 18:18:45 -07007102 public boolean setSurroundFormatEnabled(
7103 @AudioFormat.SurroundSoundEncoding int audioFormat, boolean enabled) {
Kriti Dang527e66c2021-03-04 10:37:22 +01007104 try {
7105 return getService().setSurroundFormatEnabled(audioFormat, enabled);
7106 } catch (RemoteException e) {
7107 throw e.rethrowFromSystemServer();
7108 }
7109 }
7110
7111 /**
7112 * Gets whether a certain surround format is enabled or not.
7113 * @param audioFormat a surround format
7114 *
7115 * @return whether the required surround format is enabled
7116 */
Kriti Dang527e66c2021-03-04 10:37:22 +01007117 public boolean isSurroundFormatEnabled(@AudioFormat.SurroundSoundEncoding int audioFormat) {
7118 try {
7119 return getService().isSurroundFormatEnabled(audioFormat);
7120 } catch (RemoteException e) {
7121 throw e.rethrowFromSystemServer();
7122 }
jiabin39940752018-04-02 18:18:45 -07007123 }
7124
7125 /**
7126 * @hide
7127 * Returns all surround formats that are reported by the connected HDMI device.
Kriti Dang01924232021-03-02 13:51:09 +01007128 * The return values are not affected by calling setSurroundFormatEnabled.
jiabin39940752018-04-02 18:18:45 -07007129 *
Kriti Dang01924232021-03-02 13:51:09 +01007130 * @return a list of surround formats
jiabin39940752018-04-02 18:18:45 -07007131 */
Kriti Dang1380c0e2021-06-04 14:51:48 +02007132 @TestApi
7133 @NonNull
7134 public List<Integer> getReportedSurroundFormats() {
7135 try {
7136 return getService().getReportedSurroundFormats();
7137 } catch (RemoteException e) {
7138 throw e.rethrowFromSystemServer();
jiabin39940752018-04-02 18:18:45 -07007139 }
jiabin39940752018-04-02 18:18:45 -07007140 }
7141
jiabin66f9e722018-11-02 16:20:19 -07007142 /**
7143 * Return if audio haptic coupled playback is supported or not.
7144 *
7145 * @return whether audio haptic playback supported.
7146 */
7147 public static boolean isHapticPlaybackSupported() {
7148 return AudioSystem.isHapticPlaybackSupported();
7149 }
7150
François Gaffie0699fec2018-07-09 14:35:10 +02007151 /**
7152 * @hide
7153 * Introspection API to retrieve audio product strategies.
7154 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
7155 * audio product strategies, which is indexed by a weakly typed index in order to be extended
7156 * by OEM without any needs of AOSP patches.
7157 * The {Car|Oem}AudioManager can expose API to build {@link AudioAttributes} for a given product
7158 * strategy refered either by its index or human readable string. It will allow clients
7159 * application to start streaming data using these {@link AudioAttributes} on the selected
7160 * device by Audio Policy Engine.
7161 * @return a (possibly zero-length) array of
7162 * {@see android.media.audiopolicy.AudioProductStrategy} objects.
7163 */
7164 @SystemApi
Hayden Gomes6d69bde2019-04-04 13:10:13 -07007165 @NonNull
François Gaffie0699fec2018-07-09 14:35:10 +02007166 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomes6d69bde2019-04-04 13:10:13 -07007167 public static List<AudioProductStrategy> getAudioProductStrategies() {
François Gaffie0699fec2018-07-09 14:35:10 +02007168 final IAudioService service = getService();
7169 try {
7170 return service.getAudioProductStrategies();
7171 } catch (RemoteException e) {
7172 throw e.rethrowFromSystemServer();
7173 }
7174 }
7175
François Gaffieadcd00a2018-09-18 17:06:26 +02007176 /**
7177 * @hide
7178 * Introspection API to retrieve audio volume groups.
7179 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of
7180 * audio volume groups.
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007181 * @return a (possibly zero-length) List of
7182 * {@see android.media.audiopolicy.AudioVolumeGroup} objects.
François Gaffieadcd00a2018-09-18 17:06:26 +02007183 */
7184 @SystemApi
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007185 @NonNull
François Gaffieadcd00a2018-09-18 17:06:26 +02007186 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007187 public static List<AudioVolumeGroup> getAudioVolumeGroups() {
François Gaffie9c362102018-09-21 17:43:52 +02007188 final IAudioService service = getService();
7189 try {
Hayden Gomesebd6aaa2019-04-04 13:14:21 -07007190 return service.getAudioVolumeGroups();
François Gaffie9c362102018-09-21 17:43:52 +02007191 } catch (RemoteException e) {
7192 throw e.rethrowFromSystemServer();
7193 }
François Gaffieadcd00a2018-09-18 17:06:26 +02007194 }
7195
7196 /**
7197 * @hide
7198 * Callback registered by client to be notified upon volume group change.
7199 */
7200 @SystemApi
7201 public abstract static class VolumeGroupCallback {
7202 /**
7203 * Callback method called upon audio volume group change.
7204 * @param group the group for which the volume has changed
7205 */
7206 public void onAudioVolumeGroupChanged(int group, int flags) {}
7207 }
7208
7209 /**
7210 * @hide
7211 * Register an audio volume group change listener.
7212 * @param callback the {@link VolumeGroupCallback} to register
7213 */
7214 @SystemApi
7215 public void registerVolumeGroupCallback(
7216 @NonNull Executor executor,
7217 @NonNull VolumeGroupCallback callback) {
7218 Preconditions.checkNotNull(executor, "executor must not be null");
7219 Preconditions.checkNotNull(callback, "volume group change cb must not be null");
7220 sAudioAudioVolumeGroupChangedHandler.init();
7221 // TODO: make use of executor
7222 sAudioAudioVolumeGroupChangedHandler.registerListener(callback);
7223 }
7224
7225 /**
7226 * @hide
7227 * Unregister an audio volume group change listener.
7228 * @param callback the {@link VolumeGroupCallback} to unregister
7229 */
7230 @SystemApi
7231 public void unregisterVolumeGroupCallback(
7232 @NonNull VolumeGroupCallback callback) {
7233 Preconditions.checkNotNull(callback, "volume group change cb must not be null");
7234 sAudioAudioVolumeGroupChangedHandler.unregisterListener(callback);
7235 }
jiabin39940752018-04-02 18:18:45 -07007236
jiabinad225202019-03-20 15:22:50 -07007237 /**
7238 * Return if an asset contains haptic channels or not.
jiabincfcf1032021-07-01 16:30:50 -07007239 *
7240 * @param context the {@link Context} to resolve the uri.
jiabinad225202019-03-20 15:22:50 -07007241 * @param uri the {@link Uri} of the asset.
7242 * @return true if the assert contains haptic channels.
7243 * @hide
7244 */
jiabincfcf1032021-07-01 16:30:50 -07007245 public static boolean hasHapticChannelsImpl(@NonNull Context context, @NonNull Uri uri) {
7246 MediaExtractor extractor = new MediaExtractor();
jiabinad225202019-03-20 15:22:50 -07007247 try {
jiabincfcf1032021-07-01 16:30:50 -07007248 extractor.setDataSource(context, uri, null);
7249 for (int i = 0; i < extractor.getTrackCount(); i++) {
7250 MediaFormat format = extractor.getTrackFormat(i);
7251 if (format.containsKey(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT)
7252 && format.getInteger(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) > 0) {
7253 return true;
7254 }
7255 }
7256 } catch (IOException e) {
7257 Log.e(TAG, "hasHapticChannels failure:" + e);
7258 }
7259 return false;
7260 }
7261
7262 /**
7263 * Return if an asset contains haptic channels or not.
7264 *
7265 * @param context the {@link Context} to resolve the uri.
7266 * @param uri the {@link Uri} of the asset.
7267 * @return true if the assert contains haptic channels.
7268 * @hide
7269 */
7270 public static boolean hasHapticChannels(@Nullable Context context, @NonNull Uri uri) {
7271 Objects.requireNonNull(uri);
7272 if (context != null) {
7273 return hasHapticChannelsImpl(context, uri);
7274 } else if (sContext != null) {
7275 if (DEBUG) {
7276 Log.d(TAG, "Try to use static context to query if having haptic channels");
7277 }
7278 return hasHapticChannelsImpl(sContext, uri);
7279 } else {
7280 // Try with audio service context, this may fail to get correct result.
7281 if (DEBUG) {
7282 Log.d(TAG, "Try to use audio service context to query if having haptic channels");
7283 }
7284 try {
7285 return getService().hasHapticChannels(uri);
7286 } catch (RemoteException e) {
7287 throw e.rethrowFromSystemServer();
7288 }
jiabinad225202019-03-20 15:22:50 -07007289 }
7290 }
7291
Kohsuke Yatoh900e1f12020-03-25 08:05:49 -07007292 /**
7293 * Set whether or not there is an active RTT call.
7294 * This method should be called by Telecom service.
7295 * @hide
7296 * TODO: make this a @SystemApi
7297 */
7298 public static void setRttEnabled(boolean rttEnabled) {
7299 try {
7300 getService().setRttEnabled(rttEnabled);
7301 } catch (RemoteException e) {
7302 throw e.rethrowFromSystemServer();
7303 }
7304 }
7305
Jin Seok Park16aeba382020-08-06 12:52:54 +09007306 /**
7307 * Adjusts the volume of the most relevant stream, or the given fallback
7308 * stream.
7309 * <p>
7310 * This method should only be used by applications that replace the
7311 * platform-wide management of audio settings or the main telephony
7312 * application.
7313 * <p>
7314 * This method has no effect if the device implements a fixed volume policy
7315 * as indicated by {@link #isVolumeFixed()}.
7316 * <p>This API checks if the caller has the necessary permissions based on the provided
7317 * component name, uid, and pid values.
7318 * See {@link #adjustSuggestedStreamVolume(int, int, int)}.
7319 *
7320 * @param suggestedStreamType The stream type that will be used if there
7321 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is
7322 * valid here.
7323 * @param direction The direction to adjust the volume. One of
7324 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE},
7325 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE},
7326 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}.
7327 * @param flags One or more flags.
7328 * @param packageName the package name of client application
7329 * @param uid the uid of client application
7330 * @param pid the pid of client application
7331 * @param targetSdkVersion the target sdk version of client application
7332 * @see #adjustVolume(int, int)
7333 * @see #adjustStreamVolume(int, int, int)
7334 * @see #setStreamVolume(int, int, int)
7335 * @see #isVolumeFixed()
7336 *
7337 * @hide
7338 */
7339 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7340 public void adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, int flags,
7341 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7342 try {
7343 getService().adjustSuggestedStreamVolumeForUid(suggestedStreamType, direction, flags,
7344 packageName, uid, pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7345 } catch (RemoteException e) {
7346 throw e.rethrowFromSystemServer();
7347 }
7348 }
7349
7350 /**
7351 * Adjusts the volume of a particular stream by one step in a direction.
7352 * <p>
7353 * This method should only be used by applications that replace the platform-wide
7354 * management of audio settings or the main telephony application.
7355 * <p>This method has no effect if the device implements a fixed volume policy
7356 * as indicated by {@link #isVolumeFixed()}.
7357 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed
7358 * unless the app has been granted Do Not Disturb Access.
7359 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
7360 * <p>This API checks if the caller has the necessary permissions based on the provided
7361 * component name, uid, and pid values.
7362 * See {@link #adjustStreamVolume(int, int, int)}.
7363 *
7364 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
7365 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC},
7366 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}.
7367 * @param direction The direction to adjust the volume. One of
7368 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
7369 * {@link #ADJUST_SAME}.
7370 * @param flags One or more flags.
7371 * @param packageName the package name of client application
7372 * @param uid the uid of client application
7373 * @param pid the pid of client application
7374 * @param targetSdkVersion the target sdk version of client application
7375 * @see #adjustVolume(int, int)
7376 * @see #setStreamVolume(int, int, int)
7377 * @throws SecurityException if the adjustment triggers a Do Not Disturb change
7378 * and the caller is not granted notification policy access.
7379 *
7380 * @hide
7381 */
7382 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7383 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
7384 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7385 try {
7386 getService().adjustStreamVolumeForUid(streamType, direction, flags, packageName, uid,
7387 pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7388 } catch (RemoteException e) {
7389 throw e.rethrowFromSystemServer();
7390 }
7391 }
7392
7393 /**
7394 * Sets the volume index for a particular stream.
7395 * <p>This method has no effect if the device implements a fixed volume policy
7396 * as indicated by {@link #isVolumeFixed()}.
7397 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless
7398 * the app has been granted Do Not Disturb Access.
7399 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}.
7400 * <p>This API checks if the caller has the necessary permissions based on the provided
7401 * component name, uid, and pid values.
7402 * See {@link #setStreamVolume(int, int, int)}.
7403 *
7404 * @param streamType The stream whose volume index should be set.
7405 * @param index The volume index to set. See
7406 * {@link #getStreamMaxVolume(int)} for the largest valid value.
7407 * @param flags One or more flags.
7408 * @param packageName the package name of client application
7409 * @param uid the uid of client application
7410 * @param pid the pid of client application
7411 * @param targetSdkVersion the target sdk version of client application
7412 * @see #getStreamMaxVolume(int)
7413 * @see #getStreamVolume(int)
7414 * @see #isVolumeFixed()
7415 * @throws SecurityException if the volume change triggers a Do Not Disturb change
7416 * and the caller is not granted notification policy access.
7417 *
7418 * @hide
7419 */
7420 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
7421 public void setStreamVolumeForUid(int streamType, int index, int flags,
7422 @NonNull String packageName, int uid, int pid, int targetSdkVersion) {
7423 try {
7424 getService().setStreamVolumeForUid(streamType, index, flags, packageName, uid, pid,
7425 UserHandle.getUserHandleForUid(uid), targetSdkVersion);
7426 } catch (RemoteException e) {
7427 throw e.rethrowFromSystemServer();
7428 }
7429 }
7430
7431
hjin81.lee4e984e52019-12-05 14:34:52 +09007432 /** @hide
7433 * TODO: make this a @SystemApi */
7434 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
7435 public void setMultiAudioFocusEnabled(boolean enabled) {
7436 try {
7437 getService().setMultiAudioFocusEnabled(enabled);
7438 } catch (RemoteException e) {
7439 throw e.rethrowFromSystemServer();
7440 }
7441 }
7442
Eric Laurent43a78de2020-07-24 17:11:15 -07007443
7444 /**
7445 * Retrieves the Hardware A/V synchronization ID corresponding to the given audio session ID.
7446 * For more details on Hardware A/V synchronization please refer to
7447 * <a href="https://source.android.com/devices/tv/multimedia-tunneling/">
7448 * media tunneling documentation</a>.
7449 * @param sessionId the audio session ID for which the HW A/V sync ID is retrieved.
7450 * @return the HW A/V sync ID for this audio session (an integer different from 0).
7451 * @throws UnsupportedOperationException if HW A/V synchronization is not supported.
7452 */
7453 public int getAudioHwSyncForSession(int sessionId) {
7454 int hwSyncId = AudioSystem.getAudioHwSyncForSession(sessionId);
7455 if (hwSyncId == AudioSystem.AUDIO_HW_SYNC_INVALID) {
7456 throw new UnsupportedOperationException("HW A/V synchronization is not supported.");
7457 }
7458 return hwSyncId;
7459 }
7460
Eric Laurentb36d4a12020-10-09 09:52:49 -07007461 /**
7462 * Selects the audio device that should be used for communication use cases, for instance voice
7463 * or video calls. This method can be used by voice or video chat applications to select a
7464 * different audio device than the one selected by default by the platform.
Eric Laurent7412f572021-02-11 15:10:31 +01007465 * <p>The device selection is expressed as an {@link AudioDeviceInfo} among devices returned by
7466 * {@link #getAvailableCommunicationDevices()}.
7467 * The selection is active as long as the requesting application process lives, until
7468 * {@link #clearCommunicationDevice} is called or until the device is disconnected.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007469 * It is therefore important for applications to clear the request when a call ends or the
Eric Laurent7412f572021-02-11 15:10:31 +01007470 * the requesting activity or service is stopped or destroyed.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007471 * <p>In case of simultaneous requests by multiple applications the priority is given to the
7472 * application currently controlling the audio mode (see {@link #setMode(int)}). This is the
7473 * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode
7474 * {@link #MODE_IN_CALL}. Note that <code>MODE_IN_CALL</code> can only be selected by the main
7475 * telephony application with permission
7476 * {@link android.Manifest.permission#MODIFY_PHONE_STATE}.
7477 * <p> If the requested devices is not currently available, the request will be rejected and
7478 * the method will return false.
7479 * <p>This API replaces the following deprecated APIs:
7480 * <ul>
7481 * <li> {@link #startBluetoothSco()}
7482 * <li> {@link #stopBluetoothSco()}
7483 * <li> {@link #setSpeakerphoneOn(boolean)}
7484 * </ul>
7485 * <h4>Example</h4>
7486 * <p>The example below shows how to enable and disable speakerphone mode.
7487 * <pre class="prettyprint">
7488 * // Get an AudioManager instance
7489 * AudioManager audioManager = Context.getSystemService(AudioManager.class);
Eric Laurent9a404482021-03-09 19:58:39 +01007490 * AudioDeviceInfo speakerDevice = null;
7491 * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices();
7492 * for (AudioDeviceInfo device : devices) {
7493 * if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
7494 * speakerDevice = device;
7495 * break;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007496 * }
Eric Laurent9a404482021-03-09 19:58:39 +01007497 * }
7498 * if (speakerDevice != null) {
7499 * // Turn speakerphone ON.
7500 * boolean result = audioManager.setCommunicationDevice(speakerDevice);
7501 * if (!result) {
7502 * // Handle error.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007503 * }
Eric Laurent9a404482021-03-09 19:58:39 +01007504 * // Turn speakerphone OFF.
7505 * audioManager.clearCommunicationDevice();
Eric Laurentb36d4a12020-10-09 09:52:49 -07007506 * }
7507 * </pre>
7508 * @param device the requested audio device.
7509 * @return <code>true</code> if the request was accepted, <code>false</code> otherwise.
7510 * @throws IllegalArgumentException If an invalid device is specified.
7511 */
Eric Laurent7412f572021-02-11 15:10:31 +01007512 public boolean setCommunicationDevice(@NonNull AudioDeviceInfo device) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007513 Objects.requireNonNull(device);
7514 try {
7515 if (device.getId() == 0) {
7516 throw new IllegalArgumentException("In valid device: " + device);
7517 }
Eric Laurent7412f572021-02-11 15:10:31 +01007518 return getService().setCommunicationDevice(mICallBack, device.getId());
Eric Laurentb36d4a12020-10-09 09:52:49 -07007519 } catch (RemoteException e) {
7520 throw e.rethrowFromSystemServer();
7521 }
7522 }
7523
7524 /**
7525 * Cancels previous communication device selection made with
Eric Laurent7412f572021-02-11 15:10:31 +01007526 * {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007527 */
Eric Laurent7412f572021-02-11 15:10:31 +01007528 public void clearCommunicationDevice() {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007529 try {
Eric Laurent7412f572021-02-11 15:10:31 +01007530 getService().setCommunicationDevice(mICallBack, 0);
Eric Laurentb36d4a12020-10-09 09:52:49 -07007531 } catch (RemoteException e) {
7532 throw e.rethrowFromSystemServer();
7533 }
7534 }
7535
7536 /**
7537 * Returns currently selected audio device for communication.
7538 * <p>This API replaces the following deprecated APIs:
7539 * <ul>
7540 * <li> {@link #isBluetoothScoOn()}
7541 * <li> {@link #isSpeakerphoneOn()}
7542 * </ul>
7543 * @return an {@link AudioDeviceInfo} indicating which audio device is
Eric Laurent7412f572021-02-11 15:10:31 +01007544 * currently selected for communication use cases. Can be null on platforms
7545 * not supporting {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007546 * is used.
7547 */
7548 @Nullable
Eric Laurent7412f572021-02-11 15:10:31 +01007549 public AudioDeviceInfo getCommunicationDevice() {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007550 try {
7551 return getDeviceForPortId(
Eric Laurent7412f572021-02-11 15:10:31 +01007552 getService().getCommunicationDevice(), GET_DEVICES_OUTPUTS);
7553 } catch (RemoteException e) {
7554 throw e.rethrowFromSystemServer();
7555 }
7556 }
7557
7558 /**
7559 * Returns a list of audio devices that can be selected for communication use cases via
7560 * {@link #setCommunicationDevice(AudioDeviceInfo)}.
7561 * @return a list of {@link AudioDeviceInfo} suitable for use with setCommunicationDevice().
7562 */
7563 @NonNull
7564 public List<AudioDeviceInfo> getAvailableCommunicationDevices() {
7565 try {
7566 ArrayList<AudioDeviceInfo> devices = new ArrayList<>();
7567 int[] portIds = getService().getAvailableCommunicationDeviceIds();
7568 for (int portId : portIds) {
7569 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
7570 if (device == null) {
7571 continue;
7572 }
7573 devices.add(device);
7574 }
7575 return devices;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007576 } catch (RemoteException e) {
7577 throw e.rethrowFromSystemServer();
7578 }
7579 }
7580
7581 /**
7582 * @hide
7583 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type provided.
7584 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
7585 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
7586 * The method will return null if no device of the provided type is connected.
7587 * If more than one device of the provided type is connected, an object corresponding to the
7588 * first device encountered in the enumeration list will be returned.
7589 * @param deviceType The device device for which an <code>AudioDeviceInfo</code>
Eric Laurent7412f572021-02-11 15:10:31 +01007590 * object is queried.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007591 * @return An AudioDeviceInfo object or null if no device with the requested type is connected.
7592 * @throws IllegalArgumentException If an invalid device type is specified.
7593 */
7594 @TestApi
7595 @Nullable
7596 public static AudioDeviceInfo getDeviceInfoFromType(
7597 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) {
Eric Laurent7412f572021-02-11 15:10:31 +01007598 return getDeviceInfoFromTypeAndAddress(deviceType, null);
7599 }
7600
7601 /**
7602 * @hide
7603 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type and
7604 * address provided.
7605 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class,
7606 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}.
7607 * If a null address is provided, the matching will happen on the type only.
7608 * The method will return null if no device of the provided type and address is connected.
7609 * If more than one device of the provided type is connected, an object corresponding to the
7610 * first device encountered in the enumeration list will be returned.
7611 * @param type The device device for which an <code>AudioDeviceInfo</code>
7612 * object is queried.
7613 * @param address The device address for which an <code>AudioDeviceInfo</code>
7614 * object is queried or null if requesting match on type only.
7615 * @return An AudioDeviceInfo object or null if no matching device is connected.
7616 * @throws IllegalArgumentException If an invalid device type is specified.
7617 */
7618 @Nullable
7619 public static AudioDeviceInfo getDeviceInfoFromTypeAndAddress(
7620 @AudioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address) {
Eric Laurentb36d4a12020-10-09 09:52:49 -07007621 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS);
Eric Laurent7412f572021-02-11 15:10:31 +01007622 AudioDeviceInfo deviceForType = null;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007623 for (AudioDeviceInfo device : devices) {
Eric Laurent7412f572021-02-11 15:10:31 +01007624 if (device.getType() == type) {
7625 deviceForType = device;
7626 if (address == null || address.equals(device.getAddress())) {
7627 return device;
7628 }
Eric Laurentb36d4a12020-10-09 09:52:49 -07007629 }
7630 }
Eric Laurent7412f572021-02-11 15:10:31 +01007631 return deviceForType;
Eric Laurentb36d4a12020-10-09 09:52:49 -07007632 }
7633
7634 /**
7635 * Listener registered by client to be notified upon communication audio device change.
Eric Laurent7412f572021-02-11 15:10:31 +01007636 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007637 */
7638 public interface OnCommunicationDeviceChangedListener {
7639 /**
7640 * Callback method called upon communication audio device change.
Eric Laurent7412f572021-02-11 15:10:31 +01007641 * @param device the audio device requested for communication use cases.
7642 * Can be null on platforms not supporting
7643 * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007644 */
7645 void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device);
7646 }
7647
7648 /**
7649 * Adds a listener for being notified of changes to the communication audio device.
Eric Laurent7412f572021-02-11 15:10:31 +01007650 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007651 * @param executor
7652 * @param listener
7653 */
7654 public void addOnCommunicationDeviceChangedListener(
7655 @NonNull @CallbackExecutor Executor executor,
7656 @NonNull OnCommunicationDeviceChangedListener listener) {
7657 Objects.requireNonNull(executor);
7658 Objects.requireNonNull(listener);
7659 synchronized (mCommDevListenerLock) {
7660 if (hasCommDevListener(listener)) {
7661 throw new IllegalArgumentException(
7662 "attempt to call addOnCommunicationDeviceChangedListener() "
7663 + "on a previously registered listener");
7664 }
7665 // lazy initialization of the list of strategy-preferred device listener
7666 if (mCommDevListeners == null) {
7667 mCommDevListeners = new ArrayList<>();
7668 }
7669 final int oldCbCount = mCommDevListeners.size();
7670 mCommDevListeners.add(new CommDevListenerInfo(listener, executor));
7671 if (oldCbCount == 0 && mCommDevListeners.size() > 0) {
7672 // register binder for callbacks
7673 if (mCommDevDispatcherStub == null) {
7674 mCommDevDispatcherStub = new CommunicationDeviceDispatcherStub();
7675 }
7676 try {
7677 getService().registerCommunicationDeviceDispatcher(mCommDevDispatcherStub);
7678 } catch (RemoteException e) {
7679 throw e.rethrowFromSystemServer();
7680 }
7681 }
7682 }
7683 }
7684
7685 /**
7686 * Removes a previously added listener of changes to the communication audio device.
Eric Laurent7412f572021-02-11 15:10:31 +01007687 * See {@link #setCommunicationDevice(AudioDeviceInfo)}.
Eric Laurentb36d4a12020-10-09 09:52:49 -07007688 * @param listener
7689 */
7690 public void removeOnCommunicationDeviceChangedListener(
7691 @NonNull OnCommunicationDeviceChangedListener listener) {
7692 Objects.requireNonNull(listener);
7693 synchronized (mCommDevListenerLock) {
7694 if (!removeCommDevListener(listener)) {
7695 throw new IllegalArgumentException(
7696 "attempt to call removeOnCommunicationDeviceChangedListener() "
7697 + "on an unregistered listener");
7698 }
7699 if (mCommDevListeners.size() == 0) {
7700 // unregister binder for callbacks
7701 try {
7702 getService().unregisterCommunicationDeviceDispatcher(
7703 mCommDevDispatcherStub);
7704 } catch (RemoteException e) {
7705 throw e.rethrowFromSystemServer();
7706 } finally {
7707 mCommDevDispatcherStub = null;
7708 mCommDevListeners = null;
7709 }
7710 }
7711 }
7712 }
7713
7714 private final Object mCommDevListenerLock = new Object();
7715 /**
7716 * List of listeners for preferred device for strategy and their associated Executor.
7717 * List is lazy-initialized on first registration
7718 */
7719 @GuardedBy("mCommDevListenerLock")
7720 private @Nullable ArrayList<CommDevListenerInfo> mCommDevListeners;
7721
7722 private static class CommDevListenerInfo {
7723 final @NonNull OnCommunicationDeviceChangedListener mListener;
7724 final @NonNull Executor mExecutor;
7725
7726 CommDevListenerInfo(OnCommunicationDeviceChangedListener listener, Executor exe) {
7727 mListener = listener;
7728 mExecutor = exe;
7729 }
7730 }
7731
7732 @GuardedBy("mCommDevListenerLock")
7733 private CommunicationDeviceDispatcherStub mCommDevDispatcherStub;
7734
7735 private final class CommunicationDeviceDispatcherStub
7736 extends ICommunicationDeviceDispatcher.Stub {
7737
7738 @Override
7739 public void dispatchCommunicationDeviceChanged(int portId) {
7740 // make a shallow copy of listeners so callback is not executed under lock
7741 final ArrayList<CommDevListenerInfo> commDevListeners;
7742 synchronized (mCommDevListenerLock) {
7743 if (mCommDevListeners == null || mCommDevListeners.size() == 0) {
7744 return;
7745 }
7746 commDevListeners = (ArrayList<CommDevListenerInfo>) mCommDevListeners.clone();
7747 }
7748 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS);
7749 final long ident = Binder.clearCallingIdentity();
7750 try {
7751 for (CommDevListenerInfo info : commDevListeners) {
7752 info.mExecutor.execute(() ->
7753 info.mListener.onCommunicationDeviceChanged(device));
7754 }
7755 } finally {
7756 Binder.restoreCallingIdentity(ident);
7757 }
7758 }
7759 }
7760
7761 @GuardedBy("mCommDevListenerLock")
7762 private @Nullable CommDevListenerInfo getCommDevListenerInfo(
7763 OnCommunicationDeviceChangedListener listener) {
7764 if (mCommDevListeners == null) {
7765 return null;
7766 }
7767 for (CommDevListenerInfo info : mCommDevListeners) {
7768 if (info.mListener == listener) {
7769 return info;
7770 }
7771 }
7772 return null;
7773 }
7774
7775 @GuardedBy("mCommDevListenerLock")
7776 private boolean hasCommDevListener(OnCommunicationDeviceChangedListener listener) {
7777 return getCommDevListenerInfo(listener) != null;
7778 }
7779
7780 @GuardedBy("mCommDevListenerLock")
7781 /**
7782 * @return true if the listener was removed from the list
7783 */
7784 private boolean removeCommDevListener(OnCommunicationDeviceChangedListener listener) {
7785 final CommDevListenerInfo infoToRemove = getCommDevListenerInfo(listener);
7786 if (infoToRemove != null) {
7787 mCommDevListeners.remove(infoToRemove);
7788 return true;
7789 }
7790 return false;
7791 }
7792
Paul McLeane3383cc2015-05-08 11:41:20 -07007793 //---------------------------------------------------------
7794 // Inner classes
7795 //--------------------
7796 /**
7797 * Helper class to handle the forwarding of native events to the appropriate listener
7798 * (potentially) handled in a different thread.
7799 */
7800 private class NativeEventHandlerDelegate {
7801 private final Handler mHandler;
7802
Paul McLean03346882015-05-12 15:36:56 -07007803 NativeEventHandlerDelegate(final AudioDeviceCallback callback,
Paul McLeane3383cc2015-05-08 11:41:20 -07007804 Handler handler) {
7805 // find the looper for our new event handler
7806 Looper looper;
7807 if (handler != null) {
7808 looper = handler.getLooper();
7809 } else {
7810 // no given handler, use the looper the addListener call was called in
7811 looper = Looper.getMainLooper();
7812 }
7813
7814 // construct the event handler with this looper
7815 if (looper != null) {
7816 // implement the event handler delegate
7817 mHandler = new Handler(looper) {
7818 @Override
7819 public void handleMessage(Message msg) {
7820 switch(msg.what) {
Paul McLeancbeb8a22015-06-10 08:21:27 -07007821 case MSG_DEVICES_CALLBACK_REGISTERED:
Paul McLean03346882015-05-12 15:36:56 -07007822 case MSG_DEVICES_DEVICES_ADDED:
Paul McLean03346882015-05-12 15:36:56 -07007823 if (callback != null) {
7824 callback.onAudioDevicesAdded((AudioDeviceInfo[])msg.obj);
Paul McLeane3383cc2015-05-08 11:41:20 -07007825 }
7826 break;
Paul McLean03346882015-05-12 15:36:56 -07007827
7828 case MSG_DEVICES_DEVICES_REMOVED:
7829 if (callback != null) {
7830 callback.onAudioDevicesRemoved((AudioDeviceInfo[])msg.obj);
7831 }
7832 break;
7833
Paul McLeane3383cc2015-05-08 11:41:20 -07007834 default:
7835 Log.e(TAG, "Unknown native event type: " + msg.what);
7836 break;
7837 }
7838 }
7839 };
7840 } else {
7841 mHandler = null;
7842 }
7843 }
7844
7845 Handler getHandler() {
7846 return mHandler;
7847 }
7848 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007849}