1 /* 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 17 package android.media; 18 19 import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT; 20 import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_AUDIO; 21 import static android.content.Context.DEVICE_ID_DEFAULT; 22 import static android.media.audio.Flags.FLAG_DEPRECATE_STREAM_BT_SCO; 23 import static android.media.audio.Flags.FLAG_FOCUS_EXCLUSIVE_WITH_RECORDING; 24 import static android.media.audio.Flags.FLAG_FOCUS_FREEZE_TEST_API; 25 import static android.media.audio.Flags.FLAG_REGISTER_VOLUME_CALLBACK_API_HARDENING; 26 import static android.media.audio.Flags.FLAG_SUPPORTED_DEVICE_TYPES_API; 27 import static android.media.audio.Flags.FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT; 28 import static android.media.audio.Flags.autoPublicVolumeApiHardening; 29 import static android.media.audio.Flags.cacheGetStreamMinMaxVolume; 30 import static android.media.audio.Flags.cacheGetStreamVolume; 31 import static android.media.audiopolicy.Flags.FLAG_ENABLE_FADE_MANAGER_CONFIGURATION; 32 33 import android.Manifest; 34 import android.annotation.CallbackExecutor; 35 import android.annotation.FlaggedApi; 36 import android.annotation.IntDef; 37 import android.annotation.IntRange; 38 import android.annotation.NonNull; 39 import android.annotation.Nullable; 40 import android.annotation.RequiresPermission; 41 import android.annotation.SdkConstant; 42 import android.annotation.SdkConstant.SdkConstantType; 43 import android.annotation.SuppressLint; 44 import android.annotation.SystemApi; 45 import android.annotation.SystemService; 46 import android.annotation.TestApi; 47 import android.app.NotificationManager; 48 import android.app.PendingIntent; 49 import android.app.compat.CompatChanges; 50 import android.bluetooth.BluetoothCodecConfig; 51 import android.bluetooth.BluetoothDevice; 52 import android.bluetooth.BluetoothLeAudioCodecConfig; 53 import android.companion.virtual.VirtualDeviceManager; 54 import android.compat.annotation.ChangeId; 55 import android.compat.annotation.EnabledSince; 56 import android.compat.annotation.Overridable; 57 import android.compat.annotation.UnsupportedAppUsage; 58 import android.content.AttributionSource; 59 import android.content.ComponentName; 60 import android.content.Context; 61 import android.content.Intent; 62 import android.content.pm.PackageManager; 63 import android.media.AudioAttributes.AttributeSystemUsage; 64 import android.media.CallbackUtil.ListenerInfo; 65 import android.media.audiopolicy.AudioPolicy; 66 import android.media.audiopolicy.AudioPolicy.AudioPolicyFocusListener; 67 import android.media.audiopolicy.AudioProductStrategy; 68 import android.media.audiopolicy.AudioVolumeGroup; 69 import android.media.audiopolicy.IAudioVolumeChangeDispatcher; 70 import android.media.projection.MediaProjection; 71 import android.media.session.MediaController; 72 import android.media.session.MediaSession; 73 import android.media.session.MediaSessionLegacyHelper; 74 import android.media.session.MediaSessionManager; 75 import android.net.Uri; 76 import android.os.Binder; 77 import android.os.Build; 78 import android.os.Handler; 79 import android.os.IBinder; 80 import android.os.IpcDataCache; 81 import android.os.Looper; 82 import android.os.Message; 83 import android.os.RemoteException; 84 import android.os.ServiceManager; 85 import android.os.SystemClock; 86 import android.os.UserHandle; 87 import android.provider.Settings; 88 import android.text.TextUtils; 89 import android.util.ArrayMap; 90 import android.util.IntArray; 91 import android.util.Log; 92 import android.util.Pair; 93 import android.util.Slog; 94 import android.view.KeyEvent; 95 96 import com.android.internal.annotations.GuardedBy; 97 import com.android.internal.util.Preconditions; 98 99 import java.io.IOException; 100 import java.lang.annotation.Retention; 101 import java.lang.annotation.RetentionPolicy; 102 import java.lang.ref.WeakReference; 103 import java.util.ArrayList; 104 import java.util.Arrays; 105 import java.util.Collections; 106 import java.util.HashMap; 107 import java.util.HashSet; 108 import java.util.Iterator; 109 import java.util.List; 110 import java.util.Map; 111 import java.util.Objects; 112 import java.util.Set; 113 import java.util.TreeMap; 114 import java.util.concurrent.ConcurrentHashMap; 115 import java.util.concurrent.Executor; 116 import java.util.concurrent.Executors; 117 import java.util.concurrent.TimeUnit; 118 119 /** 120 * AudioManager provides access to volume and ringer mode control. 121 */ 122 @SystemService(Context.AUDIO_SERVICE) 123 public class AudioManager { 124 125 private Context mOriginalContext; 126 private Context mApplicationContext; 127 private int mOriginalContextDeviceId = DEVICE_ID_DEFAULT; 128 private @Nullable VirtualDeviceManager mVirtualDeviceManager; // Lazy initialized. 129 private static final String TAG = "AudioManager"; 130 private static final boolean DEBUG = false; 131 private static final AudioPortEventHandler sAudioPortEventHandler = new AudioPortEventHandler(); 132 133 private static WeakReference<Context> sContext; 134 135 /** 136 * Broadcast intent, a hint for applications that audio is about to become 137 * 'noisy' due to a change in audio outputs. For example, this intent may 138 * be sent when a wired headset is unplugged, or when an A2DP audio 139 * sink is disconnected, and the audio system is about to automatically 140 * switch audio route to the speaker. Applications that are controlling 141 * audio streams may consider pausing, reducing volume or some other action 142 * on receipt of this intent so as not to surprise the user with audio 143 * from the speaker. 144 */ 145 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 146 public static final String ACTION_AUDIO_BECOMING_NOISY = "android.media.AUDIO_BECOMING_NOISY"; 147 148 /** 149 * Sticky broadcast intent action indicating that the ringer mode has 150 * changed. Includes the new ringer mode. 151 * 152 * @see #EXTRA_RINGER_MODE 153 */ 154 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 155 public static final String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED"; 156 157 /** 158 * @hide 159 * Sticky broadcast intent action indicating that the internal ringer mode has 160 * changed. Includes the new ringer mode. 161 * 162 * @see #EXTRA_RINGER_MODE 163 */ 164 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 165 public static final String INTERNAL_RINGER_MODE_CHANGED_ACTION = 166 "android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION"; 167 168 /** 169 * The new ringer mode. 170 * 171 * @see #RINGER_MODE_CHANGED_ACTION 172 * @see #RINGER_MODE_NORMAL 173 * @see #RINGER_MODE_SILENT 174 * @see #RINGER_MODE_VIBRATE 175 */ 176 public static final String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE"; 177 178 /** 179 * Broadcast intent action indicating that the vibrate setting has 180 * changed. Includes the vibrate type and its new setting. 181 * 182 * @see #EXTRA_VIBRATE_TYPE 183 * @see #EXTRA_VIBRATE_SETTING 184 * @deprecated Applications should maintain their own vibrate policy based on 185 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead. 186 */ 187 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 188 public static final String VIBRATE_SETTING_CHANGED_ACTION = 189 "android.media.VIBRATE_SETTING_CHANGED"; 190 191 /** 192 * @hide Broadcast intent when the volume for a particular stream type changes. 193 * Includes the stream, the new volume and previous volumes. 194 * Notes: 195 * - for internal platform use only, do not make public, 196 * - never used for "remote" volume changes 197 * 198 * @see #EXTRA_VOLUME_STREAM_TYPE 199 * @see #EXTRA_VOLUME_STREAM_VALUE 200 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE 201 */ 202 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 203 @UnsupportedAppUsage 204 public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION"; 205 206 /** 207 * @hide Broadcast intent when the volume for a particular stream type changes. 208 * Includes the stream, the new volume and previous volumes. 209 * Notes: 210 * - for internal platform use only, do not make public, 211 * - never used for "remote" volume changes 212 * 213 * @see #EXTRA_VOLUME_STREAM_TYPE 214 * @see #EXTRA_VOLUME_STREAM_VALUE 215 * @see #EXTRA_PREV_VOLUME_STREAM_VALUE 216 */ 217 @SystemApi 218 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 219 @SuppressLint("ActionValue") 220 public static final String ACTION_VOLUME_CHANGED = "android.media.VOLUME_CHANGED_ACTION"; 221 222 /** 223 * @hide Broadcast intent when the devices for a particular stream type changes. 224 * Includes the stream, the new devices and previous devices. 225 * Notes: 226 * - for internal platform use only, do not make public, 227 * - never used for "remote" volume changes 228 * 229 * @see #EXTRA_VOLUME_STREAM_TYPE 230 * @see #EXTRA_VOLUME_STREAM_DEVICES 231 * @see #EXTRA_PREV_VOLUME_STREAM_DEVICES 232 * @see #getDevicesForStream 233 */ 234 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 235 public static final String STREAM_DEVICES_CHANGED_ACTION = 236 "android.media.STREAM_DEVICES_CHANGED_ACTION"; 237 238 /** 239 * @hide Broadcast intent when a stream mute state changes. 240 * Includes the stream that changed and the new mute state 241 * 242 * @see #EXTRA_VOLUME_STREAM_TYPE 243 * @see #EXTRA_STREAM_VOLUME_MUTED 244 */ 245 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 246 public static final String STREAM_MUTE_CHANGED_ACTION = 247 "android.media.STREAM_MUTE_CHANGED_ACTION"; 248 249 /** 250 * @hide Broadcast intent when the master mute state changes. 251 * Includes the the new volume 252 * 253 * @see #EXTRA_MASTER_VOLUME_MUTED 254 */ 255 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 256 public static final String MASTER_MUTE_CHANGED_ACTION = 257 "android.media.MASTER_MUTE_CHANGED_ACTION"; 258 259 /** 260 * The new vibrate setting for a particular type. 261 * 262 * @see #VIBRATE_SETTING_CHANGED_ACTION 263 * @see #EXTRA_VIBRATE_TYPE 264 * @see #VIBRATE_SETTING_ON 265 * @see #VIBRATE_SETTING_OFF 266 * @see #VIBRATE_SETTING_ONLY_SILENT 267 * @deprecated Applications should maintain their own vibrate policy based on 268 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead. 269 */ 270 public static final String EXTRA_VIBRATE_SETTING = "android.media.EXTRA_VIBRATE_SETTING"; 271 272 /** 273 * The vibrate type whose setting has changed. 274 * 275 * @see #VIBRATE_SETTING_CHANGED_ACTION 276 * @see #VIBRATE_TYPE_NOTIFICATION 277 * @see #VIBRATE_TYPE_RINGER 278 * @deprecated Applications should maintain their own vibrate policy based on 279 * current ringer mode and listen to {@link #RINGER_MODE_CHANGED_ACTION} instead. 280 */ 281 public static final String EXTRA_VIBRATE_TYPE = "android.media.EXTRA_VIBRATE_TYPE"; 282 283 /** 284 * @hide The stream type for the volume changed intent. 285 */ 286 @SystemApi 287 @SuppressLint("ActionValue") 288 public static final String EXTRA_VOLUME_STREAM_TYPE = "android.media.EXTRA_VOLUME_STREAM_TYPE"; 289 290 /** 291 * @hide 292 * The stream type alias for the volume changed intent. 293 * For instance the intent may indicate a change of the {@link #STREAM_NOTIFICATION} stream 294 * type (as indicated by the {@link #EXTRA_VOLUME_STREAM_TYPE} extra), but this is also 295 * reflected by a change of the volume of its alias, {@link #STREAM_RING} on some devices, 296 * {@link #STREAM_MUSIC} on others (e.g. a television). 297 */ 298 public static final String EXTRA_VOLUME_STREAM_TYPE_ALIAS = 299 "android.media.EXTRA_VOLUME_STREAM_TYPE_ALIAS"; 300 301 /** 302 * @hide The volume associated with the stream for the volume changed intent. 303 */ 304 @SystemApi 305 @SuppressLint("ActionValue") 306 public static final String EXTRA_VOLUME_STREAM_VALUE = 307 "android.media.EXTRA_VOLUME_STREAM_VALUE"; 308 309 /** 310 * @hide The previous volume associated with the stream for the volume changed intent. 311 */ 312 public static final String EXTRA_PREV_VOLUME_STREAM_VALUE = 313 "android.media.EXTRA_PREV_VOLUME_STREAM_VALUE"; 314 315 /** 316 * @hide The devices associated with the stream for the stream devices changed intent. 317 */ 318 public static final String EXTRA_VOLUME_STREAM_DEVICES = 319 "android.media.EXTRA_VOLUME_STREAM_DEVICES"; 320 321 /** 322 * @hide The previous devices associated with the stream for the stream devices changed intent. 323 */ 324 public static final String EXTRA_PREV_VOLUME_STREAM_DEVICES = 325 "android.media.EXTRA_PREV_VOLUME_STREAM_DEVICES"; 326 327 /** 328 * @hide The new master volume mute state for the master mute changed intent. 329 * Value is boolean 330 */ 331 public static final String EXTRA_MASTER_VOLUME_MUTED = 332 "android.media.EXTRA_MASTER_VOLUME_MUTED"; 333 334 /** 335 * @hide The new stream volume mute state for the stream mute changed intent. 336 * Value is boolean 337 */ 338 public static final String EXTRA_STREAM_VOLUME_MUTED = 339 "android.media.EXTRA_STREAM_VOLUME_MUTED"; 340 341 /** 342 * Broadcast Action: Wired Headset plugged in or unplugged. 343 * 344 * You <em>cannot</em> receive this through components declared 345 * in manifests, only by explicitly registering for it with 346 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) 347 * Context.registerReceiver()}. 348 * 349 * <p>The intent will have the following extra values: 350 * <ul> 351 * <li><em>state</em> - 0 for unplugged, 1 for plugged. </li> 352 * <li><em>name</em> - Headset type, human readable string </li> 353 * <li><em>microphone</em> - 1 if headset has a microphone, 0 otherwise </li> 354 * </ul> 355 * </ul> 356 */ 357 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 358 public static final String ACTION_HEADSET_PLUG = 359 "android.intent.action.HEADSET_PLUG"; 360 361 /** 362 * Broadcast Action: A sticky broadcast indicating an HDMI cable was plugged or unplugged. 363 * 364 * The intent will have the following extra values: {@link #EXTRA_AUDIO_PLUG_STATE}, 365 * {@link #EXTRA_MAX_CHANNEL_COUNT}, {@link #EXTRA_ENCODINGS}. 366 * <p>It can only be received by explicitly registering for it with 367 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)}. 368 */ 369 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 370 public static final String ACTION_HDMI_AUDIO_PLUG = 371 "android.media.action.HDMI_AUDIO_PLUG"; 372 373 /** 374 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to communicate whether HDMI is plugged in 375 * or unplugged. 376 * An integer value of 1 indicates a plugged-in state, 0 is unplugged. 377 */ 378 public static final String EXTRA_AUDIO_PLUG_STATE = "android.media.extra.AUDIO_PLUG_STATE"; 379 380 /** 381 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the maximum number of channels 382 * supported by the HDMI device. 383 * The corresponding integer value is only available when the device is plugged in (as expressed 384 * by {@link #EXTRA_AUDIO_PLUG_STATE}). 385 */ 386 public static final String EXTRA_MAX_CHANNEL_COUNT = "android.media.extra.MAX_CHANNEL_COUNT"; 387 388 /** 389 * Extra used in {@link #ACTION_HDMI_AUDIO_PLUG} to define the audio encodings supported by 390 * the connected HDMI device. 391 * The corresponding array of encoding values is only available when the device is plugged in 392 * (as expressed by {@link #EXTRA_AUDIO_PLUG_STATE}). Encoding values are defined in 393 * {@link AudioFormat} (for instance see {@link AudioFormat#ENCODING_PCM_16BIT}). Use 394 * {@link android.content.Intent#getIntArrayExtra(String)} to retrieve the encoding values. 395 */ 396 public static final String EXTRA_ENCODINGS = "android.media.extra.ENCODINGS"; 397 398 /** Used to identify the volume of audio streams for phone calls */ 399 public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL; 400 /** Used to identify the volume of audio streams for system sounds */ 401 public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM; 402 /** Used to identify the volume of audio streams for the phone ring */ 403 public static final int STREAM_RING = AudioSystem.STREAM_RING; 404 /** Used to identify the volume of audio streams for music playback */ 405 public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC; 406 /** Used to identify the volume of audio streams for alarms */ 407 public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM; 408 /** Used to identify the volume of audio streams for notifications */ 409 public static final int STREAM_NOTIFICATION = AudioSystem.STREAM_NOTIFICATION; 410 /** @hide Used to identify the volume of audio streams for phone calls when connected 411 * to bluetooth 412 * @deprecated use {@link #STREAM_VOICE_CALL} instead */ 413 @SystemApi 414 @FlaggedApi(FLAG_DEPRECATE_STREAM_BT_SCO) 415 public static final int STREAM_BLUETOOTH_SCO = AudioSystem.STREAM_BLUETOOTH_SCO; 416 /** @hide Used to identify the volume of audio streams for enforced system sounds 417 * in certain countries (e.g camera in Japan) */ 418 @UnsupportedAppUsage 419 public static final int STREAM_SYSTEM_ENFORCED = AudioSystem.STREAM_SYSTEM_ENFORCED; 420 /** Used to identify the volume of audio streams for DTMF Tones */ 421 public static final int STREAM_DTMF = AudioSystem.STREAM_DTMF; 422 /** @hide Used to identify the volume of audio streams exclusively transmitted through the 423 * speaker (TTS) of the device */ 424 @UnsupportedAppUsage 425 public static final int STREAM_TTS = AudioSystem.STREAM_TTS; 426 /** Used to identify the volume of audio streams for accessibility prompts */ 427 public static final int STREAM_ACCESSIBILITY = AudioSystem.STREAM_ACCESSIBILITY; 428 /** @hide Used to identify the volume of audio streams for virtual assistant */ 429 @SystemApi 430 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) 431 public static final int STREAM_ASSISTANT = AudioSystem.STREAM_ASSISTANT; 432 433 /** Number of audio streams */ 434 /** 435 * @deprecated Do not iterate on volume stream type values. 436 */ 437 @Deprecated public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS; 438 439 /** @hide */ 440 private static final int[] PUBLIC_STREAM_TYPES = { AudioManager.STREAM_VOICE_CALL, 441 AudioManager.STREAM_SYSTEM, AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC, 442 AudioManager.STREAM_ALARM, AudioManager.STREAM_NOTIFICATION, 443 AudioManager.STREAM_DTMF, AudioManager.STREAM_ACCESSIBILITY }; 444 445 /** @hide */ 446 @TestApi getPublicStreamTypes()447 public static final int[] getPublicStreamTypes() { 448 return PUBLIC_STREAM_TYPES; 449 } 450 451 /** 452 * Increase the ringer volume. 453 * 454 * @see #adjustVolume(int, int) 455 * @see #adjustStreamVolume(int, int, int) 456 */ 457 public static final int ADJUST_RAISE = 1; 458 459 /** 460 * Decrease the ringer volume. 461 * 462 * @see #adjustVolume(int, int) 463 * @see #adjustStreamVolume(int, int, int) 464 */ 465 public static final int ADJUST_LOWER = -1; 466 467 /** 468 * Maintain the previous ringer volume. This may be useful when needing to 469 * show the volume toast without actually modifying the volume. 470 * 471 * @see #adjustVolume(int, int) 472 * @see #adjustStreamVolume(int, int, int) 473 */ 474 public static final int ADJUST_SAME = 0; 475 476 /** 477 * Mute the volume. Has no effect if the stream is already muted. 478 * 479 * @see #adjustVolume(int, int) 480 * @see #adjustStreamVolume(int, int, int) 481 */ 482 public static final int ADJUST_MUTE = -100; 483 484 /** 485 * Unmute the volume. Has no effect if the stream is not muted. 486 * 487 * @see #adjustVolume(int, int) 488 * @see #adjustStreamVolume(int, int, int) 489 */ 490 public static final int ADJUST_UNMUTE = 100; 491 492 /** 493 * Toggle the mute state. If muted the stream will be unmuted. If not muted 494 * the stream will be muted. 495 * 496 * @see #adjustVolume(int, int) 497 * @see #adjustStreamVolume(int, int, int) 498 */ 499 public static final int ADJUST_TOGGLE_MUTE = 101; 500 501 /** @hide */ 502 @IntDef(flag = false, prefix = "ADJUST", value = { 503 ADJUST_RAISE, 504 ADJUST_LOWER, 505 ADJUST_SAME, 506 ADJUST_MUTE, 507 ADJUST_UNMUTE, 508 ADJUST_TOGGLE_MUTE } 509 ) 510 @Retention(RetentionPolicy.SOURCE) 511 public @interface VolumeAdjustment {} 512 513 /** @hide */ adjustToString(int adj)514 public static final String adjustToString(int adj) { 515 switch (adj) { 516 case ADJUST_RAISE: return "ADJUST_RAISE"; 517 case ADJUST_LOWER: return "ADJUST_LOWER"; 518 case ADJUST_SAME: return "ADJUST_SAME"; 519 case ADJUST_MUTE: return "ADJUST_MUTE"; 520 case ADJUST_UNMUTE: return "ADJUST_UNMUTE"; 521 case ADJUST_TOGGLE_MUTE: return "ADJUST_TOGGLE_MUTE"; 522 default: return new StringBuilder("unknown adjust mode ").append(adj).toString(); 523 } 524 } 525 526 // Flags should be powers of 2! 527 528 /** 529 * Show a toast containing the current volume. 530 * 531 * @see #adjustStreamVolume(int, int, int) 532 * @see #adjustVolume(int, int) 533 * @see #setStreamVolume(int, int, int) 534 * @see #setRingerMode(int) 535 */ 536 public static final int FLAG_SHOW_UI = 1 << 0; 537 538 /** 539 * Whether to include ringer modes as possible options when changing volume. 540 * For example, if true and volume level is 0 and the volume is adjusted 541 * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent or 542 * vibrate mode. 543 * <p> 544 * By default this is on for the ring stream. If this flag is included, 545 * this behavior will be present regardless of the stream type being 546 * affected by the ringer mode. 547 * 548 * @see #adjustVolume(int, int) 549 * @see #adjustStreamVolume(int, int, int) 550 */ 551 public static final int FLAG_ALLOW_RINGER_MODES = 1 << 1; 552 553 /** 554 * Whether to play a sound when changing the volume. 555 * <p> 556 * If this is given to {@link #adjustVolume(int, int)} or 557 * {@link #adjustSuggestedStreamVolume(int, int, int)}, it may be ignored 558 * in some cases (for example, the decided stream type is not 559 * {@link AudioManager#STREAM_RING}, or the volume is being adjusted 560 * downward). 561 * 562 * @see #adjustStreamVolume(int, int, int) 563 * @see #adjustVolume(int, int) 564 * @see #setStreamVolume(int, int, int) 565 */ 566 public static final int FLAG_PLAY_SOUND = 1 << 2; 567 568 /** 569 * Removes any sounds/vibrate that may be in the queue, or are playing (related to 570 * changing volume). 571 */ 572 public static final int FLAG_REMOVE_SOUND_AND_VIBRATE = 1 << 3; 573 574 /** 575 * Whether to vibrate if going into the vibrate ringer mode. 576 */ 577 public static final int FLAG_VIBRATE = 1 << 4; 578 579 /** 580 * Indicates to VolumePanel that the volume slider should be disabled as user 581 * cannot change the stream volume 582 * @hide 583 */ 584 public static final int FLAG_FIXED_VOLUME = 1 << 5; 585 586 /** 587 * Indicates the volume set/adjust call is for Bluetooth absolute volume 588 * @hide 589 */ 590 @SystemApi 591 public static final int FLAG_BLUETOOTH_ABS_VOLUME = 1 << 6; 592 593 /** 594 * Adjusting the volume was prevented due to silent mode, display a hint in the UI. 595 * @hide 596 */ 597 public static final int FLAG_SHOW_SILENT_HINT = 1 << 7; 598 599 /** 600 * Indicates the volume call is for Hdmi Cec system audio volume 601 * @hide 602 */ 603 public static final int FLAG_HDMI_SYSTEM_AUDIO_VOLUME = 1 << 8; 604 605 /** 606 * Indicates that this should only be handled if media is actively playing. 607 * @hide 608 */ 609 public static final int FLAG_ACTIVE_MEDIA_ONLY = 1 << 9; 610 611 /** 612 * Like FLAG_SHOW_UI, but only dialog warnings and confirmations, no sliders. 613 * @hide 614 */ 615 public static final int FLAG_SHOW_UI_WARNINGS = 1 << 10; 616 617 /** 618 * Adjusting the volume down from vibrated was prevented, display a hint in the UI. 619 * @hide 620 */ 621 public static final int FLAG_SHOW_VIBRATE_HINT = 1 << 11; 622 623 /** 624 * Adjusting the volume due to a hardware key press. 625 * This flag can be used in the places in order to denote (or check) that a volume adjustment 626 * request is from a hardware key press. (e.g. {@link MediaController}). 627 * @hide 628 */ 629 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 630 public static final int FLAG_FROM_KEY = 1 << 12; 631 632 /** 633 * Indicates that an absolute volume controller is notifying AudioService of a change in the 634 * volume or mute status of an external audio system. 635 * @hide 636 */ 637 public static final int FLAG_ABSOLUTE_VOLUME = 1 << 13; 638 639 /** @hide */ 640 @IntDef(prefix = {"ENCODED_SURROUND_OUTPUT_"}, value = { 641 ENCODED_SURROUND_OUTPUT_UNKNOWN, 642 ENCODED_SURROUND_OUTPUT_AUTO, 643 ENCODED_SURROUND_OUTPUT_NEVER, 644 ENCODED_SURROUND_OUTPUT_ALWAYS, 645 ENCODED_SURROUND_OUTPUT_MANUAL 646 }) 647 @Retention(RetentionPolicy.SOURCE) 648 public @interface EncodedSurroundOutputMode {} 649 650 /** 651 * The mode for surround sound formats is unknown. 652 */ 653 public static final int ENCODED_SURROUND_OUTPUT_UNKNOWN = -1; 654 655 /** 656 * The surround sound formats are available for use if they are detected. This is the default 657 * mode. 658 */ 659 public static final int ENCODED_SURROUND_OUTPUT_AUTO = 0; 660 661 /** 662 * The surround sound formats are NEVER available, even if they are detected by the hardware. 663 * Those formats will not be reported. 664 */ 665 public static final int ENCODED_SURROUND_OUTPUT_NEVER = 1; 666 667 /** 668 * The surround sound formats are ALWAYS available, even if they are not detected by the 669 * hardware. Those formats will be reported as part of the HDMI output capability. 670 * Applications are then free to use either PCM or encoded output. 671 */ 672 public static final int ENCODED_SURROUND_OUTPUT_ALWAYS = 2; 673 674 /** 675 * Surround sound formats are available according to the choice of user, even if they are not 676 * detected by the hardware. Those formats will be reported as part of the HDMI output 677 * capability. Applications are then free to use either PCM or encoded output. 678 */ 679 public static final int ENCODED_SURROUND_OUTPUT_MANUAL = 3; 680 681 /** 682 * @hide 683 * This list contains all the flags that can be used in internal APIs for volume 684 * related operations */ 685 @IntDef(flag = true, prefix = "FLAG", value = { 686 FLAG_SHOW_UI, 687 FLAG_ALLOW_RINGER_MODES, 688 FLAG_PLAY_SOUND, 689 FLAG_REMOVE_SOUND_AND_VIBRATE, 690 FLAG_VIBRATE, 691 FLAG_FIXED_VOLUME, 692 FLAG_BLUETOOTH_ABS_VOLUME, 693 FLAG_SHOW_SILENT_HINT, 694 FLAG_HDMI_SYSTEM_AUDIO_VOLUME, 695 FLAG_ACTIVE_MEDIA_ONLY, 696 FLAG_SHOW_UI_WARNINGS, 697 FLAG_SHOW_VIBRATE_HINT, 698 FLAG_FROM_KEY, 699 FLAG_ABSOLUTE_VOLUME, 700 }) 701 @Retention(RetentionPolicy.SOURCE) 702 // TODO(308698465) remove due to potential conflict with the new flags class 703 public @interface Flags {} 704 705 /** 706 * @hide 707 * This list contains all the flags that can be used in SDK-visible methods for volume 708 * related operations. 709 * See for instance {@link #adjustVolume(int, int)}, 710 * {@link #adjustStreamVolume(int, int, int)}, 711 * {@link #adjustSuggestedStreamVolume(int, int, int)}, 712 * {@link #adjustVolumeGroupVolume(int, int, int)}, 713 * {@link #setStreamVolume(int, int, int)} 714 * The list contains all volume flags, but the values commented out of the list are there for 715 * maintenance reasons (for when adding flags or changing their visibility), 716 * and to document why some are not in the list (hidden or SystemApi). */ 717 @IntDef(flag = true, prefix = "FLAG", value = { 718 FLAG_SHOW_UI, 719 FLAG_ALLOW_RINGER_MODES, 720 FLAG_PLAY_SOUND, 721 FLAG_REMOVE_SOUND_AND_VIBRATE, 722 FLAG_VIBRATE, 723 //FLAG_FIXED_VOLUME, removed due to @hide 724 //FLAG_BLUETOOTH_ABS_VOLUME, removed due to @SystemApi 725 //FLAG_SHOW_SILENT_HINT, removed due to @hide 726 //FLAG_HDMI_SYSTEM_AUDIO_VOLUME, removed due to @hide 727 //FLAG_ACTIVE_MEDIA_ONLY, removed due to @hide 728 //FLAG_SHOW_UI_WARNINGS, removed due to @hide 729 //FLAG_SHOW_VIBRATE_HINT, removed due to @hide 730 //FLAG_FROM_KEY, removed due to @SystemApi 731 //FLAG_ABSOLUTE_VOLUME, removed due to @hide 732 }) 733 @Retention(RetentionPolicy.SOURCE) 734 public @interface PublicVolumeFlags {} 735 736 /** 737 * @hide 738 * Like PublicVolumeFlags, but for all the flags that can be used in @SystemApi methods for 739 * volume related operations. 740 * See for instance {@link #setVolumeIndexForAttributes(AudioAttributes, int, int)}, 741 * {@link #setVolumeGroupVolumeIndex(int, int, int)}, 742 * {@link #setStreamVolumeForUid(int, int, int, String, int, int, int)}, 743 * {@link #adjustStreamVolumeForUid(int, int, int, String, int, int, int)}, 744 * {@link #adjustSuggestedStreamVolumeForUid(int, int, int, String, int, int, int)} 745 * The list contains all volume flags, but the values commented out of the list are there for 746 * maintenance reasons (for when adding flags or changing their visibility), 747 * and to document which hidden values are not in the list. */ 748 @IntDef(flag = true, prefix = "FLAG", value = { 749 FLAG_SHOW_UI, 750 FLAG_ALLOW_RINGER_MODES, 751 FLAG_PLAY_SOUND, 752 FLAG_REMOVE_SOUND_AND_VIBRATE, 753 FLAG_VIBRATE, 754 //FLAG_FIXED_VOLUME, removed due to @hide 755 FLAG_BLUETOOTH_ABS_VOLUME, 756 //FLAG_SHOW_SILENT_HINT, removed due to @hide 757 //FLAG_HDMI_SYSTEM_AUDIO_VOLUME, removed due to @hide 758 //FLAG_ACTIVE_MEDIA_ONLY, removed due to @hide 759 //FLAG_SHOW_UI_WARNINGS, removed due to @hide 760 //FLAG_SHOW_VIBRATE_HINT, removed due to @hide 761 FLAG_FROM_KEY, 762 //FLAG_ABSOLUTE_VOLUME, removed due to @hide 763 }) 764 @Retention(RetentionPolicy.SOURCE) 765 public @interface SystemVolumeFlags {} 766 767 // The iterator of TreeMap#entrySet() returns the entries in ascending key order. 768 private static final TreeMap<Integer, String> FLAG_NAMES = new TreeMap<>(); 769 770 static { FLAG_NAMES.put(FLAG_SHOW_UI, "FLAG_SHOW_UI")771 FLAG_NAMES.put(FLAG_SHOW_UI, "FLAG_SHOW_UI"); FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES")772 FLAG_NAMES.put(FLAG_ALLOW_RINGER_MODES, "FLAG_ALLOW_RINGER_MODES"); FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND")773 FLAG_NAMES.put(FLAG_PLAY_SOUND, "FLAG_PLAY_SOUND"); FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE")774 FLAG_NAMES.put(FLAG_REMOVE_SOUND_AND_VIBRATE, "FLAG_REMOVE_SOUND_AND_VIBRATE"); FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE")775 FLAG_NAMES.put(FLAG_VIBRATE, "FLAG_VIBRATE"); FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME")776 FLAG_NAMES.put(FLAG_FIXED_VOLUME, "FLAG_FIXED_VOLUME"); FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME")777 FLAG_NAMES.put(FLAG_BLUETOOTH_ABS_VOLUME, "FLAG_BLUETOOTH_ABS_VOLUME"); FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT")778 FLAG_NAMES.put(FLAG_SHOW_SILENT_HINT, "FLAG_SHOW_SILENT_HINT"); FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME")779 FLAG_NAMES.put(FLAG_HDMI_SYSTEM_AUDIO_VOLUME, "FLAG_HDMI_SYSTEM_AUDIO_VOLUME"); FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY")780 FLAG_NAMES.put(FLAG_ACTIVE_MEDIA_ONLY, "FLAG_ACTIVE_MEDIA_ONLY"); FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS")781 FLAG_NAMES.put(FLAG_SHOW_UI_WARNINGS, "FLAG_SHOW_UI_WARNINGS"); FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT")782 FLAG_NAMES.put(FLAG_SHOW_VIBRATE_HINT, "FLAG_SHOW_VIBRATE_HINT"); FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY")783 FLAG_NAMES.put(FLAG_FROM_KEY, "FLAG_FROM_KEY"); FLAG_NAMES.put(FLAG_ABSOLUTE_VOLUME, "FLAG_ABSOLUTE_VOLUME")784 FLAG_NAMES.put(FLAG_ABSOLUTE_VOLUME, "FLAG_ABSOLUTE_VOLUME"); 785 } 786 787 /** @hide */ flagsToString(int flags)788 public static String flagsToString(int flags) { 789 final StringBuilder sb = new StringBuilder(); 790 for (Map.Entry<Integer, String> entry : FLAG_NAMES.entrySet()) { 791 final int flag = entry.getKey(); 792 if ((flags & flag) != 0) { 793 if (sb.length() > 0) { 794 sb.append(','); 795 } 796 sb.append(entry.getValue()); 797 flags &= ~flag; 798 } 799 } 800 if (flags != 0) { 801 if (sb.length() > 0) { 802 sb.append(','); 803 } 804 sb.append(flags); 805 } 806 return sb.toString(); 807 } 808 809 /** 810 * Ringer mode that will be silent and will not vibrate. (This overrides the 811 * vibrate setting.) 812 * 813 * @see #setRingerMode(int) 814 * @see #getRingerMode() 815 */ 816 public static final int RINGER_MODE_SILENT = 0; 817 818 /** 819 * Ringer mode that will be silent and will vibrate. (This will cause the 820 * phone ringer to always vibrate, but the notification vibrate to only 821 * vibrate if set.) 822 * 823 * @see #setRingerMode(int) 824 * @see #getRingerMode() 825 */ 826 public static final int RINGER_MODE_VIBRATE = 1; 827 828 /** 829 * Ringer mode that may be audible and may vibrate. It will be audible if 830 * the volume before changing out of this mode was audible. It will vibrate 831 * if the vibrate setting is on. 832 * 833 * @see #setRingerMode(int) 834 * @see #getRingerMode() 835 */ 836 public static final int RINGER_MODE_NORMAL = 2; 837 838 /** 839 * Maximum valid ringer mode value. Values must start from 0 and be contiguous. 840 * @hide 841 */ 842 public static final int RINGER_MODE_MAX = RINGER_MODE_NORMAL; 843 844 /** 845 * Vibrate type that corresponds to the ringer. 846 * 847 * @see #setVibrateSetting(int, int) 848 * @see #getVibrateSetting(int) 849 * @see #shouldVibrate(int) 850 * @deprecated Applications should maintain their own vibrate policy based on 851 * current ringer mode that can be queried via {@link #getRingerMode()}. 852 */ 853 public static final int VIBRATE_TYPE_RINGER = 0; 854 855 /** 856 * Vibrate type that corresponds to notifications. 857 * 858 * @see #setVibrateSetting(int, int) 859 * @see #getVibrateSetting(int) 860 * @see #shouldVibrate(int) 861 * @deprecated Applications should maintain their own vibrate policy based on 862 * current ringer mode that can be queried via {@link #getRingerMode()}. 863 */ 864 public static final int VIBRATE_TYPE_NOTIFICATION = 1; 865 866 /** 867 * Vibrate setting that suggests to never vibrate. 868 * 869 * @see #setVibrateSetting(int, int) 870 * @see #getVibrateSetting(int) 871 * @deprecated Applications should maintain their own vibrate policy based on 872 * current ringer mode that can be queried via {@link #getRingerMode()}. 873 */ 874 public static final int VIBRATE_SETTING_OFF = 0; 875 876 /** 877 * Vibrate setting that suggests to vibrate when possible. 878 * 879 * @see #setVibrateSetting(int, int) 880 * @see #getVibrateSetting(int) 881 * @deprecated Applications should maintain their own vibrate policy based on 882 * current ringer mode that can be queried via {@link #getRingerMode()}. 883 */ 884 public static final int VIBRATE_SETTING_ON = 1; 885 886 /** 887 * Vibrate setting that suggests to only vibrate when in the vibrate ringer 888 * mode. 889 * 890 * @see #setVibrateSetting(int, int) 891 * @see #getVibrateSetting(int) 892 * @deprecated Applications should maintain their own vibrate policy based on 893 * current ringer mode that can be queried via {@link #getRingerMode()}. 894 */ 895 public static final int VIBRATE_SETTING_ONLY_SILENT = 2; 896 897 /** 898 * Suggests using the default stream type. This may not be used in all 899 * places a stream type is needed. 900 */ 901 public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE; 902 903 /** @hide */ 904 @IntDef(flag = false, prefix = "DEVICE_STATE", value = { 905 DEVICE_CONNECTION_STATE_DISCONNECTED, 906 DEVICE_CONNECTION_STATE_CONNECTED} 907 ) 908 @Retention(RetentionPolicy.SOURCE) 909 public @interface DeviceConnectionState {} 910 911 /** 912 * @hide The device connection state for disconnected devices. 913 */ 914 @SystemApi 915 @SuppressLint("UnflaggedApi") // b/373465238 916 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) 917 public static final int DEVICE_CONNECTION_STATE_DISCONNECTED = 0; 918 919 /** 920 * @hide The device connection state for connected devices. 921 */ 922 @SystemApi 923 @SuppressLint("UnflaggedApi") // b/373465238 924 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) 925 public static final int DEVICE_CONNECTION_STATE_CONNECTED = 1; 926 927 private static IAudioService sService; 928 929 /** 930 * @hide 931 * For test purposes only, will throw NPE with some methods that require a Context. 932 */ 933 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) AudioManager()934 public AudioManager() { 935 } 936 937 /** 938 * @hide 939 */ 940 @UnsupportedAppUsage AudioManager(Context context)941 public AudioManager(Context context) { 942 setContext(context); 943 initPlatform(); 944 } 945 getContext()946 private Context getContext() { 947 if (mApplicationContext == null) { 948 setContext(mOriginalContext); 949 } 950 if (mApplicationContext != null) { 951 return mApplicationContext; 952 } 953 return mOriginalContext; 954 } 955 setContext(Context context)956 private void setContext(Context context) { 957 if (context == null) { 958 return; 959 } 960 mOriginalContextDeviceId = context.getDeviceId(); 961 mApplicationContext = context.getApplicationContext(); 962 if (mApplicationContext != null) { 963 mOriginalContext = null; 964 } else { 965 mOriginalContext = context; 966 } 967 sContext = new WeakReference<>(context); 968 } 969 970 @UnsupportedAppUsage getService()971 static IAudioService getService() 972 { 973 if (sService != null) { 974 return sService; 975 } 976 IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); 977 sService = IAudioService.Stub.asInterface(b); 978 return sService; 979 } 980 getVirtualDeviceManager()981 private VirtualDeviceManager getVirtualDeviceManager() { 982 if (mVirtualDeviceManager != null) { 983 return mVirtualDeviceManager; 984 } 985 mVirtualDeviceManager = getContext().getSystemService(VirtualDeviceManager.class); 986 return mVirtualDeviceManager; 987 } 988 989 /** 990 * Sends a simulated key event for a media button. To simulate a key press, you must first send 991 * a KeyEvent built with a {@link KeyEvent#ACTION_DOWN} action, then another event with the 992 * {@link KeyEvent#ACTION_UP} action. 993 * 994 * <p>The key event will be sent to the current media key event consumer which registered with 995 * {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}. 996 * 997 * @param keyEvent a media session {@link KeyEvent}, as defined by {@link 998 * KeyEvent#isMediaSessionKey}. 999 */ dispatchMediaKeyEvent(KeyEvent keyEvent)1000 public void dispatchMediaKeyEvent(KeyEvent keyEvent) { 1001 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 1002 helper.sendMediaButtonEvent(keyEvent, false); 1003 } 1004 1005 /** 1006 * @hide 1007 */ preDispatchKeyEvent(KeyEvent event, int stream)1008 public void preDispatchKeyEvent(KeyEvent event, int stream) { 1009 /* 1010 * If the user hits another key within the play sound delay, then 1011 * cancel the sound 1012 */ 1013 int keyCode = event.getKeyCode(); 1014 if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP 1015 && keyCode != KeyEvent.KEYCODE_VOLUME_MUTE 1016 && AudioSystem.PLAY_SOUND_DELAY > SystemClock.uptimeMillis()) { 1017 /* 1018 * The user has hit another key during the delay (e.g., 300ms) 1019 * since the last volume key up, so cancel any sounds. 1020 */ 1021 adjustSuggestedStreamVolume(ADJUST_SAME, 1022 stream, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE); 1023 } 1024 } 1025 1026 /** 1027 * Indicates if the device implements a fixed volume policy. 1028 * <p>Some devices may not have volume control and may operate at a fixed volume, 1029 * and may not enable muting or changing the volume of audio streams. 1030 * This method will return true on such devices. 1031 * <p>The following APIs have no effect when volume is fixed: 1032 * <ul> 1033 * <li> {@link #adjustVolume(int, int)} 1034 * <li> {@link #adjustSuggestedStreamVolume(int, int, int)} 1035 * <li> {@link #adjustStreamVolume(int, int, int)} 1036 * <li> {@link #setStreamVolume(int, int, int)} 1037 * <li> {@link #setRingerMode(int)} 1038 * <li> {@link #setStreamSolo(int, boolean)} 1039 * <li> {@link #setStreamMute(int, boolean)} 1040 * </ul> 1041 */ isVolumeFixed()1042 public boolean isVolumeFixed() { 1043 boolean res = false; 1044 try { 1045 res = getService().isVolumeFixed(); 1046 } catch (RemoteException e) { 1047 Log.e(TAG, "Error querying isVolumeFixed", e); 1048 } 1049 return res; 1050 } 1051 1052 /** 1053 * Adjusts the volume of a particular stream by one step in a direction. 1054 * <p> 1055 * This method should only be used by applications that replace the platform-wide 1056 * management of audio settings or the main telephony application. 1057 * <p>This method has no effect if the device implements a fixed volume policy 1058 * as indicated by {@link #isVolumeFixed()}. 1059 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed 1060 * unless the app has been granted Notification Policy Access. 1061 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}. 1062 * 1063 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL}, 1064 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC}, 1065 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}. 1066 * @param direction The direction to adjust the volume. One of 1067 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or 1068 * {@link #ADJUST_SAME}. 1069 * @param flags 1070 * @see #adjustVolume(int, int) 1071 * @see #setStreamVolume(int, int, int) 1072 * @throws SecurityException if the adjustment triggers a Do Not Disturb change 1073 * and the caller is not granted notification policy access. 1074 */ adjustStreamVolume(int streamType, int direction, @PublicVolumeFlags int flags)1075 public void adjustStreamVolume(int streamType, int direction, @PublicVolumeFlags int flags) { 1076 final IAudioService service = getService(); 1077 try { 1078 service.adjustStreamVolumeWithAttribution(streamType, direction, flags, 1079 getContext().getOpPackageName(), getContext().getAttributionTag()); 1080 } catch (RemoteException e) { 1081 throw e.rethrowFromSystemServer(); 1082 } 1083 } 1084 1085 /** 1086 * Adjusts the volume of the most relevant stream. For example, if a call is 1087 * active, it will have the highest priority regardless of if the in-call 1088 * screen is showing. Another example, if music is playing in the background 1089 * and a call is not active, the music stream will be adjusted. 1090 * <p> 1091 * This method should only be used by applications that replace the 1092 * platform-wide management of audio settings or the main telephony 1093 * application. 1094 * <p> 1095 * This method has no effect if the device implements a fixed volume policy 1096 * as indicated by {@link #isVolumeFixed()}. 1097 * 1098 * @param direction The direction to adjust the volume. One of 1099 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, 1100 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE}, 1101 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}. 1102 * @param flags 1103 * @see #adjustSuggestedStreamVolume(int, int, int) 1104 * @see #adjustStreamVolume(int, int, int) 1105 * @see #setStreamVolume(int, int, int) 1106 * @see #isVolumeFixed() 1107 */ adjustVolume(int direction, @PublicVolumeFlags int flags)1108 public void adjustVolume(int direction, @PublicVolumeFlags int flags) { 1109 if (applyAutoHardening()) { 1110 final IAudioService service = getService(); 1111 try { 1112 service.adjustVolume(direction, flags); 1113 } catch (RemoteException e) { 1114 throw e.rethrowFromSystemServer(); 1115 } 1116 } else { 1117 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 1118 helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags); 1119 } 1120 } 1121 1122 /** 1123 * Adjusts the volume of the most relevant stream, or the given fallback 1124 * stream. 1125 * <p> 1126 * This method should only be used by applications that replace the 1127 * platform-wide management of audio settings or the main telephony 1128 * application. 1129 * <p> 1130 * This method has no effect if the device implements a fixed volume policy 1131 * as indicated by {@link #isVolumeFixed()}. 1132 * 1133 * @param direction The direction to adjust the volume. One of 1134 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, 1135 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE}, 1136 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}. 1137 * @param suggestedStreamType The stream type that will be used if there 1138 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is 1139 * valid here. 1140 * @param flags 1141 * @see #adjustVolume(int, int) 1142 * @see #adjustStreamVolume(int, int, int) 1143 * @see #setStreamVolume(int, int, int) 1144 * @see #isVolumeFixed() 1145 */ adjustSuggestedStreamVolume(int direction, int suggestedStreamType, @PublicVolumeFlags int flags)1146 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, 1147 @PublicVolumeFlags int flags) { 1148 if (applyAutoHardening()) { 1149 final IAudioService service = getService(); 1150 try { 1151 service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags); 1152 } catch (RemoteException e) { 1153 throw e.rethrowFromSystemServer(); 1154 } 1155 } else { 1156 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 1157 helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags); 1158 } 1159 } 1160 1161 /** @hide */ 1162 @UnsupportedAppUsage 1163 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setMasterMute(boolean mute, int flags)1164 public void setMasterMute(boolean mute, int flags) { 1165 final IAudioService service = getService(); 1166 try { 1167 service.setMasterMute(mute, flags, getContext().getOpPackageName(), 1168 getContext().getUserId(), getContext().getAttributionTag()); 1169 } catch (RemoteException e) { 1170 throw e.rethrowFromSystemServer(); 1171 } 1172 } 1173 1174 /** 1175 * Returns the current ringtone mode. 1176 * 1177 * @return The current ringtone mode, one of {@link #RINGER_MODE_NORMAL}, 1178 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}. 1179 * @see #setRingerMode(int) 1180 */ getRingerMode()1181 public int getRingerMode() { 1182 final IAudioService service = getService(); 1183 try { 1184 return service.getRingerModeExternal(); 1185 } catch (RemoteException e) { 1186 throw e.rethrowFromSystemServer(); 1187 } 1188 } 1189 1190 /** 1191 * Returns the current user setting for ramping ringer on incoming phone call ringtone. 1192 * 1193 * @return true if the incoming phone call ringtone is configured to gradually increase its 1194 * volume, false otherwise. 1195 */ isRampingRingerEnabled()1196 public boolean isRampingRingerEnabled() { 1197 return Settings.System.getInt(getContext().getContentResolver(), 1198 Settings.System.APPLY_RAMPING_RINGER, 0) != 0; 1199 } 1200 1201 /** 1202 * Sets the flag for enabling ramping ringer on incoming phone call ringtone. 1203 * 1204 * @see #isRampingRingerEnabled() 1205 * @hide 1206 */ 1207 @TestApi setRampingRingerEnabled(boolean enabled)1208 public void setRampingRingerEnabled(boolean enabled) { 1209 Settings.System.putInt(getContext().getContentResolver(), 1210 Settings.System.APPLY_RAMPING_RINGER, enabled ? 1 : 0); 1211 } 1212 1213 /** 1214 * Checks valid ringer mode values. 1215 * 1216 * @return true if the ringer mode indicated is valid, false otherwise. 1217 * 1218 * @see #setRingerMode(int) 1219 * @hide 1220 */ 1221 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isValidRingerMode(int ringerMode)1222 public static boolean isValidRingerMode(int ringerMode) { 1223 if (ringerMode < 0 || ringerMode > RINGER_MODE_MAX) { 1224 return false; 1225 } 1226 final IAudioService service = getService(); 1227 try { 1228 return service.isValidRingerMode(ringerMode); 1229 } catch (RemoteException e) { 1230 throw e.rethrowFromSystemServer(); 1231 } 1232 } 1233 1234 /** 1235 * API string for caching the min volume for each stream 1236 * @hide 1237 **/ 1238 public static final String VOLUME_MIN_CACHING_API = "getStreamMinVolume"; 1239 /** 1240 * API string for caching the max volume for each stream 1241 * @hide 1242 **/ 1243 public static final String VOLUME_MAX_CACHING_API = "getStreamMaxVolume"; 1244 /** 1245 * API string for caching the volume for each stream 1246 * @hide 1247 **/ 1248 public static final String VOLUME_CACHING_API = "getStreamVolume"; 1249 private static final int VOLUME_CACHING_SIZE = 16; 1250 1251 private final IpcDataCache.QueryHandler<VolumeCacheQuery, Integer> mVolQuery = 1252 new IpcDataCache.QueryHandler<>() { 1253 @Override 1254 public Integer apply(VolumeCacheQuery query) { 1255 final IAudioService service = getService(); 1256 try { 1257 return switch (query.queryCommand) { 1258 case QUERY_VOL_MIN -> service.getStreamMinVolume(query.stream); 1259 case QUERY_VOL_MAX -> service.getStreamMaxVolume(query.stream); 1260 case QUERY_VOL -> service.getStreamVolume(query.stream); 1261 default -> { 1262 Log.w(TAG, "Not a valid volume cache query: " + query); 1263 yield null; 1264 } 1265 }; 1266 } catch (RemoteException e) { 1267 throw e.rethrowFromSystemServer(); 1268 } 1269 } 1270 1271 }; 1272 1273 private final IpcDataCache<VolumeCacheQuery, Integer> mVolMinCache = 1274 new IpcDataCache<>(VOLUME_CACHING_SIZE, IpcDataCache.MODULE_SYSTEM, 1275 VOLUME_MIN_CACHING_API, VOLUME_MIN_CACHING_API, mVolQuery); 1276 1277 private final IpcDataCache<VolumeCacheQuery, Integer> mVolMaxCache = 1278 new IpcDataCache<>(VOLUME_CACHING_SIZE, IpcDataCache.MODULE_SYSTEM, 1279 VOLUME_MAX_CACHING_API, VOLUME_MAX_CACHING_API, mVolQuery); 1280 1281 private final IpcDataCache<VolumeCacheQuery, Integer> mVolCache = 1282 new IpcDataCache<>(VOLUME_CACHING_SIZE, IpcDataCache.MODULE_SYSTEM, 1283 VOLUME_CACHING_API, VOLUME_CACHING_API, mVolQuery); 1284 1285 /** 1286 * Used to invalidate the cache for the given API 1287 * @hide 1288 **/ clearVolumeCache(String api)1289 public static void clearVolumeCache(String api) { 1290 if (cacheGetStreamMinMaxVolume() && (VOLUME_MAX_CACHING_API.equals(api) 1291 || VOLUME_MIN_CACHING_API.equals(api))) { 1292 IpcDataCache.invalidateCache(IpcDataCache.MODULE_SYSTEM, api); 1293 } else if (cacheGetStreamVolume() && VOLUME_CACHING_API.equals(api)) { 1294 IpcDataCache.invalidateCache(IpcDataCache.MODULE_SYSTEM, api); 1295 } else { 1296 Log.w(TAG, "invalid clearVolumeCache for api " + api); 1297 } 1298 } 1299 1300 private static final int QUERY_VOL_MIN = 1; 1301 private static final int QUERY_VOL_MAX = 2; 1302 private static final int QUERY_VOL = 3; 1303 /** @hide */ 1304 @IntDef(prefix = "QUERY_VOL", value = { 1305 QUERY_VOL_MIN, 1306 QUERY_VOL_MAX, 1307 QUERY_VOL} 1308 ) 1309 @Retention(RetentionPolicy.SOURCE) 1310 private @interface QueryVolCommand {} 1311 VolumeCacheQuery(int stream, @QueryVolCommand int queryCommand)1312 private record VolumeCacheQuery(int stream, @QueryVolCommand int queryCommand) { 1313 private String queryVolCommandToString() { 1314 return switch (queryCommand) { 1315 case QUERY_VOL_MIN -> "getStreamMinVolume"; 1316 case QUERY_VOL_MAX -> "getStreamMaxVolume"; 1317 case QUERY_VOL -> "getStreamVolume"; 1318 default -> "invalid command"; 1319 }; 1320 } 1321 1322 @NonNull 1323 @Override 1324 public String toString() { 1325 return TextUtils.formatSimple("VolumeCacheQuery(stream=%d, queryCommand=%s)", stream, 1326 queryVolCommandToString()); 1327 } 1328 } 1329 1330 /** 1331 * Returns the maximum volume index for a particular stream. 1332 * 1333 * @param streamType The stream type whose maximum volume index is returned. 1334 * @return The maximum valid volume index for the stream. 1335 * @see #getStreamVolume(int) 1336 */ getStreamMaxVolume(int streamType)1337 public int getStreamMaxVolume(int streamType) { 1338 if (cacheGetStreamMinMaxVolume()) { 1339 return mVolMaxCache.query(new VolumeCacheQuery(streamType, QUERY_VOL_MAX)); 1340 } 1341 final IAudioService service = getService(); 1342 try { 1343 return service.getStreamMaxVolume(streamType); 1344 } catch (RemoteException e) { 1345 throw e.rethrowFromSystemServer(); 1346 } 1347 } 1348 1349 /** 1350 * Returns the minimum volume index for a particular stream. 1351 * @param streamType The stream type whose minimum volume index is returned. Must be one of 1352 * {@link #STREAM_VOICE_CALL}, {@link #STREAM_SYSTEM}, 1353 * {@link #STREAM_RING}, {@link #STREAM_MUSIC}, {@link #STREAM_ALARM}, 1354 * {@link #STREAM_NOTIFICATION}, {@link #STREAM_DTMF} or {@link #STREAM_ACCESSIBILITY}. 1355 * @return The minimum valid volume index for the stream. 1356 * @see #getStreamVolume(int) 1357 */ getStreamMinVolume(int streamType)1358 public int getStreamMinVolume(int streamType) { 1359 if (!isPublicStreamType(streamType)) { 1360 throw new IllegalArgumentException("Invalid stream type " + streamType); 1361 } 1362 return getStreamMinVolumeInt(streamType); 1363 } 1364 1365 /** 1366 * @hide 1367 * Same as {@link #getStreamMinVolume(int)} but without the check on the public stream type. 1368 * @param streamType The stream type whose minimum volume index is returned. 1369 * @return The minimum valid volume index for the stream. 1370 * @see #getStreamVolume(int) 1371 */ 1372 @TestApi getStreamMinVolumeInt(int streamType)1373 public int getStreamMinVolumeInt(int streamType) { 1374 if (cacheGetStreamMinMaxVolume()) { 1375 return mVolMinCache.query(new VolumeCacheQuery(streamType, QUERY_VOL_MIN)); 1376 } 1377 final IAudioService service = getService(); 1378 try { 1379 return service.getStreamMinVolume(streamType); 1380 } catch (RemoteException e) { 1381 throw e.rethrowFromSystemServer(); 1382 } 1383 } 1384 1385 /** 1386 * Returns the current volume index for a particular stream. 1387 * 1388 * @param streamType The stream type whose volume index is returned. 1389 * @return The current volume index for the stream. 1390 * @see #getStreamMaxVolume(int) 1391 * @see #setStreamVolume(int, int, int) 1392 */ getStreamVolume(int streamType)1393 public int getStreamVolume(int streamType) { 1394 if (cacheGetStreamVolume()) { 1395 return mVolCache.query(new VolumeCacheQuery(streamType, QUERY_VOL)); 1396 } 1397 final IAudioService service = getService(); 1398 try { 1399 return service.getStreamVolume(streamType); 1400 } catch (RemoteException e) { 1401 throw e.rethrowFromSystemServer(); 1402 } 1403 } 1404 1405 // keep in sync with frameworks/av/services/audiopolicy/common/include/Volume.h 1406 private static final float VOLUME_MIN_DB = -758.0f; 1407 1408 /** @hide */ 1409 @IntDef(flag = false, prefix = "STREAM", value = { 1410 STREAM_VOICE_CALL, 1411 STREAM_SYSTEM, 1412 STREAM_RING, 1413 STREAM_MUSIC, 1414 STREAM_ALARM, 1415 STREAM_NOTIFICATION, 1416 STREAM_DTMF, 1417 STREAM_ACCESSIBILITY } 1418 ) 1419 @Retention(RetentionPolicy.SOURCE) 1420 public @interface PublicStreamTypes {} 1421 1422 /** 1423 * Returns the volume in dB (decibel) for the given stream type at the given volume index, on 1424 * the given type of audio output device. 1425 * @param streamType stream type for which the volume is queried. 1426 * @param index the volume index for which the volume is queried. The index value must be 1427 * between the minimum and maximum index values for the given stream type (see 1428 * {@link #getStreamMinVolume(int)} and {@link #getStreamMaxVolume(int)}). 1429 * @param deviceType the type of audio output device for which volume is queried. 1430 * @return a volume expressed in dB. 1431 * A negative value indicates the audio signal is attenuated. A typical maximum value 1432 * at the maximum volume index is 0 dB (no attenuation nor amplification). Muting is 1433 * reflected by a value of {@link Float#NEGATIVE_INFINITY}. 1434 */ getStreamVolumeDb(@ublicStreamTypes int streamType, int index, @AudioDeviceInfo.AudioDeviceTypeOut int deviceType)1435 public float getStreamVolumeDb(@PublicStreamTypes int streamType, int index, 1436 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) { 1437 if (!isPublicStreamType(streamType)) { 1438 throw new IllegalArgumentException("Invalid stream type " + streamType); 1439 } 1440 if (index > getStreamMaxVolume(streamType) || index < getStreamMinVolume(streamType)) { 1441 throw new IllegalArgumentException("Invalid stream volume index " + index); 1442 } 1443 if (!AudioDeviceInfo.isValidAudioDeviceTypeOut(deviceType)) { 1444 throw new IllegalArgumentException("Invalid audio output device type " + deviceType); 1445 } 1446 final float gain = AudioSystem.getStreamVolumeDB(streamType, index, 1447 AudioDeviceInfo.convertDeviceTypeToInternalDevice(deviceType)); 1448 if (gain <= VOLUME_MIN_DB) { 1449 return Float.NEGATIVE_INFINITY; 1450 } else { 1451 return gain; 1452 } 1453 } 1454 1455 /** 1456 * @hide 1457 * Checks whether a stream type is part of the public SDK 1458 * @param streamType 1459 * @return true if the stream type is available in SDK 1460 */ isPublicStreamType(int streamType)1461 public static boolean isPublicStreamType(int streamType) { 1462 switch (streamType) { 1463 case STREAM_VOICE_CALL: 1464 case STREAM_SYSTEM: 1465 case STREAM_RING: 1466 case STREAM_MUSIC: 1467 case STREAM_ALARM: 1468 case STREAM_NOTIFICATION: 1469 case STREAM_DTMF: 1470 case STREAM_ACCESSIBILITY: 1471 return true; 1472 default: 1473 return false; 1474 } 1475 } 1476 1477 /** 1478 * Get last audible volume before stream was muted. 1479 * 1480 * @hide 1481 */ 1482 @SystemApi 1483 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") getLastAudibleStreamVolume(int streamType)1484 public int getLastAudibleStreamVolume(int streamType) { 1485 final IAudioService service = getService(); 1486 try { 1487 return service.getLastAudibleStreamVolume(streamType); 1488 } catch (RemoteException e) { 1489 throw e.rethrowFromSystemServer(); 1490 } 1491 } 1492 1493 /** 1494 * Get the stream type whose volume is driving the UI sounds volume. 1495 * UI sounds are screen lock/unlock, camera shutter, key clicks... 1496 * It is assumed that this stream type is also tied to ringer mode changes. 1497 * @hide 1498 */ getUiSoundsStreamType()1499 public int getUiSoundsStreamType() { 1500 final IAudioService service = getService(); 1501 try { 1502 return service.getUiSoundsStreamType(); 1503 } catch (RemoteException e) { 1504 throw e.rethrowFromSystemServer(); 1505 } 1506 } 1507 1508 /** 1509 * Sets the ringer mode. 1510 * <p> 1511 * Silent mode will mute the volume and will not vibrate. Vibrate mode will 1512 * mute the volume and vibrate. Normal mode will be audible and may vibrate 1513 * according to user settings. 1514 * <p>This method has no effect if the device implements a fixed volume policy 1515 * as indicated by {@link #isVolumeFixed()}. 1516 * * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed 1517 * unless the app has been granted Notification Policy Access. 1518 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}. 1519 * @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL}, 1520 * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}. 1521 * @see #getRingerMode() 1522 * @see #isVolumeFixed() 1523 */ setRingerMode(int ringerMode)1524 public void setRingerMode(int ringerMode) { 1525 if (!isValidRingerMode(ringerMode)) { 1526 return; 1527 } 1528 final IAudioService service = getService(); 1529 try { 1530 service.setRingerModeExternal(ringerMode, getContext().getOpPackageName()); 1531 } catch (RemoteException e) { 1532 throw e.rethrowFromSystemServer(); 1533 } 1534 } 1535 1536 /** 1537 * Sets the volume index for a particular stream. 1538 * <p>This method has no effect if the device implements a fixed volume policy 1539 * as indicated by {@link #isVolumeFixed()}. 1540 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless 1541 * the app has been granted Notification Policy Access. 1542 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}. 1543 * @param streamType The stream whose volume index should be set. 1544 * @param index The volume index to set. See 1545 * {@link #getStreamMaxVolume(int)} for the largest valid value. 1546 * @param flags 1547 * @see #getStreamMaxVolume(int) 1548 * @see #getStreamVolume(int) 1549 * @see #isVolumeFixed() 1550 * @throws SecurityException if the volume change triggers a Do Not Disturb change 1551 * and the caller is not granted notification policy access. 1552 */ setStreamVolume(int streamType, int index, @PublicVolumeFlags int flags)1553 public void setStreamVolume(int streamType, int index, @PublicVolumeFlags int flags) { 1554 final IAudioService service = getService(); 1555 try { 1556 service.setStreamVolumeWithAttribution(streamType, index, flags, 1557 getContext().getOpPackageName(), getContext().getAttributionTag()); 1558 } catch (RemoteException e) { 1559 throw e.rethrowFromSystemServer(); 1560 } 1561 } 1562 1563 /** 1564 * Sets the volume index for a particular {@link AudioAttributes}. 1565 * @param attr The {@link AudioAttributes} whose volume index should be set. 1566 * @param index The volume index to set. See 1567 * {@link #getMaxVolumeIndexForAttributes(AudioAttributes)} for the largest valid value 1568 * {@link #getMinVolumeIndexForAttributes(AudioAttributes)} for the lowest valid value. 1569 * @param flags 1570 * @see #getMaxVolumeIndexForAttributes(AudioAttributes) 1571 * @see #getMinVolumeIndexForAttributes(AudioAttributes) 1572 * @see #isVolumeFixed() 1573 * @hide 1574 */ 1575 @SystemApi 1576 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setVolumeIndexForAttributes(@onNull AudioAttributes attr, int index, @SystemVolumeFlags int flags)1577 public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, 1578 @SystemVolumeFlags int flags) { 1579 Preconditions.checkNotNull(attr, "attr must not be null"); 1580 final IAudioService service = getService(); 1581 int groupId = getVolumeGroupIdForAttributes(attr); 1582 setVolumeGroupVolumeIndex(groupId, index, flags); 1583 } 1584 1585 /** 1586 * Returns the current volume index for a particular {@link AudioAttributes}. 1587 * 1588 * @param attr The {@link AudioAttributes} whose volume index is returned. 1589 * @return The current volume index for the stream. 1590 * @see #getMaxVolumeIndexForAttributes(AudioAttributes) 1591 * @see #getMinVolumeIndexForAttributes(AudioAttributes) 1592 * @see #setVolumeForAttributes(AudioAttributes, int, int) 1593 * @hide 1594 */ 1595 @SystemApi 1596 @IntRange(from = 0) 1597 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) getVolumeIndexForAttributes(@onNull AudioAttributes attr)1598 public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) { 1599 Preconditions.checkNotNull(attr, "attr must not be null"); 1600 final IAudioService service = getService(); 1601 int groupId = getVolumeGroupIdForAttributes(attr); 1602 return getVolumeGroupVolumeIndex(groupId); 1603 } 1604 1605 /** 1606 * Returns the maximum volume index for a particular {@link AudioAttributes}. 1607 * 1608 * @param attr The {@link AudioAttributes} whose maximum volume index is returned. 1609 * @return The maximum valid volume index for the {@link AudioAttributes}. 1610 * @see #getVolumeIndexForAttributes(AudioAttributes) 1611 * @hide 1612 */ 1613 @SystemApi 1614 @IntRange(from = 0) 1615 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) getMaxVolumeIndexForAttributes(@onNull AudioAttributes attr)1616 public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) { 1617 Preconditions.checkNotNull(attr, "attr must not be null"); 1618 final IAudioService service = getService(); 1619 int groupId = getVolumeGroupIdForAttributes(attr); 1620 return getVolumeGroupMaxVolumeIndex(groupId); 1621 } 1622 1623 /** 1624 * Returns the minimum volume index for a particular {@link AudioAttributes}. 1625 * 1626 * @param attr The {@link AudioAttributes} whose minimum volume index is returned. 1627 * @return The minimum valid volume index for the {@link AudioAttributes}. 1628 * @see #getVolumeIndexForAttributes(AudioAttributes) 1629 * @hide 1630 */ 1631 @SystemApi 1632 @IntRange(from = 0) 1633 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) getMinVolumeIndexForAttributes(@onNull AudioAttributes attr)1634 public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) { 1635 Preconditions.checkNotNull(attr, "attr must not be null"); 1636 final IAudioService service = getService(); 1637 int groupId = getVolumeGroupIdForAttributes(attr); 1638 return getVolumeGroupMinVolumeIndex(groupId); 1639 } 1640 1641 /** 1642 * Returns the volume group id associated to the given {@link AudioAttributes}. 1643 * 1644 * @param attributes The {@link AudioAttributes} to consider. 1645 * @return audio volume group id supporting the given {@link AudioAttributes} if found, 1646 * {@code android.media.audiopolicy.AudioVolumeGroup.DEFAULT_VOLUME_GROUP} otherwise. 1647 */ getVolumeGroupIdForAttributes(@onNull AudioAttributes attributes)1648 public int getVolumeGroupIdForAttributes(@NonNull AudioAttributes attributes) { 1649 Preconditions.checkNotNull(attributes, "Audio Attributes must not be null"); 1650 return AudioProductStrategy.getVolumeGroupIdForAudioAttributes(attributes, 1651 /* fallbackOnDefault= */ true); 1652 } 1653 1654 /** 1655 * Sets the volume index for a particular group associated to given id. 1656 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} 1657 * to retrieve the volume group id supporting the given {@link AudioAttributes}. 1658 * 1659 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider. 1660 * @param index The volume index to set. See 1661 * {@link #getVolumeGroupMaxVolumeIndex(id)} for the largest valid value 1662 * {@link #getVolumeGroupMinVolumeIndex(id)} for the lowest valid value. 1663 * @param flags 1664 * @hide 1665 */ 1666 @SystemApi 1667 @RequiresPermission(anyOf = { 1668 android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED, 1669 android.Manifest.permission.MODIFY_AUDIO_ROUTING 1670 }) setVolumeGroupVolumeIndex(int groupId, int index, @SystemVolumeFlags int flags)1671 public void setVolumeGroupVolumeIndex(int groupId, int index, @SystemVolumeFlags int flags) { 1672 final IAudioService service = getService(); 1673 try { 1674 service.setVolumeGroupVolumeIndex(groupId, index, flags, 1675 getContext().getOpPackageName(), getContext().getAttributionTag()); 1676 } catch (RemoteException e) { 1677 throw e.rethrowFromSystemServer(); 1678 } 1679 } 1680 1681 /** 1682 * Returns the current volume index for a particular group associated to given id. 1683 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} 1684 * to retrieve the volume group id supporting the given {@link AudioAttributes}. 1685 * 1686 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider. 1687 * @return The current volume index for the stream. 1688 * @hide 1689 */ 1690 @SystemApi 1691 @IntRange(from = 0) 1692 @RequiresPermission(anyOf = { 1693 android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED, 1694 android.Manifest.permission.MODIFY_AUDIO_ROUTING 1695 }) getVolumeGroupVolumeIndex(int groupId)1696 public int getVolumeGroupVolumeIndex(int groupId) { 1697 final IAudioService service = getService(); 1698 try { 1699 return service.getVolumeGroupVolumeIndex(groupId); 1700 } catch (RemoteException e) { 1701 throw e.rethrowFromSystemServer(); 1702 } 1703 } 1704 1705 /** 1706 * Returns the maximum volume index for a particular group associated to given id. 1707 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} 1708 * to retrieve the volume group id supporting the given {@link AudioAttributes}. 1709 * 1710 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider. 1711 * @return The maximum valid volume index for the {@link AudioAttributes}. 1712 * @hide 1713 */ 1714 @SystemApi 1715 @IntRange(from = 0) 1716 @RequiresPermission(anyOf = { 1717 android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED, 1718 android.Manifest.permission.MODIFY_AUDIO_ROUTING 1719 }) getVolumeGroupMaxVolumeIndex(int groupId)1720 public int getVolumeGroupMaxVolumeIndex(int groupId) { 1721 final IAudioService service = getService(); 1722 try { 1723 return service.getVolumeGroupMaxVolumeIndex(groupId); 1724 } catch (RemoteException e) { 1725 throw e.rethrowFromSystemServer(); 1726 } 1727 } 1728 1729 /** 1730 * Returns the minimum volume index for a particular group associated to given id. 1731 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} 1732 * to retrieve the volume group id supporting the given {@link AudioAttributes}. 1733 * 1734 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider. 1735 * @return The minimum valid volume index for the {@link AudioAttributes}. 1736 * @hide 1737 */ 1738 @SystemApi 1739 @IntRange(from = 0) 1740 @RequiresPermission(anyOf = { 1741 android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED, 1742 android.Manifest.permission.MODIFY_AUDIO_ROUTING 1743 }) getVolumeGroupMinVolumeIndex(int groupId)1744 public int getVolumeGroupMinVolumeIndex(int groupId) { 1745 final IAudioService service = getService(); 1746 try { 1747 return service.getVolumeGroupMinVolumeIndex(groupId); 1748 } catch (RemoteException e) { 1749 throw e.rethrowFromSystemServer(); 1750 } 1751 } 1752 1753 /** 1754 * Adjusts the volume of a particular group associated to given id by one step in a direction. 1755 * <p> If the volume group is associated to a stream type, it fallbacks on 1756 * {@link #adjustStreamVolume(int, int, int)} for compatibility reason. 1757 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve 1758 * the volume group id supporting the given {@link AudioAttributes}. 1759 * 1760 * @param groupId of the audio volume group to consider. 1761 * @param direction The direction to adjust the volume. One of 1762 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or 1763 * {@link #ADJUST_SAME}. 1764 * @param flags 1765 * @throws SecurityException if the adjustment triggers a Do Not Disturb change and the caller 1766 * is not granted notification policy access. 1767 */ adjustVolumeGroupVolume(int groupId, int direction, @PublicVolumeFlags int flags)1768 public void adjustVolumeGroupVolume(int groupId, int direction, @PublicVolumeFlags int flags) { 1769 IAudioService service = getService(); 1770 try { 1771 service.adjustVolumeGroupVolume(groupId, direction, flags, 1772 getContext().getOpPackageName()); 1773 } catch (RemoteException e) { 1774 throw e.rethrowFromSystemServer(); 1775 } 1776 } 1777 1778 /** 1779 * Get last audible volume of the group associated to given id before it was muted. 1780 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve 1781 * the volume group id supporting the given {@link AudioAttributes}. 1782 * 1783 * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider. 1784 * @return current volume if not muted, volume before muted otherwise. 1785 * @hide 1786 */ 1787 @SystemApi 1788 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") 1789 @IntRange(from = 0) getLastAudibleVolumeForVolumeGroup(int groupId)1790 public int getLastAudibleVolumeForVolumeGroup(int groupId) { 1791 IAudioService service = getService(); 1792 try { 1793 return service.getLastAudibleVolumeForVolumeGroup(groupId); 1794 } catch (RemoteException e) { 1795 throw e.rethrowFromSystemServer(); 1796 } 1797 } 1798 1799 /** 1800 * Returns the current mute state for a particular volume group associated to the given id. 1801 * <p> Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve 1802 * the volume group id supporting the given {@link AudioAttributes}. 1803 * 1804 * @param groupId of the audio volume group to consider. 1805 * @return The mute state for the given audio volume group id. 1806 * @see #adjustVolumeGroupVolume(int, int, int) 1807 */ isVolumeGroupMuted(int groupId)1808 public boolean isVolumeGroupMuted(int groupId) { 1809 IAudioService service = getService(); 1810 try { 1811 return service.isVolumeGroupMuted(groupId); 1812 } catch (RemoteException e) { 1813 throw e.rethrowFromSystemServer(); 1814 } 1815 } 1816 1817 /** 1818 * Set the system usages to be supported on this device. 1819 * @param systemUsages array of system usages to support {@link AttributeSystemUsage} 1820 * @hide 1821 */ 1822 @SystemApi 1823 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setSupportedSystemUsages(@onNull @ttributeSystemUsage int[] systemUsages)1824 public void setSupportedSystemUsages(@NonNull @AttributeSystemUsage int[] systemUsages) { 1825 Objects.requireNonNull(systemUsages, "systemUsages must not be null"); 1826 final IAudioService service = getService(); 1827 try { 1828 service.setSupportedSystemUsages(systemUsages); 1829 } catch (RemoteException e) { 1830 throw e.rethrowFromSystemServer(); 1831 } 1832 } 1833 1834 /** 1835 * Get the system usages supported on this device. 1836 * @return array of supported system usages {@link AttributeSystemUsage} 1837 * @hide 1838 */ 1839 @SystemApi 1840 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) getSupportedSystemUsages()1841 public @NonNull @AttributeSystemUsage int[] getSupportedSystemUsages() { 1842 final IAudioService service = getService(); 1843 try { 1844 return service.getSupportedSystemUsages(); 1845 } catch (RemoteException e) { 1846 throw e.rethrowFromSystemServer(); 1847 } 1848 } 1849 1850 /** 1851 * Solo or unsolo a particular stream. 1852 * <p> 1853 * Do not use. This method has been deprecated and is now a no-op. 1854 * {@link #requestAudioFocus} should be used for exclusive audio playback. 1855 * 1856 * @param streamType The stream to be soloed/unsoloed. 1857 * @param state The required solo state: true for solo ON, false for solo 1858 * OFF 1859 * @see #isVolumeFixed() 1860 * @deprecated Do not use. If you need exclusive audio playback use 1861 * {@link #requestAudioFocus}. 1862 */ 1863 @Deprecated setStreamSolo(int streamType, boolean state)1864 public void setStreamSolo(int streamType, boolean state) { 1865 Log.w(TAG, "setStreamSolo has been deprecated. Do not use."); 1866 } 1867 1868 /** 1869 * Mute or unmute an audio stream. 1870 * <p> 1871 * This method should only be used by applications that replace the 1872 * platform-wide management of audio settings or the main telephony 1873 * application. 1874 * <p> 1875 * This method has no effect if the device implements a fixed volume policy 1876 * as indicated by {@link #isVolumeFixed()}. 1877 * <p> 1878 * This method was deprecated in API level 22. Prior to API level 22 this 1879 * method had significantly different behavior and should be used carefully. 1880 * The following applies only to pre-22 platforms: 1881 * <ul> 1882 * <li>The mute command is protected against client process death: if a 1883 * process with an active mute request on a stream dies, this stream will be 1884 * unmuted automatically.</li> 1885 * <li>The mute requests for a given stream are cumulative: the AudioManager 1886 * can receive several mute requests from one or more clients and the stream 1887 * will be unmuted only when the same number of unmute requests are 1888 * received.</li> 1889 * <li>For a better user experience, applications MUST unmute a muted stream 1890 * in onPause() and mute is again in onResume() if appropriate.</li> 1891 * </ul> 1892 * 1893 * @param streamType The stream to be muted/unmuted. 1894 * @param state The required mute state: true for mute ON, false for mute 1895 * OFF 1896 * @see #isVolumeFixed() 1897 * @deprecated Use {@link #adjustStreamVolume(int, int, int)} with 1898 * {@link #ADJUST_MUTE} or {@link #ADJUST_UNMUTE} instead. 1899 */ 1900 @Deprecated setStreamMute(int streamType, boolean state)1901 public void setStreamMute(int streamType, boolean state) { 1902 Log.w(TAG, "setStreamMute is deprecated. adjustStreamVolume should be used instead."); 1903 int direction = state ? ADJUST_MUTE : ADJUST_UNMUTE; 1904 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { 1905 adjustSuggestedStreamVolume(direction, streamType, 0); 1906 } else { 1907 adjustStreamVolume(streamType, direction, 0); 1908 } 1909 } 1910 1911 /** 1912 * Returns the current mute state for a particular stream. 1913 * 1914 * @param streamType The stream to get mute state for. 1915 * @return The mute state for the given stream. 1916 * @see #adjustStreamVolume(int, int, int) 1917 */ isStreamMute(int streamType)1918 public boolean isStreamMute(int streamType) { 1919 final IAudioService service = getService(); 1920 try { 1921 return service.isStreamMute(streamType); 1922 } catch (RemoteException e) { 1923 throw e.rethrowFromSystemServer(); 1924 } 1925 } 1926 1927 /** 1928 * get master mute state. 1929 * 1930 * @hide 1931 */ 1932 @UnsupportedAppUsage isMasterMute()1933 public boolean isMasterMute() { 1934 final IAudioService service = getService(); 1935 try { 1936 return service.isMasterMute(); 1937 } catch (RemoteException e) { 1938 throw e.rethrowFromSystemServer(); 1939 } 1940 } 1941 1942 /** 1943 * forces the stream controlled by hard volume keys 1944 * specifying streamType == -1 releases control to the 1945 * logic. 1946 * 1947 * @hide 1948 */ 1949 @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) 1950 @UnsupportedAppUsage forceVolumeControlStream(int streamType)1951 public void forceVolumeControlStream(int streamType) { 1952 final IAudioService service = getService(); 1953 try { 1954 service.forceVolumeControlStream(streamType, mICallBack); 1955 } catch (RemoteException e) { 1956 throw e.rethrowFromSystemServer(); 1957 } 1958 } 1959 1960 /** 1961 * Returns whether a particular type should vibrate according to user 1962 * settings and the current ringer mode. 1963 * <p> 1964 * This shouldn't be needed by most clients that use notifications to 1965 * vibrate. The notification manager will not vibrate if the policy doesn't 1966 * allow it, so the client should always set a vibrate pattern and let the 1967 * notification manager control whether or not to actually vibrate. 1968 * 1969 * @param vibrateType The type of vibrate. One of 1970 * {@link #VIBRATE_TYPE_NOTIFICATION} or 1971 * {@link #VIBRATE_TYPE_RINGER}. 1972 * @return Whether the type should vibrate at the instant this method is 1973 * called. 1974 * @see #setVibrateSetting(int, int) 1975 * @see #getVibrateSetting(int) 1976 * @deprecated Applications should maintain their own vibrate policy based on 1977 * current ringer mode that can be queried via {@link #getRingerMode()}. 1978 */ shouldVibrate(int vibrateType)1979 public boolean shouldVibrate(int vibrateType) { 1980 final IAudioService service = getService(); 1981 try { 1982 return service.shouldVibrate(vibrateType); 1983 } catch (RemoteException e) { 1984 throw e.rethrowFromSystemServer(); 1985 } 1986 } 1987 1988 /** 1989 * Returns whether the user's vibrate setting for a vibrate type. 1990 * <p> 1991 * This shouldn't be needed by most clients that want to vibrate, instead 1992 * see {@link #shouldVibrate(int)}. 1993 * 1994 * @param vibrateType The type of vibrate. One of 1995 * {@link #VIBRATE_TYPE_NOTIFICATION} or 1996 * {@link #VIBRATE_TYPE_RINGER}. 1997 * @return The vibrate setting, one of {@link #VIBRATE_SETTING_ON}, 1998 * {@link #VIBRATE_SETTING_OFF}, or 1999 * {@link #VIBRATE_SETTING_ONLY_SILENT}. 2000 * @see #setVibrateSetting(int, int) 2001 * @see #shouldVibrate(int) 2002 * @deprecated Applications should maintain their own vibrate policy based on 2003 * current ringer mode that can be queried via {@link #getRingerMode()}. 2004 */ getVibrateSetting(int vibrateType)2005 public int getVibrateSetting(int vibrateType) { 2006 final IAudioService service = getService(); 2007 try { 2008 return service.getVibrateSetting(vibrateType); 2009 } catch (RemoteException e) { 2010 throw e.rethrowFromSystemServer(); 2011 } 2012 } 2013 2014 /** 2015 * Sets the setting for when the vibrate type should vibrate. 2016 * <p> 2017 * This method should only be used by applications that replace the platform-wide 2018 * management of audio settings or the main telephony application. 2019 * 2020 * @param vibrateType The type of vibrate. One of 2021 * {@link #VIBRATE_TYPE_NOTIFICATION} or 2022 * {@link #VIBRATE_TYPE_RINGER}. 2023 * @param vibrateSetting The vibrate setting, one of 2024 * {@link #VIBRATE_SETTING_ON}, 2025 * {@link #VIBRATE_SETTING_OFF}, or 2026 * {@link #VIBRATE_SETTING_ONLY_SILENT}. 2027 * @see #getVibrateSetting(int) 2028 * @see #shouldVibrate(int) 2029 * @deprecated Applications should maintain their own vibrate policy based on 2030 * current ringer mode that can be queried via {@link #getRingerMode()}. 2031 */ setVibrateSetting(int vibrateType, int vibrateSetting)2032 public void setVibrateSetting(int vibrateType, int vibrateSetting) { 2033 final IAudioService service = getService(); 2034 try { 2035 service.setVibrateSetting(vibrateType, vibrateSetting); 2036 } catch (RemoteException e) { 2037 throw e.rethrowFromSystemServer(); 2038 } 2039 } 2040 2041 /** 2042 * Sets the speakerphone on or off. 2043 * <p> 2044 * This method should only be used by applications that replace the platform-wide 2045 * management of audio settings or the main telephony application. 2046 * 2047 * @param on set <var>true</var> to turn on speakerphone; 2048 * <var>false</var> to turn it off 2049 * @deprecated Use {@link AudioManager#setCommunicationDevice(AudioDeviceInfo)} or 2050 * {@link AudioManager#clearCommunicationDevice()} instead. 2051 */ setSpeakerphoneOn(boolean on)2052 @Deprecated public void setSpeakerphoneOn(boolean on) { 2053 final IAudioService service = getService(); 2054 try { 2055 service.setSpeakerphoneOn(mICallBack, on, getAttributionSource()); 2056 } catch (RemoteException e) { 2057 throw e.rethrowFromSystemServer(); 2058 } 2059 } 2060 getAttributionSource()2061 private AttributionSource getAttributionSource() { 2062 Context context = getContext(); 2063 return (context != null) 2064 ? context.getAttributionSource() : AttributionSource.myAttributionSource(); 2065 } 2066 2067 /** 2068 * Checks whether the speakerphone is on or off. 2069 * 2070 * @return true if speakerphone is on, false if it's off 2071 * @deprecated Use {@link AudioManager#getCommunicationDevice()} instead. 2072 */ isSpeakerphoneOn()2073 @Deprecated public boolean isSpeakerphoneOn() { 2074 final IAudioService service = getService(); 2075 try { 2076 return service.isSpeakerphoneOn(); 2077 } catch (RemoteException e) { 2078 throw e.rethrowFromSystemServer(); 2079 } 2080 } 2081 2082 /** 2083 * Specifies whether the audio played by this app may or may not be captured by other apps or 2084 * the system. 2085 * 2086 * The default is {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}. 2087 * 2088 * There are multiple ways to set this policy: 2089 * <ul> 2090 * <li> for each track independently, see 2091 * {@link AudioAttributes.Builder#setAllowedCapturePolicy(int)} </li> 2092 * <li> application-wide at runtime, with this method </li> 2093 * <li> application-wide at build time, see {@code allowAudioPlaybackCapture} in the application 2094 * manifest. </li> 2095 * </ul> 2096 * The most restrictive policy is always applied. 2097 * 2098 * See {@link AudioPlaybackCaptureConfiguration} for more details on 2099 * which audio signals can be captured. 2100 * 2101 * @param capturePolicy one of 2102 * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}, 2103 * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}, 2104 * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}. 2105 * @throws RuntimeException if the argument is not a valid value. 2106 */ setAllowedCapturePolicy(@udioAttributes.CapturePolicy int capturePolicy)2107 public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) { 2108 // TODO: also pass the package in case multiple packages have the same UID 2109 final IAudioService service = getService(); 2110 try { 2111 int result = service.setAllowedCapturePolicy(capturePolicy); 2112 if (result != AudioSystem.AUDIO_STATUS_OK) { 2113 Log.e(TAG, "Could not setAllowedCapturePolicy: " + result); 2114 return; 2115 } 2116 } catch (RemoteException e) { 2117 throw e.rethrowFromSystemServer(); 2118 } 2119 } 2120 2121 /** 2122 * Return the capture policy. 2123 * @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or 2124 * the default if it was not called. 2125 */ 2126 @AudioAttributes.CapturePolicy getAllowedCapturePolicy()2127 public int getAllowedCapturePolicy() { 2128 int result = AudioAttributes.ALLOW_CAPTURE_BY_ALL; 2129 try { 2130 result = getService().getAllowedCapturePolicy(); 2131 } catch (RemoteException e) { 2132 Log.e(TAG, "Failed to query allowed capture policy: " + e); 2133 } 2134 return result; 2135 } 2136 2137 //==================================================================== 2138 // Audio Product Strategy routing 2139 2140 /** 2141 * @hide 2142 * Set the preferred device for a given strategy, i.e. the audio routing to be used by 2143 * this audio strategy. Note that the device may not be available at the time the preferred 2144 * device is set, but it will be used once made available. 2145 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting 2146 * this preference for this strategy.</p> 2147 * @param strategy the audio strategy whose routing will be affected 2148 * @param device the audio device to route to when available 2149 * @return true if the operation was successful, false otherwise 2150 */ 2151 @SystemApi 2152 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setPreferredDeviceForStrategy(@onNull AudioProductStrategy strategy, @NonNull AudioDeviceAttributes device)2153 public boolean setPreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy, 2154 @NonNull AudioDeviceAttributes device) { 2155 return setPreferredDevicesForStrategy(strategy, Arrays.asList(device)); 2156 } 2157 2158 /** 2159 * @hide 2160 * Removes the preferred audio device(s) previously set with 2161 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or 2162 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}. 2163 * @param strategy the audio strategy whose routing will be affected 2164 * @return true if the operation was successful, false otherwise (invalid strategy, or no 2165 * device set for example) 2166 */ 2167 @SystemApi 2168 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) removePreferredDeviceForStrategy(@onNull AudioProductStrategy strategy)2169 public boolean removePreferredDeviceForStrategy(@NonNull AudioProductStrategy strategy) { 2170 Objects.requireNonNull(strategy); 2171 try { 2172 final int status = 2173 getService().removePreferredDevicesForStrategy(strategy.getId()); 2174 return status == AudioSystem.SUCCESS; 2175 } catch (RemoteException e) { 2176 throw e.rethrowFromSystemServer(); 2177 } 2178 } 2179 2180 /** 2181 * @hide 2182 * Return the preferred device for an audio strategy, previously set with 2183 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or 2184 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)} 2185 * @param strategy the strategy to query 2186 * @return the preferred device for that strategy, if multiple devices are set as preferred 2187 * devices, the first one in the list will be returned. Null will be returned if none was 2188 * ever set or if the strategy is invalid 2189 */ 2190 @SystemApi 2191 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) 2192 @Nullable getPreferredDeviceForStrategy( @onNull AudioProductStrategy strategy)2193 public AudioDeviceAttributes getPreferredDeviceForStrategy( 2194 @NonNull AudioProductStrategy strategy) { 2195 List<AudioDeviceAttributes> devices = getPreferredDevicesForStrategy(strategy); 2196 return devices.isEmpty() ? null : devices.get(0); 2197 } 2198 2199 /** 2200 * @hide 2201 * Set the preferred devices for a given strategy, i.e. the audio routing to be used by 2202 * this audio strategy. Note that the devices may not be available at the time the preferred 2203 * devices is set, but it will be used once made available. 2204 * <p>Use {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} to cancel setting 2205 * this preference for this strategy.</p> 2206 * Note that the list of devices is not a list ranked by preference, but a list of one or more 2207 * devices used simultaneously to output the same audio signal. 2208 * @param strategy the audio strategy whose routing will be affected 2209 * @param devices a non-empty list of the audio devices to route to when available 2210 * @return true if the operation was successful, false otherwise 2211 */ 2212 @SystemApi 2213 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setPreferredDevicesForStrategy(@onNull AudioProductStrategy strategy, @NonNull List<AudioDeviceAttributes> devices)2214 public boolean setPreferredDevicesForStrategy(@NonNull AudioProductStrategy strategy, 2215 @NonNull List<AudioDeviceAttributes> devices) { 2216 Objects.requireNonNull(strategy); 2217 Objects.requireNonNull(devices); 2218 if (devices.isEmpty()) { 2219 throw new IllegalArgumentException( 2220 "Tried to set preferred devices for strategy with a empty list"); 2221 } 2222 for (AudioDeviceAttributes device : devices) { 2223 Objects.requireNonNull(device); 2224 } 2225 try { 2226 final int status = 2227 getService().setPreferredDevicesForStrategy(strategy.getId(), devices); 2228 return status == AudioSystem.SUCCESS; 2229 } catch (RemoteException e) { 2230 throw e.rethrowFromSystemServer(); 2231 } 2232 } 2233 2234 /** 2235 * @hide 2236 * Return the preferred devices for an audio strategy, previously set with 2237 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} 2238 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)} 2239 * @param strategy the strategy to query 2240 * @return list of the preferred devices for that strategy 2241 */ 2242 @SystemApi 2243 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) 2244 @NonNull getPreferredDevicesForStrategy( @onNull AudioProductStrategy strategy)2245 public List<AudioDeviceAttributes> getPreferredDevicesForStrategy( 2246 @NonNull AudioProductStrategy strategy) { 2247 Objects.requireNonNull(strategy); 2248 try { 2249 return getService().getPreferredDevicesForStrategy(strategy.getId()); 2250 } catch (RemoteException e) { 2251 throw e.rethrowFromSystemServer(); 2252 } 2253 } 2254 2255 /** 2256 * @hide 2257 * Set a device as non-default for a given strategy, i.e. the audio routing to be avoided by 2258 * this audio strategy. 2259 * <p>Use 2260 * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)} 2261 * to cancel setting this preference for this strategy.</p> 2262 * @param strategy the audio strategy whose routing will be affected 2263 * @param device the audio device to not route to when available 2264 * @return true if the operation was successful, false otherwise 2265 */ 2266 @SystemApi 2267 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setDeviceAsNonDefaultForStrategy(@onNull AudioProductStrategy strategy, @NonNull AudioDeviceAttributes device)2268 public boolean setDeviceAsNonDefaultForStrategy(@NonNull AudioProductStrategy strategy, 2269 @NonNull AudioDeviceAttributes device) { 2270 Objects.requireNonNull(strategy); 2271 Objects.requireNonNull(device); 2272 try { 2273 final int status = 2274 getService().setDeviceAsNonDefaultForStrategy(strategy.getId(), device); 2275 return status == AudioSystem.SUCCESS; 2276 } catch (RemoteException e) { 2277 throw e.rethrowFromSystemServer(); 2278 } 2279 } 2280 2281 /** 2282 * @hide 2283 * Removes the audio device(s) from the non-default device list previously set with 2284 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)} 2285 * @param strategy the audio strategy whose routing will be affected 2286 * @param device the audio device to remove from the non-default device list 2287 * @return true if the operation was successful, false otherwise (invalid strategy, or no 2288 * device set for example) 2289 */ 2290 @SystemApi 2291 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) removeDeviceAsNonDefaultForStrategy(@onNull AudioProductStrategy strategy, @NonNull AudioDeviceAttributes device)2292 public boolean removeDeviceAsNonDefaultForStrategy(@NonNull AudioProductStrategy strategy, 2293 @NonNull AudioDeviceAttributes device) { 2294 Objects.requireNonNull(strategy); 2295 Objects.requireNonNull(device); 2296 try { 2297 final int status = 2298 getService().removeDeviceAsNonDefaultForStrategy(strategy.getId(), device); 2299 return status == AudioSystem.SUCCESS; 2300 } catch (RemoteException e) { 2301 throw e.rethrowFromSystemServer(); 2302 } 2303 } 2304 2305 /** 2306 * @hide 2307 * Gets the audio device(s) from the non-default device list previously set with 2308 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)} 2309 * @param strategy the audio strategy to query 2310 * @return list of non-default devices for the strategy 2311 */ 2312 @SystemApi 2313 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) 2314 @NonNull getNonDefaultDevicesForStrategy( @onNull AudioProductStrategy strategy)2315 public List<AudioDeviceAttributes> getNonDefaultDevicesForStrategy( 2316 @NonNull AudioProductStrategy strategy) { 2317 Objects.requireNonNull(strategy); 2318 try { 2319 return getService().getNonDefaultDevicesForStrategy(strategy.getId()); 2320 } catch (RemoteException e) { 2321 throw e.rethrowFromSystemServer(); 2322 } 2323 } 2324 2325 /** 2326 * @hide 2327 * Interface to be notified of changes in the preferred audio device set for a given audio 2328 * strategy. 2329 * <p>Note that this listener will only be invoked whenever 2330 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)} or 2331 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)} 2332 * {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in 2333 * preferred device. It will not be invoked directly after registration with 2334 * {@link #addOnPreferredDeviceForStrategyChangedListener(Executor, OnPreferredDeviceForStrategyChangedListener)} 2335 * to indicate which strategies had preferred devices at the time of registration.</p> 2336 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes) 2337 * @see #removePreferredDeviceForStrategy(AudioProductStrategy) 2338 * @see #getPreferredDeviceForStrategy(AudioProductStrategy) 2339 * @deprecated use #OnPreferredDevicesForStrategyChangedListener 2340 */ 2341 @SystemApi 2342 @Deprecated 2343 public interface OnPreferredDeviceForStrategyChangedListener { 2344 /** 2345 * Called on the listener to indicate that the preferred audio device for the given 2346 * strategy has changed. 2347 * @param strategy the {@link AudioProductStrategy} whose preferred device changed 2348 * @param device <code>null</code> if the preferred device was removed, or the newly set 2349 * preferred audio device 2350 */ onPreferredDeviceForStrategyChanged(@onNull AudioProductStrategy strategy, @Nullable AudioDeviceAttributes device)2351 void onPreferredDeviceForStrategyChanged(@NonNull AudioProductStrategy strategy, 2352 @Nullable AudioDeviceAttributes device); 2353 } 2354 2355 /** 2356 * @hide 2357 * Interface to be notified of changes in the preferred audio devices set for a given audio 2358 * strategy. 2359 * <p>Note that this listener will only be invoked whenever 2360 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)}, 2361 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}, 2362 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}, 2363 * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)} 2364 * or {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in 2365 * preferred device(s). It will not be invoked directly after registration with 2366 * {@link #addOnPreferredDevicesForStrategyChangedListener( 2367 * Executor, OnPreferredDevicesForStrategyChangedListener)} 2368 * to indicate which strategies had preferred devices at the time of registration.</p> 2369 * @see #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes) 2370 * @see #setPreferredDevicesForStrategy(AudioProductStrategy, List) 2371 * @see #removePreferredDeviceForStrategy(AudioProductStrategy) 2372 * @see #getPreferredDevicesForStrategy(AudioProductStrategy) 2373 */ 2374 @SystemApi 2375 public interface OnPreferredDevicesForStrategyChangedListener { 2376 /** 2377 * Called on the listener to indicate that the preferred audio devices for the given 2378 * strategy has changed. 2379 * @param strategy the {@link AudioProductStrategy} whose preferred device changed 2380 * @param devices a list of newly set preferred audio devices 2381 */ onPreferredDevicesForStrategyChanged(@onNull AudioProductStrategy strategy, @NonNull List<AudioDeviceAttributes> devices)2382 void onPreferredDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy, 2383 @NonNull List<AudioDeviceAttributes> devices); 2384 } 2385 2386 /** 2387 * @hide 2388 * Adds a listener for being notified of changes to the strategy-preferred audio device. 2389 * @param executor 2390 * @param listener 2391 * @throws SecurityException if the caller doesn't hold the required permission 2392 * @deprecated use {@link #addOnPreferredDevicesForStrategyChangedListener( 2393 * Executor, AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead 2394 */ 2395 @SystemApi 2396 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) 2397 @Deprecated addOnPreferredDeviceForStrategyChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnPreferredDeviceForStrategyChangedListener listener)2398 public void addOnPreferredDeviceForStrategyChangedListener( 2399 @NonNull @CallbackExecutor Executor executor, 2400 @NonNull OnPreferredDeviceForStrategyChangedListener listener) 2401 throws SecurityException { 2402 // No-op, the method is deprecated. 2403 } 2404 2405 /** 2406 * @hide 2407 * Removes a previously added listener of changes to the strategy-preferred audio device. 2408 * @param listener 2409 * @deprecated use {@link #removeOnPreferredDevicesForStrategyChangedListener( 2410 * AudioManager.OnPreferredDevicesForStrategyChangedListener)} instead 2411 */ 2412 @SystemApi 2413 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) 2414 @Deprecated removeOnPreferredDeviceForStrategyChangedListener( @onNull OnPreferredDeviceForStrategyChangedListener listener)2415 public void removeOnPreferredDeviceForStrategyChangedListener( 2416 @NonNull OnPreferredDeviceForStrategyChangedListener listener) { 2417 // No-op, the method is deprecated. 2418 } 2419 2420 /** 2421 * @hide 2422 * Adds a listener for being notified of changes to the strategy-preferred audio device. 2423 * @param executor 2424 * @param listener 2425 * @throws SecurityException if the caller doesn't hold the required permission 2426 */ 2427 @SystemApi 2428 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) addOnPreferredDevicesForStrategyChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnPreferredDevicesForStrategyChangedListener listener)2429 public void addOnPreferredDevicesForStrategyChangedListener( 2430 @NonNull @CallbackExecutor Executor executor, 2431 @NonNull OnPreferredDevicesForStrategyChangedListener listener) 2432 throws SecurityException { 2433 Objects.requireNonNull(executor); 2434 Objects.requireNonNull(listener); 2435 mPrefDevListenerMgr.addListener( 2436 executor, listener, "addOnPreferredDevicesForStrategyChangedListener", 2437 () -> new StrategyPreferredDevicesDispatcherStub()); 2438 } 2439 2440 /** 2441 * @hide 2442 * Removes a previously added listener of changes to the strategy-preferred audio device. 2443 * @param listener 2444 */ 2445 @SystemApi 2446 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) removeOnPreferredDevicesForStrategyChangedListener( @onNull OnPreferredDevicesForStrategyChangedListener listener)2447 public void removeOnPreferredDevicesForStrategyChangedListener( 2448 @NonNull OnPreferredDevicesForStrategyChangedListener listener) { 2449 Objects.requireNonNull(listener); 2450 mPrefDevListenerMgr.removeListener( 2451 listener, "removeOnPreferredDevicesForStrategyChangedListener"); 2452 } 2453 2454 /** 2455 * @hide 2456 * Interface to be notified of changes in the non-default audio devices set for a given audio 2457 * strategy. 2458 * <p>Note that this listener will only be invoked whenever 2459 * {@link #setPreferredDeviceForStrategy(AudioProductStrategy, AudioDeviceAttributes)}, 2460 * {@link #setPreferredDevicesForStrategy(AudioProductStrategy, List<AudioDeviceAttributes>)}, 2461 * {@link #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)}, 2462 * {@link #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes)} 2463 * or {@link #removePreferredDeviceForStrategy(AudioProductStrategy)} causes a change in 2464 * non-default device(s). It will not be invoked directly after registration with 2465 * {@link #addOnNonDefaultDevicesForStrategyChangedListener( 2466 * Executor, OnNonDefaultDevicesForStrategyChangedListener)} 2467 * to indicate which strategies had preferred devices at the time of registration.</p> 2468 * @see #setDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes) 2469 * @see #removeDeviceAsNonDefaultForStrategy(AudioProductStrategy, AudioDeviceAttributes) 2470 */ 2471 @SystemApi 2472 public interface OnNonDefaultDevicesForStrategyChangedListener { 2473 /** 2474 * Called on the listener to indicate that the non-default audio devices for the given 2475 * strategy has changed. 2476 * @param strategy the {@link AudioProductStrategy} whose non-default device changed 2477 * @param devices a list of newly set non-default audio devices 2478 */ onNonDefaultDevicesForStrategyChanged(@onNull AudioProductStrategy strategy, @NonNull List<AudioDeviceAttributes> devices)2479 void onNonDefaultDevicesForStrategyChanged(@NonNull AudioProductStrategy strategy, 2480 @NonNull List<AudioDeviceAttributes> devices); 2481 } 2482 2483 /** 2484 * @hide 2485 * Adds a listener for being notified of changes to the non-default audio devices for 2486 * strategies. 2487 * @param executor 2488 * @param listener 2489 * @throws SecurityException if the caller doesn't hold the required permission 2490 */ 2491 @SystemApi 2492 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) addOnNonDefaultDevicesForStrategyChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnNonDefaultDevicesForStrategyChangedListener listener)2493 public void addOnNonDefaultDevicesForStrategyChangedListener( 2494 @NonNull @CallbackExecutor Executor executor, 2495 @NonNull OnNonDefaultDevicesForStrategyChangedListener listener) 2496 throws SecurityException { 2497 Objects.requireNonNull(executor); 2498 Objects.requireNonNull(listener); 2499 2500 mNonDefDevListenerMgr.addListener( 2501 executor, listener, "addOnNonDefaultDevicesForStrategyChangedListener", 2502 () -> new StrategyNonDefaultDevicesDispatcherStub()); 2503 } 2504 2505 /** 2506 * @hide 2507 * Removes a previously added listener of changes to the non-default audio device for 2508 * strategies. 2509 * @param listener 2510 */ 2511 @SystemApi 2512 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) removeOnNonDefaultDevicesForStrategyChangedListener( @onNull OnNonDefaultDevicesForStrategyChangedListener listener)2513 public void removeOnNonDefaultDevicesForStrategyChangedListener( 2514 @NonNull OnNonDefaultDevicesForStrategyChangedListener listener) { 2515 Objects.requireNonNull(listener); 2516 mNonDefDevListenerMgr.removeListener( 2517 listener, "removeOnNonDefaultDevicesForStrategyChangedListener"); 2518 } 2519 2520 /** 2521 * Manages the OnPreferredDevicesForStrategyChangedListener listeners and the 2522 * StrategyPreferredDevicesDispatcherStub 2523 */ 2524 private final CallbackUtil.LazyListenerManager<OnPreferredDevicesForStrategyChangedListener> 2525 mPrefDevListenerMgr = new CallbackUtil.LazyListenerManager(); 2526 2527 /** 2528 * Manages the OnNonDefaultDevicesForStrategyChangedListener listeners and the 2529 * StrategyNonDefaultDevicesDispatcherStub 2530 */ 2531 private final CallbackUtil.LazyListenerManager<OnNonDefaultDevicesForStrategyChangedListener> 2532 mNonDefDevListenerMgr = new CallbackUtil.LazyListenerManager(); 2533 2534 private final class StrategyPreferredDevicesDispatcherStub 2535 extends IStrategyPreferredDevicesDispatcher.Stub 2536 implements CallbackUtil.DispatcherStub { 2537 2538 @Override dispatchPrefDevicesChanged(int strategyId, @NonNull List<AudioDeviceAttributes> devices)2539 public void dispatchPrefDevicesChanged(int strategyId, 2540 @NonNull List<AudioDeviceAttributes> devices) { 2541 final AudioProductStrategy strategy = 2542 AudioProductStrategy.getAudioProductStrategyWithId(strategyId); 2543 2544 mPrefDevListenerMgr.callListeners( 2545 (listener) -> listener.onPreferredDevicesForStrategyChanged(strategy, devices)); 2546 } 2547 2548 @Override register(boolean register)2549 public void register(boolean register) { 2550 try { 2551 if (register) { 2552 getService().registerStrategyPreferredDevicesDispatcher(this); 2553 } else { 2554 getService().unregisterStrategyPreferredDevicesDispatcher(this); 2555 } 2556 } catch (RemoteException e) { 2557 e.rethrowFromSystemServer(); 2558 } 2559 } 2560 } 2561 2562 private final class StrategyNonDefaultDevicesDispatcherStub 2563 extends IStrategyNonDefaultDevicesDispatcher.Stub 2564 implements CallbackUtil.DispatcherStub { 2565 2566 @Override dispatchNonDefDevicesChanged(int strategyId, @NonNull List<AudioDeviceAttributes> devices)2567 public void dispatchNonDefDevicesChanged(int strategyId, 2568 @NonNull List<AudioDeviceAttributes> devices) { 2569 final AudioProductStrategy strategy = 2570 AudioProductStrategy.getAudioProductStrategyWithId(strategyId); 2571 2572 mNonDefDevListenerMgr.callListeners( 2573 (listener) -> listener.onNonDefaultDevicesForStrategyChanged( 2574 strategy, devices)); 2575 } 2576 2577 @Override register(boolean register)2578 public void register(boolean register) { 2579 try { 2580 if (register) { 2581 getService().registerStrategyNonDefaultDevicesDispatcher(this); 2582 } else { 2583 getService().unregisterStrategyNonDefaultDevicesDispatcher(this); 2584 } 2585 } catch (RemoteException e) { 2586 e.rethrowFromSystemServer(); 2587 } 2588 } 2589 } 2590 2591 //==================================================================== 2592 // Audio Capture Preset routing 2593 2594 /** 2595 * @hide 2596 * Set the preferred device for a given capture preset, i.e. the audio routing to be used by 2597 * this capture preset. Note that the device may not be available at the time the preferred 2598 * device is set, but it will be used once made available. 2599 * <p>Use {@link #clearPreferredDevicesForCapturePreset(int)} to cancel setting this preference 2600 * for this capture preset.</p> 2601 * @param capturePreset the audio capture preset whose routing will be affected 2602 * @param device the audio device to route to when available 2603 * @return true if the operation was successful, false otherwise 2604 */ 2605 @SystemApi 2606 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setPreferredDeviceForCapturePreset(@ediaRecorder.SystemSource int capturePreset, @NonNull AudioDeviceAttributes device)2607 public boolean setPreferredDeviceForCapturePreset(@MediaRecorder.SystemSource int capturePreset, 2608 @NonNull AudioDeviceAttributes device) { 2609 return setPreferredDevicesForCapturePreset(capturePreset, Arrays.asList(device)); 2610 } 2611 2612 /** 2613 * @hide 2614 * Remove all the preferred audio devices previously set 2615 * @param capturePreset the audio capture preset whose routing will be affected 2616 * @return true if the operation was successful, false otherwise (invalid capture preset, or no 2617 * device set for example) 2618 */ 2619 @SystemApi 2620 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) clearPreferredDevicesForCapturePreset( @ediaRecorder.SystemSource int capturePreset)2621 public boolean clearPreferredDevicesForCapturePreset( 2622 @MediaRecorder.SystemSource int capturePreset) { 2623 if (!MediaRecorder.isValidAudioSource(capturePreset)) { 2624 return false; 2625 } 2626 try { 2627 final int status = getService().clearPreferredDevicesForCapturePreset(capturePreset); 2628 return status == AudioSystem.SUCCESS; 2629 } catch (RemoteException e) { 2630 throw e.rethrowFromSystemServer(); 2631 } 2632 } 2633 2634 /** 2635 * @hide 2636 * Return the preferred devices for an audio capture preset, previously set with 2637 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} 2638 * @param capturePreset the capture preset to query 2639 * @return a list that contains preferred devices for that capture preset. 2640 */ 2641 @NonNull 2642 @SystemApi 2643 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) getPreferredDevicesForCapturePreset( @ediaRecorder.SystemSource int capturePreset)2644 public List<AudioDeviceAttributes> getPreferredDevicesForCapturePreset( 2645 @MediaRecorder.SystemSource int capturePreset) { 2646 if (!MediaRecorder.isValidAudioSource(capturePreset)) { 2647 return new ArrayList<AudioDeviceAttributes>(); 2648 } 2649 try { 2650 return getService().getPreferredDevicesForCapturePreset(capturePreset); 2651 } catch (RemoteException e) { 2652 throw e.rethrowFromSystemServer(); 2653 } 2654 } 2655 setPreferredDevicesForCapturePreset( @ediaRecorder.SystemSource int capturePreset, @NonNull List<AudioDeviceAttributes> devices)2656 private boolean setPreferredDevicesForCapturePreset( 2657 @MediaRecorder.SystemSource int capturePreset, 2658 @NonNull List<AudioDeviceAttributes> devices) { 2659 Objects.requireNonNull(devices); 2660 if (!MediaRecorder.isValidAudioSource(capturePreset)) { 2661 return false; 2662 } 2663 if (devices.size() != 1) { 2664 throw new IllegalArgumentException( 2665 "Only support setting one preferred devices for capture preset"); 2666 } 2667 for (AudioDeviceAttributes device : devices) { 2668 Objects.requireNonNull(device); 2669 } 2670 try { 2671 final int status = 2672 getService().setPreferredDevicesForCapturePreset(capturePreset, devices); 2673 return status == AudioSystem.SUCCESS; 2674 } catch (RemoteException e) { 2675 throw e.rethrowFromSystemServer(); 2676 } 2677 } 2678 2679 /** 2680 * @hide 2681 * Interface to be notified of changes in the preferred audio devices set for a given capture 2682 * preset. 2683 * <p>Note that this listener will only be invoked whenever 2684 * {@link #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes)} or 2685 * {@link #clearPreferredDevicesForCapturePreset(int)} causes a change in 2686 * preferred device. It will not be invoked directly after registration with 2687 * {@link #addOnPreferredDevicesForCapturePresetChangedListener( 2688 * Executor, OnPreferredDevicesForCapturePresetChangedListener)} 2689 * to indicate which strategies had preferred devices at the time of registration.</p> 2690 * @see #setPreferredDeviceForCapturePreset(int, AudioDeviceAttributes) 2691 * @see #clearPreferredDevicesForCapturePreset(int) 2692 * @see #getPreferredDevicesForCapturePreset(int) 2693 */ 2694 @SystemApi 2695 public interface OnPreferredDevicesForCapturePresetChangedListener { 2696 /** 2697 * Called on the listener to indicate that the preferred audio devices for the given 2698 * capture preset has changed. 2699 * @param capturePreset the capture preset whose preferred device changed 2700 * @param devices a list of newly set preferred audio devices 2701 */ onPreferredDevicesForCapturePresetChanged( @ediaRecorder.SystemSource int capturePreset, @NonNull List<AudioDeviceAttributes> devices)2702 void onPreferredDevicesForCapturePresetChanged( 2703 @MediaRecorder.SystemSource int capturePreset, 2704 @NonNull List<AudioDeviceAttributes> devices); 2705 } 2706 2707 /** 2708 * @hide 2709 * Adds a listener for being notified of changes to the capture-preset-preferred audio device. 2710 * @param executor 2711 * @param listener 2712 * @throws SecurityException if the caller doesn't hold the required permission 2713 */ 2714 @SystemApi 2715 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) addOnPreferredDevicesForCapturePresetChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnPreferredDevicesForCapturePresetChangedListener listener)2716 public void addOnPreferredDevicesForCapturePresetChangedListener( 2717 @NonNull @CallbackExecutor Executor executor, 2718 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) 2719 throws SecurityException { 2720 Objects.requireNonNull(executor); 2721 Objects.requireNonNull(listener); 2722 int status = addOnDevRoleForCapturePresetChangedListener( 2723 executor, listener, AudioSystem.DEVICE_ROLE_PREFERRED); 2724 if (status == AudioSystem.ERROR) { 2725 // This must not happen 2726 throw new RuntimeException("Unknown error happened"); 2727 } 2728 if (status == AudioSystem.BAD_VALUE) { 2729 throw new IllegalArgumentException( 2730 "attempt to call addOnPreferredDevicesForCapturePresetChangedListener() " 2731 + "on a previously registered listener"); 2732 } 2733 } 2734 2735 /** 2736 * @hide 2737 * Removes a previously added listener of changes to the capture-preset-preferred audio device. 2738 * @param listener 2739 */ 2740 @SystemApi 2741 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) removeOnPreferredDevicesForCapturePresetChangedListener( @onNull OnPreferredDevicesForCapturePresetChangedListener listener)2742 public void removeOnPreferredDevicesForCapturePresetChangedListener( 2743 @NonNull OnPreferredDevicesForCapturePresetChangedListener listener) { 2744 Objects.requireNonNull(listener); 2745 int status = removeOnDevRoleForCapturePresetChangedListener( 2746 listener, AudioSystem.DEVICE_ROLE_PREFERRED); 2747 if (status == AudioSystem.ERROR) { 2748 // This must not happen 2749 throw new RuntimeException("Unknown error happened"); 2750 } 2751 if (status == AudioSystem.BAD_VALUE) { 2752 throw new IllegalArgumentException( 2753 "attempt to call removeOnPreferredDevicesForCapturePresetChangedListener() " 2754 + "on an unregistered listener"); 2755 } 2756 } 2757 addOnDevRoleForCapturePresetChangedListener( @onNull @allbackExecutor Executor executor, @NonNull T listener, int deviceRole)2758 private <T> int addOnDevRoleForCapturePresetChangedListener( 2759 @NonNull @CallbackExecutor Executor executor, 2760 @NonNull T listener, int deviceRole) { 2761 Objects.requireNonNull(executor); 2762 Objects.requireNonNull(listener); 2763 DevRoleListeners<T> devRoleListeners = 2764 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole); 2765 if (devRoleListeners == null) { 2766 return AudioSystem.ERROR; 2767 } 2768 synchronized (devRoleListeners.mDevRoleListenersLock) { 2769 if (devRoleListeners.hasDevRoleListener(listener)) { 2770 return AudioSystem.BAD_VALUE; 2771 } 2772 // lazy initialization of the list of device role listener 2773 if (devRoleListeners.mListenerInfos == null) { 2774 devRoleListeners.mListenerInfos = new ArrayList<>(); 2775 } 2776 final int oldCbCount = devRoleListeners.mListenerInfos.size(); 2777 devRoleListeners.mListenerInfos.add(new DevRoleListenerInfo<T>(executor, listener)); 2778 if (oldCbCount == 0 && devRoleListeners.mListenerInfos.size() > 0) { 2779 // register binder for callbacks 2780 synchronized (mDevRoleForCapturePresetListenersLock) { 2781 int deviceRoleListenerStatus = mDeviceRoleListenersStatus; 2782 mDeviceRoleListenersStatus |= (1 << deviceRole); 2783 if (deviceRoleListenerStatus != 0) { 2784 // There are already device role changed listeners active. 2785 return AudioSystem.SUCCESS; 2786 } 2787 if (mDevicesRoleForCapturePresetDispatcherStub == null) { 2788 mDevicesRoleForCapturePresetDispatcherStub = 2789 new CapturePresetDevicesRoleDispatcherStub(); 2790 } 2791 try { 2792 getService().registerCapturePresetDevicesRoleDispatcher( 2793 mDevicesRoleForCapturePresetDispatcherStub); 2794 } catch (RemoteException e) { 2795 throw e.rethrowFromSystemServer(); 2796 } 2797 } 2798 } 2799 } 2800 return AudioSystem.SUCCESS; 2801 } 2802 removeOnDevRoleForCapturePresetChangedListener( @onNull T listener, int deviceRole)2803 private <T> int removeOnDevRoleForCapturePresetChangedListener( 2804 @NonNull T listener, int deviceRole) { 2805 Objects.requireNonNull(listener); 2806 DevRoleListeners<T> devRoleListeners = 2807 (DevRoleListeners<T>) mDevRoleForCapturePresetListeners.get(deviceRole); 2808 if (devRoleListeners == null) { 2809 return AudioSystem.ERROR; 2810 } 2811 synchronized (devRoleListeners.mDevRoleListenersLock) { 2812 if (!devRoleListeners.removeDevRoleListener(listener)) { 2813 return AudioSystem.BAD_VALUE; 2814 } 2815 if (devRoleListeners.mListenerInfos.size() == 0) { 2816 // unregister binder for callbacks 2817 synchronized (mDevRoleForCapturePresetListenersLock) { 2818 mDeviceRoleListenersStatus ^= (1 << deviceRole); 2819 if (mDeviceRoleListenersStatus != 0) { 2820 // There are some other device role changed listeners active. 2821 return AudioSystem.SUCCESS; 2822 } 2823 try { 2824 getService().unregisterCapturePresetDevicesRoleDispatcher( 2825 mDevicesRoleForCapturePresetDispatcherStub); 2826 } catch (RemoteException e) { 2827 throw e.rethrowFromSystemServer(); 2828 } 2829 } 2830 } 2831 } 2832 return AudioSystem.SUCCESS; 2833 } 2834 2835 private final Map<Integer, Object> mDevRoleForCapturePresetListeners = Map.of( 2836 AudioSystem.DEVICE_ROLE_PREFERRED, 2837 new DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>()); 2838 2839 private class DevRoleListenerInfo<T> { 2840 final @NonNull Executor mExecutor; 2841 final @NonNull T mListener; DevRoleListenerInfo(Executor executor, T listener)2842 DevRoleListenerInfo(Executor executor, T listener) { 2843 mExecutor = executor; 2844 mListener = listener; 2845 } 2846 } 2847 2848 private class DevRoleListeners<T> { 2849 private final Object mDevRoleListenersLock = new Object(); 2850 @GuardedBy("mDevRoleListenersLock") 2851 private @Nullable ArrayList<DevRoleListenerInfo<T>> mListenerInfos; 2852 2853 @GuardedBy("mDevRoleListenersLock") getDevRoleListenerInfo(T listener)2854 private @Nullable DevRoleListenerInfo<T> getDevRoleListenerInfo(T listener) { 2855 if (mListenerInfos == null) { 2856 return null; 2857 } 2858 for (DevRoleListenerInfo<T> listenerInfo : mListenerInfos) { 2859 if (listenerInfo.mListener == listener) { 2860 return listenerInfo; 2861 } 2862 } 2863 return null; 2864 } 2865 2866 @GuardedBy("mDevRoleListenersLock") hasDevRoleListener(T listener)2867 private boolean hasDevRoleListener(T listener) { 2868 return getDevRoleListenerInfo(listener) != null; 2869 } 2870 2871 @GuardedBy("mDevRoleListenersLock") removeDevRoleListener(T listener)2872 private boolean removeDevRoleListener(T listener) { 2873 final DevRoleListenerInfo<T> infoToRemove = getDevRoleListenerInfo(listener); 2874 if (infoToRemove != null) { 2875 mListenerInfos.remove(infoToRemove); 2876 return true; 2877 } 2878 return false; 2879 } 2880 } 2881 2882 private final Object mDevRoleForCapturePresetListenersLock = new Object(); 2883 /** 2884 * Record if there is a listener added for device role change. If there is a listener added for 2885 * a specified device role change, the bit at position `1 << device_role` is set. 2886 */ 2887 @GuardedBy("mDevRoleForCapturePresetListenersLock") 2888 private int mDeviceRoleListenersStatus = 0; 2889 @GuardedBy("mDevRoleForCapturePresetListenersLock") 2890 private CapturePresetDevicesRoleDispatcherStub mDevicesRoleForCapturePresetDispatcherStub; 2891 2892 private final class CapturePresetDevicesRoleDispatcherStub 2893 extends ICapturePresetDevicesRoleDispatcher.Stub { 2894 2895 @Override dispatchDevicesRoleChanged( int capturePreset, int role, List<AudioDeviceAttributes> devices)2896 public void dispatchDevicesRoleChanged( 2897 int capturePreset, int role, List<AudioDeviceAttributes> devices) { 2898 final Object listenersObj = mDevRoleForCapturePresetListeners.get(role); 2899 if (listenersObj == null) { 2900 return; 2901 } 2902 switch (role) { 2903 case AudioSystem.DEVICE_ROLE_PREFERRED: { 2904 final DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener> 2905 listeners = 2906 (DevRoleListeners<OnPreferredDevicesForCapturePresetChangedListener>) 2907 listenersObj; 2908 final ArrayList<DevRoleListenerInfo< 2909 OnPreferredDevicesForCapturePresetChangedListener>> prefDevListeners; 2910 synchronized (listeners.mDevRoleListenersLock) { 2911 if (listeners.mListenerInfos.isEmpty()) { 2912 return; 2913 } 2914 prefDevListeners = (ArrayList<DevRoleListenerInfo< 2915 OnPreferredDevicesForCapturePresetChangedListener>>) 2916 listeners.mListenerInfos.clone(); 2917 } 2918 final long ident = Binder.clearCallingIdentity(); 2919 try { 2920 for (DevRoleListenerInfo< 2921 OnPreferredDevicesForCapturePresetChangedListener> info : 2922 prefDevListeners) { 2923 info.mExecutor.execute(() -> 2924 info.mListener.onPreferredDevicesForCapturePresetChanged( 2925 capturePreset, devices)); 2926 } 2927 } finally { 2928 Binder.restoreCallingIdentity(ident); 2929 } 2930 } break; 2931 default: 2932 break; 2933 } 2934 } 2935 } 2936 2937 //==================================================================== 2938 // Direct playback query 2939 2940 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}: 2941 direct playback not supported. */ 2942 public static final int DIRECT_PLAYBACK_NOT_SUPPORTED = AudioSystem.DIRECT_NOT_SUPPORTED; 2943 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}: 2944 direct offload playback supported. Compressed offload is a variant of direct playback. 2945 It is the feature that allows audio processing tasks to be done on the Android device but 2946 not on the application processor, instead, it is handled by dedicated hardware such as audio 2947 DSPs. That will allow the application processor to be idle as much as possible, which is 2948 good for power saving. Compressed offload playback supports 2949 {@link AudioTrack.StreamEventCallback} for event notifications. */ 2950 public static final int DIRECT_PLAYBACK_OFFLOAD_SUPPORTED = 2951 AudioSystem.DIRECT_OFFLOAD_SUPPORTED; 2952 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}: 2953 direct offload playback supported with gapless transitions. Compressed offload is a variant 2954 of direct playback. It is the feature that allows audio processing tasks to be done on the 2955 Android device but not on the application processor, instead, it is handled by dedicated 2956 hardware such as audio DSPs. That will allow the application processor to be idle as much as 2957 possible, which is good for power saving. Compressed offload playback supports 2958 {@link AudioTrack.StreamEventCallback} for event notifications. Gapless transitions 2959 indicates the ability to play consecutive audio tracks without an audio silence in 2960 between. */ 2961 public static final int DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED = 2962 AudioSystem.DIRECT_OFFLOAD_GAPLESS_SUPPORTED; 2963 /** Return value for {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)}: 2964 direct playback supported. This value covers direct playback that is bitstream pass-through 2965 such as compressed pass-through. */ 2966 public static final int DIRECT_PLAYBACK_BITSTREAM_SUPPORTED = 2967 AudioSystem.DIRECT_BITSTREAM_SUPPORTED; 2968 2969 /** @hide */ 2970 @IntDef(flag = true, prefix = "DIRECT_PLAYBACK_", value = { 2971 DIRECT_PLAYBACK_NOT_SUPPORTED, 2972 DIRECT_PLAYBACK_OFFLOAD_SUPPORTED, 2973 DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED, 2974 DIRECT_PLAYBACK_BITSTREAM_SUPPORTED} 2975 ) 2976 @Retention(RetentionPolicy.SOURCE) 2977 public @interface AudioDirectPlaybackMode {} 2978 2979 /** 2980 * Returns a bitfield representing the different forms of direct playback currently available 2981 * for a given audio format. 2982 * <p>Direct playback means that the audio stream is not altered by the framework. The audio 2983 * stream will not be resampled, volume scaled, downmixed or mixed with other content by 2984 * the framework. But it may be wrapped in a higher level protocol such as IEC61937 for 2985 * passthrough. 2986 * <p>Checking for direct support can help the app select the representation of audio content 2987 * that most closely matches the capabilities of the device and peripherals (e.g. A/V receiver) 2988 * connected to it. Note that the provided stream can still be re-encoded or mixed with other 2989 * streams, if needed. 2990 * @param format the audio format (codec, sample rate, channels) being checked. 2991 * @param attributes the {@link AudioAttributes} to be used for playback 2992 * @return the direct playback mode available with given format and attributes. The returned 2993 * value will be {@link #DIRECT_PLAYBACK_NOT_SUPPORTED} or a combination of 2994 * {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED}, 2995 * {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} and 2996 * {@link #DIRECT_PLAYBACK_BITSTREAM_SUPPORTED}. Note that if 2997 * {@link #DIRECT_PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} is present in the returned value, 2998 * then {@link #DIRECT_PLAYBACK_OFFLOAD_SUPPORTED} will be too. 2999 */ 3000 @AudioDirectPlaybackMode getDirectPlaybackSupport(@onNull AudioFormat format, @NonNull AudioAttributes attributes)3001 public static int getDirectPlaybackSupport(@NonNull AudioFormat format, 3002 @NonNull AudioAttributes attributes) { 3003 Objects.requireNonNull(format); 3004 Objects.requireNonNull(attributes); 3005 return AudioSystem.getDirectPlaybackSupport(format, attributes); 3006 } 3007 3008 //==================================================================== 3009 // Offload query 3010 /** 3011 * Returns whether offloaded playback of an audio format is supported on the device. 3012 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream 3013 * is not competing with other software resources. In general, it is supported by dedicated 3014 * hardware, such as audio DSPs. 3015 * <p>Note that this query only provides information about the support of an audio format, 3016 * it does not indicate whether the resources necessary for the offloaded playback are 3017 * available at that instant. 3018 * @param format the audio format (codec, sample rate, channels) being checked. 3019 * @param attributes the {@link AudioAttributes} to be used for playback 3020 * @return true if the given audio format can be offloaded. 3021 */ isOffloadedPlaybackSupported(@onNull AudioFormat format, @NonNull AudioAttributes attributes)3022 public static boolean isOffloadedPlaybackSupported(@NonNull AudioFormat format, 3023 @NonNull AudioAttributes attributes) { 3024 if (format == null) { 3025 throw new NullPointerException("Illegal null AudioFormat"); 3026 } 3027 if (attributes == null) { 3028 throw new NullPointerException("Illegal null AudioAttributes"); 3029 } 3030 return AudioSystem.getOffloadSupport(format, attributes) != PLAYBACK_OFFLOAD_NOT_SUPPORTED; 3031 } 3032 3033 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}: 3034 offload playback not supported */ 3035 public static final int PLAYBACK_OFFLOAD_NOT_SUPPORTED = AudioSystem.OFFLOAD_NOT_SUPPORTED; 3036 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}: 3037 offload playback supported */ 3038 public static final int PLAYBACK_OFFLOAD_SUPPORTED = AudioSystem.OFFLOAD_SUPPORTED; 3039 /** Return value for {@link #getPlaybackOffloadSupport(AudioFormat, AudioAttributes)}: 3040 offload playback supported with gapless transitions */ 3041 public static final int PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED = 3042 AudioSystem.OFFLOAD_GAPLESS_SUPPORTED; 3043 3044 /** @hide */ 3045 @IntDef(flag = false, prefix = "PLAYBACK_OFFLOAD_", value = { 3046 PLAYBACK_OFFLOAD_NOT_SUPPORTED, 3047 PLAYBACK_OFFLOAD_SUPPORTED, 3048 PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED } 3049 ) 3050 @Retention(RetentionPolicy.SOURCE) 3051 public @interface AudioOffloadMode {} 3052 3053 /** 3054 * Returns whether offloaded playback of an audio format is supported on the device or not and 3055 * when supported whether gapless transitions are possible or not. 3056 * <p>Offloaded playback is the feature where the decoding and playback of an audio stream 3057 * is not competing with other software resources. In general, it is supported by dedicated 3058 * hardware, such as audio DSPs. 3059 * <p>Note that this query only provides information about the support of an audio format, 3060 * it does not indicate whether the resources necessary for the offloaded playback are 3061 * available at that instant. 3062 * @param format the audio format (codec, sample rate, channels) being checked. 3063 * @param attributes the {@link AudioAttributes} to be used for playback 3064 * @return {@link #PLAYBACK_OFFLOAD_NOT_SUPPORTED} if offload playback if not supported, 3065 * {@link #PLAYBACK_OFFLOAD_SUPPORTED} if offload playback is supported or 3066 * {@link #PLAYBACK_OFFLOAD_GAPLESS_SUPPORTED} if gapless transitions are 3067 * also supported. 3068 * @deprecated Use {@link #getDirectPlaybackSupport(AudioFormat, AudioAttributes)} instead 3069 */ 3070 @Deprecated 3071 @AudioOffloadMode getPlaybackOffloadSupport(@onNull AudioFormat format, @NonNull AudioAttributes attributes)3072 public static int getPlaybackOffloadSupport(@NonNull AudioFormat format, 3073 @NonNull AudioAttributes attributes) { 3074 if (format == null) { 3075 throw new NullPointerException("Illegal null AudioFormat"); 3076 } 3077 if (attributes == null) { 3078 throw new NullPointerException("Illegal null AudioAttributes"); 3079 } 3080 return AudioSystem.getOffloadSupport(format, attributes); 3081 } 3082 3083 //==================================================================== 3084 // Immersive audio 3085 3086 /** 3087 * Return a handle to the optional platform's {@link Spatializer} 3088 * @return the {@code Spatializer} instance. 3089 * @see Spatializer#getImmersiveAudioLevel() to check for the level of support of the effect 3090 * on the platform 3091 */ getSpatializer()3092 public @NonNull Spatializer getSpatializer() { 3093 return new Spatializer(this); 3094 } 3095 3096 //==================================================================== 3097 // Bluetooth SCO control 3098 /** 3099 * Sticky broadcast intent action indicating that the Bluetooth SCO audio 3100 * connection state has changed. The intent contains on extra {@link #EXTRA_SCO_AUDIO_STATE} 3101 * indicating the new state which is either {@link #SCO_AUDIO_STATE_DISCONNECTED} 3102 * or {@link #SCO_AUDIO_STATE_CONNECTED} 3103 * 3104 * @see #startBluetoothSco() 3105 * @deprecated Use {@link #ACTION_SCO_AUDIO_STATE_UPDATED} instead 3106 */ 3107 @Deprecated 3108 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 3109 public static final String ACTION_SCO_AUDIO_STATE_CHANGED = 3110 "android.media.SCO_AUDIO_STATE_CHANGED"; 3111 3112 /** 3113 * Sticky broadcast intent action indicating that the Bluetooth SCO audio 3114 * connection state has been updated. 3115 * <p>This intent has two extras: 3116 * <ul> 3117 * <li> {@link #EXTRA_SCO_AUDIO_STATE} - The new SCO audio state. </li> 3118 * <li> {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE}- The previous SCO audio state. </li> 3119 * </ul> 3120 * <p> EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE can be any of: 3121 * <ul> 3122 * <li> {@link #SCO_AUDIO_STATE_DISCONNECTED}, </li> 3123 * <li> {@link #SCO_AUDIO_STATE_CONNECTING} or </li> 3124 * <li> {@link #SCO_AUDIO_STATE_CONNECTED}, </li> 3125 * </ul> 3126 * @see #startBluetoothSco() 3127 */ 3128 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 3129 public static final String ACTION_SCO_AUDIO_STATE_UPDATED = 3130 "android.media.ACTION_SCO_AUDIO_STATE_UPDATED"; 3131 3132 /** 3133 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_CHANGED} or 3134 * {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the new bluetooth SCO connection state. 3135 */ 3136 public static final String EXTRA_SCO_AUDIO_STATE = 3137 "android.media.extra.SCO_AUDIO_STATE"; 3138 3139 /** 3140 * Extra for intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} containing the previous 3141 * bluetooth SCO connection state. 3142 */ 3143 public static final String EXTRA_SCO_AUDIO_PREVIOUS_STATE = 3144 "android.media.extra.SCO_AUDIO_PREVIOUS_STATE"; 3145 3146 /** 3147 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE 3148 * indicating that the SCO audio channel is not established 3149 */ 3150 public static final int SCO_AUDIO_STATE_DISCONNECTED = 0; 3151 /** 3152 * Value for extra {@link #EXTRA_SCO_AUDIO_STATE} or {@link #EXTRA_SCO_AUDIO_PREVIOUS_STATE} 3153 * indicating that the SCO audio channel is established 3154 */ 3155 public static final int SCO_AUDIO_STATE_CONNECTED = 1; 3156 /** 3157 * Value for extra EXTRA_SCO_AUDIO_STATE or EXTRA_SCO_AUDIO_PREVIOUS_STATE 3158 * indicating that the SCO audio channel is being established 3159 */ 3160 public static final int SCO_AUDIO_STATE_CONNECTING = 2; 3161 /** 3162 * Value for extra EXTRA_SCO_AUDIO_STATE indicating that 3163 * there was an error trying to obtain the state 3164 */ 3165 public static final int SCO_AUDIO_STATE_ERROR = -1; 3166 3167 3168 /** 3169 * Indicates if current platform supports use of SCO for off call use cases. 3170 * Application wanted to use bluetooth SCO audio when the phone is not in call 3171 * must first call this method to make sure that the platform supports this 3172 * feature. 3173 * @return true if bluetooth SCO can be used for audio when not in call 3174 * false otherwise 3175 * @see #startBluetoothSco() 3176 */ isBluetoothScoAvailableOffCall()3177 public boolean isBluetoothScoAvailableOffCall() { 3178 return getContext().getResources().getBoolean( 3179 com.android.internal.R.bool.config_bluetooth_sco_off_call); 3180 } 3181 3182 /** 3183 * Start bluetooth SCO audio connection. 3184 * <p>Requires Permission: 3185 * {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}. 3186 * <p>This method can be used by applications wanting to send and received audio 3187 * to/from a bluetooth SCO headset while the phone is not in call. 3188 * <p>As the SCO connection establishment can take several seconds, 3189 * applications should not rely on the connection to be available when the method 3190 * returns but instead register to receive the intent {@link #ACTION_SCO_AUDIO_STATE_UPDATED} 3191 * and wait for the state to be {@link #SCO_AUDIO_STATE_CONNECTED}. 3192 * <p>As the ACTION_SCO_AUDIO_STATE_UPDATED intent is sticky, the application can check the SCO 3193 * audio state before calling startBluetoothSco() by reading the intent returned by the receiver 3194 * registration. If the state is already CONNECTED, no state change will be received via the 3195 * intent after calling startBluetoothSco(). It is however useful to call startBluetoothSco() 3196 * so that the connection stays active in case the current initiator stops the connection. 3197 * <p>Unless the connection is already active as described above, the state will always 3198 * transition from DISCONNECTED to CONNECTING and then either to CONNECTED if the connection 3199 * succeeds or back to DISCONNECTED if the connection fails (e.g no headset is connected). 3200 * <p>When finished with the SCO connection or if the establishment fails, the application must 3201 * call {@link #stopBluetoothSco()} to clear the request and turn down the bluetooth connection. 3202 * <p>Even if a SCO connection is established, the following restrictions apply on audio 3203 * output streams so that they can be routed to SCO headset: 3204 * <ul> 3205 * <li> the stream type must be {@link #STREAM_VOICE_CALL} </li> 3206 * <li> the format must be mono </li> 3207 * <li> the sampling must be 16kHz or 8kHz </li> 3208 * </ul> 3209 * <p>The following restrictions apply on input streams: 3210 * <ul> 3211 * <li> the format must be mono </li> 3212 * <li> the sampling must be 8kHz </li> 3213 * </ul> 3214 * <p>Note that the phone application always has the priority on the usage of the SCO 3215 * connection for telephony. If this method is called while the phone is in call 3216 * it will be ignored. Similarly, if a call is received or sent while an application 3217 * is using the SCO connection, the connection will be lost for the application and NOT 3218 * returned automatically when the call ends. 3219 * <p>NOTE: up to and including API version 3220 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method initiates a virtual 3221 * voice call to the bluetooth headset. 3222 * After API version {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2} only a raw SCO audio 3223 * connection is established. 3224 * @see #stopBluetoothSco() 3225 * @see #ACTION_SCO_AUDIO_STATE_UPDATED 3226 * @deprecated Use {@link AudioManager#setCommunicationDevice(AudioDeviceInfo)} instead. 3227 */ startBluetoothSco()3228 @Deprecated public void startBluetoothSco() { 3229 final IAudioService service = getService(); 3230 try { 3231 service.startBluetoothSco(mICallBack, 3232 getContext().getApplicationInfo().targetSdkVersion, 3233 getAttributionSource()); 3234 } catch (RemoteException e) { 3235 throw e.rethrowFromSystemServer(); 3236 } 3237 } 3238 3239 /** 3240 * @hide 3241 * Start bluetooth SCO audio connection in virtual call mode. 3242 * <p>Requires Permission: 3243 * {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}. 3244 * <p>Similar to {@link #startBluetoothSco()} with explicit selection of virtual call mode. 3245 * Telephony and communication applications (VoIP, Video Chat) should preferably select 3246 * virtual call mode. 3247 * Applications using voice input for search or commands should first try raw audio connection 3248 * with {@link #startBluetoothSco()} and fall back to startBluetoothScoVirtualCall() in case of 3249 * failure. 3250 * @see #startBluetoothSco() 3251 * @see #stopBluetoothSco() 3252 * @see #ACTION_SCO_AUDIO_STATE_UPDATED 3253 */ 3254 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) startBluetoothScoVirtualCall()3255 public void startBluetoothScoVirtualCall() { 3256 final IAudioService service = getService(); 3257 try { 3258 service.startBluetoothScoVirtualCall(mICallBack, getAttributionSource()); 3259 } catch (RemoteException e) { 3260 throw e.rethrowFromSystemServer(); 3261 } 3262 } 3263 3264 /** 3265 * Stop bluetooth SCO audio connection. 3266 * <p>Requires Permission: 3267 * {@link Manifest.permission#MODIFY_AUDIO_SETTINGS}. 3268 * <p>This method must be called by applications having requested the use of 3269 * bluetooth SCO audio with {@link #startBluetoothSco()} when finished with the SCO 3270 * connection or if connection fails. 3271 * @see #startBluetoothSco() 3272 * @deprecated Use {@link AudioManager#clearCommunicationDevice()} instead. 3273 */ 3274 // Also used for connections started with {@link #startBluetoothScoVirtualCall()} stopBluetoothSco()3275 @Deprecated public void stopBluetoothSco() { 3276 final IAudioService service = getService(); 3277 try { 3278 service.stopBluetoothSco(mICallBack, getAttributionSource()); 3279 } catch (RemoteException e) { 3280 throw e.rethrowFromSystemServer(); 3281 } 3282 } 3283 3284 /** 3285 * Request use of Bluetooth SCO headset for communications. 3286 * <p> 3287 * This method should only be used by applications that replace the platform-wide 3288 * management of audio settings or the main telephony application. 3289 * 3290 * @param on set <var>true</var> to use bluetooth SCO for communications; 3291 * <var>false</var> to not use bluetooth SCO for communications 3292 */ setBluetoothScoOn(boolean on)3293 public void setBluetoothScoOn(boolean on){ 3294 final IAudioService service = getService(); 3295 try { 3296 service.setBluetoothScoOn(on); 3297 } catch (RemoteException e) { 3298 throw e.rethrowFromSystemServer(); 3299 } 3300 } 3301 3302 /** 3303 * Checks whether communications use Bluetooth SCO. 3304 * 3305 * @return true if SCO is used for communications; 3306 * false if otherwise 3307 * @deprecated Use {@link AudioManager#getCommunicationDevice()} instead. 3308 */ isBluetoothScoOn()3309 @Deprecated public boolean isBluetoothScoOn() { 3310 final IAudioService service = getService(); 3311 try { 3312 return service.isBluetoothScoOn(); 3313 } catch (RemoteException e) { 3314 throw e.rethrowFromSystemServer(); 3315 } 3316 } 3317 3318 /** 3319 * @deprecated Use {@link MediaRouter#selectRoute} instead. 3320 */ setBluetoothA2dpOn(boolean on)3321 @Deprecated public void setBluetoothA2dpOn(boolean on){ 3322 } 3323 3324 /** 3325 * Checks whether a Bluetooth A2DP audio peripheral is connected or not. 3326 * 3327 * @return true if a Bluetooth A2DP peripheral is connected 3328 * false if otherwise 3329 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices. 3330 */ isBluetoothA2dpOn()3331 public boolean isBluetoothA2dpOn() { 3332 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"") 3333 == AudioSystem.DEVICE_STATE_AVAILABLE) { 3334 return true; 3335 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"") 3336 == AudioSystem.DEVICE_STATE_AVAILABLE) { 3337 return true; 3338 } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,"") 3339 == AudioSystem.DEVICE_STATE_AVAILABLE) { 3340 return true; 3341 } 3342 return false; 3343 } 3344 3345 /** 3346 * Sets audio routing to the wired headset on or off. 3347 * 3348 * @param on set <var>true</var> to route audio to/from wired 3349 * headset; <var>false</var> disable wired headset audio 3350 * @deprecated Do not use. 3351 */ setWiredHeadsetOn(boolean on)3352 @Deprecated public void setWiredHeadsetOn(boolean on){ 3353 } 3354 3355 /** 3356 * Checks whether a wired headset is connected or not. 3357 * <p>This is not a valid indication that audio playback is 3358 * actually over the wired headset as audio routing depends on other conditions. 3359 * 3360 * @return true if a wired headset is connected. 3361 * false if otherwise 3362 * @deprecated Use {@link AudioManager#getDevices(int)} instead to list available audio devices. 3363 */ isWiredHeadsetOn()3364 public boolean isWiredHeadsetOn() { 3365 if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADSET,"") 3366 == AudioSystem.DEVICE_STATE_UNAVAILABLE && 3367 AudioSystem.getDeviceConnectionState(DEVICE_OUT_WIRED_HEADPHONE,"") 3368 == AudioSystem.DEVICE_STATE_UNAVAILABLE && 3369 AudioSystem.getDeviceConnectionState(DEVICE_OUT_USB_HEADSET, "") 3370 == AudioSystem.DEVICE_STATE_UNAVAILABLE) { 3371 return false; 3372 } else { 3373 return true; 3374 } 3375 } 3376 3377 /** 3378 * Sets the microphone mute on or off. 3379 * <p> 3380 * This method should only be used by applications that replace the platform-wide 3381 * management of audio settings or the main telephony application. 3382 * 3383 * @param on set <var>true</var> to mute the microphone; 3384 * <var>false</var> to turn mute off 3385 */ setMicrophoneMute(boolean on)3386 public void setMicrophoneMute(boolean on) { 3387 final IAudioService service = getService(); 3388 try { 3389 service.setMicrophoneMute(on, getContext().getOpPackageName(), 3390 getContext().getUserId(), getContext().getAttributionTag()); 3391 } catch (RemoteException e) { 3392 throw e.rethrowFromSystemServer(); 3393 } 3394 } 3395 3396 /** 3397 * @hide 3398 * Sets the microphone from switch mute on or off. 3399 * <p> 3400 * This method should only be used by InputManager to notify 3401 * Audio Subsystem about Microphone Mute switch state. 3402 * 3403 * @param on set <var>true</var> to mute the microphone; 3404 * <var>false</var> to turn mute off 3405 */ 3406 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setMicrophoneMuteFromSwitch(boolean on)3407 public void setMicrophoneMuteFromSwitch(boolean on) { 3408 final IAudioService service = getService(); 3409 try { 3410 service.setMicrophoneMuteFromSwitch(on); 3411 } catch (RemoteException e) { 3412 throw e.rethrowFromSystemServer(); 3413 } 3414 } 3415 3416 /** 3417 * Checks whether the microphone mute is on or off. 3418 * 3419 * @return true if microphone is muted, false if it's not 3420 */ isMicrophoneMute()3421 public boolean isMicrophoneMute() { 3422 final IAudioService service = getService(); 3423 try { 3424 return service.isMicrophoneMuted(); 3425 } catch (RemoteException e) { 3426 throw e.rethrowFromSystemServer(); 3427 } 3428 } 3429 3430 /** 3431 * Broadcast Action: microphone muting state changed. 3432 * 3433 * You <em>cannot</em> receive this through components declared 3434 * in manifests, only by explicitly registering for it with 3435 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) 3436 * Context.registerReceiver()}. 3437 * 3438 * <p>The intent has no extra values, use {@link #isMicrophoneMute} to check whether the 3439 * microphone is muted. 3440 */ 3441 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 3442 public static final String ACTION_MICROPHONE_MUTE_CHANGED = 3443 "android.media.action.MICROPHONE_MUTE_CHANGED"; 3444 3445 /** 3446 * Broadcast Action: speakerphone state changed. 3447 * 3448 * You <em>cannot</em> receive this through components declared 3449 * in manifests, only by explicitly registering for it with 3450 * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) 3451 * Context.registerReceiver()}. 3452 * 3453 * <p>The intent has no extra values, use {@link #isSpeakerphoneOn} to check whether the 3454 * speakerphone functionality is enabled or not. 3455 */ 3456 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 3457 public static final String ACTION_SPEAKERPHONE_STATE_CHANGED = 3458 "android.media.action.SPEAKERPHONE_STATE_CHANGED"; 3459 3460 /** 3461 * Sets the audio mode. 3462 * <p> 3463 * The audio mode encompasses audio routing AND the behavior of 3464 * the telephony layer. Therefore this method should only be used by applications that 3465 * replace the platform-wide management of audio settings or the main telephony application. 3466 * In particular, the {@link #MODE_IN_CALL} mode should only be used by the telephony 3467 * application when it places a phone call, as it will cause signals from the radio layer 3468 * to feed the platform mixer. 3469 * 3470 * @param mode the requested audio mode. 3471 * Informs the HAL about the current audio state so that 3472 * it can route the audio appropriately. 3473 */ setMode(@udioMode int mode)3474 public void setMode(@AudioMode int mode) { 3475 final IAudioService service = getService(); 3476 try { 3477 service.setMode(mode, mICallBack, mApplicationContext.getOpPackageName()); 3478 } catch (RemoteException e) { 3479 throw e.rethrowFromSystemServer(); 3480 } 3481 } 3482 3483 /** 3484 * This change id controls use of audio modes for call audio redirection. 3485 * @hide 3486 */ 3487 @ChangeId 3488 @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU) 3489 public static final long CALL_REDIRECTION_AUDIO_MODES = 189472651L; // buganizer id 3490 3491 /** 3492 * Returns the current audio mode. 3493 * 3494 * @return the current audio mode. 3495 */ 3496 @AudioMode getMode()3497 public int getMode() { 3498 final IAudioService service = getService(); 3499 try { 3500 int mode = service.getMode(); 3501 int sdk; 3502 try { 3503 sdk = getContext().getApplicationInfo().targetSdkVersion; 3504 } catch (NullPointerException e) { 3505 // some tests don't have a Context 3506 sdk = Build.VERSION.SDK_INT; 3507 } 3508 if (mode == MODE_CALL_SCREENING && sdk <= Build.VERSION_CODES.Q) { 3509 mode = MODE_IN_CALL; 3510 } else if (mode == MODE_CALL_REDIRECT 3511 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) { 3512 mode = MODE_IN_CALL; 3513 } else if (mode == MODE_COMMUNICATION_REDIRECT 3514 && !CompatChanges.isChangeEnabled(CALL_REDIRECTION_AUDIO_MODES)) { 3515 mode = MODE_IN_COMMUNICATION; 3516 } 3517 return mode; 3518 } catch (RemoteException e) { 3519 throw e.rethrowFromSystemServer(); 3520 } 3521 } 3522 3523 /** 3524 * Interface definition of a callback that is notified when the audio mode changes 3525 */ 3526 public interface OnModeChangedListener { 3527 /** 3528 * Called on the listener to indicate that the audio mode has changed 3529 * 3530 * @param mode The current audio mode 3531 */ onModeChanged(@udioMode int mode)3532 void onModeChanged(@AudioMode int mode); 3533 } 3534 3535 /** 3536 * manages the OnModeChangedListener listeners and the ModeDispatcherStub 3537 */ 3538 private final CallbackUtil.LazyListenerManager<OnModeChangedListener> mModeChangedListenerMgr = 3539 new CallbackUtil.LazyListenerManager(); 3540 3541 3542 final class ModeDispatcherStub extends IAudioModeDispatcher.Stub 3543 implements CallbackUtil.DispatcherStub { 3544 3545 @Override register(boolean register)3546 public void register(boolean register) { 3547 try { 3548 if (register) { 3549 getService().registerModeDispatcher(this); 3550 } else { 3551 getService().unregisterModeDispatcher(this); 3552 } 3553 } catch (RemoteException e) { 3554 e.rethrowFromSystemServer(); 3555 } 3556 } 3557 3558 @Override dispatchAudioModeChanged(int mode)3559 public void dispatchAudioModeChanged(int mode) { 3560 mModeChangedListenerMgr.callListeners((listener) -> listener.onModeChanged(mode)); 3561 } 3562 } 3563 3564 /** 3565 * Adds a listener to be notified of changes to the audio mode. 3566 * See {@link #getMode()} 3567 * @param executor 3568 * @param listener 3569 */ addOnModeChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnModeChangedListener listener)3570 public void addOnModeChangedListener( 3571 @NonNull @CallbackExecutor Executor executor, 3572 @NonNull OnModeChangedListener listener) { 3573 mModeChangedListenerMgr.addListener(executor, listener, "addOnModeChangedListener", 3574 () -> new ModeDispatcherStub()); 3575 } 3576 3577 /** 3578 * Removes a previously added listener for changes to audio mode. 3579 * See {@link #getMode()} 3580 * @param listener 3581 */ removeOnModeChangedListener(@onNull OnModeChangedListener listener)3582 public void removeOnModeChangedListener(@NonNull OnModeChangedListener listener) { 3583 mModeChangedListenerMgr.removeListener(listener, "removeOnModeChangedListener"); 3584 } 3585 3586 /** 3587 * Indicates if the platform supports a special call screening and call monitoring mode. 3588 * <p> 3589 * When this mode is supported, it is possible to perform call screening and monitoring 3590 * functions while other use cases like music or movie playback are active. 3591 * <p> 3592 * Use {@link #setMode(int)} with mode {@link #MODE_CALL_SCREENING} to place the platform in 3593 * call screening mode. 3594 * <p> 3595 * If call screening mode is not supported, setting mode to 3596 * MODE_CALL_SCREENING will be ignored and will not change current mode reported by 3597 * {@link #getMode()}. 3598 * @return true if call screening mode is supported, false otherwise. 3599 */ isCallScreeningModeSupported()3600 public boolean isCallScreeningModeSupported() { 3601 final IAudioService service = getService(); 3602 try { 3603 return service.isCallScreeningModeSupported(); 3604 } catch (RemoteException e) { 3605 throw e.rethrowFromSystemServer(); 3606 } 3607 } 3608 3609 /* modes for setMode/getMode/setRoute/getRoute */ 3610 /** 3611 * Audio hardware modes. 3612 */ 3613 /** 3614 * Invalid audio mode. 3615 */ 3616 public static final int MODE_INVALID = AudioSystem.MODE_INVALID; 3617 /** 3618 * Current audio mode. Used to apply audio routing to current mode. 3619 */ 3620 public static final int MODE_CURRENT = AudioSystem.MODE_CURRENT; 3621 /** 3622 * Normal audio mode: not ringing and no call established. 3623 */ 3624 public static final int MODE_NORMAL = AudioSystem.MODE_NORMAL; 3625 /** 3626 * Ringing audio mode. An incoming is being signaled. 3627 */ 3628 public static final int MODE_RINGTONE = AudioSystem.MODE_RINGTONE; 3629 /** 3630 * In call audio mode. A telephony call is established. 3631 */ 3632 public static final int MODE_IN_CALL = AudioSystem.MODE_IN_CALL; 3633 /** 3634 * In communication audio mode. An audio/video chat or VoIP call is established. 3635 */ 3636 public static final int MODE_IN_COMMUNICATION = AudioSystem.MODE_IN_COMMUNICATION; 3637 /** 3638 * Call screening in progress. Call is connected and audio is accessible to call 3639 * screening applications but other audio use cases are still possible. 3640 */ 3641 public static final int MODE_CALL_SCREENING = AudioSystem.MODE_CALL_SCREENING; 3642 3643 /** 3644 * A telephony call is established and its audio is being redirected to another device. 3645 */ 3646 public static final int MODE_CALL_REDIRECT = AudioSystem.MODE_CALL_REDIRECT; 3647 3648 /** 3649 * An audio/video chat or VoIP call is established and its audio is being redirected to another 3650 * device. 3651 */ 3652 public static final int MODE_COMMUNICATION_REDIRECT = AudioSystem.MODE_COMMUNICATION_REDIRECT; 3653 3654 /** @hide */ 3655 @IntDef(flag = false, prefix = "MODE_", value = { 3656 MODE_NORMAL, 3657 MODE_RINGTONE, 3658 MODE_IN_CALL, 3659 MODE_IN_COMMUNICATION, 3660 MODE_CALL_SCREENING, 3661 MODE_CALL_REDIRECT, 3662 MODE_COMMUNICATION_REDIRECT} 3663 ) 3664 @Retention(RetentionPolicy.SOURCE) 3665 public @interface AudioMode {} 3666 3667 /* Routing bits for setRouting/getRouting API */ 3668 /** 3669 * Routing audio output to earpiece 3670 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3671 * setBluetoothScoOn() methods instead. 3672 */ 3673 @Deprecated public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE; 3674 /** 3675 * Routing audio output to speaker 3676 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3677 * setBluetoothScoOn() methods instead. 3678 */ 3679 @Deprecated public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER; 3680 /** 3681 * @deprecated use {@link #ROUTE_BLUETOOTH_SCO} 3682 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3683 * setBluetoothScoOn() methods instead. 3684 */ 3685 @Deprecated public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH_SCO; 3686 /** 3687 * Routing audio output to bluetooth SCO 3688 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3689 * setBluetoothScoOn() methods instead. 3690 */ 3691 @Deprecated public static final int ROUTE_BLUETOOTH_SCO = AudioSystem.ROUTE_BLUETOOTH_SCO; 3692 /** 3693 * Routing audio output to headset 3694 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3695 * setBluetoothScoOn() methods instead. 3696 */ 3697 @Deprecated public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET; 3698 /** 3699 * Routing audio output to bluetooth A2DP 3700 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3701 * setBluetoothScoOn() methods instead. 3702 */ 3703 @Deprecated public static final int ROUTE_BLUETOOTH_A2DP = AudioSystem.ROUTE_BLUETOOTH_A2DP; 3704 /** 3705 * Used for mask parameter of {@link #setRouting(int,int,int)}. 3706 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3707 * setBluetoothScoOn() methods instead. 3708 */ 3709 @Deprecated public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL; 3710 3711 /** 3712 * Sets the audio routing for a specified mode 3713 * 3714 * @param mode audio mode to change route. E.g., MODE_RINGTONE. 3715 * @param routes bit vector of routes requested, created from one or 3716 * more of ROUTE_xxx types. Set bits indicate that route should be on 3717 * @param mask bit vector of routes to change, created from one or more of 3718 * ROUTE_xxx types. Unset bits indicate the route should be left unchanged 3719 * 3720 * @deprecated Do not set audio routing directly, use setSpeakerphoneOn(), 3721 * setBluetoothScoOn() methods instead. 3722 */ 3723 @Deprecated setRouting(int mode, int routes, int mask)3724 public void setRouting(int mode, int routes, int mask) { 3725 } 3726 3727 /** 3728 * Returns the current audio routing bit vector for a specified mode. 3729 * 3730 * @param mode audio mode to get route (e.g., MODE_RINGTONE) 3731 * @return an audio route bit vector that can be compared with ROUTE_xxx 3732 * bits 3733 * @deprecated Do not query audio routing directly, use isSpeakerphoneOn(), 3734 * isBluetoothScoOn(), isBluetoothA2dpOn() and isWiredHeadsetOn() methods instead. 3735 */ 3736 @Deprecated getRouting(int mode)3737 public int getRouting(int mode) { 3738 return -1; 3739 } 3740 3741 /** 3742 * Checks whether any music is active. 3743 * 3744 * @return true if any music tracks are active. 3745 */ isMusicActive()3746 public boolean isMusicActive() { 3747 final IAudioService service = getService(); 3748 try { 3749 return service.isMusicActive(false /*remotely*/); 3750 } catch (RemoteException e) { 3751 throw e.rethrowFromSystemServer(); 3752 } 3753 } 3754 3755 /** 3756 * @hide 3757 * Checks whether any music or media is actively playing on a remote device (e.g. wireless 3758 * display). Note that BT audio sinks are not considered remote devices. 3759 * @return true if {@link AudioManager#STREAM_MUSIC} is active on a remote device 3760 */ 3761 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isMusicActiveRemotely()3762 public boolean isMusicActiveRemotely() { 3763 final IAudioService service = getService(); 3764 try { 3765 return service.isMusicActive(true /*remotely*/); 3766 } catch (RemoteException e) { 3767 throw e.rethrowFromSystemServer(); 3768 } 3769 } 3770 3771 /** 3772 * @hide 3773 * Checks whether the current audio focus is exclusive. 3774 * @return true if the top of the audio focus stack requested focus 3775 * with {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} 3776 */ isAudioFocusExclusive()3777 public boolean isAudioFocusExclusive() { 3778 final IAudioService service = getService(); 3779 try { 3780 return service.getCurrentAudioFocus() == AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE; 3781 } catch (RemoteException e) { 3782 throw e.rethrowFromSystemServer(); 3783 } 3784 } 3785 3786 /** 3787 * Return a new audio session identifier not associated with any player or effect. 3788 * An audio session identifier is a system wide unique identifier for a set of audio streams 3789 * (one or more mixed together). 3790 * <p>The primary use of the audio session ID is to associate audio effects to audio players, 3791 * such as {@link MediaPlayer} or {@link AudioTrack}: all audio effects sharing the same audio 3792 * session ID will be applied to the mixed audio content of the players that share the same 3793 * audio session. 3794 * <p>This method can for instance be used when creating one of the 3795 * {@link android.media.audiofx.AudioEffect} objects to define the audio session of the effect, 3796 * or to specify a session for a speech synthesis utterance 3797 * in {@link android.speech.tts.TextToSpeech.Engine}. 3798 * @return a new unclaimed and unused audio session identifier, or {@link #ERROR} when the 3799 * system failed to generate a new session, a condition in which audio playback or recording 3800 * will subsequently fail as well. 3801 */ generateAudioSessionId()3802 public int generateAudioSessionId() { 3803 int session = AudioSystem.newAudioSessionId(); 3804 if (session > 0) { 3805 return session; 3806 } else { 3807 Log.e(TAG, "Failure to generate a new audio session ID"); 3808 return ERROR; 3809 } 3810 } 3811 3812 /** 3813 * A special audio session ID to indicate that the audio session ID isn't known and the 3814 * framework should generate a new value. This can be used when building a new 3815 * {@link AudioTrack} instance with 3816 * {@link AudioTrack#AudioTrack(AudioAttributes, AudioFormat, int, int, int)}. 3817 */ 3818 public static final int AUDIO_SESSION_ID_GENERATE = AudioSystem.AUDIO_SESSION_ALLOCATE; 3819 3820 3821 /* 3822 * Sets a generic audio configuration parameter. The use of these parameters 3823 * are platform dependant, see libaudio 3824 * 3825 * ** Temporary interface - DO NOT USE 3826 * 3827 * TODO: Replace with a more generic key:value get/set mechanism 3828 * 3829 * param key name of parameter to set. Must not be null. 3830 * param value value of parameter. Must not be null. 3831 */ 3832 /** 3833 * @hide 3834 * @deprecated Use {@link #setParameters(String)} instead 3835 */ setParameter(String key, String value)3836 @Deprecated public void setParameter(String key, String value) { 3837 setParameters(key+"="+value); 3838 } 3839 3840 /** 3841 * Sets a variable number of parameter values to audio hardware. 3842 * 3843 * @param keyValuePairs list of parameters key value pairs in the form: 3844 * key1=value1;key2=value2;... 3845 * 3846 */ setParameters(String keyValuePairs)3847 public void setParameters(String keyValuePairs) { 3848 AudioSystem.setParameters(keyValuePairs); 3849 } 3850 3851 /** 3852 * @hide 3853 */ 3854 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 3855 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK) setHfpEnabled(boolean enable)3856 public void setHfpEnabled(boolean enable) { 3857 AudioSystem.setParameters("hfp_enable=" + enable); 3858 } 3859 3860 /** 3861 * @hide 3862 */ 3863 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 3864 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK) setHfpVolume(int volume)3865 public void setHfpVolume(int volume) { 3866 AudioSystem.setParameters("hfp_volume=" + volume); 3867 } 3868 3869 /** 3870 * @hide 3871 */ 3872 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 3873 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK) setHfpSamplingRate(int rate)3874 public void setHfpSamplingRate(int rate) { 3875 AudioSystem.setParameters("hfp_set_sampling_rate=" + rate); 3876 } 3877 3878 /** 3879 * @hide 3880 */ 3881 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 3882 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK) setBluetoothHeadsetProperties(@onNull String name, boolean hasNrecEnabled, boolean hasWbsEnabled)3883 public void setBluetoothHeadsetProperties(@NonNull String name, boolean hasNrecEnabled, 3884 boolean hasWbsEnabled) { 3885 AudioSystem.setParameters("bt_headset_name=" + name 3886 + ";bt_headset_nrec=" + (hasNrecEnabled ? "on" : "off") 3887 + ";bt_wbs=" + (hasWbsEnabled ? "on" : "off")); 3888 } 3889 3890 /** 3891 * @hide 3892 */ 3893 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 3894 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK) setA2dpSuspended(boolean enable)3895 public void setA2dpSuspended(boolean enable) { 3896 final IAudioService service = getService(); 3897 try { 3898 service.setA2dpSuspended(enable); 3899 } catch (RemoteException e) { 3900 throw e.rethrowFromSystemServer(); 3901 } 3902 } 3903 3904 /** 3905 * Suspends the use of LE Audio. 3906 * 3907 * @param enable {@code true} to suspend le audio, {@code false} to unsuspend 3908 * 3909 * @hide 3910 */ 3911 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 3912 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK) setLeAudioSuspended(boolean enable)3913 public void setLeAudioSuspended(boolean enable) { 3914 final IAudioService service = getService(); 3915 try { 3916 service.setLeAudioSuspended(enable); 3917 } catch (RemoteException e) { 3918 throw e.rethrowFromSystemServer(); 3919 } 3920 } 3921 3922 /** 3923 * Gets a variable number of parameter values from audio hardware. 3924 * 3925 * @param keys list of parameters 3926 * @return list of parameters key value pairs in the form: 3927 * key1=value1;key2=value2;... 3928 */ getParameters(String keys)3929 public String getParameters(String keys) { 3930 return AudioSystem.getParameters(keys); 3931 } 3932 3933 /* Sound effect identifiers */ 3934 /** 3935 * Keyboard and direction pad click sound 3936 * @see #playSoundEffect(int) 3937 */ 3938 public static final int FX_KEY_CLICK = 0; 3939 /** 3940 * Focus has moved up 3941 * @see #playSoundEffect(int) 3942 */ 3943 public static final int FX_FOCUS_NAVIGATION_UP = 1; 3944 /** 3945 * Focus has moved down 3946 * @see #playSoundEffect(int) 3947 */ 3948 public static final int FX_FOCUS_NAVIGATION_DOWN = 2; 3949 /** 3950 * Focus has moved left 3951 * @see #playSoundEffect(int) 3952 */ 3953 public static final int FX_FOCUS_NAVIGATION_LEFT = 3; 3954 /** 3955 * Focus has moved right 3956 * @see #playSoundEffect(int) 3957 */ 3958 public static final int FX_FOCUS_NAVIGATION_RIGHT = 4; 3959 /** 3960 * IME standard keypress sound 3961 * @see #playSoundEffect(int) 3962 */ 3963 public static final int FX_KEYPRESS_STANDARD = 5; 3964 /** 3965 * IME spacebar keypress sound 3966 * @see #playSoundEffect(int) 3967 */ 3968 public static final int FX_KEYPRESS_SPACEBAR = 6; 3969 /** 3970 * IME delete keypress sound 3971 * @see #playSoundEffect(int) 3972 */ 3973 public static final int FX_KEYPRESS_DELETE = 7; 3974 /** 3975 * IME return_keypress sound 3976 * @see #playSoundEffect(int) 3977 */ 3978 public static final int FX_KEYPRESS_RETURN = 8; 3979 3980 /** 3981 * Invalid keypress sound 3982 * @see #playSoundEffect(int) 3983 */ 3984 public static final int FX_KEYPRESS_INVALID = 9; 3985 3986 /** 3987 * Back sound 3988 * @see #playSoundEffect(int) 3989 */ 3990 public static final int FX_BACK = 10; 3991 3992 /** 3993 * @hide Home sound 3994 * <p> 3995 * To be played by the framework when the home app becomes active if config_enableHomeSound is 3996 * set to true. This is currently only used on TV devices. 3997 * Note that this sound is only available if a sound file is specified in audio_assets.xml. 3998 * @see #playSoundEffect(int) 3999 */ 4000 public static final int FX_HOME = 11; 4001 4002 /** 4003 * @hide Navigation repeat sound 1 4004 * <p> 4005 * To be played by the framework when a focus navigation is repeatedly triggered 4006 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true. 4007 * This is currently only used on TV devices. 4008 * Note that this sound is only available if a sound file is specified in audio_assets.xml 4009 * @see #playSoundEffect(int) 4010 */ 4011 public static final int FX_FOCUS_NAVIGATION_REPEAT_1 = 12; 4012 4013 /** 4014 * @hide Navigation repeat sound 2 4015 * <p> 4016 * To be played by the framework when a focus navigation is repeatedly triggered 4017 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true. 4018 * This is currently only used on TV devices. 4019 * Note that this sound is only available if a sound file is specified in audio_assets.xml 4020 * @see #playSoundEffect(int) 4021 */ 4022 public static final int FX_FOCUS_NAVIGATION_REPEAT_2 = 13; 4023 4024 /** 4025 * @hide Navigation repeat sound 3 4026 * <p> 4027 * To be played by the framework when a focus navigation is repeatedly triggered 4028 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true. 4029 * This is currently only used on TV devices. 4030 * Note that this sound is only available if a sound file is specified in audio_assets.xml 4031 * @see #playSoundEffect(int) 4032 */ 4033 public static final int FX_FOCUS_NAVIGATION_REPEAT_3 = 14; 4034 4035 /** 4036 * @hide Navigation repeat sound 4 4037 * <p> 4038 * To be played by the framework when a focus navigation is repeatedly triggered 4039 * (e.g. due to long-pressing) and {@link #areNavigationRepeatSoundEffectsEnabled()} is true. 4040 * This is currently only used on TV devices. 4041 * Note that this sound is only available if a sound file is specified in audio_assets.xml 4042 * @see #playSoundEffect(int) 4043 */ 4044 public static final int FX_FOCUS_NAVIGATION_REPEAT_4 = 15; 4045 4046 /** 4047 * @hide Number of sound effects 4048 */ 4049 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4050 public static final int NUM_SOUND_EFFECTS = 16; 4051 4052 /** @hide */ 4053 @IntDef(prefix = { "FX_" }, value = { 4054 FX_KEY_CLICK, 4055 FX_FOCUS_NAVIGATION_UP, 4056 FX_FOCUS_NAVIGATION_DOWN, 4057 FX_FOCUS_NAVIGATION_LEFT, 4058 FX_FOCUS_NAVIGATION_RIGHT, 4059 FX_KEYPRESS_STANDARD, 4060 FX_KEYPRESS_SPACEBAR, 4061 FX_KEYPRESS_DELETE, 4062 FX_KEYPRESS_RETURN, 4063 FX_KEYPRESS_INVALID, 4064 FX_BACK 4065 }) 4066 @Retention(RetentionPolicy.SOURCE) 4067 public @interface SystemSoundEffect {} 4068 4069 /** 4070 * @hide Number of FX_FOCUS_NAVIGATION_REPEAT_* sound effects 4071 */ 4072 public static final int NUM_NAVIGATION_REPEAT_SOUND_EFFECTS = 4; 4073 4074 /** 4075 * @hide 4076 * @param n a value in [0, {@link #NUM_NAVIGATION_REPEAT_SOUND_EFFECTS}[ 4077 * @return The id of a navigation repeat sound effect or -1 if out of bounds 4078 */ getNthNavigationRepeatSoundEffect(int n)4079 public static int getNthNavigationRepeatSoundEffect(int n) { 4080 switch (n) { 4081 case 0: 4082 return FX_FOCUS_NAVIGATION_REPEAT_1; 4083 case 1: 4084 return FX_FOCUS_NAVIGATION_REPEAT_2; 4085 case 2: 4086 return FX_FOCUS_NAVIGATION_REPEAT_3; 4087 case 3: 4088 return FX_FOCUS_NAVIGATION_REPEAT_4; 4089 default: 4090 Log.w(TAG, "Invalid navigation repeat sound effect id: " + n); 4091 return -1; 4092 } 4093 } 4094 4095 /** 4096 * @hide 4097 */ setNavigationRepeatSoundEffectsEnabled(boolean enabled)4098 public void setNavigationRepeatSoundEffectsEnabled(boolean enabled) { 4099 try { 4100 getService().setNavigationRepeatSoundEffectsEnabled(enabled); 4101 } catch (RemoteException e) { 4102 4103 } 4104 } 4105 4106 /** 4107 * @hide 4108 * @return true if the navigation repeat sound effects are enabled 4109 */ areNavigationRepeatSoundEffectsEnabled()4110 public boolean areNavigationRepeatSoundEffectsEnabled() { 4111 try { 4112 return getService().areNavigationRepeatSoundEffectsEnabled(); 4113 } catch (RemoteException e) { 4114 throw e.rethrowFromSystemServer(); 4115 } 4116 } 4117 4118 /** 4119 * @hide 4120 * @param enabled 4121 */ setHomeSoundEffectEnabled(boolean enabled)4122 public void setHomeSoundEffectEnabled(boolean enabled) { 4123 try { 4124 getService().setHomeSoundEffectEnabled(enabled); 4125 } catch (RemoteException e) { 4126 4127 } 4128 } 4129 4130 /** 4131 * @hide 4132 * @return true if the home sound effect is enabled 4133 */ isHomeSoundEffectEnabled()4134 public boolean isHomeSoundEffectEnabled() { 4135 try { 4136 return getService().isHomeSoundEffectEnabled(); 4137 } catch (RemoteException e) { 4138 throw e.rethrowFromSystemServer(); 4139 } 4140 } 4141 4142 /** 4143 * Plays a sound effect (Key clicks, lid open/close...) 4144 * @param effectType The type of sound effect. 4145 * NOTE: This version uses the UI settings to determine 4146 * whether sounds are heard or not. 4147 */ playSoundEffect(@ystemSoundEffect int effectType)4148 public void playSoundEffect(@SystemSoundEffect int effectType) { 4149 playSoundEffect(effectType, UserHandle.USER_CURRENT); 4150 } 4151 4152 /** 4153 * Plays a sound effect (Key clicks, lid open/close...) 4154 * @param effectType The type of sound effect. 4155 * @param userId The current user to pull sound settings from 4156 * NOTE: This version uses the UI settings to determine 4157 * whether sounds are heard or not. 4158 * @hide 4159 */ playSoundEffect(@ystemSoundEffect int effectType, int userId)4160 public void playSoundEffect(@SystemSoundEffect int effectType, int userId) { 4161 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) { 4162 return; 4163 } 4164 4165 if (delegateSoundEffectToVdm(effectType)) { 4166 return; 4167 } 4168 4169 final IAudioService service = getService(); 4170 try { 4171 service.playSoundEffect(effectType, userId); 4172 } catch (RemoteException e) { 4173 throw e.rethrowFromSystemServer(); 4174 } 4175 } 4176 4177 /** 4178 * Plays a sound effect (Key clicks, lid open/close...) 4179 * @param effectType The type of sound effect. 4180 * @param volume Sound effect volume. 4181 * The volume value is a raw scalar so UI controls should be scaled logarithmically. 4182 * If a volume of -1 is specified, the AudioManager.STREAM_MUSIC stream volume minus 3dB will be used. 4183 * NOTE: This version is for applications that have their own 4184 * settings panel for enabling and controlling volume. 4185 */ playSoundEffect(@ystemSoundEffect int effectType, float volume)4186 public void playSoundEffect(@SystemSoundEffect int effectType, float volume) { 4187 if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) { 4188 return; 4189 } 4190 4191 if (delegateSoundEffectToVdm(effectType)) { 4192 return; 4193 } 4194 4195 final IAudioService service = getService(); 4196 try { 4197 service.playSoundEffectVolume(effectType, volume); 4198 } catch (RemoteException e) { 4199 throw e.rethrowFromSystemServer(); 4200 } 4201 } 4202 4203 /** 4204 * Checks whether this {@link AudioManager} instance is associated with {@link VirtualDevice} 4205 * configured with custom device policy for audio. If there is such device, request to play 4206 * sound effect is forwarded to {@link VirtualDeviceManager}. 4207 * 4208 * @param effectType - The type of sound effect. 4209 * @return true if the request was forwarded to {@link VirtualDeviceManager} instance, 4210 * false otherwise. 4211 */ delegateSoundEffectToVdm(@ystemSoundEffect int effectType)4212 private boolean delegateSoundEffectToVdm(@SystemSoundEffect int effectType) { 4213 if (hasCustomPolicyVirtualDeviceContext()) { 4214 VirtualDeviceManager vdm = getVirtualDeviceManager(); 4215 if (vdm != null) { 4216 vdm.playSoundEffect(mOriginalContextDeviceId, effectType); 4217 return true; 4218 } 4219 } 4220 return false; 4221 } 4222 hasCustomPolicyVirtualDeviceContext()4223 private boolean hasCustomPolicyVirtualDeviceContext() { 4224 if (mOriginalContextDeviceId == DEVICE_ID_DEFAULT) { 4225 return false; 4226 } 4227 4228 VirtualDeviceManager vdm = getVirtualDeviceManager(); 4229 return vdm != null && vdm.getDevicePolicy(mOriginalContextDeviceId, POLICY_TYPE_AUDIO) 4230 != DEVICE_POLICY_DEFAULT; 4231 } 4232 4233 /** 4234 * Load Sound effects. 4235 * This method must be called when sound effects are enabled. 4236 */ loadSoundEffects()4237 public void loadSoundEffects() { 4238 final IAudioService service = getService(); 4239 try { 4240 service.loadSoundEffects(); 4241 } catch (RemoteException e) { 4242 throw e.rethrowFromSystemServer(); 4243 } 4244 } 4245 4246 /** 4247 * Unload Sound effects. 4248 * This method can be called to free some memory when 4249 * sound effects are disabled. 4250 */ unloadSoundEffects()4251 public void unloadSoundEffects() { 4252 final IAudioService service = getService(); 4253 try { 4254 service.unloadSoundEffects(); 4255 } catch (RemoteException e) { 4256 throw e.rethrowFromSystemServer(); 4257 } 4258 } 4259 4260 /** 4261 * @hide 4262 */ audioFocusToString(int focus)4263 public static String audioFocusToString(int focus) { 4264 switch (focus) { 4265 case AUDIOFOCUS_NONE: 4266 return "AUDIOFOCUS_NONE"; 4267 case AUDIOFOCUS_GAIN: 4268 return "AUDIOFOCUS_GAIN"; 4269 case AUDIOFOCUS_GAIN_TRANSIENT: 4270 return "AUDIOFOCUS_GAIN_TRANSIENT"; 4271 case AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK: 4272 return "AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK"; 4273 case AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE: 4274 return "AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE"; 4275 case AUDIOFOCUS_LOSS: 4276 return "AUDIOFOCUS_LOSS"; 4277 case AUDIOFOCUS_LOSS_TRANSIENT: 4278 return "AUDIOFOCUS_LOSS_TRANSIENT"; 4279 case AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // Note CAN_DUCK not MAY_DUCK. 4280 return "AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK"; 4281 default: 4282 return "AUDIO_FOCUS_UNKNOWN(" + focus + ")"; 4283 } 4284 } 4285 4286 /** 4287 * Used to indicate no audio focus has been gained or lost, or requested. 4288 */ 4289 public static final int AUDIOFOCUS_NONE = 0; 4290 4291 /** 4292 * Used to indicate a gain of audio focus, or a request of audio focus, of unknown duration. 4293 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 4294 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 4295 */ 4296 public static final int AUDIOFOCUS_GAIN = 1; 4297 /** 4298 * Used to indicate a temporary gain or request of audio focus, anticipated to last a short 4299 * amount of time. Examples of temporary changes are the playback of driving directions, or an 4300 * event notification. 4301 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 4302 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 4303 */ 4304 public static final int AUDIOFOCUS_GAIN_TRANSIENT = 2; 4305 /** 4306 * Used to indicate a temporary request of audio focus, anticipated to last a short 4307 * amount of time, and where it is acceptable for other audio applications to keep playing 4308 * after having lowered their output level (also referred to as "ducking"). 4309 * Examples of temporary changes are the playback of driving directions where playback of music 4310 * in the background is acceptable. 4311 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 4312 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 4313 */ 4314 public static final int AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK = 3; 4315 /** 4316 * Used to indicate a temporary request of audio focus, anticipated to last a short 4317 * amount of time, during which no other applications, or system components, should play 4318 * anything. Examples of exclusive and transient audio focus requests are voice 4319 * memo recording and speech recognition, during which the system shouldn't play any 4320 * notifications, and media playback should have paused. 4321 * @see #requestAudioFocus(OnAudioFocusChangeListener, int, int) 4322 */ 4323 public static final int AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE = 4; 4324 /** 4325 * Used to indicate a loss of audio focus of unknown duration. 4326 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 4327 */ 4328 public static final int AUDIOFOCUS_LOSS = -1 * AUDIOFOCUS_GAIN; 4329 /** 4330 * Used to indicate a transient loss of audio focus. 4331 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 4332 */ 4333 public static final int AUDIOFOCUS_LOSS_TRANSIENT = -1 * AUDIOFOCUS_GAIN_TRANSIENT; 4334 /** 4335 * Used to indicate a transient loss of audio focus where the loser of the audio focus can 4336 * lower its output volume if it wants to continue playing (also referred to as "ducking"), as 4337 * the new focus owner doesn't require others to be silent. 4338 * @see OnAudioFocusChangeListener#onAudioFocusChange(int) 4339 */ 4340 public static final int AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK = 4341 -1 * AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK; 4342 4343 /** 4344 * Interface definition for a callback to be invoked when the audio focus of the system is 4345 * updated. 4346 */ 4347 public interface OnAudioFocusChangeListener { 4348 /** 4349 * Called on the listener to notify it the audio focus for this listener has been changed. 4350 * The focusChange value indicates whether the focus was gained, 4351 * whether the focus was lost, and whether that loss is transient, or whether the new focus 4352 * holder will hold it for an unknown amount of time. 4353 * When losing focus, listeners can use the focus change information to decide what 4354 * behavior to adopt when losing focus. A music player could for instance elect to lower 4355 * the volume of its music stream (duck) for transient focus losses, and pause otherwise. 4356 * @param focusChange the type of focus change, one of {@link AudioManager#AUDIOFOCUS_GAIN}, 4357 * {@link AudioManager#AUDIOFOCUS_LOSS}, {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT} 4358 * and {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}. 4359 */ onAudioFocusChange(int focusChange)4360 public void onAudioFocusChange(int focusChange); 4361 } 4362 4363 /** 4364 * Internal class to hold the AudioFocusRequest as well as the Handler for the callback 4365 */ 4366 private static class FocusRequestInfo { 4367 @NonNull final AudioFocusRequest mRequest; 4368 @Nullable final Handler mHandler; FocusRequestInfo(@onNull AudioFocusRequest afr, @Nullable Handler handler)4369 FocusRequestInfo(@NonNull AudioFocusRequest afr, @Nullable Handler handler) { 4370 mRequest = afr; 4371 mHandler = handler; 4372 } 4373 } 4374 4375 /** 4376 * Map to convert focus event listener IDs, as used in the AudioService audio focus stack, 4377 * to actual listener objects. 4378 */ 4379 @UnsupportedAppUsage 4380 private final ConcurrentHashMap<String, FocusRequestInfo> mAudioFocusIdListenerMap = 4381 new ConcurrentHashMap<String, FocusRequestInfo>(); 4382 findFocusRequestInfo(String id)4383 private FocusRequestInfo findFocusRequestInfo(String id) { 4384 return mAudioFocusIdListenerMap.get(id); 4385 } 4386 4387 /** 4388 * Handler for events (audio focus change, recording config change) coming from the 4389 * audio service. 4390 */ 4391 private final ServiceEventHandlerDelegate mServiceEventHandlerDelegate = 4392 new ServiceEventHandlerDelegate(null); 4393 4394 /** 4395 * Event types 4396 */ 4397 private final static int MSSG_FOCUS_CHANGE = 0; 4398 private final static int MSSG_RECORDING_CONFIG_CHANGE = 1; 4399 private final static int MSSG_PLAYBACK_CONFIG_CHANGE = 2; 4400 4401 /** 4402 * Helper class to handle the forwarding of audio service events to the appropriate listener 4403 */ 4404 private class ServiceEventHandlerDelegate { 4405 private final Handler mHandler; 4406 ServiceEventHandlerDelegate(Handler handler)4407 ServiceEventHandlerDelegate(Handler handler) { 4408 Looper looper; 4409 if (handler == null) { 4410 if ((looper = Looper.myLooper()) == null) { 4411 looper = Looper.getMainLooper(); 4412 } 4413 } else { 4414 looper = handler.getLooper(); 4415 } 4416 4417 if (looper != null) { 4418 // implement the event handler delegate to receive events from audio service 4419 mHandler = new Handler(looper) { 4420 @Override 4421 public void handleMessage(Message msg) { 4422 switch (msg.what) { 4423 case MSSG_FOCUS_CHANGE: { 4424 final FocusRequestInfo fri = findFocusRequestInfo((String)msg.obj); 4425 if (fri != null) { 4426 final OnAudioFocusChangeListener listener = 4427 fri.mRequest.getOnAudioFocusChangeListener(); 4428 if (listener != null) { 4429 Slog.i(TAG, "dispatching onAudioFocusChange(" 4430 + msg.arg1 + ") to " + msg.obj); 4431 listener.onAudioFocusChange(msg.arg1); 4432 } 4433 } 4434 } break; 4435 case MSSG_RECORDING_CONFIG_CHANGE: { 4436 final RecordConfigChangeCallbackData cbData = 4437 (RecordConfigChangeCallbackData) msg.obj; 4438 if (cbData.mCb != null) { 4439 cbData.mCb.onRecordingConfigChanged(cbData.mConfigs); 4440 } 4441 } break; 4442 case MSSG_PLAYBACK_CONFIG_CHANGE: { 4443 final PlaybackConfigChangeCallbackData cbData = 4444 (PlaybackConfigChangeCallbackData) msg.obj; 4445 if (cbData.mCb != null) { 4446 if (DEBUG) { 4447 Log.d(TAG, "dispatching onPlaybackConfigChanged()"); 4448 } 4449 cbData.mCb.onPlaybackConfigChanged(cbData.mConfigs); 4450 } 4451 } break; 4452 default: 4453 Log.e(TAG, "Unknown event " + msg.what); 4454 } 4455 } 4456 }; 4457 } else { 4458 mHandler = null; 4459 } 4460 } 4461 getHandler()4462 Handler getHandler() { 4463 return mHandler; 4464 } 4465 } 4466 4467 private final IAudioFocusDispatcher mAudioFocusDispatcher = new IAudioFocusDispatcher.Stub() { 4468 @Override 4469 public void dispatchAudioFocusChange(int focusChange, String id) { 4470 final FocusRequestInfo fri = findFocusRequestInfo(id); 4471 if (fri != null) { 4472 final OnAudioFocusChangeListener listener = 4473 fri.mRequest.getOnAudioFocusChangeListener(); 4474 if (listener != null) { 4475 final Handler h = (fri.mHandler == null) ? 4476 mServiceEventHandlerDelegate.getHandler() : fri.mHandler; 4477 final Message m = h.obtainMessage( 4478 MSSG_FOCUS_CHANGE/*what*/, focusChange/*arg1*/, 0/*arg2 ignored*/, 4479 id/*obj*/); 4480 h.sendMessage(m); 4481 } 4482 } 4483 } 4484 4485 @Override 4486 public void dispatchFocusResultFromExtPolicy(int requestResult, String clientId) { 4487 synchronized (mFocusRequestsLock) { 4488 // TODO use generation counter as the key instead 4489 final BlockingFocusResultReceiver focusReceiver = 4490 mFocusRequestsAwaitingResult.remove(clientId); 4491 if (focusReceiver != null) { 4492 focusReceiver.notifyResult(requestResult); 4493 } else { 4494 Log.e(TAG, "dispatchFocusResultFromExtPolicy found no result receiver"); 4495 } 4496 } 4497 } 4498 }; 4499 getIdForAudioFocusListener(OnAudioFocusChangeListener l)4500 private String getIdForAudioFocusListener(OnAudioFocusChangeListener l) { 4501 if (l == null) { 4502 return new String(this.toString()); 4503 } else { 4504 return new String(this.toString() + l.toString()); 4505 } 4506 } 4507 4508 /** 4509 * @hide 4510 * Registers a listener to be called when audio focus changes and keeps track of the associated 4511 * focus request (including Handler to use for the listener). 4512 * @param afr the full request parameters 4513 */ registerAudioFocusRequest(@onNull AudioFocusRequest afr)4514 public void registerAudioFocusRequest(@NonNull AudioFocusRequest afr) { 4515 final Handler h = afr.getOnAudioFocusChangeListenerHandler(); 4516 final FocusRequestInfo fri = new FocusRequestInfo(afr, (h == null) ? null : 4517 new ServiceEventHandlerDelegate(h).getHandler()); 4518 final String key = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener()); 4519 mAudioFocusIdListenerMap.put(key, fri); 4520 } 4521 4522 /** 4523 * @hide 4524 * Causes the specified listener to not be called anymore when focus is gained or lost. 4525 * @param l the listener to unregister. 4526 */ unregisterAudioFocusRequest(OnAudioFocusChangeListener l)4527 public void unregisterAudioFocusRequest(OnAudioFocusChangeListener l) { 4528 // remove locally 4529 mAudioFocusIdListenerMap.remove(getIdForAudioFocusListener(l)); 4530 } 4531 4532 4533 /** 4534 * A failed focus change request. 4535 */ 4536 public static final int AUDIOFOCUS_REQUEST_FAILED = 0; 4537 /** 4538 * A successful focus change request. 4539 */ 4540 public static final int AUDIOFOCUS_REQUEST_GRANTED = 1; 4541 /** 4542 * A focus change request whose granting is delayed: the request was successful, but the 4543 * requester will only be granted audio focus once the condition that prevented immediate 4544 * granting has ended. 4545 * See {@link #requestAudioFocus(AudioFocusRequest)} and 4546 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} 4547 */ 4548 public static final int AUDIOFOCUS_REQUEST_DELAYED = 2; 4549 4550 /** @hide */ 4551 @IntDef(flag = false, prefix = "AUDIOFOCUS_REQUEST", value = { 4552 AUDIOFOCUS_REQUEST_FAILED, 4553 AUDIOFOCUS_REQUEST_GRANTED, 4554 AUDIOFOCUS_REQUEST_DELAYED } 4555 ) 4556 @Retention(RetentionPolicy.SOURCE) 4557 public @interface FocusRequestResult {} 4558 4559 /** 4560 * @hide 4561 * code returned when a synchronous focus request on the client-side is to be blocked 4562 * until the external audio focus policy decides on the response for the client 4563 */ 4564 public static final int AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY = 100; 4565 4566 /** 4567 * Timeout duration in ms when waiting on an external focus policy for the result for a 4568 * focus request 4569 */ 4570 private static final int EXT_FOCUS_POLICY_TIMEOUT_MS = 250; 4571 4572 private static final String FOCUS_CLIENT_ID_STRING = "android_audio_focus_client_id"; 4573 4574 private final Object mFocusRequestsLock = new Object(); 4575 /** 4576 * Map of all receivers of focus request results, one per unresolved focus request. 4577 * Receivers are added before sending the request to the external focus policy, 4578 * and are removed either after receiving the result, or after the timeout. 4579 * This variable is lazily initialized. 4580 */ 4581 @GuardedBy("mFocusRequestsLock") 4582 private HashMap<String, BlockingFocusResultReceiver> mFocusRequestsAwaitingResult; 4583 4584 4585 /** 4586 * Request audio focus. 4587 * Send a request to obtain the audio focus 4588 * @param l the listener to be notified of audio focus changes 4589 * @param streamType the main audio stream type affected by the focus request 4590 * @param durationHint use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request 4591 * is temporary, and focus will be abandonned shortly. Examples of transient requests are 4592 * for the playback of driving directions, or notifications sounds. 4593 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for 4594 * the previous focus owner to keep playing if it ducks its audio output. 4595 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request 4596 * that benefits from the system not playing disruptive sounds like notifications, for 4597 * usecases such as voice memo recording, or speech recognition. 4598 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such 4599 * as the playback of a song or a video. 4600 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 4601 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest)} 4602 */ requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint)4603 public int requestAudioFocus(OnAudioFocusChangeListener l, int streamType, int durationHint) { 4604 PlayerBase.deprecateStreamTypeForPlayback(streamType, 4605 "AudioManager", "requestAudioFocus()"); 4606 int status = AUDIOFOCUS_REQUEST_FAILED; 4607 4608 try { 4609 // status is guaranteed to be either AUDIOFOCUS_REQUEST_FAILED or 4610 // AUDIOFOCUS_REQUEST_GRANTED as focus is requested without the 4611 // AUDIOFOCUS_FLAG_DELAY_OK flag 4612 status = requestAudioFocus(l, 4613 new AudioAttributes.Builder() 4614 .setInternalLegacyStreamType(streamType).build(), 4615 durationHint, 4616 0 /* flags, legacy behavior */); 4617 } catch (IllegalArgumentException e) { 4618 Log.e(TAG, "Audio focus request denied due to ", e); 4619 } 4620 4621 return status; 4622 } 4623 4624 // when adding new flags, add them to the relevant AUDIOFOCUS_FLAGS_APPS or SYSTEM masks 4625 /** 4626 * @hide 4627 * Use this flag when requesting audio focus to indicate it is ok for the requester to not be 4628 * granted audio focus immediately (as indicated by {@link #AUDIOFOCUS_REQUEST_DELAYED}) when 4629 * the system is in a state where focus cannot change, but be granted focus later when 4630 * this condition ends. 4631 */ 4632 @SystemApi 4633 public static final int AUDIOFOCUS_FLAG_DELAY_OK = 0x1 << 0; 4634 /** 4635 * @hide 4636 * Use this flag when requesting audio focus to indicate that the requester 4637 * will pause its media playback (if applicable) when losing audio focus with 4638 * {@link #AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}, rather than ducking. 4639 * <br>On some platforms, the ducking may be handled without the application being aware of it 4640 * (i.e. it will not transiently lose focus). For applications that for instance play spoken 4641 * content, such as audio book or podcast players, ducking may never be acceptable, and will 4642 * thus always pause. This flag enables them to be declared as such whenever they request focus. 4643 */ 4644 @SystemApi 4645 public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 0x1 << 1; 4646 /** 4647 * @hide 4648 * Use this flag to lock audio focus so granting is temporarily disabled. 4649 * <br>This flag can only be used by owners of a registered 4650 * {@link android.media.audiopolicy.AudioPolicy} in 4651 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int, AudioPolicy)} 4652 */ 4653 @SystemApi 4654 public static final int AUDIOFOCUS_FLAG_LOCK = 0x1 << 2; 4655 4656 /** 4657 * @hide 4658 * flag set on test API calls, 4659 * see {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)}, 4660 */ 4661 public static final int AUDIOFOCUS_FLAG_TEST = 0x1 << 3; 4662 /** @hide */ 4663 public static final int AUDIOFOCUS_FLAGS_APPS = AUDIOFOCUS_FLAG_DELAY_OK 4664 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS; 4665 /** @hide */ 4666 public static final int AUDIOFOCUS_FLAGS_SYSTEM = AUDIOFOCUS_FLAG_DELAY_OK 4667 | AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS | AUDIOFOCUS_FLAG_LOCK; 4668 4669 /** 4670 * Request audio focus. 4671 * See the {@link AudioFocusRequest} for information about the options available to configure 4672 * your request, and notification of focus gain and loss. 4673 * @param focusRequest a {@link AudioFocusRequest} instance used to configure how focus is 4674 * requested. 4675 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED} 4676 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}. 4677 * <br>Note that the return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus 4678 * is requested without building the {@link AudioFocusRequest} with 4679 * {@link AudioFocusRequest.Builder#setAcceptsDelayedFocusGain(boolean)} set to 4680 * {@code true}. 4681 * @throws NullPointerException if passed a null argument 4682 */ requestAudioFocus(@onNull AudioFocusRequest focusRequest)4683 public int requestAudioFocus(@NonNull AudioFocusRequest focusRequest) { 4684 return requestAudioFocus(focusRequest, null /* no AudioPolicy*/); 4685 } 4686 4687 /** 4688 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus. 4689 * @param focusRequest the {@link AudioFocusRequest} that was used when requesting focus 4690 * with {@link #requestAudioFocus(AudioFocusRequest)}. 4691 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 4692 * @throws IllegalArgumentException if passed a null argument 4693 */ abandonAudioFocusRequest(@onNull AudioFocusRequest focusRequest)4694 public int abandonAudioFocusRequest(@NonNull AudioFocusRequest focusRequest) { 4695 if (focusRequest == null) { 4696 throw new IllegalArgumentException("Illegal null AudioFocusRequest"); 4697 } 4698 return abandonAudioFocus(focusRequest.getOnAudioFocusChangeListener(), 4699 focusRequest.getAudioAttributes()); 4700 } 4701 4702 /** 4703 * @hide 4704 * Request audio focus. 4705 * Send a request to obtain the audio focus. This method differs from 4706 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)} in that it can express 4707 * that the requester accepts delayed grants of audio focus. 4708 * @param l the listener to be notified of audio focus changes. It is not allowed to be null 4709 * when the request is flagged with {@link #AUDIOFOCUS_FLAG_DELAY_OK}. 4710 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for 4711 * requesting audio focus. 4712 * @param focusReqType use {@link #AUDIOFOCUS_GAIN_TRANSIENT} to indicate this focus request 4713 * is temporary, and focus will be abandoned shortly. Examples of transient requests are 4714 * for the playback of driving directions, or notifications sounds. 4715 * Use {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} to indicate also that it's ok for 4716 * the previous focus owner to keep playing if it ducks its audio output. 4717 * Alternatively use {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE} for a temporary request 4718 * that benefits from the system not playing disruptive sounds like notifications, for 4719 * usecases such as voice memo recording, or speech recognition. 4720 * Use {@link #AUDIOFOCUS_GAIN} for a focus request of unknown duration such 4721 * as the playback of a song or a video. 4722 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK}, 4723 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS} and {@link #AUDIOFOCUS_FLAG_LOCK}. 4724 * <br>Use 0 when not using any flags for the request, which behaves like 4725 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio 4726 * focus is granted immediately, or the grant request fails because the system is in a 4727 * state where focus cannot change (e.g. a phone call). 4728 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED} 4729 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}. 4730 * The return value is never {@link #AUDIOFOCUS_REQUEST_DELAYED} when focus is requested 4731 * without the {@link #AUDIOFOCUS_FLAG_DELAY_OK} flag. 4732 * @throws IllegalArgumentException 4733 */ 4734 @SystemApi 4735 @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) requestAudioFocus(OnAudioFocusChangeListener l, @NonNull AudioAttributes requestAttributes, int focusReqType, int flags)4736 public int requestAudioFocus(OnAudioFocusChangeListener l, 4737 @NonNull AudioAttributes requestAttributes, 4738 int focusReqType, 4739 int flags) throws IllegalArgumentException { 4740 if (flags != (flags & AUDIOFOCUS_FLAGS_APPS)) { 4741 throw new IllegalArgumentException("Invalid flags 0x" 4742 + Integer.toHexString(flags).toUpperCase()); 4743 } 4744 return requestAudioFocus(l, requestAttributes, focusReqType, 4745 flags & AUDIOFOCUS_FLAGS_APPS, 4746 null /* no AudioPolicy*/); 4747 } 4748 4749 /** 4750 * @hide 4751 * Request or lock audio focus. 4752 * This method is to be used by system components that have registered an 4753 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it 4754 * so focus granting is temporarily disabled. 4755 * @param l see the description of the same parameter in 4756 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)} 4757 * @param requestAttributes non null {@link AudioAttributes} describing the main reason for 4758 * requesting audio focus. 4759 * @param focusReqType see the description of the same parameter in 4760 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)} 4761 * @param flags 0 or a combination of {link #AUDIOFOCUS_FLAG_DELAY_OK}, 4762 * {@link #AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS}, and {@link #AUDIOFOCUS_FLAG_LOCK}. 4763 * <br>Use 0 when not using any flags for the request, which behaves like 4764 * {@link #requestAudioFocus(OnAudioFocusChangeListener, int, int)}, where either audio 4765 * focus is granted immediately, or the grant request fails because the system is in a 4766 * state where focus cannot change (e.g. a phone call). 4767 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking 4768 * focus, or null. 4769 * @return see the description of the same return value in 4770 * {@link #requestAudioFocus(OnAudioFocusChangeListener, AudioAttributes, int, int)} 4771 * @throws IllegalArgumentException 4772 * @deprecated use {@link #requestAudioFocus(AudioFocusRequest, AudioPolicy)} 4773 */ 4774 @SystemApi 4775 @RequiresPermission(anyOf= { 4776 Manifest.permission.MODIFY_PHONE_STATE, 4777 Manifest.permission.MODIFY_AUDIO_ROUTING 4778 }) requestAudioFocus(OnAudioFocusChangeListener l, @NonNull AudioAttributes requestAttributes, int focusReqType, int flags, AudioPolicy ap)4779 public int requestAudioFocus(OnAudioFocusChangeListener l, 4780 @NonNull AudioAttributes requestAttributes, 4781 int focusReqType, 4782 int flags, 4783 AudioPolicy ap) throws IllegalArgumentException { 4784 // parameter checking 4785 if (requestAttributes == null) { 4786 throw new IllegalArgumentException("Illegal null AudioAttributes argument"); 4787 } 4788 if (!AudioFocusRequest.isValidFocusGain(focusReqType)) { 4789 throw new IllegalArgumentException("Invalid duration hint"); 4790 } 4791 if (flags != (flags & AUDIOFOCUS_FLAGS_SYSTEM)) { 4792 throw new IllegalArgumentException("Illegal flags 0x" 4793 + Integer.toHexString(flags).toUpperCase()); 4794 } 4795 if (((flags & AUDIOFOCUS_FLAG_DELAY_OK) == AUDIOFOCUS_FLAG_DELAY_OK) && (l == null)) { 4796 throw new IllegalArgumentException( 4797 "Illegal null focus listener when flagged as accepting delayed focus grant"); 4798 } 4799 if (((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) 4800 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) && (l == null)) { 4801 throw new IllegalArgumentException( 4802 "Illegal null focus listener when flagged as pausing instead of ducking"); 4803 } 4804 if (((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) && (ap == null)) { 4805 throw new IllegalArgumentException( 4806 "Illegal null audio policy when locking audio focus"); 4807 } 4808 4809 final AudioFocusRequest afr = new AudioFocusRequest.Builder(focusReqType) 4810 .setOnAudioFocusChangeListenerInt(l, null /* no Handler for this legacy API */) 4811 .setAudioAttributes(requestAttributes) 4812 .setAcceptsDelayedFocusGain((flags & AUDIOFOCUS_FLAG_DELAY_OK) 4813 == AUDIOFOCUS_FLAG_DELAY_OK) 4814 .setWillPauseWhenDucked((flags & AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) 4815 == AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS) 4816 .setLocksFocus((flags & AUDIOFOCUS_FLAG_LOCK) == AUDIOFOCUS_FLAG_LOCK) 4817 .build(); 4818 return requestAudioFocus(afr, ap); 4819 } 4820 4821 /** 4822 * @hide 4823 * Test API to request audio focus for an arbitrary client operating from a (fake) given UID. 4824 * Used to simulate conditions of the test, not the behavior of the focus requester under test. 4825 * @param afr the parameters of the request 4826 * @param clientFakeId the identifier of the AudioManager the client would be requesting from 4827 * @param clientFakeUid the UID of the client, here an arbitrary int, 4828 * doesn't have to be a real UID 4829 * @param clientTargetSdk the target SDK used by the client 4830 * @return return code indicating status of the request 4831 */ 4832 @TestApi 4833 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") requestAudioFocusForTest(@onNull AudioFocusRequest afr, @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk)4834 public @FocusRequestResult int requestAudioFocusForTest(@NonNull AudioFocusRequest afr, 4835 @NonNull String clientFakeId, int clientFakeUid, int clientTargetSdk) { 4836 Objects.requireNonNull(afr); 4837 Objects.requireNonNull(clientFakeId); 4838 int status; 4839 BlockingFocusResultReceiver focusReceiver; 4840 synchronized (mFocusRequestsLock) { 4841 try { 4842 status = getService().requestAudioFocusForTest(afr.getAudioAttributes(), 4843 afr.getFocusGain(), 4844 mICallBack, 4845 mAudioFocusDispatcher, 4846 clientFakeId, "com.android.test.fakeclient", 4847 afr.getFlags() | AudioManager.AUDIOFOCUS_FLAG_TEST, 4848 clientFakeUid, clientTargetSdk); 4849 } catch (RemoteException e) { 4850 throw e.rethrowFromSystemServer(); 4851 } 4852 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) { 4853 // default path with no external focus policy 4854 return status; 4855 } 4856 4857 focusReceiver = addClientIdToFocusReceiverLocked(clientFakeId); 4858 } 4859 4860 return handleExternalAudioPolicyWaitIfNeeded(clientFakeId, focusReceiver, afr); 4861 } 4862 4863 /** 4864 * @hide 4865 * Test API to abandon audio focus for an arbitrary client. 4866 * Used to simulate conditions of the test, not the behavior of the focus requester under test. 4867 * @param afr the parameters used for the request 4868 * @param clientFakeId clientFakeId the identifier of the AudioManager from which the client 4869 * would be requesting 4870 * @return return code indicating status of the request 4871 */ 4872 @TestApi 4873 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") abandonAudioFocusForTest(@onNull AudioFocusRequest afr, @NonNull String clientFakeId)4874 public @FocusRequestResult int abandonAudioFocusForTest(@NonNull AudioFocusRequest afr, 4875 @NonNull String clientFakeId) { 4876 Objects.requireNonNull(afr); 4877 Objects.requireNonNull(clientFakeId); 4878 try { 4879 return getService().abandonAudioFocusForTest(mAudioFocusDispatcher, 4880 clientFakeId, afr.getAudioAttributes(), "com.android.test.fakeclient"); 4881 } catch (RemoteException e) { 4882 throw e.rethrowFromSystemServer(); 4883 } 4884 } 4885 4886 /** 4887 * @hide 4888 * Return the duration of the fade out applied when a player of the given AudioAttributes 4889 * is losing audio focus 4890 * @param aa the AudioAttributes of the player losing focus with {@link #AUDIOFOCUS_LOSS} 4891 * @return a duration in ms, 0 indicates no fade out is applied 4892 */ 4893 @TestApi 4894 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") getFadeOutDurationOnFocusLossMillis(@onNull AudioAttributes aa)4895 public @IntRange(from = 0) long getFadeOutDurationOnFocusLossMillis(@NonNull AudioAttributes aa) 4896 { 4897 Objects.requireNonNull(aa); 4898 try { 4899 return getService().getFadeOutDurationOnFocusLossMillis(aa); 4900 } catch (RemoteException e) { 4901 throw e.rethrowFromSystemServer(); 4902 } 4903 } 4904 4905 /** 4906 * @hide 4907 * Test method to return the list of UIDs currently marked as ducked because of their 4908 * audio focus status 4909 * @return the list of UIDs, can be empty when no app is being ducked. 4910 */ 4911 @TestApi 4912 @FlaggedApi(FLAG_FOCUS_FREEZE_TEST_API) 4913 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") getFocusDuckedUidsForTest()4914 public @NonNull List<Integer> getFocusDuckedUidsForTest() { 4915 try { 4916 return getService().getFocusDuckedUidsForTest(); 4917 } catch (RemoteException e) { 4918 throw e.rethrowFromSystemServer(); 4919 } 4920 } 4921 4922 /** 4923 * @hide 4924 * Test method to return the duration of the fade out applied on the players of a focus loser 4925 * @return the fade out duration in ms 4926 */ 4927 @TestApi 4928 @FlaggedApi(FLAG_FOCUS_FREEZE_TEST_API) 4929 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") getFocusFadeOutDurationForTest()4930 public long getFocusFadeOutDurationForTest() { 4931 try { 4932 return getService().getFocusFadeOutDurationForTest(); 4933 } catch (RemoteException e) { 4934 throw e.rethrowFromSystemServer(); 4935 } 4936 } 4937 4938 /** 4939 * @hide 4940 * Test method to return the length of time after a fade-out before the focus loser is unmuted 4941 * (and is faded back in). 4942 * @return the time gap after a fade-out completion on focus loss, and fade-in start in ms. 4943 */ 4944 @TestApi 4945 @FlaggedApi(FLAG_FOCUS_FREEZE_TEST_API) 4946 @RequiresPermission("android.permission.QUERY_AUDIO_STATE") getFocusUnmuteDelayAfterFadeOutForTest()4947 public long getFocusUnmuteDelayAfterFadeOutForTest() { 4948 try { 4949 return getService().getFocusUnmuteDelayAfterFadeOutForTest(); 4950 } catch (RemoteException e) { 4951 throw e.rethrowFromSystemServer(); 4952 } 4953 } 4954 4955 /** 4956 * @hide 4957 * Test method to start preventing applications from requesting audio focus during a test, 4958 * which could interfere with the functionality/behavior under test. 4959 * Calling this method needs to be paired with a call to {@link #exitAudioFocusFreezeForTest} 4960 * when the testing is done. If this is not the case (e.g. in case of a test crash), 4961 * a death observer mechanism will ensure the system is not left in a bad state, but this should 4962 * not be relied on when implementing tests. 4963 * @param exemptedUids a list of UIDs that are exempt from the freeze. This would for instance 4964 * be those of the test runner and other players used in the test, or the "fake" UIDs used 4965 * for testing with {@link #requestAudioFocusForTest(AudioFocusRequest, String, int, int)}. 4966 * @return true if the focus freeze mode is successfully entered, false if there was an issue, 4967 * such as another freeze in place at the time of invocation. 4968 * A false result should result in a test failure as this would indicate the system is not 4969 * in a proper state with a predictable behavior for audio focus management. 4970 */ 4971 @TestApi 4972 @FlaggedApi(FLAG_FOCUS_FREEZE_TEST_API) 4973 @RequiresPermission("Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED") enterAudioFocusFreezeForTest(@onNull List<Integer> exemptedUids)4974 public boolean enterAudioFocusFreezeForTest(@NonNull List<Integer> exemptedUids) { 4975 Objects.requireNonNull(exemptedUids); 4976 try { 4977 final int[] uids = exemptedUids.stream().mapToInt(Integer::intValue).toArray(); 4978 return getService().enterAudioFocusFreezeForTest(mICallBack, uids); 4979 } catch (RemoteException e) { 4980 throw e.rethrowFromSystemServer(); 4981 } 4982 } 4983 4984 /** 4985 * @hide 4986 * Test method to end preventing applications from requesting audio focus during a test. 4987 * @return true if the focus freeze mode is successfully exited, false if there was an issue, 4988 * such as the freeze already having ended, or not started. 4989 */ 4990 @TestApi 4991 @FlaggedApi(FLAG_FOCUS_FREEZE_TEST_API) 4992 @RequiresPermission("Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED") exitAudioFocusFreezeForTest()4993 public boolean exitAudioFocusFreezeForTest() { 4994 try { 4995 return getService().exitAudioFocusFreezeForTest(mICallBack); 4996 } catch (RemoteException e) { 4997 throw e.rethrowFromSystemServer(); 4998 } 4999 } 5000 5001 /** 5002 * @hide 5003 * Request or lock audio focus. 5004 * This method is to be used by system components that have registered an 5005 * {@link android.media.audiopolicy.AudioPolicy} to request audio focus, but also to "lock" it 5006 * so focus granting is temporarily disabled. 5007 * @param afr see the description of the same parameter in 5008 * {@link #requestAudioFocus(AudioFocusRequest)} 5009 * @param ap a registered {@link android.media.audiopolicy.AudioPolicy} instance when locking 5010 * focus, or null. 5011 * @return {@link #AUDIOFOCUS_REQUEST_FAILED}, {@link #AUDIOFOCUS_REQUEST_GRANTED} 5012 * or {@link #AUDIOFOCUS_REQUEST_DELAYED}. 5013 * @throws NullPointerException if the AudioFocusRequest is null 5014 * @throws IllegalArgumentException when trying to lock focus without an AudioPolicy 5015 */ 5016 @SystemApi 5017 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) requestAudioFocus(@onNull AudioFocusRequest afr, @Nullable AudioPolicy ap)5018 public int requestAudioFocus(@NonNull AudioFocusRequest afr, @Nullable AudioPolicy ap) { 5019 if (afr == null) { 5020 throw new NullPointerException("Illegal null AudioFocusRequest"); 5021 } 5022 // this can only be checked now, not during the creation of the AudioFocusRequest instance 5023 if (afr.locksFocus() && ap == null) { 5024 throw new IllegalArgumentException( 5025 "Illegal null audio policy when locking audio focus"); 5026 } 5027 5028 if (hasCustomPolicyVirtualDeviceContext()) { 5029 // If the focus request was made within context associated with VirtualDevice 5030 // configured with custom device policy for audio, bypass audio service focus handling. 5031 // The custom device policy for audio means that audio associated with this device 5032 // is likely rerouted to VirtualAudioDevice and playback on the VirtualAudioDevice 5033 // shouldn't affect non-virtual audio tracks (and vice versa). 5034 return AUDIOFOCUS_REQUEST_GRANTED; 5035 } 5036 5037 registerAudioFocusRequest(afr); 5038 final IAudioService service = getService(); 5039 final int status; 5040 int sdk; 5041 try { 5042 sdk = getContext().getApplicationInfo().targetSdkVersion; 5043 } catch (NullPointerException e) { 5044 // some tests don't have a Context 5045 sdk = Build.VERSION.SDK_INT; 5046 } 5047 5048 final String clientId = getIdForAudioFocusListener(afr.getOnAudioFocusChangeListener()); 5049 BlockingFocusResultReceiver focusReceiver; 5050 synchronized (mFocusRequestsLock) { 5051 5052 try { 5053 // TODO status contains result and generation counter for ext policy 5054 status = service.requestAudioFocus(afr.getAudioAttributes(), 5055 afr.getFocusGain(), mICallBack, 5056 mAudioFocusDispatcher, 5057 clientId, 5058 getContext().getOpPackageName() /* package name */, 5059 getContext().getAttributionTag(), 5060 afr.getFlags(), 5061 ap != null ? ap.cb() : null, 5062 sdk); 5063 } catch (RemoteException e) { 5064 throw e.rethrowFromSystemServer(); 5065 } 5066 if (status != AudioManager.AUDIOFOCUS_REQUEST_WAITING_FOR_EXT_POLICY) { 5067 // default path with no external focus policy 5068 return status; 5069 } 5070 focusReceiver = addClientIdToFocusReceiverLocked(clientId); 5071 } 5072 5073 return handleExternalAudioPolicyWaitIfNeeded(clientId, focusReceiver, afr); 5074 } 5075 5076 @GuardedBy("mFocusRequestsLock") addClientIdToFocusReceiverLocked(String clientId)5077 private BlockingFocusResultReceiver addClientIdToFocusReceiverLocked(String clientId) { 5078 BlockingFocusResultReceiver focusReceiver; 5079 if (mFocusRequestsAwaitingResult == null) { 5080 mFocusRequestsAwaitingResult = 5081 new HashMap<String, BlockingFocusResultReceiver>(1); 5082 } 5083 focusReceiver = new BlockingFocusResultReceiver(clientId); 5084 mFocusRequestsAwaitingResult.put(clientId, focusReceiver); 5085 return focusReceiver; 5086 } 5087 handleExternalAudioPolicyWaitIfNeeded(String clientId, BlockingFocusResultReceiver focusReceiver, @NonNull AudioFocusRequest afr)5088 private @FocusRequestResult int handleExternalAudioPolicyWaitIfNeeded(String clientId, 5089 BlockingFocusResultReceiver focusReceiver, @NonNull AudioFocusRequest afr) { 5090 focusReceiver.waitForResult(EXT_FOCUS_POLICY_TIMEOUT_MS); 5091 if (!focusReceiver.receivedResult()) { 5092 if (DEBUG) { 5093 Log.e(TAG, "handleExternalAudioPolicyWaitIfNeeded" 5094 + " response from ext policy timed out, denying request"); 5095 } 5096 try { 5097 // To prevent from orphan focus holder, cleanup 5098 abandonAudioFocus(afr.getOnAudioFocusChangeListener()); 5099 } catch (Exception e) { 5100 Log.e(TAG, "handleExternalAudioPolicyWaitIfNeeded failed to abandon audio" 5101 +" focus after time out, error: " + e.getMessage()); 5102 } 5103 } 5104 5105 synchronized (mFocusRequestsLock) { 5106 mFocusRequestsAwaitingResult.remove(clientId); 5107 } 5108 return focusReceiver.requestResult(); 5109 } 5110 5111 // helper class that abstracts out the handling of spurious wakeups in Object.wait() 5112 private static final class SafeWaitObject { 5113 private boolean mQuit = false; 5114 safeNotify()5115 public void safeNotify() { 5116 synchronized (this) { 5117 mQuit = true; 5118 this.notify(); 5119 } 5120 } 5121 safeWait(long millis)5122 public void safeWait(long millis) throws InterruptedException { 5123 final long timeOutTime = java.lang.System.currentTimeMillis() + millis; 5124 synchronized (this) { 5125 while (!mQuit) { 5126 final long timeToWait = timeOutTime - java.lang.System.currentTimeMillis(); 5127 if (timeToWait <= 0) { 5128 break; 5129 } 5130 this.wait(timeToWait); 5131 } 5132 } 5133 } 5134 } 5135 5136 private static final class BlockingFocusResultReceiver { 5137 private final SafeWaitObject mLock = new SafeWaitObject(); 5138 @GuardedBy("mLock") 5139 private boolean mResultReceived = false; 5140 // request denied by default (e.g. timeout) 5141 private int mFocusRequestResult = AudioManager.AUDIOFOCUS_REQUEST_FAILED; 5142 private final String mFocusClientId; 5143 BlockingFocusResultReceiver(String clientId)5144 BlockingFocusResultReceiver(String clientId) { 5145 mFocusClientId = clientId; 5146 } 5147 receivedResult()5148 boolean receivedResult() { return mResultReceived; } requestResult()5149 int requestResult() { return mFocusRequestResult; } 5150 notifyResult(int requestResult)5151 void notifyResult(int requestResult) { 5152 synchronized (mLock) { 5153 mResultReceived = true; 5154 mFocusRequestResult = requestResult; 5155 mLock.safeNotify(); 5156 } 5157 } 5158 waitForResult(long timeOutMs)5159 public void waitForResult(long timeOutMs) { 5160 synchronized (mLock) { 5161 if (mResultReceived) { 5162 // the result was received before waiting 5163 return; 5164 } 5165 try { 5166 mLock.safeWait(timeOutMs); 5167 } catch (InterruptedException e) { } 5168 } 5169 } 5170 } 5171 5172 /** 5173 * @hide 5174 * Used internally by telephony package to request audio focus. Will cause the focus request 5175 * to be associated with the "voice communication" identifier only used in AudioService 5176 * to identify this use case. 5177 * @param streamType use STREAM_RING for focus requests when ringing, VOICE_CALL for 5178 * the establishment of the call 5179 * @param focusReqType the type of focus request. AUDIOFOCUS_GAIN_TRANSIENT is recommended so 5180 * media applications resume after a call 5181 */ 5182 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) requestAudioFocusForCall(int streamType, int focusReqType)5183 public void requestAudioFocusForCall(int streamType, int focusReqType) { 5184 final IAudioService service = getService(); 5185 try { 5186 service.requestAudioFocus(new AudioAttributes.Builder() 5187 .setInternalLegacyStreamType(streamType).build(), 5188 focusReqType, mICallBack, null, 5189 AudioSystem.IN_VOICE_COMM_FOCUS_ID, 5190 getContext().getOpPackageName(), 5191 getContext().getAttributionTag(), 5192 AUDIOFOCUS_FLAG_LOCK, 5193 null /* policy token */, 0 /* sdk n/a here*/); 5194 } catch (RemoteException e) { 5195 throw e.rethrowFromSystemServer(); 5196 } 5197 } 5198 5199 /** 5200 * @hide 5201 * Return the volume ramping time for a sound to be played after the given focus request, 5202 * and to play a sound of the given attributes 5203 * @param focusGain 5204 * @param attr 5205 * @return 5206 */ getFocusRampTimeMs(int focusGain, AudioAttributes attr)5207 public int getFocusRampTimeMs(int focusGain, AudioAttributes attr) { 5208 final IAudioService service = getService(); 5209 try { 5210 return service.getFocusRampTimeMs(focusGain, attr); 5211 } catch (RemoteException e) { 5212 throw e.rethrowFromSystemServer(); 5213 } 5214 } 5215 5216 /** 5217 * @hide 5218 * Set the result to the audio focus request received through 5219 * {@link AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}. 5220 * @param afi the information about the focus requester 5221 * @param requestResult the result to the focus request to be passed to the requester 5222 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy. 5223 */ 5224 @SystemApi 5225 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setFocusRequestResult(@onNull AudioFocusInfo afi, @FocusRequestResult int requestResult, @NonNull AudioPolicy ap)5226 public void setFocusRequestResult(@NonNull AudioFocusInfo afi, 5227 @FocusRequestResult int requestResult, @NonNull AudioPolicy ap) { 5228 if (afi == null) { 5229 throw new IllegalArgumentException("Illegal null AudioFocusInfo"); 5230 } 5231 if (ap == null) { 5232 throw new IllegalArgumentException("Illegal null AudioPolicy"); 5233 } 5234 final IAudioService service = getService(); 5235 try { 5236 service.setFocusRequestResultFromExtPolicy(afi, requestResult, ap.cb()); 5237 } catch (RemoteException e) { 5238 throw e.rethrowFromSystemServer(); 5239 } 5240 } 5241 5242 /** 5243 * @hide 5244 * Notifies an application with a focus listener of gain or loss of audio focus. 5245 * This method can only be used by owners of an {@link AudioPolicy} configured with 5246 * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true. 5247 * @param afi the recipient of the focus change, that has previously requested audio focus, and 5248 * that was received by the {@code AudioPolicy} through 5249 * {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)}. 5250 * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN}, 5251 * {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or 5252 * {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}) 5253 * or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS}, 5254 * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}, 5255 * or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}). 5256 * <br>For the focus gain, the change type should be the same as the app requested. 5257 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy. 5258 * @return {@link #AUDIOFOCUS_REQUEST_GRANTED} if the dispatch was successfully sent, or 5259 * {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener, or 5260 * if there was an error sending the request. 5261 * @throws NullPointerException if the {@link AudioFocusInfo} or {@link AudioPolicy} are null. 5262 */ 5263 @SystemApi 5264 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) dispatchAudioFocusChange(@onNull AudioFocusInfo afi, int focusChange, @NonNull AudioPolicy ap)5265 public int dispatchAudioFocusChange(@NonNull AudioFocusInfo afi, int focusChange, 5266 @NonNull AudioPolicy ap) { 5267 if (afi == null) { 5268 throw new NullPointerException("Illegal null AudioFocusInfo"); 5269 } 5270 if (ap == null) { 5271 throw new NullPointerException("Illegal null AudioPolicy"); 5272 } 5273 final IAudioService service = getService(); 5274 try { 5275 return service.dispatchFocusChange(afi, focusChange, ap.cb()); 5276 } catch (RemoteException e) { 5277 throw e.rethrowFromSystemServer(); 5278 } 5279 } 5280 5281 /** 5282 * Notifies an application with a focus listener of gain or loss of audio focus 5283 * 5284 * <p>This is similar to {@link #dispatchAudioFocusChange(AudioFocusInfo, int, AudioPolicy)} but 5285 * with additional functionality of fade. The players of the application with audio focus 5286 * change, provided they meet the active {@link FadeManagerConfiguration} requirements, are 5287 * faded before dispatching the callback to the application. For example, players of the 5288 * application losing audio focus will be faded out, whereas players of the application gaining 5289 * audio focus will be faded in, if needed. 5290 * 5291 * <p>The applicability of fade is decided against the supplied active {@link AudioFocusInfo}. 5292 * This list cannot be {@code null}. The list can be empty if no other active 5293 * {@link AudioFocusInfo} available at the time of the dispatch. 5294 * 5295 * <p>The {@link FadeManagerConfiguration} supplied here is prioritized over existing fade 5296 * configurations. If none supplied, either the {@link FadeManagerConfiguration} set through 5297 * {@link AudioPolicy} or the default will be used to determine the fade properties. 5298 * 5299 * <p>This method can only be used by owners of an {@link AudioPolicy} configured with 5300 * {@link AudioPolicy.Builder#setIsAudioFocusPolicy(boolean)} set to true. 5301 * 5302 * @param afi the recipient of the focus change, that has previously requested audio focus, and 5303 * that was received by the {@code AudioPolicy} through 5304 * {@link AudioPolicy.AudioPolicyFocusListener#onAudioFocusRequest(AudioFocusInfo, int)} 5305 * @param focusChange one of focus gain types ({@link #AUDIOFOCUS_GAIN}, 5306 * {@link #AUDIOFOCUS_GAIN_TRANSIENT}, {@link #AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK} or 5307 * {@link #AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE}) 5308 * or one of the focus loss types ({@link AudioManager#AUDIOFOCUS_LOSS}, 5309 * {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT}, 5310 * or {@link AudioManager#AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK}). 5311 * <br>For the focus gain, the change type should be the same as the app requested 5312 * @param ap a valid registered {@link AudioPolicy} configured as a focus policy. 5313 * @param otherActiveAfis active {@link AudioFocusInfo} that are granted audio focus at the time 5314 * of dispatch 5315 * @param transientFadeMgrConfig {@link FadeManagerConfiguration} that will be used for fading 5316 * players resulting from this dispatch. This is a transient configuration that is only 5317 * valid for this focus change and shall be discarded after processing this request. 5318 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} if the focus client didn't have a listener or if 5319 * there was an error sending the request, or {@link #AUDIOFOCUS_REQUEST_GRANTED} if the 5320 * dispatch was successfully sent, or {@link #AUDIOFOCUS_REQUEST_DELAYED} if 5321 * the request was successful but the dispatch of focus change was delayed due to a fade 5322 * operation. 5323 * @hide 5324 */ 5325 @FlaggedApi(FLAG_ENABLE_FADE_MANAGER_CONFIGURATION) 5326 @SystemApi 5327 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) 5328 @FocusRequestResult dispatchAudioFocusChangeWithFade(@onNull AudioFocusInfo afi, int focusChange, @NonNull AudioPolicy ap, @NonNull List<AudioFocusInfo> otherActiveAfis, @Nullable FadeManagerConfiguration transientFadeMgrConfig)5329 public int dispatchAudioFocusChangeWithFade(@NonNull AudioFocusInfo afi, int focusChange, 5330 @NonNull AudioPolicy ap, @NonNull List<AudioFocusInfo> otherActiveAfis, 5331 @Nullable FadeManagerConfiguration transientFadeMgrConfig) { 5332 Objects.requireNonNull(afi, "AudioFocusInfo cannot be null"); 5333 Objects.requireNonNull(ap, "AudioPolicy cannot be null"); 5334 Objects.requireNonNull(otherActiveAfis, "Other active AudioFocusInfo list cannot be null"); 5335 5336 IAudioService service = getService(); 5337 try { 5338 return service.dispatchFocusChangeWithFade(afi, focusChange, ap.cb(), otherActiveAfis, 5339 transientFadeMgrConfig); 5340 } catch (RemoteException e) { 5341 throw e.rethrowFromSystemServer(); 5342 } 5343 } 5344 5345 /** 5346 * @hide 5347 * Used internally by telephony package to abandon audio focus, typically after a call or 5348 * when ringing ends and the call is rejected or not answered. 5349 * Should match one or more calls to {@link #requestAudioFocusForCall(int, int)}. 5350 */ 5351 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) abandonAudioFocusForCall()5352 public void abandonAudioFocusForCall() { 5353 final IAudioService service = getService(); 5354 try { 5355 service.abandonAudioFocus(null, AudioSystem.IN_VOICE_COMM_FOCUS_ID, 5356 null /*AudioAttributes, legacy behavior*/, getContext().getOpPackageName()); 5357 } catch (RemoteException e) { 5358 throw e.rethrowFromSystemServer(); 5359 } 5360 } 5361 5362 /** 5363 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus. 5364 * @param l the listener with which focus was requested. 5365 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 5366 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)} 5367 */ abandonAudioFocus(OnAudioFocusChangeListener l)5368 public int abandonAudioFocus(OnAudioFocusChangeListener l) { 5369 return abandonAudioFocus(l, null /*AudioAttributes, legacy behavior*/); 5370 } 5371 5372 /** 5373 * @hide 5374 * Abandon audio focus. Causes the previous focus owner, if any, to receive focus. 5375 * @param l the listener with which focus was requested. 5376 * @param aa the {@link AudioAttributes} with which audio focus was requested 5377 * @return {@link #AUDIOFOCUS_REQUEST_FAILED} or {@link #AUDIOFOCUS_REQUEST_GRANTED} 5378 * @deprecated use {@link #abandonAudioFocusRequest(AudioFocusRequest)} 5379 */ 5380 @SystemApi 5381 @SuppressLint("RequiresPermission") // no permission enforcement, but only "undoes" what would 5382 // have been done by a matching requestAudioFocus abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa)5383 public int abandonAudioFocus(OnAudioFocusChangeListener l, AudioAttributes aa) { 5384 if (hasCustomPolicyVirtualDeviceContext()) { 5385 // If this AudioManager instance is running within VirtualDevice context configured 5386 // with custom device policy for audio, the audio focus handling is bypassed. 5387 return AUDIOFOCUS_REQUEST_GRANTED; 5388 } 5389 unregisterAudioFocusRequest(l); 5390 final IAudioService service = getService(); 5391 try { 5392 return service.abandonAudioFocus(mAudioFocusDispatcher, 5393 getIdForAudioFocusListener(l), aa, getContext().getOpPackageName()); 5394 } catch (RemoteException e) { 5395 throw e.rethrowFromSystemServer(); 5396 } 5397 } 5398 5399 //==================================================================== 5400 // Remote Control 5401 /** 5402 * Register a component to be the sole receiver of MEDIA_BUTTON intents. 5403 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver} 5404 * that will receive the media button intent. This broadcast receiver must be declared 5405 * in the application manifest. The package of the component must match that of 5406 * the context you're registering from. 5407 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead. 5408 */ 5409 @Deprecated registerMediaButtonEventReceiver(ComponentName eventReceiver)5410 public void registerMediaButtonEventReceiver(ComponentName eventReceiver) { 5411 if (eventReceiver == null) { 5412 return; 5413 } 5414 if (!eventReceiver.getPackageName().equals(getContext().getPackageName())) { 5415 Log.e(TAG, "registerMediaButtonEventReceiver() error: " + 5416 "receiver and context package names don't match"); 5417 return; 5418 } 5419 // construct a PendingIntent for the media button and register it 5420 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 5421 // the associated intent will be handled by the component being registered 5422 mediaButtonIntent.setComponent(eventReceiver); 5423 PendingIntent pi = PendingIntent.getBroadcast(getContext(), 5424 0/*requestCode, ignored*/, mediaButtonIntent, 5425 PendingIntent.FLAG_IMMUTABLE); 5426 registerMediaButtonIntent(pi, eventReceiver); 5427 } 5428 5429 /** 5430 * Register a component to be the sole receiver of MEDIA_BUTTON intents. This is like 5431 * {@link #registerMediaButtonEventReceiver(android.content.ComponentName)}, but allows 5432 * the buttons to go to any PendingIntent. Note that you should only use this form if 5433 * you know you will continue running for the full time until unregistering the 5434 * PendingIntent. 5435 * @param eventReceiver target that will receive media button intents. The PendingIntent 5436 * will be sent an {@link Intent#ACTION_MEDIA_BUTTON} event when a media button action 5437 * occurs, with {@link Intent#EXTRA_KEY_EVENT} added and holding the key code of the 5438 * media button that was pressed. 5439 * @deprecated Use {@link MediaSession#setMediaButtonReceiver(PendingIntent)} instead. 5440 */ 5441 @Deprecated registerMediaButtonEventReceiver(PendingIntent eventReceiver)5442 public void registerMediaButtonEventReceiver(PendingIntent eventReceiver) { 5443 if (eventReceiver == null) { 5444 return; 5445 } 5446 registerMediaButtonIntent(eventReceiver, null); 5447 } 5448 5449 /** 5450 * @hide 5451 * no-op if (pi == null) or (eventReceiver == null) 5452 */ registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver)5453 public void registerMediaButtonIntent(PendingIntent pi, ComponentName eventReceiver) { 5454 if (pi == null) { 5455 Log.e(TAG, "Cannot call registerMediaButtonIntent() with a null parameter"); 5456 return; 5457 } 5458 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 5459 helper.addMediaButtonListener(pi, eventReceiver, getContext()); 5460 } 5461 5462 /** 5463 * Unregister the receiver of MEDIA_BUTTON intents. 5464 * @param eventReceiver identifier of a {@link android.content.BroadcastReceiver} 5465 * that was registered with {@link #registerMediaButtonEventReceiver(ComponentName)}. 5466 * @deprecated Use {@link MediaSession} instead. 5467 */ 5468 @Deprecated unregisterMediaButtonEventReceiver(ComponentName eventReceiver)5469 public void unregisterMediaButtonEventReceiver(ComponentName eventReceiver) { 5470 if (eventReceiver == null) { 5471 return; 5472 } 5473 // construct a PendingIntent for the media button and unregister it 5474 Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 5475 // the associated intent will be handled by the component being registered 5476 mediaButtonIntent.setComponent(eventReceiver); 5477 PendingIntent pi = PendingIntent.getBroadcast(getContext(), 5478 0/*requestCode, ignored*/, mediaButtonIntent, 5479 PendingIntent.FLAG_IMMUTABLE); 5480 unregisterMediaButtonIntent(pi); 5481 } 5482 5483 /** 5484 * Unregister the receiver of MEDIA_BUTTON intents. 5485 * @param eventReceiver same PendingIntent that was registed with 5486 * {@link #registerMediaButtonEventReceiver(PendingIntent)}. 5487 * @deprecated Use {@link MediaSession} instead. 5488 */ 5489 @Deprecated unregisterMediaButtonEventReceiver(PendingIntent eventReceiver)5490 public void unregisterMediaButtonEventReceiver(PendingIntent eventReceiver) { 5491 if (eventReceiver == null) { 5492 return; 5493 } 5494 unregisterMediaButtonIntent(eventReceiver); 5495 } 5496 5497 /** 5498 * @hide 5499 */ unregisterMediaButtonIntent(PendingIntent pi)5500 public void unregisterMediaButtonIntent(PendingIntent pi) { 5501 MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(getContext()); 5502 helper.removeMediaButtonListener(pi); 5503 } 5504 5505 /** 5506 * Registers the remote control client for providing information to display on the remote 5507 * controls. 5508 * @param rcClient The remote control client from which remote controls will receive 5509 * information to display. 5510 * @see RemoteControlClient 5511 * @deprecated Use {@link MediaSession} instead. 5512 */ 5513 @Deprecated registerRemoteControlClient(RemoteControlClient rcClient)5514 public void registerRemoteControlClient(RemoteControlClient rcClient) { 5515 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) { 5516 return; 5517 } 5518 rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(getContext())); 5519 } 5520 5521 /** 5522 * Unregisters the remote control client that was providing information to display on the 5523 * remote controls. 5524 * @param rcClient The remote control client to unregister. 5525 * @see #registerRemoteControlClient(RemoteControlClient) 5526 * @deprecated Use {@link MediaSession} instead. 5527 */ 5528 @Deprecated unregisterRemoteControlClient(RemoteControlClient rcClient)5529 public void unregisterRemoteControlClient(RemoteControlClient rcClient) { 5530 if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) { 5531 return; 5532 } 5533 rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(getContext())); 5534 } 5535 5536 /** 5537 * Registers a {@link RemoteController} instance for it to receive media 5538 * metadata updates and playback state information from applications using 5539 * {@link RemoteControlClient}, and control their playback. 5540 * <p> 5541 * Registration requires the {@link RemoteController.OnClientUpdateListener} listener to be 5542 * one of the enabled notification listeners (see 5543 * {@link android.service.notification.NotificationListenerService}). 5544 * 5545 * @param rctlr the object to register. 5546 * @return true if the {@link RemoteController} was successfully registered, 5547 * false if an error occurred, due to an internal system error, or 5548 * insufficient permissions. 5549 * @deprecated Use 5550 * {@link MediaSessionManager#addOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener, ComponentName)} 5551 * and {@link MediaController} instead. 5552 */ 5553 @Deprecated registerRemoteController(RemoteController rctlr)5554 public boolean registerRemoteController(RemoteController rctlr) { 5555 if (rctlr == null) { 5556 return false; 5557 } 5558 rctlr.startListeningToSessions(); 5559 return true; 5560 } 5561 5562 /** 5563 * Unregisters a {@link RemoteController}, causing it to no longer receive 5564 * media metadata and playback state information, and no longer be capable 5565 * of controlling playback. 5566 * 5567 * @param rctlr the object to unregister. 5568 * @deprecated Use 5569 * {@link MediaSessionManager#removeOnActiveSessionsChangedListener(android.media.session.MediaSessionManager.OnActiveSessionsChangedListener)} 5570 * instead. 5571 */ 5572 @Deprecated unregisterRemoteController(RemoteController rctlr)5573 public void unregisterRemoteController(RemoteController rctlr) { 5574 if (rctlr == null) { 5575 return; 5576 } 5577 rctlr.stopListeningToSessions(); 5578 } 5579 5580 5581 //==================================================================== 5582 // Audio policy 5583 /** 5584 * @hide 5585 * Register the given {@link AudioPolicy}. 5586 * This call is synchronous and blocks until the registration process successfully completed 5587 * or failed to complete. 5588 * @param policy the non-null {@link AudioPolicy} to register. 5589 * @return {@link #ERROR} if there was an error communicating with the registration service 5590 * or if the user doesn't have the required 5591 * {@link Manifest.permission#MODIFY_AUDIO_ROUTING} permission, 5592 * {@link #SUCCESS} otherwise. 5593 */ 5594 @SystemApi 5595 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) registerAudioPolicy(@onNull AudioPolicy policy)5596 public int registerAudioPolicy(@NonNull AudioPolicy policy) { 5597 return registerAudioPolicyStatic(policy); 5598 } 5599 registerAudioPolicyStatic(@onNull AudioPolicy policy)5600 static int registerAudioPolicyStatic(@NonNull AudioPolicy policy) { 5601 if (policy == null) { 5602 throw new IllegalArgumentException("Illegal null AudioPolicy argument"); 5603 } 5604 final IAudioService service = getService(); 5605 try { 5606 MediaProjection projection = policy.getMediaProjection(); 5607 String regId = service.registerAudioPolicy(policy.getConfig(), policy.cb(), 5608 policy.hasFocusListener(), policy.isFocusPolicy(), policy.isTestFocusPolicy(), 5609 policy.isVolumeController(), 5610 projection == null ? null : projection.getProjection(), 5611 policy.getAttributionSource()); 5612 if (regId == null) { 5613 return ERROR; 5614 } else { 5615 policy.setRegistration(regId); 5616 } 5617 // successful registration 5618 } catch (RemoteException e) { 5619 throw e.rethrowFromSystemServer(); 5620 } 5621 return SUCCESS; 5622 } 5623 5624 /** 5625 * @hide 5626 * Unregisters an {@link AudioPolicy} asynchronously. 5627 * @param policy the non-null {@link AudioPolicy} to unregister. 5628 */ 5629 @SystemApi 5630 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) unregisterAudioPolicyAsync(@onNull AudioPolicy policy)5631 public void unregisterAudioPolicyAsync(@NonNull AudioPolicy policy) { 5632 unregisterAudioPolicyAsyncStatic(policy); 5633 } 5634 unregisterAudioPolicyAsyncStatic(@onNull AudioPolicy policy)5635 static void unregisterAudioPolicyAsyncStatic(@NonNull AudioPolicy policy) { 5636 if (policy == null) { 5637 throw new IllegalArgumentException("Illegal null AudioPolicy argument"); 5638 } 5639 final IAudioService service = getService(); 5640 try { 5641 service.unregisterAudioPolicyAsync(policy.cb()); 5642 policy.reset(); 5643 } catch (RemoteException e) { 5644 throw e.rethrowFromSystemServer(); 5645 } 5646 } 5647 5648 /** 5649 * @hide 5650 * Unregisters an {@link AudioPolicy} synchronously. 5651 * This method also invalidates all {@link AudioRecord} and {@link AudioTrack} objects 5652 * associated with mixes of this policy. 5653 * @param policy the non-null {@link AudioPolicy} to unregister. 5654 */ 5655 @SystemApi 5656 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) unregisterAudioPolicy(@onNull AudioPolicy policy)5657 public void unregisterAudioPolicy(@NonNull AudioPolicy policy) { 5658 Preconditions.checkNotNull(policy, "Illegal null AudioPolicy argument"); 5659 final IAudioService service = getService(); 5660 try { 5661 policy.invalidateCaptorsAndInjectors(); 5662 service.unregisterAudioPolicy(policy.cb()); 5663 policy.reset(); 5664 } catch (RemoteException e) { 5665 throw e.rethrowFromSystemServer(); 5666 } 5667 } 5668 5669 /** 5670 * @hide 5671 * @return All currently registered audio policy mixes. 5672 */ 5673 @TestApi 5674 @FlaggedApi(android.media.audiopolicy.Flags.FLAG_AUDIO_MIX_TEST_API) 5675 @NonNull getRegisteredPolicyMixes()5676 public List<android.media.audiopolicy.AudioMix> getRegisteredPolicyMixes() { 5677 if (!android.media.audiopolicy.Flags.audioMixTestApi()) { 5678 return Collections.emptyList(); 5679 } 5680 5681 final IAudioService service = getService(); 5682 try { 5683 return service.getRegisteredPolicyMixes(); 5684 } catch (RemoteException e) { 5685 throw e.rethrowFromSystemServer(); 5686 } 5687 } 5688 5689 /** 5690 * @hide 5691 * @return true if an AudioPolicy was previously registered 5692 */ 5693 @TestApi hasRegisteredDynamicPolicy()5694 public boolean hasRegisteredDynamicPolicy() { 5695 final IAudioService service = getService(); 5696 try { 5697 return service.hasRegisteredDynamicPolicy(); 5698 } catch (RemoteException e) { 5699 throw e.rethrowFromSystemServer(); 5700 } 5701 } 5702 5703 //==================================================================== 5704 // Notification of playback activity & playback configuration 5705 /** 5706 * Interface for receiving update notifications about the playback activity on the system. 5707 * Extend this abstract class and register it with 5708 * {@link AudioManager#registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)} 5709 * to be notified. 5710 * Use {@link AudioManager#getActivePlaybackConfigurations()} to query the current 5711 * configuration. 5712 * @see AudioPlaybackConfiguration 5713 */ 5714 public static abstract class AudioPlaybackCallback { 5715 /** 5716 * Called whenever the playback activity and configuration has changed. 5717 * @param configs list containing the results of 5718 * {@link AudioManager#getActivePlaybackConfigurations()}. 5719 */ onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs)5720 public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {} 5721 } 5722 5723 private static class AudioPlaybackCallbackInfo { 5724 final AudioPlaybackCallback mCb; 5725 final Handler mHandler; AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler)5726 AudioPlaybackCallbackInfo(AudioPlaybackCallback cb, Handler handler) { 5727 mCb = cb; 5728 mHandler = handler; 5729 } 5730 } 5731 5732 private final static class PlaybackConfigChangeCallbackData { 5733 final AudioPlaybackCallback mCb; 5734 final List<AudioPlaybackConfiguration> mConfigs; 5735 PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb, List<AudioPlaybackConfiguration> configs)5736 PlaybackConfigChangeCallbackData(AudioPlaybackCallback cb, 5737 List<AudioPlaybackConfiguration> configs) { 5738 mCb = cb; 5739 mConfigs = configs; 5740 } 5741 } 5742 5743 /** 5744 * Register a callback to be notified of audio playback changes through 5745 * {@link AudioPlaybackCallback} 5746 * @param cb non-null callback to register 5747 * @param handler the {@link Handler} object for the thread on which to execute 5748 * the callback. If <code>null</code>, the {@link Handler} associated with the main 5749 * {@link Looper} will be used. 5750 */ registerAudioPlaybackCallback(@onNull AudioPlaybackCallback cb, @Nullable Handler handler)5751 public void registerAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb, 5752 @Nullable Handler handler) 5753 { 5754 if (cb == null) { 5755 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument"); 5756 } 5757 5758 synchronized(mPlaybackCallbackLock) { 5759 // lazy initialization of the list of playback callbacks 5760 if (mPlaybackCallbackList == null) { 5761 mPlaybackCallbackList = new ArrayList<AudioPlaybackCallbackInfo>(); 5762 } 5763 final int oldCbCount = mPlaybackCallbackList.size(); 5764 if (!hasPlaybackCallback_sync(cb)) { 5765 mPlaybackCallbackList.add(new AudioPlaybackCallbackInfo(cb, 5766 new ServiceEventHandlerDelegate(handler).getHandler())); 5767 final int newCbCount = mPlaybackCallbackList.size(); 5768 if ((oldCbCount == 0) && (newCbCount > 0)) { 5769 // register binder for callbacks 5770 try { 5771 getService().registerPlaybackCallback(mPlayCb); 5772 } catch (RemoteException e) { 5773 throw e.rethrowFromSystemServer(); 5774 } 5775 } 5776 } else { 5777 Log.w(TAG, "attempt to call registerAudioPlaybackCallback() on a previously" 5778 + "registered callback"); 5779 } 5780 } 5781 } 5782 5783 /** 5784 * Unregister an audio playback callback previously registered with 5785 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}. 5786 * @param cb non-null callback to unregister 5787 */ unregisterAudioPlaybackCallback(@onNull AudioPlaybackCallback cb)5788 public void unregisterAudioPlaybackCallback(@NonNull AudioPlaybackCallback cb) { 5789 if (cb == null) { 5790 throw new IllegalArgumentException("Illegal null AudioPlaybackCallback argument"); 5791 } 5792 synchronized(mPlaybackCallbackLock) { 5793 if (mPlaybackCallbackList == null) { 5794 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback" 5795 + " that was never registered"); 5796 return; 5797 } 5798 final int oldCbCount = mPlaybackCallbackList.size(); 5799 if (removePlaybackCallback_sync(cb)) { 5800 final int newCbCount = mPlaybackCallbackList.size(); 5801 if ((oldCbCount > 0) && (newCbCount == 0)) { 5802 // unregister binder for callbacks 5803 try { 5804 getService().unregisterPlaybackCallback(mPlayCb); 5805 } catch (RemoteException e) { 5806 throw e.rethrowFromSystemServer(); 5807 } 5808 } 5809 } else { 5810 Log.w(TAG, "attempt to call unregisterAudioPlaybackCallback() on a callback" 5811 + " already unregistered or never registered"); 5812 } 5813 } 5814 } 5815 5816 /** 5817 * Returns the current active audio playback configurations of the device 5818 * @return a non-null list of playback configurations. An empty list indicates there is no 5819 * playback active when queried. 5820 * @see AudioPlaybackConfiguration 5821 */ getActivePlaybackConfigurations()5822 public @NonNull List<AudioPlaybackConfiguration> getActivePlaybackConfigurations() { 5823 final IAudioService service = getService(); 5824 try { 5825 return service.getActivePlaybackConfigurations(); 5826 } catch (RemoteException e) { 5827 throw e.rethrowFromSystemServer(); 5828 } 5829 } 5830 5831 /** 5832 * All operations on this list are sync'd on mPlaybackCallbackLock. 5833 * List is lazy-initialized in 5834 * {@link #registerAudioPlaybackCallback(AudioPlaybackCallback, Handler)}. 5835 * List can be null. 5836 */ 5837 private List<AudioPlaybackCallbackInfo> mPlaybackCallbackList; 5838 private final Object mPlaybackCallbackLock = new Object(); 5839 5840 /** 5841 * Must be called synchronized on mPlaybackCallbackLock 5842 */ hasPlaybackCallback_sync(@onNull AudioPlaybackCallback cb)5843 private boolean hasPlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) { 5844 if (mPlaybackCallbackList != null) { 5845 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) { 5846 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) { 5847 return true; 5848 } 5849 } 5850 } 5851 return false; 5852 } 5853 5854 /** 5855 * Must be called synchronized on mPlaybackCallbackLock 5856 */ removePlaybackCallback_sync(@onNull AudioPlaybackCallback cb)5857 private boolean removePlaybackCallback_sync(@NonNull AudioPlaybackCallback cb) { 5858 if (mPlaybackCallbackList != null) { 5859 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) { 5860 if (cb.equals(mPlaybackCallbackList.get(i).mCb)) { 5861 mPlaybackCallbackList.remove(i); 5862 return true; 5863 } 5864 } 5865 } 5866 return false; 5867 } 5868 5869 private final IPlaybackConfigDispatcher mPlayCb = new IPlaybackConfigDispatcher.Stub() { 5870 @Override 5871 public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs, 5872 boolean flush) { 5873 if (flush) { 5874 Binder.flushPendingCommands(); 5875 } 5876 synchronized(mPlaybackCallbackLock) { 5877 if (mPlaybackCallbackList != null) { 5878 for (int i=0 ; i < mPlaybackCallbackList.size() ; i++) { 5879 final AudioPlaybackCallbackInfo arci = mPlaybackCallbackList.get(i); 5880 if (arci.mHandler != null) { 5881 final Message m = arci.mHandler.obtainMessage( 5882 MSSG_PLAYBACK_CONFIG_CHANGE/*what*/, 5883 new PlaybackConfigChangeCallbackData(arci.mCb, configs)/*obj*/); 5884 arci.mHandler.sendMessage(m); 5885 } 5886 } 5887 } 5888 } 5889 } 5890 5891 }; 5892 5893 //==================================================================== 5894 // Notification of recording activity & recording configuration 5895 /** 5896 * Interface for receiving update notifications about the recording configuration. Extend 5897 * this abstract class and register it with 5898 * {@link AudioManager#registerAudioRecordingCallback(AudioRecordingCallback, Handler)} 5899 * to be notified. 5900 * Use {@link AudioManager#getActiveRecordingConfigurations()} to query the current 5901 * configuration. 5902 * @see AudioRecordingConfiguration 5903 */ 5904 public static abstract class AudioRecordingCallback { 5905 /** 5906 * Called whenever the device recording configuration has changed. 5907 * @param configs list containing the results of 5908 * {@link AudioManager#getActiveRecordingConfigurations()}. 5909 */ onRecordingConfigChanged(List<AudioRecordingConfiguration> configs)5910 public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {} 5911 } 5912 5913 private static class AudioRecordingCallbackInfo { 5914 final AudioRecordingCallback mCb; 5915 final Handler mHandler; AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler)5916 AudioRecordingCallbackInfo(AudioRecordingCallback cb, Handler handler) { 5917 mCb = cb; 5918 mHandler = handler; 5919 } 5920 } 5921 5922 private final static class RecordConfigChangeCallbackData { 5923 final AudioRecordingCallback mCb; 5924 final List<AudioRecordingConfiguration> mConfigs; 5925 RecordConfigChangeCallbackData(AudioRecordingCallback cb, List<AudioRecordingConfiguration> configs)5926 RecordConfigChangeCallbackData(AudioRecordingCallback cb, 5927 List<AudioRecordingConfiguration> configs) { 5928 mCb = cb; 5929 mConfigs = configs; 5930 } 5931 } 5932 5933 /** 5934 * Register a callback to be notified of audio recording changes through 5935 * {@link AudioRecordingCallback} 5936 * @param cb non-null callback to register 5937 * @param handler the {@link Handler} object for the thread on which to execute 5938 * the callback. If <code>null</code>, the {@link Handler} associated with the main 5939 * {@link Looper} will be used. 5940 */ registerAudioRecordingCallback(@onNull AudioRecordingCallback cb, @Nullable Handler handler)5941 public void registerAudioRecordingCallback(@NonNull AudioRecordingCallback cb, 5942 @Nullable Handler handler) 5943 { 5944 if (cb == null) { 5945 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument"); 5946 } 5947 5948 synchronized(mRecordCallbackLock) { 5949 // lazy initialization of the list of recording callbacks 5950 if (mRecordCallbackList == null) { 5951 mRecordCallbackList = new ArrayList<AudioRecordingCallbackInfo>(); 5952 } 5953 final int oldCbCount = mRecordCallbackList.size(); 5954 if (!hasRecordCallback_sync(cb)) { 5955 mRecordCallbackList.add(new AudioRecordingCallbackInfo(cb, 5956 new ServiceEventHandlerDelegate(handler).getHandler())); 5957 final int newCbCount = mRecordCallbackList.size(); 5958 if ((oldCbCount == 0) && (newCbCount > 0)) { 5959 // register binder for callbacks 5960 final IAudioService service = getService(); 5961 try { 5962 service.registerRecordingCallback(mRecCb); 5963 } catch (RemoteException e) { 5964 throw e.rethrowFromSystemServer(); 5965 } 5966 } 5967 } else { 5968 Log.w(TAG, "attempt to call registerAudioRecordingCallback() on a previously" 5969 + "registered callback"); 5970 } 5971 } 5972 } 5973 5974 /** 5975 * Unregister an audio recording callback previously registered with 5976 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}. 5977 * @param cb non-null callback to unregister 5978 */ unregisterAudioRecordingCallback(@onNull AudioRecordingCallback cb)5979 public void unregisterAudioRecordingCallback(@NonNull AudioRecordingCallback cb) { 5980 if (cb == null) { 5981 throw new IllegalArgumentException("Illegal null AudioRecordingCallback argument"); 5982 } 5983 synchronized(mRecordCallbackLock) { 5984 if (mRecordCallbackList == null) { 5985 return; 5986 } 5987 final int oldCbCount = mRecordCallbackList.size(); 5988 if (removeRecordCallback_sync(cb)) { 5989 final int newCbCount = mRecordCallbackList.size(); 5990 if ((oldCbCount > 0) && (newCbCount == 0)) { 5991 // unregister binder for callbacks 5992 final IAudioService service = getService(); 5993 try { 5994 service.unregisterRecordingCallback(mRecCb); 5995 } catch (RemoteException e) { 5996 throw e.rethrowFromSystemServer(); 5997 } 5998 } 5999 } else { 6000 Log.w(TAG, "attempt to call unregisterAudioRecordingCallback() on a callback" 6001 + " already unregistered or never registered"); 6002 } 6003 } 6004 } 6005 6006 /** 6007 * Returns the current active audio recording configurations of the device. 6008 * @return a non-null list of recording configurations. An empty list indicates there is 6009 * no recording active when queried. 6010 * @see AudioRecordingConfiguration 6011 */ getActiveRecordingConfigurations()6012 public @NonNull List<AudioRecordingConfiguration> getActiveRecordingConfigurations() { 6013 final IAudioService service = getService(); 6014 try { 6015 return service.getActiveRecordingConfigurations(); 6016 } catch (RemoteException e) { 6017 throw e.rethrowFromSystemServer(); 6018 } 6019 } 6020 6021 /** 6022 * constants for the recording events, to keep in sync 6023 * with frameworks/av/include/media/AudioPolicy.h 6024 */ 6025 /** @hide */ 6026 public static final int RECORD_CONFIG_EVENT_NONE = -1; 6027 /** @hide */ 6028 public static final int RECORD_CONFIG_EVENT_START = 0; 6029 /** @hide */ 6030 public static final int RECORD_CONFIG_EVENT_STOP = 1; 6031 /** @hide */ 6032 public static final int RECORD_CONFIG_EVENT_UPDATE = 2; 6033 /** @hide */ 6034 public static final int RECORD_CONFIG_EVENT_RELEASE = 3; 6035 /** 6036 * keep in sync with frameworks/native/include/audiomanager/AudioManager.h 6037 */ 6038 /** @hide */ 6039 public static final int RECORD_RIID_INVALID = -1; 6040 /** @hide */ 6041 public static final int RECORDER_STATE_STARTED = 0; 6042 /** @hide */ 6043 public static final int RECORDER_STATE_STOPPED = 1; 6044 6045 /** 6046 * All operations on this list are sync'd on mRecordCallbackLock. 6047 * List is lazy-initialized in 6048 * {@link #registerAudioRecordingCallback(AudioRecordingCallback, Handler)}. 6049 * List can be null. 6050 */ 6051 private List<AudioRecordingCallbackInfo> mRecordCallbackList; 6052 private final Object mRecordCallbackLock = new Object(); 6053 6054 /** 6055 * Must be called synchronized on mRecordCallbackLock 6056 */ hasRecordCallback_sync(@onNull AudioRecordingCallback cb)6057 private boolean hasRecordCallback_sync(@NonNull AudioRecordingCallback cb) { 6058 if (mRecordCallbackList != null) { 6059 for (int i=0 ; i < mRecordCallbackList.size() ; i++) { 6060 if (cb.equals(mRecordCallbackList.get(i).mCb)) { 6061 return true; 6062 } 6063 } 6064 } 6065 return false; 6066 } 6067 6068 /** 6069 * Must be called synchronized on mRecordCallbackLock 6070 */ removeRecordCallback_sync(@onNull AudioRecordingCallback cb)6071 private boolean removeRecordCallback_sync(@NonNull AudioRecordingCallback cb) { 6072 if (mRecordCallbackList != null) { 6073 for (int i=0 ; i < mRecordCallbackList.size() ; i++) { 6074 if (cb.equals(mRecordCallbackList.get(i).mCb)) { 6075 mRecordCallbackList.remove(i); 6076 return true; 6077 } 6078 } 6079 } 6080 return false; 6081 } 6082 6083 private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() { 6084 @Override 6085 public void dispatchRecordingConfigChange(List<AudioRecordingConfiguration> configs) { 6086 synchronized(mRecordCallbackLock) { 6087 if (mRecordCallbackList != null) { 6088 for (int i=0 ; i < mRecordCallbackList.size() ; i++) { 6089 final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i); 6090 if (arci.mHandler != null) { 6091 final Message m = arci.mHandler.obtainMessage( 6092 MSSG_RECORDING_CONFIG_CHANGE/*what*/, 6093 new RecordConfigChangeCallbackData(arci.mCb, configs)/*obj*/); 6094 arci.mHandler.sendMessage(m); 6095 } 6096 } 6097 } 6098 } 6099 } 6100 6101 }; 6102 6103 //===================================================================== 6104 6105 /** 6106 * @hide 6107 * Reload audio settings. This method is called by Settings backup 6108 * agent when audio settings are restored and causes the AudioService 6109 * to read and apply restored settings. 6110 */ 6111 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) reloadAudioSettings()6112 public void reloadAudioSettings() { 6113 final IAudioService service = getService(); 6114 try { 6115 service.reloadAudioSettings(); 6116 } catch (RemoteException e) { 6117 throw e.rethrowFromSystemServer(); 6118 } 6119 } 6120 6121 /** 6122 * {@hide} 6123 */ 6124 private final IBinder mICallBack = new Binder(); 6125 6126 /** 6127 * Checks whether the phone is in silent mode, with or without vibrate. 6128 * 6129 * @return true if phone is in silent mode, with or without vibrate. 6130 * 6131 * @see #getRingerMode() 6132 * 6133 * @hide pending API Council approval 6134 */ 6135 @UnsupportedAppUsage isSilentMode()6136 public boolean isSilentMode() { 6137 int ringerMode = getRingerMode(); 6138 boolean silentMode = 6139 (ringerMode == RINGER_MODE_SILENT) || 6140 (ringerMode == RINGER_MODE_VIBRATE); 6141 return silentMode; 6142 } 6143 6144 // This section re-defines new output device constants from AudioSystem, because the AudioSystem 6145 // class is not used by other parts of the framework, which instead use definitions and methods 6146 // from AudioManager. AudioSystem is an internal class used by AudioManager and AudioService. 6147 6148 /** @hide 6149 * The audio device code for representing "no device." */ 6150 public static final int DEVICE_NONE = AudioSystem.DEVICE_NONE; 6151 /** @hide 6152 * The audio output device code for the small speaker at the front of the device used 6153 * when placing calls. Does not refer to an in-ear headphone without attached microphone, 6154 * such as earbuds, earphones, or in-ear monitors (IEM). Those would be handled as a 6155 * {@link #DEVICE_OUT_WIRED_HEADPHONE}. 6156 */ 6157 @UnsupportedAppUsage 6158 public static final int DEVICE_OUT_EARPIECE = AudioSystem.DEVICE_OUT_EARPIECE; 6159 /** @hide 6160 * The audio output device code for the built-in speaker */ 6161 @UnsupportedAppUsage 6162 public static final int DEVICE_OUT_SPEAKER = AudioSystem.DEVICE_OUT_SPEAKER; 6163 /** @hide 6164 * The audio output device code for a wired headset with attached microphone */ 6165 @UnsupportedAppUsage 6166 public static final int DEVICE_OUT_WIRED_HEADSET = AudioSystem.DEVICE_OUT_WIRED_HEADSET; 6167 /** @hide 6168 * The audio output device code for a wired headphone without attached microphone */ 6169 @UnsupportedAppUsage 6170 public static final int DEVICE_OUT_WIRED_HEADPHONE = AudioSystem.DEVICE_OUT_WIRED_HEADPHONE; 6171 /** @hide 6172 * The audio output device code for a USB headphone with attached microphone */ 6173 public static final int DEVICE_OUT_USB_HEADSET = AudioSystem.DEVICE_OUT_USB_HEADSET; 6174 /** @hide 6175 * The audio output device code for generic Bluetooth SCO, for voice */ 6176 public static final int DEVICE_OUT_BLUETOOTH_SCO = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; 6177 /** @hide 6178 * The audio output device code for Bluetooth SCO Headset Profile (HSP) and 6179 * Hands-Free Profile (HFP), for voice 6180 */ 6181 @UnsupportedAppUsage 6182 public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 6183 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; 6184 /** @hide 6185 * The audio output device code for Bluetooth SCO car audio, for voice */ 6186 public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 6187 AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT; 6188 /** @hide 6189 * The audio output device code for generic Bluetooth A2DP, for music */ 6190 @UnsupportedAppUsage 6191 public static final int DEVICE_OUT_BLUETOOTH_A2DP = AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP; 6192 /** @hide 6193 * The audio output device code for Bluetooth A2DP headphones, for music */ 6194 @UnsupportedAppUsage 6195 public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 6196 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; 6197 /** @hide 6198 * The audio output device code for Bluetooth A2DP external speaker, for music */ 6199 @UnsupportedAppUsage 6200 public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 6201 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; 6202 /** @hide 6203 * The audio output device code for S/PDIF (legacy) or HDMI 6204 * Deprecated: replaced by {@link #DEVICE_OUT_HDMI} */ 6205 public static final int DEVICE_OUT_AUX_DIGITAL = AudioSystem.DEVICE_OUT_AUX_DIGITAL; 6206 /** @hide 6207 * The audio output device code for HDMI */ 6208 @UnsupportedAppUsage 6209 public static final int DEVICE_OUT_HDMI = AudioSystem.DEVICE_OUT_HDMI; 6210 /** @hide 6211 * The audio output device code for an analog wired headset attached via a 6212 * docking station 6213 */ 6214 @UnsupportedAppUsage 6215 public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET; 6216 /** @hide 6217 * The audio output device code for a digital wired headset attached via a 6218 * docking station 6219 */ 6220 @UnsupportedAppUsage 6221 public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET; 6222 /** @hide 6223 * The audio output device code for a USB audio accessory. The accessory is in USB host 6224 * mode and the Android device in USB device mode 6225 */ 6226 public static final int DEVICE_OUT_USB_ACCESSORY = AudioSystem.DEVICE_OUT_USB_ACCESSORY; 6227 /** @hide 6228 * The audio output device code for a USB audio device. The device is in USB device 6229 * mode and the Android device in USB host mode 6230 */ 6231 public static final int DEVICE_OUT_USB_DEVICE = AudioSystem.DEVICE_OUT_USB_DEVICE; 6232 /** @hide 6233 * The audio output device code for projection output. 6234 */ 6235 public static final int DEVICE_OUT_REMOTE_SUBMIX = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX; 6236 /** @hide 6237 * The audio output device code the telephony voice TX path. 6238 */ 6239 public static final int DEVICE_OUT_TELEPHONY_TX = AudioSystem.DEVICE_OUT_TELEPHONY_TX; 6240 /** @hide 6241 * The audio output device code for an analog jack with line impedance detected. 6242 */ 6243 public static final int DEVICE_OUT_LINE = AudioSystem.DEVICE_OUT_LINE; 6244 /** @hide 6245 * The audio output device code for HDMI Audio Return Channel. 6246 */ 6247 public static final int DEVICE_OUT_HDMI_ARC = AudioSystem.DEVICE_OUT_HDMI_ARC; 6248 /** @hide 6249 * The audio output device code for HDMI enhanced Audio Return Channel. 6250 */ 6251 public static final int DEVICE_OUT_HDMI_EARC = AudioSystem.DEVICE_OUT_HDMI_EARC; 6252 /** @hide 6253 * The audio output device code for S/PDIF digital connection. 6254 */ 6255 public static final int DEVICE_OUT_SPDIF = AudioSystem.DEVICE_OUT_SPDIF; 6256 /** @hide 6257 * The audio output device code for built-in FM transmitter. 6258 */ 6259 public static final int DEVICE_OUT_FM = AudioSystem.DEVICE_OUT_FM; 6260 /** @hide 6261 * The audio output device code for echo reference injection point. 6262 */ 6263 public static final int DEVICE_OUT_ECHO_CANCELLER = AudioSystem.DEVICE_OUT_ECHO_CANCELLER; 6264 /** @hide 6265 * The audio output device code for a BLE audio headset. 6266 */ 6267 public static final int DEVICE_OUT_BLE_HEADSET = AudioSystem.DEVICE_OUT_BLE_HEADSET; 6268 /** @hide 6269 * The audio output device code for a BLE audio speaker. 6270 */ 6271 public static final int DEVICE_OUT_BLE_SPEAKER = AudioSystem.DEVICE_OUT_BLE_SPEAKER; 6272 /** @hide 6273 * The audio output device code for a BLE audio brodcast group. 6274 */ 6275 public static final int DEVICE_OUT_BLE_BROADCAST = AudioSystem.DEVICE_OUT_BLE_BROADCAST; 6276 /** @hide 6277 * The audio output device code for a wireless speaker group supporting multichannel content. 6278 */ 6279 public static final int DEVICE_OUT_MULTICHANNEL_GROUP = 6280 AudioSystem.DEVICE_OUT_MULTICHANNEL_GROUP; 6281 /** @hide 6282 * This is not used as a returned value from {@link #getDevicesForStream}, but could be 6283 * used in the future in a set method to select whatever default device is chosen by the 6284 * platform-specific implementation. 6285 */ 6286 public static final int DEVICE_OUT_DEFAULT = AudioSystem.DEVICE_OUT_DEFAULT; 6287 6288 /** @hide 6289 * The audio input device code for default built-in microphone 6290 */ 6291 public static final int DEVICE_IN_BUILTIN_MIC = AudioSystem.DEVICE_IN_BUILTIN_MIC; 6292 /** @hide 6293 * The audio input device code for a Bluetooth SCO headset 6294 */ 6295 public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET = 6296 AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET; 6297 /** @hide 6298 * The audio input device code for wired headset microphone 6299 */ 6300 public static final int DEVICE_IN_WIRED_HEADSET = 6301 AudioSystem.DEVICE_IN_WIRED_HEADSET; 6302 /** @hide 6303 * The audio input device code for HDMI 6304 */ 6305 public static final int DEVICE_IN_HDMI = 6306 AudioSystem.DEVICE_IN_HDMI; 6307 /** @hide 6308 * The audio input device code for HDMI ARC 6309 */ 6310 public static final int DEVICE_IN_HDMI_ARC = 6311 AudioSystem.DEVICE_IN_HDMI_ARC; 6312 6313 /** @hide 6314 * The audio input device code for HDMI EARC 6315 */ 6316 public static final int DEVICE_IN_HDMI_EARC = 6317 AudioSystem.DEVICE_IN_HDMI_EARC; 6318 6319 /** @hide 6320 * The audio input device code for telephony voice RX path 6321 */ 6322 public static final int DEVICE_IN_TELEPHONY_RX = 6323 AudioSystem.DEVICE_IN_TELEPHONY_RX; 6324 /** @hide 6325 * The audio input device code for built-in microphone pointing to the back 6326 */ 6327 public static final int DEVICE_IN_BACK_MIC = 6328 AudioSystem.DEVICE_IN_BACK_MIC; 6329 /** @hide 6330 * The audio input device code for analog from a docking station 6331 */ 6332 public static final int DEVICE_IN_ANLG_DOCK_HEADSET = 6333 AudioSystem.DEVICE_IN_ANLG_DOCK_HEADSET; 6334 /** @hide 6335 * The audio input device code for digital from a docking station 6336 */ 6337 public static final int DEVICE_IN_DGTL_DOCK_HEADSET = 6338 AudioSystem.DEVICE_IN_DGTL_DOCK_HEADSET; 6339 /** @hide 6340 * The audio input device code for a USB audio accessory. The accessory is in USB host 6341 * mode and the Android device in USB device mode 6342 */ 6343 public static final int DEVICE_IN_USB_ACCESSORY = 6344 AudioSystem.DEVICE_IN_USB_ACCESSORY; 6345 /** @hide 6346 * The audio input device code for a USB audio device. The device is in USB device 6347 * mode and the Android device in USB host mode 6348 */ 6349 public static final int DEVICE_IN_USB_DEVICE = 6350 AudioSystem.DEVICE_IN_USB_DEVICE; 6351 /** @hide 6352 * The audio input device code for a FM radio tuner 6353 */ 6354 public static final int DEVICE_IN_FM_TUNER = AudioSystem.DEVICE_IN_FM_TUNER; 6355 /** @hide 6356 * The audio input device code for a TV tuner 6357 */ 6358 public static final int DEVICE_IN_TV_TUNER = AudioSystem.DEVICE_IN_TV_TUNER; 6359 /** @hide 6360 * The audio input device code for an analog jack with line impedance detected 6361 */ 6362 public static final int DEVICE_IN_LINE = AudioSystem.DEVICE_IN_LINE; 6363 /** @hide 6364 * The audio input device code for a S/PDIF digital connection 6365 */ 6366 public static final int DEVICE_IN_SPDIF = AudioSystem.DEVICE_IN_SPDIF; 6367 /** @hide 6368 * The audio input device code for audio loopback 6369 */ 6370 public static final int DEVICE_IN_LOOPBACK = AudioSystem.DEVICE_IN_LOOPBACK; 6371 /** @hide 6372 * The audio input device code for an echo reference capture point. 6373 */ 6374 public static final int DEVICE_IN_ECHO_REFERENCE = AudioSystem.DEVICE_IN_ECHO_REFERENCE; 6375 /** @hide 6376 * The audio input device code for a BLE audio headset. 6377 */ 6378 public static final int DEVICE_IN_BLE_HEADSET = AudioSystem.DEVICE_IN_BLE_HEADSET; 6379 6380 /** 6381 * Return true if the device code corresponds to an output device. 6382 * @hide 6383 */ isOutputDevice(int device)6384 public static boolean isOutputDevice(int device) 6385 { 6386 return !AudioSystem.isInputDevice(device); 6387 } 6388 6389 /** 6390 * Return true if the device code corresponds to an input device. 6391 * @hide 6392 */ isInputDevice(int device)6393 public static boolean isInputDevice(int device) 6394 { 6395 return AudioSystem.isInputDevice(device); 6396 } 6397 6398 6399 /** 6400 * Return the enabled devices for the specified output stream type. 6401 * 6402 * @param streamType The stream type to query. One of 6403 * {@link #STREAM_VOICE_CALL}, 6404 * {@link #STREAM_SYSTEM}, 6405 * {@link #STREAM_RING}, 6406 * {@link #STREAM_MUSIC}, 6407 * {@link #STREAM_ALARM}, 6408 * {@link #STREAM_NOTIFICATION}, 6409 * {@link #STREAM_DTMF}, 6410 * {@link #STREAM_ACCESSIBILITY}. 6411 * 6412 * @return The bit-mask "or" of audio output device codes for all enabled devices on this 6413 * stream. Zero or more of 6414 * {@link #DEVICE_OUT_EARPIECE}, 6415 * {@link #DEVICE_OUT_SPEAKER}, 6416 * {@link #DEVICE_OUT_WIRED_HEADSET}, 6417 * {@link #DEVICE_OUT_WIRED_HEADPHONE}, 6418 * {@link #DEVICE_OUT_BLUETOOTH_SCO}, 6419 * {@link #DEVICE_OUT_BLUETOOTH_SCO_HEADSET}, 6420 * {@link #DEVICE_OUT_BLUETOOTH_SCO_CARKIT}, 6421 * {@link #DEVICE_OUT_BLUETOOTH_A2DP}, 6422 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES}, 6423 * {@link #DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER}, 6424 * {@link #DEVICE_OUT_HDMI}, 6425 * {@link #DEVICE_OUT_ANLG_DOCK_HEADSET}, 6426 * {@link #DEVICE_OUT_DGTL_DOCK_HEADSET}. 6427 * {@link #DEVICE_OUT_USB_ACCESSORY}. 6428 * {@link #DEVICE_OUT_USB_DEVICE}. 6429 * {@link #DEVICE_OUT_REMOTE_SUBMIX}. 6430 * {@link #DEVICE_OUT_TELEPHONY_TX}. 6431 * {@link #DEVICE_OUT_LINE}. 6432 * {@link #DEVICE_OUT_HDMI_ARC}. 6433 * {@link #DEVICE_OUT_HDMI_EARC}. 6434 * {@link #DEVICE_OUT_SPDIF}. 6435 * {@link #DEVICE_OUT_FM}. 6436 * {@link #DEVICE_OUT_DEFAULT} is not used here. 6437 * 6438 * The implementation may support additional device codes beyond those listed, so 6439 * the application should ignore any bits which it does not recognize. 6440 * Note that the information may be imprecise when the implementation 6441 * cannot distinguish whether a particular device is enabled. 6442 * 6443 * @deprecated on {@link android.os.Build.VERSION_CODES#T} as new devices 6444 * will have multi-bit device types. 6445 * Prefer to use {@link #getDevicesForAttributes()} instead, 6446 * noting that getDevicesForStream() has a few small discrepancies 6447 * for better volume handling. 6448 * @hide 6449 */ 6450 @UnsupportedAppUsage 6451 @Deprecated getDevicesForStream(int streamType)6452 public int getDevicesForStream(int streamType) { 6453 switch (streamType) { 6454 case STREAM_VOICE_CALL: 6455 case STREAM_SYSTEM: 6456 case STREAM_RING: 6457 case STREAM_MUSIC: 6458 case STREAM_ALARM: 6459 case STREAM_NOTIFICATION: 6460 case STREAM_DTMF: 6461 case STREAM_ACCESSIBILITY: 6462 final IAudioService service = getService(); 6463 try { 6464 return service.getDeviceMaskForStream(streamType); 6465 } catch (RemoteException e) { 6466 throw e.rethrowFromSystemServer(); 6467 } 6468 default: 6469 return 0; 6470 } 6471 } 6472 6473 /** 6474 * @hide 6475 * Get the audio devices that would be used for the routing of the given audio attributes. 6476 * @param attributes the {@link AudioAttributes} for which the routing is being queried. 6477 * For queries about output devices (playback use cases), a valid usage must be specified in 6478 * the audio attributes via AudioAttributes.Builder.setUsage(). The capture preset MUST NOT 6479 * be changed from default. 6480 * For queries about input devices (capture use case), a valid capture preset MUST be 6481 * specified in the audio attributes via AudioAttributes.Builder.setCapturePreset(). If a 6482 * capture preset is present, then this has precedence over any usage or content type also 6483 * present in the audio attrirutes. 6484 * @return an empty list if there was an issue with the request, a list of audio devices 6485 * otherwise (typically one device, except for duplicated paths). 6486 */ 6487 @SystemApi 6488 @RequiresPermission(anyOf = { 6489 Manifest.permission.MODIFY_AUDIO_ROUTING, 6490 Manifest.permission.QUERY_AUDIO_STATE 6491 }) getDevicesForAttributes( @onNull AudioAttributes attributes)6492 public @NonNull List<AudioDeviceAttributes> getDevicesForAttributes( 6493 @NonNull AudioAttributes attributes) { 6494 Objects.requireNonNull(attributes); 6495 final IAudioService service = getService(); 6496 try { 6497 return service.getDevicesForAttributes(attributes); 6498 } catch (RemoteException e) { 6499 throw e.rethrowFromSystemServer(); 6500 } 6501 } 6502 6503 // Each listener corresponds to a unique callback stub because each listener can subscribe to 6504 // different AudioAttributes. 6505 private final ConcurrentHashMap<OnDevicesForAttributesChangedListener, 6506 IDevicesForAttributesCallbackStub> mDevicesForAttributesListenerToStub = 6507 new ConcurrentHashMap<>(); 6508 6509 private static final class IDevicesForAttributesCallbackStub 6510 extends IDevicesForAttributesCallback.Stub { 6511 ListenerInfo<OnDevicesForAttributesChangedListener> mInfo; 6512 IDevicesForAttributesCallbackStub(@onNull OnDevicesForAttributesChangedListener listener, @NonNull Executor executor)6513 IDevicesForAttributesCallbackStub(@NonNull OnDevicesForAttributesChangedListener listener, 6514 @NonNull Executor executor) { 6515 mInfo = new ListenerInfo<>(listener, executor); 6516 } 6517 register(boolean register, AudioAttributes attributes)6518 public void register(boolean register, AudioAttributes attributes) { 6519 try { 6520 if (register) { 6521 getService().addOnDevicesForAttributesChangedListener(attributes, this); 6522 } else { 6523 getService().removeOnDevicesForAttributesChangedListener(this); 6524 } 6525 } catch (RemoteException e) { 6526 throw e.rethrowFromSystemServer(); 6527 } 6528 } 6529 6530 @Override onDevicesForAttributesChanged(AudioAttributes attributes, boolean forVolume, List<AudioDeviceAttributes> devices)6531 public void onDevicesForAttributesChanged(AudioAttributes attributes, boolean forVolume, 6532 List<AudioDeviceAttributes> devices) { 6533 // forVolume is ignored. The case where it is `true` is not handled. 6534 mInfo.mExecutor.execute(() -> 6535 mInfo.mListener.onDevicesForAttributesChanged( 6536 attributes, devices)); 6537 } 6538 } 6539 6540 /** 6541 * @hide 6542 * Interface to be notified of when routing changes for the registered audio attributes. 6543 */ 6544 @SystemApi 6545 public interface OnDevicesForAttributesChangedListener { 6546 /** 6547 * Called on the listener to indicate that the audio devices for the given audio 6548 * attributes have changed. 6549 * @param attributes the {@link AudioAttributes} whose routing changed 6550 * @param devices a list of newly routed audio devices 6551 */ onDevicesForAttributesChanged(@onNull AudioAttributes attributes, @NonNull List<AudioDeviceAttributes> devices)6552 void onDevicesForAttributesChanged(@NonNull AudioAttributes attributes, 6553 @NonNull List<AudioDeviceAttributes> devices); 6554 } 6555 6556 /** 6557 * @hide 6558 * Adds a listener for being notified of routing changes for the given {@link AudioAttributes}. 6559 * @param attributes the {@link AudioAttributes} to listen for routing changes 6560 * @param executor 6561 * @param listener 6562 */ 6563 @SystemApi 6564 @RequiresPermission(anyOf = { 6565 Manifest.permission.MODIFY_AUDIO_ROUTING, 6566 Manifest.permission.QUERY_AUDIO_STATE 6567 }) addOnDevicesForAttributesChangedListener(@onNull AudioAttributes attributes, @NonNull @CallbackExecutor Executor executor, @NonNull OnDevicesForAttributesChangedListener listener)6568 public void addOnDevicesForAttributesChangedListener(@NonNull AudioAttributes attributes, 6569 @NonNull @CallbackExecutor Executor executor, 6570 @NonNull OnDevicesForAttributesChangedListener listener) { 6571 Objects.requireNonNull(attributes); 6572 Objects.requireNonNull(executor); 6573 Objects.requireNonNull(listener); 6574 6575 synchronized (mDevicesForAttributesListenerToStub) { 6576 IDevicesForAttributesCallbackStub callbackStub = 6577 mDevicesForAttributesListenerToStub.get(listener); 6578 6579 if (callbackStub == null) { 6580 callbackStub = new IDevicesForAttributesCallbackStub(listener, executor); 6581 mDevicesForAttributesListenerToStub.put(listener, callbackStub); 6582 } 6583 6584 callbackStub.register(true, attributes); 6585 } 6586 } 6587 6588 /** 6589 * @hide 6590 * Removes a previously registered listener for being notified of routing changes for the given 6591 * {@link AudioAttributes}. 6592 * @param listener 6593 */ 6594 @SystemApi 6595 @RequiresPermission(anyOf = { 6596 Manifest.permission.MODIFY_AUDIO_ROUTING, 6597 Manifest.permission.QUERY_AUDIO_STATE 6598 }) removeOnDevicesForAttributesChangedListener( @onNull OnDevicesForAttributesChangedListener listener)6599 public void removeOnDevicesForAttributesChangedListener( 6600 @NonNull OnDevicesForAttributesChangedListener listener) { 6601 Objects.requireNonNull(listener); 6602 6603 synchronized (mDevicesForAttributesListenerToStub) { 6604 IDevicesForAttributesCallbackStub callbackStub = 6605 mDevicesForAttributesListenerToStub.get(listener); 6606 if (callbackStub != null) { 6607 callbackStub.register(false, null /* attributes */); 6608 } 6609 6610 mDevicesForAttributesListenerToStub.remove(listener); 6611 } 6612 } 6613 6614 /** 6615 * Get the audio devices that would be used for the routing of the given audio attributes. 6616 * These are the devices anticipated to play sound from an {@link AudioTrack} created with 6617 * the specified {@link AudioAttributes}. 6618 * The audio routing can change if audio devices are physically connected or disconnected or 6619 * concurrently through {@link AudioRouting} or {@link MediaRouter}. 6620 * @param attributes the {@link AudioAttributes} for which the routing is being queried 6621 * @return an empty list if there was an issue with the request, a list of 6622 * {@link AudioDeviceInfo} otherwise (typically one device, except for duplicated paths). 6623 */ getAudioDevicesForAttributes( @onNull AudioAttributes attributes)6624 public @NonNull List<AudioDeviceInfo> getAudioDevicesForAttributes( 6625 @NonNull AudioAttributes attributes) { 6626 final List<AudioDeviceAttributes> devicesForAttributes; 6627 try { 6628 Objects.requireNonNull(attributes); 6629 final IAudioService service = getService(); 6630 devicesForAttributes = service.getDevicesForAttributesUnprotected(attributes); 6631 } catch (Exception e) { 6632 Log.i(TAG, "No audio devices available for specified attributes."); 6633 return Collections.emptyList(); 6634 } 6635 6636 // Map from AudioDeviceAttributes to AudioDeviceInfo 6637 AudioDeviceInfo[] outputDeviceInfos = getDevicesStatic(GET_DEVICES_OUTPUTS); 6638 List<AudioDeviceInfo> deviceInfosForAttributes = new ArrayList<>(); 6639 for (AudioDeviceAttributes deviceForAttributes : devicesForAttributes) { 6640 for (AudioDeviceInfo deviceInfo : outputDeviceInfos) { 6641 if (deviceForAttributes.getType() == deviceInfo.getType() 6642 && TextUtils.equals(deviceForAttributes.getAddress(), 6643 deviceInfo.getAddress())) { 6644 deviceInfosForAttributes.add(deviceInfo); 6645 } 6646 } 6647 } 6648 return Collections.unmodifiableList(deviceInfosForAttributes); 6649 } 6650 6651 /** 6652 * @hide 6653 * Volume behavior for an audio device that has no particular volume behavior set. Invalid as 6654 * an argument to {@link #setDeviceVolumeBehavior(AudioDeviceAttributes, int)} and should not 6655 * be returned by {@link #getDeviceVolumeBehavior(AudioDeviceAttributes)}. 6656 */ 6657 public static final int DEVICE_VOLUME_BEHAVIOR_UNSET = -1; 6658 /** 6659 * @hide 6660 * Volume behavior for an audio device where a software attenuation is applied 6661 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int) 6662 * @deprecated use {@link AudioDeviceVolumeManager#DEVICE_VOLUME_BEHAVIOR_VARIABLE} instead 6663 */ 6664 @SystemApi 6665 @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT) 6666 public static final int DEVICE_VOLUME_BEHAVIOR_VARIABLE = 0; 6667 /** 6668 * @hide 6669 * Volume behavior for an audio device where the volume is always set to provide no attenuation 6670 * nor gain (e.g. unit gain). 6671 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int) 6672 * @deprecated use {@link AudioDeviceVolumeManager#DEVICE_VOLUME_BEHAVIOR_FULL} instead 6673 */ 6674 @SystemApi 6675 @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT) 6676 public static final int DEVICE_VOLUME_BEHAVIOR_FULL = 1; 6677 /** 6678 * @hide 6679 * Volume behavior for an audio device where the volume is either set to muted, or to provide 6680 * no attenuation nor gain (e.g. unit gain). 6681 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int) 6682 * @deprecated use {@link AudioDeviceVolumeManager#DEVICE_VOLUME_BEHAVIOR_FIXED} instead 6683 */ 6684 @SystemApi 6685 @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT) 6686 public static final int DEVICE_VOLUME_BEHAVIOR_FIXED = 2; 6687 /** 6688 * @hide 6689 * Volume behavior for an audio device where no software attenuation is applied, and 6690 * the volume is kept synchronized between the host and the device itself through a 6691 * device-specific protocol such as BT AVRCP. 6692 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int) 6693 * @deprecated use {@link AudioDeviceVolumeManager#DEVICE_VOLUME_BEHAVIOR_ABSOLUTE} instead 6694 */ 6695 @SystemApi 6696 @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT) 6697 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE = 3; 6698 /** 6699 * @hide 6700 * Volume behavior for an audio device where no software attenuation is applied, and 6701 * the volume is kept synchronized between the host and the device itself through a 6702 * device-specific protocol (such as for hearing aids), based on the audio mode (e.g. 6703 * normal vs in phone call). 6704 * @see #setMode(int) 6705 * @see #setDeviceVolumeBehavior(AudioDeviceAttributes, int) 6706 * @deprecated use {@link AudioDeviceVolumeManager#DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE} 6707 * instead 6708 */ 6709 @SystemApi 6710 @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT) 6711 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE = 4; 6712 6713 /** 6714 * @hide 6715 * A variant of {@link #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE} where the host cannot reliably set 6716 * the volume percentage of the audio device. Specifically, {@link #setStreamVolume} will have 6717 * no effect, or an unreliable effect. 6718 * @deprecated use {@link AudioDeviceVolumeManager#DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY} 6719 * instead 6720 */ 6721 @SystemApi 6722 @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT) 6723 public static final int DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY = 5; 6724 6725 /** @hide */ 6726 @IntDef({ 6727 DEVICE_VOLUME_BEHAVIOR_VARIABLE, 6728 DEVICE_VOLUME_BEHAVIOR_FULL, 6729 DEVICE_VOLUME_BEHAVIOR_FIXED, 6730 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE, 6731 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE, 6732 DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY, 6733 }) 6734 @Retention(RetentionPolicy.SOURCE) 6735 public @interface DeviceVolumeBehavior {} 6736 6737 /** 6738 * @hide 6739 * Sets the volume behavior for an audio output device. 6740 * @see #DEVICE_VOLUME_BEHAVIOR_VARIABLE 6741 * @see #DEVICE_VOLUME_BEHAVIOR_FULL 6742 * @see #DEVICE_VOLUME_BEHAVIOR_FIXED 6743 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE 6744 * @see #DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE 6745 * @param device the device to be affected 6746 * @param deviceVolumeBehavior one of the device behaviors 6747 * 6748 * @deprecated use 6749 * {@link AudioDeviceVolumeManager#setDeviceVolumeBehavior(AudioDeviceAttributes, int)} instead 6750 */ 6751 @SystemApi 6752 @RequiresPermission(anyOf = { 6753 Manifest.permission.MODIFY_AUDIO_ROUTING, 6754 Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED 6755 }) 6756 @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT) setDeviceVolumeBehavior(@onNull AudioDeviceAttributes device, @DeviceVolumeBehavior int deviceVolumeBehavior)6757 public void setDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device, 6758 @DeviceVolumeBehavior int deviceVolumeBehavior) { 6759 // verify arguments (validity of device type is enforced in server) 6760 Objects.requireNonNull(device); 6761 AudioDeviceVolumeManager.enforceValidVolumeBehavior(deviceVolumeBehavior); 6762 // communicate with service 6763 final IAudioService service = getService(); 6764 try { 6765 service.setDeviceVolumeBehavior(device, deviceVolumeBehavior, 6766 mApplicationContext.getOpPackageName()); 6767 } catch (RemoteException e) { 6768 throw e.rethrowFromSystemServer(); 6769 } 6770 } 6771 6772 /** 6773 * @hide 6774 * Controls whether DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY may be returned by 6775 * getDeviceVolumeBehavior. If this is disabled, DEVICE_VOLUME_BEHAVIOR_FULL is returned 6776 * in its place. 6777 */ 6778 @ChangeId 6779 @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.UPSIDE_DOWN_CAKE) 6780 @Overridable 6781 public static final long RETURN_DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY = 240663182L; 6782 6783 /** 6784 * @hide 6785 * Returns the volume device behavior for the given audio device 6786 * @param device the audio device 6787 * @return the volume behavior for the device 6788 * @deprecated use 6789 * {@link AudioDeviceVolumeManager#getDeviceVolumeBehavior(AudioDeviceAttributes)} instead 6790 */ 6791 @SystemApi 6792 @RequiresPermission(anyOf = { 6793 Manifest.permission.MODIFY_AUDIO_ROUTING, 6794 Manifest.permission.QUERY_AUDIO_STATE, 6795 Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED 6796 }) 6797 @FlaggedApi(FLAG_UNIFY_ABSOLUTE_VOLUME_MANAGEMENT) 6798 public @DeviceVolumeBehavior getDeviceVolumeBehavior(@onNull AudioDeviceAttributes device)6799 int getDeviceVolumeBehavior(@NonNull AudioDeviceAttributes device) { 6800 // verify arguments (validity of device type is enforced in server) 6801 Objects.requireNonNull(device); 6802 // communicate with service 6803 final IAudioService service = getService(); 6804 try { 6805 int behavior = service.getDeviceVolumeBehavior(device); 6806 if (!CompatChanges.isChangeEnabled(RETURN_DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY) 6807 && behavior == DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY) { 6808 return AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL; 6809 } 6810 return behavior; 6811 } catch (RemoteException e) { 6812 throw e.rethrowFromSystemServer(); 6813 } 6814 } 6815 6816 /** 6817 * Indicate wired accessory connection state change. 6818 * @param device type of device connected/disconnected (AudioManager.DEVICE_OUT_xxx) 6819 * @param state new connection state: 1 connected, 0 disconnected 6820 * @param name device name 6821 * {@hide} 6822 */ 6823 @UnsupportedAppUsage 6824 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setWiredDeviceConnectionState(int device, int state, String address, String name)6825 public void setWiredDeviceConnectionState(int device, int state, String address, String name) { 6826 AudioDeviceAttributes attributes = new AudioDeviceAttributes(device, address, name); 6827 setWiredDeviceConnectionState(attributes, state); 6828 } 6829 6830 /** 6831 * @hide 6832 * Indicate wired accessory connection state change and attributes. 6833 * @param attributes attributes of the connected device 6834 * @param state new connection state 6835 */ 6836 @SystemApi 6837 @SuppressLint("UnflaggedApi") // b/373465238 6838 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setWiredDeviceConnectionState(@onNull AudioDeviceAttributes attributes, @DeviceConnectionState int state)6839 public void setWiredDeviceConnectionState(@NonNull AudioDeviceAttributes attributes, 6840 @DeviceConnectionState int state) { 6841 final IAudioService service = getService(); 6842 try { 6843 service.setWiredDeviceConnectionState(attributes, state, 6844 mApplicationContext.getOpPackageName()); 6845 } catch (RemoteException e) { 6846 throw e.rethrowFromSystemServer(); 6847 } 6848 } 6849 6850 /** 6851 * Indicate wired accessory connection state change. 6852 * @param device {@link AudioDeviceAttributes} of the device to "fake-connect" 6853 * @param connected true for connected, false for disconnected 6854 * {@hide} 6855 */ 6856 @TestApi 6857 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setTestDeviceConnectionState(@onNull AudioDeviceAttributes device, boolean connected)6858 public void setTestDeviceConnectionState(@NonNull AudioDeviceAttributes device, 6859 boolean connected) { 6860 try { 6861 getService().setTestDeviceConnectionState(device, connected); 6862 } catch (RemoteException e) { 6863 throw e.rethrowFromSystemServer(); 6864 } 6865 } 6866 6867 /** 6868 * Indicate Bluetooth profile connection state change. 6869 * Configuration changes for A2DP are indicated by having the same <code>newDevice</code> and 6870 * <code>previousDevice</code> 6871 * This operation is asynchronous. 6872 * 6873 * @param newDevice Bluetooth device connected or null if there is no new devices 6874 * @param previousDevice Bluetooth device disconnected or null if there is no disconnected 6875 * devices 6876 * @param info contain all info related to the device. {@link BluetoothProfileConnectionInfo} 6877 * {@hide} 6878 */ 6879 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 6880 @RequiresPermission(Manifest.permission.BLUETOOTH_STACK) handleBluetoothActiveDeviceChanged(@ullable BluetoothDevice newDevice, @Nullable BluetoothDevice previousDevice, @NonNull BluetoothProfileConnectionInfo info)6881 public void handleBluetoothActiveDeviceChanged(@Nullable BluetoothDevice newDevice, 6882 @Nullable BluetoothDevice previousDevice, 6883 @NonNull BluetoothProfileConnectionInfo info) { 6884 final IAudioService service = getService(); 6885 try { 6886 service.handleBluetoothActiveDeviceChanged(newDevice, previousDevice, info); 6887 } catch (RemoteException e) { 6888 throw e.rethrowFromSystemServer(); 6889 } 6890 } 6891 6892 /** {@hide} */ getRingtonePlayer()6893 public IRingtonePlayer getRingtonePlayer() { 6894 try { 6895 return getService().getRingtonePlayer(); 6896 } catch (RemoteException e) { 6897 throw e.rethrowFromSystemServer(); 6898 } 6899 } 6900 6901 /** 6902 * Used as a key for {@link #getProperty} to request the native or optimal output sample rate 6903 * for this device's low latency output stream, in decimal Hz. Latency-sensitive apps 6904 * should use this value as a default, and offer the user the option to override it. 6905 * The low latency output stream is typically either the device's primary output stream, 6906 * or another output stream with smaller buffers. 6907 */ 6908 // FIXME Deprecate 6909 public static final String PROPERTY_OUTPUT_SAMPLE_RATE = 6910 "android.media.property.OUTPUT_SAMPLE_RATE"; 6911 6912 /** 6913 * Used as a key for {@link #getProperty} to request the native or optimal output buffer size 6914 * for this device's low latency output stream, in decimal PCM frames. Latency-sensitive apps 6915 * should use this value as a minimum, and offer the user the option to override it. 6916 * The low latency output stream is typically either the device's primary output stream, 6917 * or another output stream with smaller buffers. 6918 */ 6919 // FIXME Deprecate 6920 public static final String PROPERTY_OUTPUT_FRAMES_PER_BUFFER = 6921 "android.media.property.OUTPUT_FRAMES_PER_BUFFER"; 6922 6923 /** 6924 * Used as a key for {@link #getProperty} to determine if the default microphone audio source 6925 * supports near-ultrasound frequencies (range of 18 - 21 kHz). 6926 */ 6927 public static final String PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND = 6928 "android.media.property.SUPPORT_MIC_NEAR_ULTRASOUND"; 6929 6930 /** 6931 * Used as a key for {@link #getProperty} to determine if the default speaker audio path 6932 * supports near-ultrasound frequencies (range of 18 - 21 kHz). 6933 */ 6934 public static final String PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND = 6935 "android.media.property.SUPPORT_SPEAKER_NEAR_ULTRASOUND"; 6936 6937 /** 6938 * Used as a key for {@link #getProperty} to determine if the unprocessed audio source is 6939 * available and supported with the expected frequency range and level response. 6940 */ 6941 public static final String PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED = 6942 "android.media.property.SUPPORT_AUDIO_SOURCE_UNPROCESSED"; 6943 /** 6944 * Returns the value of the property with the specified key. 6945 * @param key One of the strings corresponding to a property key: either 6946 * {@link #PROPERTY_OUTPUT_SAMPLE_RATE}, 6947 * {@link #PROPERTY_OUTPUT_FRAMES_PER_BUFFER}, 6948 * {@link #PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND}, 6949 * {@link #PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND}, or 6950 * {@link #PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED}. 6951 * @return A string representing the associated value for that property key, 6952 * or null if there is no value for that key. 6953 */ getProperty(String key)6954 public String getProperty(String key) { 6955 if (PROPERTY_OUTPUT_SAMPLE_RATE.equals(key)) { 6956 int outputSampleRate = AudioSystem.getPrimaryOutputSamplingRate(); 6957 return outputSampleRate > 0 ? Integer.toString(outputSampleRate) : null; 6958 } else if (PROPERTY_OUTPUT_FRAMES_PER_BUFFER.equals(key)) { 6959 int outputFramesPerBuffer = AudioSystem.getPrimaryOutputFrameCount(); 6960 return outputFramesPerBuffer > 0 ? Integer.toString(outputFramesPerBuffer) : null; 6961 } else if (PROPERTY_SUPPORT_MIC_NEAR_ULTRASOUND.equals(key)) { 6962 // Will throw a RuntimeException Resources.NotFoundException if this config value is 6963 // not found. 6964 return String.valueOf(getContext().getResources().getBoolean( 6965 com.android.internal.R.bool.config_supportMicNearUltrasound)); 6966 } else if (PROPERTY_SUPPORT_SPEAKER_NEAR_ULTRASOUND.equals(key)) { 6967 return String.valueOf(getContext().getResources().getBoolean( 6968 com.android.internal.R.bool.config_supportSpeakerNearUltrasound)); 6969 } else if (PROPERTY_SUPPORT_AUDIO_SOURCE_UNPROCESSED.equals(key)) { 6970 return String.valueOf(getContext().getResources().getBoolean( 6971 com.android.internal.R.bool.config_supportAudioSourceUnprocessed)); 6972 } else { 6973 // null or unknown key 6974 return null; 6975 } 6976 } 6977 6978 /** 6979 * @hide 6980 * Sets an additional audio output device delay in milliseconds. 6981 * 6982 * The additional output delay is a request to the output device to 6983 * delay audio presentation (generally with respect to video presentation for better 6984 * synchronization). 6985 * It may not be supported by all output devices, 6986 * and typically increases the audio latency by the amount of additional 6987 * audio delay requested. 6988 * 6989 * If additional audio delay is supported by an audio output device, 6990 * it is expected to be supported for all output streams (and configurations) 6991 * opened on that device. 6992 * 6993 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}. 6994 * @param delayMillis delay in milliseconds desired. This should be in range of {@code 0} 6995 * to the value returned by {@link #getMaxAdditionalOutputDeviceDelay()}. 6996 * @return true if successful, false if the device does not support output device delay 6997 * or the delay is not in range of {@link #getMaxAdditionalOutputDeviceDelay()}. 6998 */ 6999 @SystemApi 7000 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setAdditionalOutputDeviceDelay( @onNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis)7001 public boolean setAdditionalOutputDeviceDelay( 7002 @NonNull AudioDeviceInfo device, @IntRange(from = 0) long delayMillis) { 7003 Objects.requireNonNull(device); 7004 try { 7005 return getService().setAdditionalOutputDeviceDelay( 7006 new AudioDeviceAttributes(device), delayMillis); 7007 } catch (RemoteException e) { 7008 throw e.rethrowFromSystemServer(); 7009 } 7010 } 7011 7012 /** 7013 * @hide 7014 * Returns the current additional audio output device delay in milliseconds. 7015 * 7016 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}. 7017 * @return the additional output device delay. This is a non-negative number. 7018 * {@code 0} is returned if unsupported. 7019 */ 7020 @SystemApi 7021 @IntRange(from = 0) getAdditionalOutputDeviceDelay(@onNull AudioDeviceInfo device)7022 public long getAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) { 7023 Objects.requireNonNull(device); 7024 try { 7025 return getService().getAdditionalOutputDeviceDelay(new AudioDeviceAttributes(device)); 7026 } catch (RemoteException e) { 7027 throw e.rethrowFromSystemServer(); 7028 } 7029 } 7030 7031 /** 7032 * @hide 7033 * Returns the maximum additional audio output device delay in milliseconds. 7034 * 7035 * @param device an instance of {@link AudioDeviceInfo} returned from {@link getDevices()}. 7036 * @return the maximum output device delay in milliseconds that can be set. 7037 * This is a non-negative number 7038 * representing the additional audio delay supported for the device. 7039 * {@code 0} is returned if unsupported. 7040 */ 7041 @SystemApi 7042 @IntRange(from = 0) getMaxAdditionalOutputDeviceDelay(@onNull AudioDeviceInfo device)7043 public long getMaxAdditionalOutputDeviceDelay(@NonNull AudioDeviceInfo device) { 7044 Objects.requireNonNull(device); 7045 try { 7046 return getService().getMaxAdditionalOutputDeviceDelay( 7047 new AudioDeviceAttributes(device)); 7048 } catch (RemoteException e) { 7049 throw e.rethrowFromSystemServer(); 7050 } 7051 } 7052 7053 /** 7054 * Returns the estimated latency for the given stream type in milliseconds. 7055 * 7056 * DO NOT UNHIDE. The existing approach for doing A/V sync has too many problems. We need 7057 * a better solution. 7058 * @hide 7059 */ 7060 @UnsupportedAppUsage getOutputLatency(int streamType)7061 public int getOutputLatency(int streamType) { 7062 return AudioSystem.getOutputLatency(streamType); 7063 } 7064 7065 /** 7066 * Registers a global volume controller interface. Currently limited to SystemUI. 7067 * 7068 * @hide 7069 */ setVolumeController(IVolumeController controller)7070 public void setVolumeController(IVolumeController controller) { 7071 try { 7072 getService().setVolumeController(controller); 7073 } catch (RemoteException e) { 7074 throw e.rethrowFromSystemServer(); 7075 } 7076 } 7077 7078 /** 7079 * Returns the registered volume controller interface. 7080 * 7081 * @hide 7082 */ 7083 @Nullable getVolumeController()7084 public IVolumeController getVolumeController() { 7085 try { 7086 return getService().getVolumeController(); 7087 } catch (RemoteException e) { 7088 throw e.rethrowFromSystemServer(); 7089 } 7090 } 7091 7092 /** 7093 * Notify audio manager about volume controller visibility changes. 7094 * Currently limited to SystemUI. 7095 * 7096 * @hide 7097 */ notifyVolumeControllerVisible(IVolumeController controller, boolean visible)7098 public void notifyVolumeControllerVisible(IVolumeController controller, boolean visible) { 7099 try { 7100 getService().notifyVolumeControllerVisible(controller, visible); 7101 } catch (RemoteException e) { 7102 throw e.rethrowFromSystemServer(); 7103 } 7104 } 7105 7106 /** 7107 * Test method for enabling/disabling the volume controller long press timeout for checking 7108 * whether two consecutive volume adjustments should be treated as a volume long press. 7109 * 7110 * <p>Used only for testing 7111 * 7112 * @param enable true for enabling, otherwise will be disabled (test mode) 7113 * 7114 * @hide 7115 **/ 7116 @TestApi 7117 @SuppressLint("UnflaggedApi") // @TestApi without associated feature. 7118 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) setVolumeControllerLongPressTimeoutEnabled(boolean enable)7119 public void setVolumeControllerLongPressTimeoutEnabled(boolean enable) { 7120 try { 7121 getService().setVolumeControllerLongPressTimeoutEnabled(enable); 7122 } catch (RemoteException e) { 7123 throw e.rethrowFromSystemServer(); 7124 } 7125 } 7126 7127 /** 7128 * Only useful for volume controllers. 7129 * @hide 7130 */ isStreamAffectedByRingerMode(int streamType)7131 public boolean isStreamAffectedByRingerMode(int streamType) { 7132 try { 7133 return getService().isStreamAffectedByRingerMode(streamType); 7134 } catch (RemoteException e) { 7135 throw e.rethrowFromSystemServer(); 7136 } 7137 } 7138 7139 /** 7140 * Only useful for volume controllers. 7141 * @hide 7142 */ isStreamAffectedByMute(int streamType)7143 public boolean isStreamAffectedByMute(int streamType) { 7144 try { 7145 return getService().isStreamAffectedByMute(streamType); 7146 } catch (RemoteException e) { 7147 throw e.rethrowFromSystemServer(); 7148 } 7149 } 7150 7151 /** 7152 * Check whether a user can mute this stream type from a given UI element. 7153 * 7154 * <p>Only useful for volume controllers. 7155 * 7156 * @param streamType type of stream to check if it's mutable from UI 7157 * 7158 * @hide 7159 */ isStreamMutableByUi(int streamType)7160 public boolean isStreamMutableByUi(int streamType) { 7161 try { 7162 return getService().isStreamMutableByUi(streamType); 7163 } catch (RemoteException e) { 7164 throw e.rethrowFromSystemServer(); 7165 } 7166 } 7167 7168 /** 7169 * Only useful for volume controllers. 7170 * @hide 7171 */ disableSafeMediaVolume()7172 public void disableSafeMediaVolume() { 7173 try { 7174 getService().disableSafeMediaVolume(mApplicationContext.getOpPackageName()); 7175 } catch (RemoteException e) { 7176 throw e.rethrowFromSystemServer(); 7177 } 7178 } 7179 7180 /** 7181 * @hide 7182 * Lower media volume to RS1 interval 7183 */ lowerVolumeToRs1()7184 public void lowerVolumeToRs1() { 7185 try { 7186 getService().lowerVolumeToRs1(mApplicationContext.getOpPackageName()); 7187 } catch (RemoteException e) { 7188 throw e.rethrowFromSystemServer(); 7189 } 7190 } 7191 7192 /** 7193 * @hide 7194 * @return the RS2 upper bound used for momentary exposure warnings 7195 */ 7196 @TestApi 7197 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) getRs2Value()7198 public float getRs2Value() { 7199 try { 7200 return getService().getOutputRs2UpperBound(); 7201 } catch (RemoteException e) { 7202 throw e.rethrowFromSystemServer(); 7203 } 7204 } 7205 7206 /** 7207 * @hide 7208 * Sets the RS2 upper bound used for momentary exposure warnings 7209 */ 7210 @TestApi 7211 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) setRs2Value(float rs2Value)7212 public void setRs2Value(float rs2Value) { 7213 try { 7214 getService().setOutputRs2UpperBound(rs2Value); 7215 } catch (RemoteException e) { 7216 throw e.rethrowFromSystemServer(); 7217 } 7218 } 7219 7220 /** 7221 * @hide 7222 * @return the current computed sound dose value 7223 */ 7224 @TestApi 7225 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) getCsd()7226 public float getCsd() { 7227 try { 7228 return getService().getCsd(); 7229 } catch (RemoteException e) { 7230 throw e.rethrowFromSystemServer(); 7231 } 7232 } 7233 7234 /** 7235 * @hide 7236 * Sets the computed sound dose value to {@code csd}. A negative value will 7237 * reset all the CSD related timeouts: after a momentary exposure warning and 7238 * before the momentary exposure reaches RS2 (see IEC62368-1 10.6.5) 7239 */ 7240 @TestApi 7241 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) setCsd(float csd)7242 public void setCsd(float csd) { 7243 try { 7244 getService().setCsd(csd); 7245 } catch (RemoteException e) { 7246 throw e.rethrowFromSystemServer(); 7247 } 7248 } 7249 7250 /** 7251 * @hide 7252 * Forces the computation of MEL values (used for CSD) on framework level. This will have the 7253 * result of ignoring the MEL values computed on HAL level. Should only be used in testing 7254 * since this can affect the certification of a device with EN50332-3 regulation. 7255 */ 7256 @TestApi 7257 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) forceUseFrameworkMel(boolean useFrameworkMel)7258 public void forceUseFrameworkMel(boolean useFrameworkMel) { 7259 try { 7260 getService().forceUseFrameworkMel(useFrameworkMel); 7261 } catch (RemoteException e) { 7262 throw e.rethrowFromSystemServer(); 7263 } 7264 } 7265 7266 /** 7267 * @hide 7268 * Forces the computation of CSD on all output devices. 7269 */ 7270 @TestApi 7271 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) forceComputeCsdOnAllDevices(boolean computeCsdOnAllDevices)7272 public void forceComputeCsdOnAllDevices(boolean computeCsdOnAllDevices) { 7273 try { 7274 getService().forceComputeCsdOnAllDevices(computeCsdOnAllDevices); 7275 } catch (RemoteException e) { 7276 throw e.rethrowFromSystemServer(); 7277 } 7278 } 7279 7280 /** 7281 * @hide 7282 * Returns whether CSD is enabled and supported by the current active audio module HAL. 7283 * This method will return {@code false) for setups in which CSD as a feature is available 7284 * (see {@link AudioManager#isCsdAsAFeatureAvailable()}) and not enabled (see 7285 * {@link AudioManager#isCsdAsAFeatureEnabled()}). 7286 */ 7287 @TestApi 7288 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) isCsdEnabled()7289 public boolean isCsdEnabled() { 7290 try { 7291 return getService().isCsdEnabled(); 7292 } catch (RemoteException e) { 7293 throw e.rethrowFromSystemServer(); 7294 } 7295 } 7296 7297 /** 7298 * @hide 7299 * Returns whether CSD as a feature can be manipulated by a client. This method 7300 * returns {@code true} in countries where there isn't a safe hearing regulation 7301 * enforced. 7302 */ 7303 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) isCsdAsAFeatureAvailable()7304 public boolean isCsdAsAFeatureAvailable() { 7305 try { 7306 return getService().isCsdAsAFeatureAvailable(); 7307 } catch (RemoteException e) { 7308 throw e.rethrowFromSystemServer(); 7309 } 7310 } 7311 7312 /** 7313 * @hide 7314 * Returns {@code true} if the client has enabled CSD. This function should only 7315 * be called if {@link AudioManager#isCsdAsAFeatureAvailable()} returns {@code true}. 7316 */ 7317 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) isCsdAsAFeatureEnabled()7318 public boolean isCsdAsAFeatureEnabled() { 7319 try { 7320 return getService().isCsdAsAFeatureEnabled(); 7321 } catch (RemoteException e) { 7322 throw e.rethrowFromSystemServer(); 7323 } 7324 } 7325 7326 /** 7327 * @hide 7328 * Enables/disables the CSD feature. This function should only be called if 7329 * {@link AudioManager#isCsdAsAFeatureAvailable()} returns {@code true}. 7330 */ 7331 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) setCsdAsAFeatureEnabled(boolean csdToggleValue)7332 public void setCsdAsAFeatureEnabled(boolean csdToggleValue) { 7333 try { 7334 getService().setCsdAsAFeatureEnabled(csdToggleValue); 7335 } catch (RemoteException e) { 7336 throw e.rethrowFromSystemServer(); 7337 } 7338 } 7339 7340 /** 7341 * @hide 7342 * Describes an audio device that has not been categorized with a specific 7343 * audio type. 7344 */ 7345 public static final int AUDIO_DEVICE_CATEGORY_UNKNOWN = 0; 7346 7347 /** 7348 * @hide 7349 * Describes an audio device which is categorized as something different. 7350 */ 7351 public static final int AUDIO_DEVICE_CATEGORY_OTHER = 1; 7352 7353 /** 7354 * @hide 7355 * Describes an audio device which was categorized as speakers. 7356 */ 7357 public static final int AUDIO_DEVICE_CATEGORY_SPEAKER = 2; 7358 7359 /** 7360 * @hide 7361 * Describes an audio device which was categorized as headphones. 7362 */ 7363 public static final int AUDIO_DEVICE_CATEGORY_HEADPHONES = 3; 7364 7365 /** 7366 * @hide 7367 * Describes an audio device which was categorized as car-kit. 7368 */ 7369 public static final int AUDIO_DEVICE_CATEGORY_CARKIT = 4; 7370 7371 /** 7372 * @hide 7373 * Describes an audio device which was categorized as watch. 7374 */ 7375 public static final int AUDIO_DEVICE_CATEGORY_WATCH = 5; 7376 7377 /** 7378 * @hide 7379 * Describes an audio device which was categorized as hearing aid. 7380 */ 7381 public static final int AUDIO_DEVICE_CATEGORY_HEARING_AID = 6; 7382 7383 /** 7384 * @hide 7385 * Describes an audio device which was categorized as receiver. 7386 */ 7387 public static final int AUDIO_DEVICE_CATEGORY_RECEIVER = 7; 7388 7389 /** @hide */ 7390 @IntDef(flag = false, prefix = "AUDIO_DEVICE_CATEGORY", value = { 7391 AUDIO_DEVICE_CATEGORY_UNKNOWN, 7392 AUDIO_DEVICE_CATEGORY_OTHER, 7393 AUDIO_DEVICE_CATEGORY_SPEAKER, 7394 AUDIO_DEVICE_CATEGORY_HEADPHONES, 7395 AUDIO_DEVICE_CATEGORY_CARKIT, 7396 AUDIO_DEVICE_CATEGORY_WATCH, 7397 AUDIO_DEVICE_CATEGORY_HEARING_AID, 7398 AUDIO_DEVICE_CATEGORY_RECEIVER } 7399 ) 7400 @Retention(RetentionPolicy.SOURCE) 7401 public @interface AudioDeviceCategory {} 7402 7403 /** @hide */ audioDeviceCategoryToString(int audioDeviceCategory)7404 public static String audioDeviceCategoryToString(int audioDeviceCategory) { 7405 switch (audioDeviceCategory) { 7406 case AUDIO_DEVICE_CATEGORY_UNKNOWN: return "AUDIO_DEVICE_CATEGORY_UNKNOWN"; 7407 case AUDIO_DEVICE_CATEGORY_OTHER: return "AUDIO_DEVICE_CATEGORY_OTHER"; 7408 case AUDIO_DEVICE_CATEGORY_SPEAKER: return "AUDIO_DEVICE_CATEGORY_SPEAKER"; 7409 case AUDIO_DEVICE_CATEGORY_HEADPHONES: return "AUDIO_DEVICE_CATEGORY_HEADPHONES"; 7410 case AUDIO_DEVICE_CATEGORY_CARKIT: return "AUDIO_DEVICE_CATEGORY_CARKIT"; 7411 case AUDIO_DEVICE_CATEGORY_WATCH: return "AUDIO_DEVICE_CATEGORY_WATCH"; 7412 case AUDIO_DEVICE_CATEGORY_HEARING_AID: return "AUDIO_DEVICE_CATEGORY_HEARING_AID"; 7413 case AUDIO_DEVICE_CATEGORY_RECEIVER: return "AUDIO_DEVICE_CATEGORY_RECEIVER"; 7414 default: 7415 return new StringBuilder("unknown AudioDeviceCategory ").append( 7416 audioDeviceCategory).toString(); 7417 } 7418 } 7419 7420 /** 7421 * @hide 7422 * Sets the audio device type of a Bluetooth device given its MAC address 7423 * 7424 * @return {@code true} if the device type was set successfully. If the 7425 * audio device type was automatically identified this method will 7426 * return {@code false}. 7427 */ 7428 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) setBluetoothAudioDeviceCategory(@onNull String address, @AudioDeviceCategory int btAudioDeviceCategory)7429 public boolean setBluetoothAudioDeviceCategory(@NonNull String address, 7430 @AudioDeviceCategory int btAudioDeviceCategory) { 7431 try { 7432 return getService().setBluetoothAudioDeviceCategory(address, btAudioDeviceCategory); 7433 } catch (RemoteException e) { 7434 throw e.rethrowFromSystemServer(); 7435 } 7436 } 7437 7438 /** 7439 * @hide 7440 * Gets the audio device type of a Bluetooth device given its MAC address 7441 */ 7442 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) 7443 @AudioDeviceCategory getBluetoothAudioDeviceCategory(@onNull String address)7444 public int getBluetoothAudioDeviceCategory(@NonNull String address) { 7445 try { 7446 return getService().getBluetoothAudioDeviceCategory(address); 7447 } catch (RemoteException e) { 7448 throw e.rethrowFromSystemServer(); 7449 } 7450 } 7451 7452 /** 7453 * @hide 7454 * Returns {@code true} if the audio device type of a Bluetooth device can 7455 * be automatically identified 7456 */ 7457 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) isBluetoothAudioDeviceCategoryFixed(@onNull String address)7458 public boolean isBluetoothAudioDeviceCategoryFixed(@NonNull String address) { 7459 try { 7460 return getService().isBluetoothAudioDeviceCategoryFixed(address); 7461 } catch (RemoteException e) { 7462 throw e.rethrowFromSystemServer(); 7463 } 7464 } 7465 7466 /** 7467 * @hide 7468 * Sound dose warning at every 100% of dose during integration window 7469 */ 7470 public static final int CSD_WARNING_DOSE_REACHED_1X = 1; 7471 /** 7472 * @hide 7473 * Sound dose warning when 500% of dose is reached during integration window 7474 */ 7475 public static final int CSD_WARNING_DOSE_REPEATED_5X = 2; 7476 /** 7477 * @hide 7478 * Sound dose warning after a momentary exposure event 7479 */ 7480 public static final int CSD_WARNING_MOMENTARY_EXPOSURE = 3; 7481 /** 7482 * @hide 7483 * Sound dose warning at every 100% of dose during integration window 7484 */ 7485 public static final int CSD_WARNING_ACCUMULATION_START = 4; 7486 7487 /** @hide */ 7488 @IntDef(flag = false, value = { 7489 CSD_WARNING_DOSE_REACHED_1X, 7490 CSD_WARNING_DOSE_REPEATED_5X, 7491 CSD_WARNING_MOMENTARY_EXPOSURE, 7492 CSD_WARNING_ACCUMULATION_START } 7493 ) 7494 @Retention(RetentionPolicy.SOURCE) 7495 public @interface CsdWarning {} 7496 7497 /** 7498 * Only useful for volume controllers. 7499 * @hide 7500 */ 7501 @UnsupportedAppUsage setRingerModeInternal(int ringerMode)7502 public void setRingerModeInternal(int ringerMode) { 7503 try { 7504 getService().setRingerModeInternal(ringerMode, getContext().getOpPackageName()); 7505 } catch (RemoteException e) { 7506 throw e.rethrowFromSystemServer(); 7507 } 7508 } 7509 7510 /** 7511 * Only useful for volume controllers. 7512 * @hide 7513 */ 7514 @UnsupportedAppUsage getRingerModeInternal()7515 public int getRingerModeInternal() { 7516 try { 7517 return getService().getRingerModeInternal(); 7518 } catch (RemoteException e) { 7519 throw e.rethrowFromSystemServer(); 7520 } 7521 } 7522 7523 /** 7524 * Only useful for volume controllers. 7525 * @hide 7526 */ setVolumePolicy(VolumePolicy policy)7527 public void setVolumePolicy(VolumePolicy policy) { 7528 try { 7529 getService().setVolumePolicy(policy); 7530 } catch (RemoteException e) { 7531 throw e.rethrowFromSystemServer(); 7532 } 7533 } 7534 7535 /** 7536 * @hide 7537 * Queries the volume policy 7538 * @return the volume policy currently in use 7539 */ 7540 @TestApi 7541 @SuppressLint("UnflaggedApi") // @TestApi without associated feature. getVolumePolicy()7542 public @NonNull VolumePolicy getVolumePolicy() { 7543 try { 7544 return getService().getVolumePolicy(); 7545 } catch (RemoteException e) { 7546 throw e.rethrowFromSystemServer(); 7547 } 7548 } 7549 7550 /** 7551 * Set Hdmi Cec system audio mode. 7552 * 7553 * @param on whether to be on system audio mode 7554 * @return output device type. 0 (DEVICE_NONE) if failed to set device. 7555 * @hide 7556 */ setHdmiSystemAudioSupported(boolean on)7557 public int setHdmiSystemAudioSupported(boolean on) { 7558 try { 7559 return getService().setHdmiSystemAudioSupported(on); 7560 } catch (RemoteException e) { 7561 throw e.rethrowFromSystemServer(); 7562 } 7563 } 7564 7565 /** 7566 * Returns true if Hdmi Cec system audio mode is supported. 7567 * 7568 * @hide 7569 */ 7570 @SystemApi 7571 @SuppressLint("RequiresPermission") // FIXME is this still used? isHdmiSystemAudioSupported()7572 public boolean isHdmiSystemAudioSupported() { 7573 try { 7574 return getService().isHdmiSystemAudioSupported(); 7575 } catch (RemoteException e) { 7576 throw e.rethrowFromSystemServer(); 7577 } 7578 } 7579 7580 /** 7581 * Return codes for listAudioPorts(), createAudioPatch() ... 7582 */ 7583 7584 /** @hide */ 7585 @SystemApi 7586 public static final int SUCCESS = AudioSystem.SUCCESS; 7587 /** 7588 * A default error code. 7589 */ 7590 public static final int ERROR = AudioSystem.ERROR; 7591 /** @hide 7592 * CANDIDATE FOR PUBLIC API 7593 */ 7594 public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE; 7595 /** @hide 7596 */ 7597 public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION; 7598 /** @hide 7599 */ 7600 public static final int ERROR_PERMISSION_DENIED = AudioSystem.PERMISSION_DENIED; 7601 /** @hide 7602 */ 7603 public static final int ERROR_NO_INIT = AudioSystem.NO_INIT; 7604 /** 7605 * An error code indicating that the object reporting it is no longer valid and needs to 7606 * be recreated. 7607 */ 7608 public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT; 7609 7610 /** 7611 * Returns a list of descriptors for all audio ports managed by the audio framework. 7612 * Audio ports are nodes in the audio framework or audio hardware that can be configured 7613 * or connected and disconnected with createAudioPatch() or releaseAudioPatch(). 7614 * See AudioPort for a list of attributes of each audio port. 7615 * @param ports An AudioPort ArrayList where the list will be returned. 7616 * @hide 7617 */ 7618 @UnsupportedAppUsage listAudioPorts(ArrayList<AudioPort> ports)7619 public static int listAudioPorts(ArrayList<AudioPort> ports) { 7620 return updateAudioPortCache(ports, null, null); 7621 } 7622 7623 /** 7624 * Returns a list of descriptors for all audio ports managed by the audio framework as 7625 * it was before the last update calback. 7626 * @param ports An AudioPort ArrayList where the list will be returned. 7627 * @hide 7628 */ listPreviousAudioPorts(ArrayList<AudioPort> ports)7629 public static int listPreviousAudioPorts(ArrayList<AudioPort> ports) { 7630 return updateAudioPortCache(null, null, ports); 7631 } 7632 7633 /** 7634 * Specialized version of listAudioPorts() listing only audio devices (AudioDevicePort) 7635 * @see listAudioPorts(ArrayList<AudioPort>) 7636 * @hide 7637 */ listAudioDevicePorts(ArrayList<AudioDevicePort> devices)7638 public static int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) { 7639 if (devices == null) { 7640 return ERROR_BAD_VALUE; 7641 } 7642 ArrayList<AudioPort> ports = new ArrayList<AudioPort>(); 7643 int status = updateAudioPortCache(ports, null, null); 7644 if (status == SUCCESS) { 7645 filterDevicePorts(ports, devices); 7646 } 7647 return status; 7648 } 7649 7650 /** 7651 * Specialized version of listPreviousAudioPorts() listing only audio devices (AudioDevicePort) 7652 * @see listPreviousAudioPorts(ArrayList<AudioPort>) 7653 * @hide 7654 */ listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices)7655 public static int listPreviousAudioDevicePorts(ArrayList<AudioDevicePort> devices) { 7656 if (devices == null) { 7657 return ERROR_BAD_VALUE; 7658 } 7659 ArrayList<AudioPort> ports = new ArrayList<AudioPort>(); 7660 int status = updateAudioPortCache(null, null, ports); 7661 if (status == SUCCESS) { 7662 filterDevicePorts(ports, devices); 7663 } 7664 return status; 7665 } 7666 filterDevicePorts(ArrayList<AudioPort> ports, ArrayList<AudioDevicePort> devices)7667 private static void filterDevicePorts(ArrayList<AudioPort> ports, 7668 ArrayList<AudioDevicePort> devices) { 7669 devices.clear(); 7670 for (int i = 0; i < ports.size(); i++) { 7671 if (ports.get(i) instanceof AudioDevicePort) { 7672 devices.add((AudioDevicePort)ports.get(i)); 7673 } 7674 } 7675 } 7676 7677 /** 7678 * Create a connection between two or more devices. The framework will reject the request if 7679 * device types are not compatible or the implementation does not support the requested 7680 * configuration. 7681 * NOTE: current implementation is limited to one source and one sink per patch. 7682 * @param patch AudioPatch array where the newly created patch will be returned. 7683 * As input, if patch[0] is not null, the specified patch will be replaced by the 7684 * new patch created. This avoids calling releaseAudioPatch() when modifying a 7685 * patch and allows the implementation to optimize transitions. 7686 * @param sources List of source audio ports. All must be AudioPort.ROLE_SOURCE. 7687 * @param sinks List of sink audio ports. All must be AudioPort.ROLE_SINK. 7688 * 7689 * @return - {@link #SUCCESS} if connection is successful. 7690 * - {@link #ERROR_BAD_VALUE} if incompatible device types are passed. 7691 * - {@link #ERROR_INVALID_OPERATION} if the requested connection is not supported. 7692 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to create 7693 * a patch. 7694 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead 7695 * - {@link #ERROR} if patch cannot be connected for any other reason. 7696 * 7697 * patch[0] contains the newly created patch 7698 * @hide 7699 */ 7700 @UnsupportedAppUsage createAudioPatch(AudioPatch[] patch, AudioPortConfig[] sources, AudioPortConfig[] sinks)7701 public static int createAudioPatch(AudioPatch[] patch, 7702 AudioPortConfig[] sources, 7703 AudioPortConfig[] sinks) { 7704 return AudioSystem.createAudioPatch(patch, sources, sinks); 7705 } 7706 7707 /** 7708 * Releases an existing audio patch connection. 7709 * @param patch The audio patch to disconnect. 7710 * @return - {@link #SUCCESS} if disconnection is successful. 7711 * - {@link #ERROR_BAD_VALUE} if the specified patch does not exist. 7712 * - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to release 7713 * a patch. 7714 * - {@link #ERROR_DEAD_OBJECT} if the server process is dead 7715 * - {@link #ERROR} if patch cannot be released for any other reason. 7716 * @hide 7717 */ 7718 @UnsupportedAppUsage releaseAudioPatch(AudioPatch patch)7719 public static int releaseAudioPatch(AudioPatch patch) { 7720 return AudioSystem.releaseAudioPatch(patch); 7721 } 7722 7723 /** 7724 * List all existing connections between audio ports. 7725 * @param patches An AudioPatch array where the list will be returned. 7726 * @hide 7727 */ 7728 @UnsupportedAppUsage listAudioPatches(ArrayList<AudioPatch> patches)7729 public static int listAudioPatches(ArrayList<AudioPatch> patches) { 7730 return updateAudioPortCache(null, patches, null); 7731 } 7732 7733 /** 7734 * Set the gain on the specified AudioPort. The AudioGainConfig config is build by 7735 * AudioGain.buildConfig() 7736 * @hide 7737 */ setAudioPortGain(AudioPort port, AudioGainConfig gain)7738 public static int setAudioPortGain(AudioPort port, AudioGainConfig gain) { 7739 if (port == null || gain == null) { 7740 return ERROR_BAD_VALUE; 7741 } 7742 AudioPortConfig activeConfig = port.activeConfig(); 7743 AudioPortConfig config = new AudioPortConfig(port, activeConfig.samplingRate(), 7744 activeConfig.channelMask(), activeConfig.format(), gain); 7745 config.mConfigMask = AudioPortConfig.GAIN; 7746 return AudioSystem.setAudioPortConfig(config); 7747 } 7748 7749 /** 7750 * Listener registered by client to be notified upon new audio port connections, 7751 * disconnections or attributes update. 7752 * @hide 7753 */ 7754 public interface OnAudioPortUpdateListener { 7755 /** 7756 * Callback method called upon audio port list update. 7757 * @param portList the updated list of audio ports 7758 */ onAudioPortListUpdate(AudioPort[] portList)7759 public void onAudioPortListUpdate(AudioPort[] portList); 7760 7761 /** 7762 * Callback method called upon audio patch list update. 7763 * @param patchList the updated list of audio patches 7764 */ onAudioPatchListUpdate(AudioPatch[] patchList)7765 public void onAudioPatchListUpdate(AudioPatch[] patchList); 7766 7767 /** 7768 * Callback method called when the mediaserver dies 7769 */ onServiceDied()7770 public void onServiceDied(); 7771 } 7772 7773 /** 7774 * Register an audio port list update listener. 7775 * @hide 7776 */ 7777 @UnsupportedAppUsage registerAudioPortUpdateListener(OnAudioPortUpdateListener l)7778 public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) { 7779 sAudioPortEventHandler.init(); 7780 sAudioPortEventHandler.registerListener(l); 7781 } 7782 7783 /** 7784 * Unregister an audio port list update listener. 7785 * @hide 7786 */ 7787 @UnsupportedAppUsage unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l)7788 public void unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l) { 7789 sAudioPortEventHandler.unregisterListener(l); 7790 } 7791 7792 // 7793 // AudioPort implementation 7794 // 7795 7796 private static final int AUDIOPORT_GENERATION_INIT = 0; 7797 private static Object sAudioPortGenerationLock = new Object(); 7798 @GuardedBy("sAudioPortGenerationLock") 7799 private static int sAudioPortGeneration = AUDIOPORT_GENERATION_INIT; 7800 private static ArrayList<AudioPort> sAudioPortsCached = new ArrayList<AudioPort>(); 7801 private static ArrayList<AudioPort> sPreviousAudioPortsCached = new ArrayList<AudioPort>(); 7802 private static ArrayList<AudioPatch> sAudioPatchesCached = new ArrayList<AudioPatch>(); 7803 resetAudioPortGeneration()7804 static int resetAudioPortGeneration() { 7805 int generation; 7806 synchronized (sAudioPortGenerationLock) { 7807 generation = sAudioPortGeneration; 7808 sAudioPortGeneration = AUDIOPORT_GENERATION_INIT; 7809 } 7810 return generation; 7811 } 7812 updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches, ArrayList<AudioPort> previousPorts)7813 static int updateAudioPortCache(ArrayList<AudioPort> ports, ArrayList<AudioPatch> patches, 7814 ArrayList<AudioPort> previousPorts) { 7815 sAudioPortEventHandler.init(); 7816 synchronized (sAudioPortGenerationLock) { 7817 7818 if (sAudioPortGeneration == AUDIOPORT_GENERATION_INIT) { 7819 int[] patchGeneration = new int[1]; 7820 int[] portGeneration = new int[1]; 7821 int status; 7822 ArrayList<AudioPort> newPorts = new ArrayList<AudioPort>(); 7823 ArrayList<AudioPatch> newPatches = new ArrayList<AudioPatch>(); 7824 7825 do { 7826 newPorts.clear(); 7827 status = AudioSystem.listAudioPorts(newPorts, portGeneration); 7828 if (status != SUCCESS) { 7829 Log.w(TAG, "updateAudioPortCache: listAudioPorts failed"); 7830 return status; 7831 } 7832 newPatches.clear(); 7833 status = AudioSystem.listAudioPatches(newPatches, patchGeneration); 7834 if (status != SUCCESS) { 7835 Log.w(TAG, "updateAudioPortCache: listAudioPatches failed"); 7836 return status; 7837 } 7838 // Loop until patch generation is the same as port generation unless audio ports 7839 // and audio patches are not null. 7840 } while (patchGeneration[0] != portGeneration[0] 7841 && (ports == null || patches == null)); 7842 // If the patch generation doesn't equal port generation, return ERROR here in case 7843 // of mismatch between audio ports and audio patches. 7844 if (patchGeneration[0] != portGeneration[0]) { 7845 return ERROR; 7846 } 7847 7848 for (int i = 0; i < newPatches.size(); i++) { 7849 for (int j = 0; j < newPatches.get(i).sources().length; j++) { 7850 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sources()[j], 7851 newPorts); 7852 newPatches.get(i).sources()[j] = portCfg; 7853 } 7854 for (int j = 0; j < newPatches.get(i).sinks().length; j++) { 7855 AudioPortConfig portCfg = updatePortConfig(newPatches.get(i).sinks()[j], 7856 newPorts); 7857 newPatches.get(i).sinks()[j] = portCfg; 7858 } 7859 } 7860 for (Iterator<AudioPatch> i = newPatches.iterator(); i.hasNext(); ) { 7861 AudioPatch newPatch = i.next(); 7862 boolean hasInvalidPort = false; 7863 for (AudioPortConfig portCfg : newPatch.sources()) { 7864 if (portCfg == null) { 7865 hasInvalidPort = true; 7866 break; 7867 } 7868 } 7869 for (AudioPortConfig portCfg : newPatch.sinks()) { 7870 if (portCfg == null) { 7871 hasInvalidPort = true; 7872 break; 7873 } 7874 } 7875 if (hasInvalidPort) { 7876 // Temporarily remove patches with invalid ports. One who created the patch 7877 // is responsible for dealing with the port change. 7878 i.remove(); 7879 } 7880 } 7881 7882 sPreviousAudioPortsCached = sAudioPortsCached; 7883 sAudioPortsCached = newPorts; 7884 sAudioPatchesCached = newPatches; 7885 sAudioPortGeneration = portGeneration[0]; 7886 } 7887 if (ports != null) { 7888 ports.clear(); 7889 ports.addAll(sAudioPortsCached); 7890 } 7891 if (patches != null) { 7892 patches.clear(); 7893 patches.addAll(sAudioPatchesCached); 7894 } 7895 if (previousPorts != null) { 7896 previousPorts.clear(); 7897 previousPorts.addAll(sPreviousAudioPortsCached); 7898 } 7899 } 7900 return SUCCESS; 7901 } 7902 updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports)7903 static AudioPortConfig updatePortConfig(AudioPortConfig portCfg, ArrayList<AudioPort> ports) { 7904 AudioPort port = portCfg.port(); 7905 int k; 7906 for (k = 0; k < ports.size(); k++) { 7907 // compare handles because the port returned by JNI is not of the correct 7908 // subclass 7909 if (ports.get(k).handle().equals(port.handle())) { 7910 port = ports.get(k); 7911 break; 7912 } 7913 } 7914 if (k == ports.size()) { 7915 // This can happen in case of stale audio patch referring to a removed device and is 7916 // handled by the caller. 7917 return null; 7918 } 7919 AudioGainConfig gainCfg = portCfg.gain(); 7920 if (gainCfg != null) { 7921 AudioGain gain = port.gain(gainCfg.index()); 7922 gainCfg = gain.buildConfig(gainCfg.mode(), 7923 gainCfg.channelMask(), 7924 gainCfg.values(), 7925 gainCfg.rampDurationMs()); 7926 } 7927 return port.buildConfig(portCfg.samplingRate(), 7928 portCfg.channelMask(), 7929 portCfg.format(), 7930 gainCfg); 7931 } 7932 7933 private OnAmPortUpdateListener mPortListener = null; 7934 7935 /** 7936 * The message sent to apps when the contents of the device list changes if they provide 7937 * a {@link Handler} object to {@link registerAudioDeviceCallback}. 7938 */ 7939 private final static int MSG_DEVICES_CALLBACK_REGISTERED = 0; 7940 private final static int MSG_DEVICES_DEVICES_ADDED = 1; 7941 private final static int MSG_DEVICES_DEVICES_REMOVED = 2; 7942 7943 /** 7944 * The list of {@link AudioDeviceCallback} objects to receive add/remove notifications. 7945 */ 7946 private final ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate> mDeviceCallbacks = 7947 new ArrayMap<AudioDeviceCallback, NativeEventHandlerDelegate>(); 7948 7949 /** 7950 * The following are flags to allow users of {@link AudioManager#getDevices(int)} to filter 7951 * the results list to only those device types they are interested in. 7952 */ 7953 /** 7954 * Specifies to the {@link AudioManager#getDevices(int)} method to include 7955 * source (i.e. input) audio devices. 7956 */ 7957 public static final int GET_DEVICES_INPUTS = 0x0001; 7958 7959 /** 7960 * Specifies to the {@link AudioManager#getDevices(int)} method to include 7961 * sink (i.e. output) audio devices. 7962 */ 7963 public static final int GET_DEVICES_OUTPUTS = 0x0002; 7964 7965 /** @hide */ 7966 @IntDef(flag = true, prefix = "GET_DEVICES", value = { 7967 GET_DEVICES_INPUTS, 7968 GET_DEVICES_OUTPUTS } 7969 ) 7970 @Retention(RetentionPolicy.SOURCE) 7971 public @interface AudioDeviceRole {} 7972 7973 /** 7974 * Specifies to the {@link AudioManager#getDevices(int)} method to include both 7975 * source and sink devices. 7976 */ 7977 public static final int GET_DEVICES_ALL = GET_DEVICES_OUTPUTS | GET_DEVICES_INPUTS; 7978 7979 /** 7980 * Determines if a given AudioDevicePort meets the specified filter criteria. 7981 * @param port The port to test. 7982 * @param flags A set of bitflags specifying the criteria to test. 7983 * @see {@link GET_DEVICES_OUTPUTS} and {@link GET_DEVICES_INPUTS} 7984 **/ checkFlags(AudioDevicePort port, int flags)7985 private static boolean checkFlags(AudioDevicePort port, int flags) { 7986 return port.role() == AudioPort.ROLE_SINK && (flags & GET_DEVICES_OUTPUTS) != 0 || 7987 port.role() == AudioPort.ROLE_SOURCE && (flags & GET_DEVICES_INPUTS) != 0; 7988 } 7989 checkTypes(AudioDevicePort port)7990 private static boolean checkTypes(AudioDevicePort port) { 7991 return AudioDeviceInfo.convertInternalDeviceToDeviceType(port.type()) != 7992 AudioDeviceInfo.TYPE_UNKNOWN; 7993 } 7994 7995 /** 7996 * Returns a Set of unique Integers corresponding to audio device type identifiers that can 7997 * <i>potentially</i> be connected to the system and meeting the criteria specified in the 7998 * <code>direction</code> parameter. 7999 * Note that this set contains {@link AudioDeviceInfo} device type identifiers for both devices 8000 * currently available <i>and</i> those that can be available if the user connects an audio 8001 * peripheral. Examples include TYPE_WIRED_HEADSET if the Android device supports an analog 8002 * headset jack or TYPE_USB_DEVICE if the Android device supports a USB host-mode port. 8003 * These are generally a superset of device type identifiers associated with the 8004 * AudioDeviceInfo objects returned from AudioManager.getDevices(). 8005 * @param direction The constant specifying whether input or output devices are queried. 8006 * @see #GET_DEVICES_OUTPUTS 8007 * @see #GET_DEVICES_INPUTS 8008 * @return A (possibly zero-length) Set of Integer objects corresponding to the audio 8009 * device types of devices supported by the implementation. 8010 * @throws IllegalArgumentException If an invalid direction constant is specified. 8011 */ 8012 @FlaggedApi(FLAG_SUPPORTED_DEVICE_TYPES_API) 8013 public @NonNull Set<Integer> getSupportedDeviceTypes(@udioDeviceRole int direction)8014 getSupportedDeviceTypes(@AudioDeviceRole int direction) { 8015 if (direction != GET_DEVICES_OUTPUTS && direction != GET_DEVICES_INPUTS) { 8016 throw new IllegalArgumentException("AudioManager.getSupportedDeviceTypes(0x" 8017 + Integer.toHexString(direction) + ") - Invalid."); 8018 } 8019 8020 IntArray internalDeviceTypes = new IntArray(); 8021 int status = AudioSystem.getSupportedDeviceTypes(direction, internalDeviceTypes); 8022 if (status != AudioManager.SUCCESS) { 8023 Log.e(TAG, "AudioManager.getSupportedDeviceTypes(" + direction + ") failed. status:" 8024 + status); 8025 } 8026 8027 // convert to external (AudioDeviceInfo.getType()) device IDs 8028 HashSet<Integer> externalDeviceTypes = new HashSet<Integer>(); 8029 for (int index = 0; index < internalDeviceTypes.size(); index++) { 8030 // Set will eliminate any duplicates which AudioSystem.getSupportedDeviceTypes() 8031 // returns 8032 externalDeviceTypes.add( 8033 AudioDeviceInfo.convertInternalDeviceToDeviceType( 8034 internalDeviceTypes.get(index))); 8035 } 8036 8037 return externalDeviceTypes; 8038 } 8039 8040 /** 8041 * Returns an array of {@link AudioDeviceInfo} objects corresponding to the audio devices 8042 * currently connected to the system and meeting the criteria specified in the 8043 * <code>flags</code> parameter. 8044 * Notes that Android audio framework only support one device per device type. In that case, 8045 * if there are multiple audio device with the same device type connected to the Android device, 8046 * only the last reported device will be known by Android audio framework and returned by this 8047 * API. 8048 * @param flags A set of bitflags specifying the criteria to test. 8049 * @see #GET_DEVICES_OUTPUTS 8050 * @see #GET_DEVICES_INPUTS 8051 * @see #GET_DEVICES_ALL 8052 * @return A (possibly zero-length) array of AudioDeviceInfo objects. 8053 */ getDevices(@udioDeviceRole int flags)8054 public AudioDeviceInfo[] getDevices(@AudioDeviceRole int flags) { 8055 return getDevicesStatic(flags); 8056 } 8057 8058 /** 8059 * Does the actual computation to generate an array of (externally-visible) AudioDeviceInfo 8060 * objects from the current (internal) AudioDevicePort list. 8061 */ 8062 private static AudioDeviceInfo[] infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags)8063 infoListFromPortList(ArrayList<AudioDevicePort> ports, int flags) { 8064 8065 // figure out how many AudioDeviceInfo we need space for... 8066 int numRecs = 0; 8067 for (AudioDevicePort port : ports) { 8068 if (checkTypes(port) && checkFlags(port, flags)) { 8069 numRecs++; 8070 } 8071 } 8072 8073 // Now load them up... 8074 AudioDeviceInfo[] deviceList = new AudioDeviceInfo[numRecs]; 8075 int slot = 0; 8076 for (AudioDevicePort port : ports) { 8077 if (checkTypes(port) && checkFlags(port, flags)) { 8078 deviceList[slot++] = new AudioDeviceInfo(port); 8079 } 8080 } 8081 8082 return deviceList; 8083 } 8084 8085 /* 8086 * Calculate the list of ports that are in ports_B, but not in ports_A. This is used by 8087 * the add/remove callback mechanism to provide a list of the newly added or removed devices 8088 * rather than the whole list and make the app figure it out. 8089 * Note that calling this method with: 8090 * ports_A == PREVIOUS_ports and ports_B == CURRENT_ports will calculated ADDED ports. 8091 * ports_A == CURRENT_ports and ports_B == PREVIOUS_ports will calculated REMOVED ports. 8092 */ calcListDeltas( ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags)8093 private static AudioDeviceInfo[] calcListDeltas( 8094 ArrayList<AudioDevicePort> ports_A, ArrayList<AudioDevicePort> ports_B, int flags) { 8095 8096 ArrayList<AudioDevicePort> delta_ports = new ArrayList<AudioDevicePort>(); 8097 for (int cur_index = 0; cur_index < ports_B.size(); cur_index++) { 8098 boolean cur_port_found = false; 8099 AudioDevicePort cur_port = ports_B.get(cur_index); 8100 for (int prev_index = 0; 8101 prev_index < ports_A.size() && !cur_port_found; 8102 prev_index++) { 8103 // Do not compare devices by port ID as these change when the native 8104 // audio server restarts 8105 cur_port_found = cur_port.isSameAs(ports_A.get(prev_index)); 8106 } 8107 8108 if (!cur_port_found) { 8109 delta_ports.add(cur_port); 8110 } 8111 } 8112 8113 return infoListFromPortList(delta_ports, flags); 8114 } 8115 8116 /** 8117 * Generates a list of AudioDeviceInfo objects corresponding to the audio devices currently 8118 * connected to the system and meeting the criteria specified in the <code>flags</code> 8119 * parameter. 8120 * This is an internal function. The public API front is getDevices(int). 8121 * @param flags A set of bitflags specifying the criteria to test. 8122 * @see #GET_DEVICES_OUTPUTS 8123 * @see #GET_DEVICES_INPUTS 8124 * @see #GET_DEVICES_ALL 8125 * @return A (possibly zero-length) array of AudioDeviceInfo objects. 8126 * @hide 8127 */ getDevicesStatic(int flags)8128 public static AudioDeviceInfo[] getDevicesStatic(int flags) { 8129 ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>(); 8130 int status = AudioManager.listAudioDevicePorts(ports); 8131 if (status != AudioManager.SUCCESS) { 8132 // fail and bail! 8133 return new AudioDeviceInfo[0]; // Always return an array. 8134 } 8135 8136 return infoListFromPortList(ports, flags); 8137 } 8138 8139 /** 8140 * Returns an {@link AudioDeviceInfo} corresponding to the specified {@link AudioPort} ID. 8141 * @param portId The audio port ID to look up for. 8142 * @param flags A set of bitflags specifying the criteria to test. 8143 * @see #GET_DEVICES_OUTPUTS 8144 * @see #GET_DEVICES_INPUTS 8145 * @see #GET_DEVICES_ALL 8146 * @return An AudioDeviceInfo or null if no device with matching port ID is found. 8147 * @hide 8148 */ getDeviceForPortId(int portId, int flags)8149 public static AudioDeviceInfo getDeviceForPortId(int portId, int flags) { 8150 if (portId == 0) { 8151 return null; 8152 } 8153 AudioDeviceInfo[] devices = getDevicesStatic(flags); 8154 for (AudioDeviceInfo device : devices) { 8155 if (device.getId() == portId) { 8156 return device; 8157 } 8158 } 8159 return null; 8160 } 8161 8162 /** 8163 * Registers an {@link AudioDeviceCallback} object to receive notifications of changes 8164 * to the set of connected audio devices. 8165 * @param callback The {@link AudioDeviceCallback} object to receive connect/disconnect 8166 * notifications. 8167 * @param handler Specifies the {@link Handler} object for the thread on which to execute 8168 * the callback. If <code>null</code>, the {@link Handler} associated with the main 8169 * {@link Looper} will be used. 8170 */ registerAudioDeviceCallback(AudioDeviceCallback callback, @Nullable Handler handler)8171 public void registerAudioDeviceCallback(AudioDeviceCallback callback, 8172 @Nullable Handler handler) { 8173 synchronized (mDeviceCallbacks) { 8174 if (callback != null && !mDeviceCallbacks.containsKey(callback)) { 8175 if (mDeviceCallbacks.size() == 0) { 8176 if (mPortListener == null) { 8177 mPortListener = new OnAmPortUpdateListener(); 8178 } 8179 registerAudioPortUpdateListener(mPortListener); 8180 } 8181 NativeEventHandlerDelegate delegate = 8182 new NativeEventHandlerDelegate(callback, handler); 8183 mDeviceCallbacks.put(callback, delegate); 8184 broadcastDeviceListChange_sync(delegate.getHandler()); 8185 } 8186 } 8187 } 8188 8189 /** 8190 * Unregisters an {@link AudioDeviceCallback} object which has been previously registered 8191 * to receive notifications of changes to the set of connected audio devices. 8192 * @param callback The {@link AudioDeviceCallback} object that was previously registered 8193 * with {@link AudioManager#registerAudioDeviceCallback} to be unregistered. 8194 */ unregisterAudioDeviceCallback(AudioDeviceCallback callback)8195 public void unregisterAudioDeviceCallback(AudioDeviceCallback callback) { 8196 synchronized (mDeviceCallbacks) { 8197 if (mDeviceCallbacks.containsKey(callback)) { 8198 mDeviceCallbacks.remove(callback); 8199 if (mDeviceCallbacks.size() == 0) { 8200 unregisterAudioPortUpdateListener(mPortListener); 8201 } 8202 } 8203 } 8204 } 8205 8206 /** 8207 * Set port id for microphones by matching device type and address. 8208 * @hide 8209 */ setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones)8210 public static void setPortIdForMicrophones(ArrayList<MicrophoneInfo> microphones) { 8211 AudioDeviceInfo[] devices = getDevicesStatic(AudioManager.GET_DEVICES_INPUTS); 8212 for (int i = microphones.size() - 1; i >= 0; i--) { 8213 boolean foundPortId = false; 8214 for (AudioDeviceInfo device : devices) { 8215 if (device.getPort().type() == microphones.get(i).getInternalDeviceType() 8216 && TextUtils.equals(device.getAddress(), microphones.get(i).getAddress())) { 8217 microphones.get(i).setId(device.getId()); 8218 foundPortId = true; 8219 break; 8220 } 8221 } 8222 if (!foundPortId) { 8223 Log.i(TAG, "Failed to find port id for device with type:" 8224 + microphones.get(i).getType() + " address:" 8225 + microphones.get(i).getAddress()); 8226 microphones.remove(i); 8227 } 8228 } 8229 } 8230 8231 /** 8232 * Convert {@link AudioDeviceInfo} to {@link MicrophoneInfo}. 8233 * @hide 8234 */ microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo)8235 public static MicrophoneInfo microphoneInfoFromAudioDeviceInfo(AudioDeviceInfo deviceInfo) { 8236 @AudioDeviceInfo.AudioDeviceType int deviceType = deviceInfo.getType(); 8237 int micLocation = (deviceType == AudioDeviceInfo.TYPE_BUILTIN_MIC 8238 || deviceType == AudioDeviceInfo.TYPE_TELEPHONY) ? MicrophoneInfo.LOCATION_MAINBODY 8239 : deviceType == AudioDeviceInfo.TYPE_UNKNOWN ? MicrophoneInfo.LOCATION_UNKNOWN 8240 : MicrophoneInfo.LOCATION_PERIPHERAL; 8241 MicrophoneInfo microphone = new MicrophoneInfo( 8242 deviceInfo.getPort().name() + deviceInfo.getId(), 8243 deviceInfo.getPort().type(), deviceInfo.getAddress(), micLocation, 8244 MicrophoneInfo.GROUP_UNKNOWN, MicrophoneInfo.INDEX_IN_THE_GROUP_UNKNOWN, 8245 MicrophoneInfo.POSITION_UNKNOWN, MicrophoneInfo.ORIENTATION_UNKNOWN, 8246 new ArrayList<Pair<Float, Float>>(), new ArrayList<Pair<Integer, Integer>>(), 8247 MicrophoneInfo.SENSITIVITY_UNKNOWN, MicrophoneInfo.SPL_UNKNOWN, 8248 MicrophoneInfo.SPL_UNKNOWN, MicrophoneInfo.DIRECTIONALITY_UNKNOWN); 8249 microphone.setId(deviceInfo.getId()); 8250 return microphone; 8251 } 8252 8253 /** 8254 * Add {@link MicrophoneInfo} by device information while filtering certain types. 8255 */ addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones, HashSet<Integer> filterTypes)8256 private void addMicrophonesFromAudioDeviceInfo(ArrayList<MicrophoneInfo> microphones, 8257 HashSet<Integer> filterTypes) { 8258 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_INPUTS); 8259 for (AudioDeviceInfo device : devices) { 8260 if (filterTypes.contains(device.getType())) { 8261 continue; 8262 } 8263 MicrophoneInfo microphone = microphoneInfoFromAudioDeviceInfo(device); 8264 microphones.add(microphone); 8265 } 8266 } 8267 8268 /** 8269 * Returns a list of {@link MicrophoneInfo} that corresponds to the characteristics 8270 * of all available microphones. The list is empty when no microphones are available 8271 * on the device. An error during the query will result in an IOException being thrown. 8272 * 8273 * @return a list that contains all microphones' characteristics 8274 * @throws IOException if an error occurs. 8275 */ getMicrophones()8276 public List<MicrophoneInfo> getMicrophones() throws IOException { 8277 ArrayList<MicrophoneInfo> microphones = new ArrayList<MicrophoneInfo>(); 8278 int status = AudioSystem.getMicrophones(microphones); 8279 HashSet<Integer> filterTypes = new HashSet<>(); 8280 filterTypes.add(AudioDeviceInfo.TYPE_TELEPHONY); 8281 if (status != AudioManager.SUCCESS) { 8282 // fail and populate microphones with unknown characteristics by device information. 8283 if (status != AudioManager.ERROR_INVALID_OPERATION) { 8284 Log.e(TAG, "getMicrophones failed:" + status); 8285 } 8286 Log.i(TAG, "fallback on device info"); 8287 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes); 8288 return microphones; 8289 } 8290 setPortIdForMicrophones(microphones); 8291 filterTypes.add(AudioDeviceInfo.TYPE_BUILTIN_MIC); 8292 addMicrophonesFromAudioDeviceInfo(microphones, filterTypes); 8293 return microphones; 8294 } 8295 8296 /** 8297 * Returns a list of audio formats that corresponds to encoding formats 8298 * supported on offload path for A2DP playback. 8299 * 8300 * @return a list of {@link BluetoothCodecConfig} objects containing encoding formats 8301 * supported for offload A2DP playback 8302 * @hide 8303 */ 8304 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) getHwOffloadFormatsSupportedForA2dp()8305 public @NonNull List<BluetoothCodecConfig> getHwOffloadFormatsSupportedForA2dp() { 8306 ArrayList<Integer> formatsList = new ArrayList<>(); 8307 ArrayList<BluetoothCodecConfig> codecConfigList = new ArrayList<>(); 8308 8309 int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia( 8310 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, formatsList); 8311 if (status != AudioManager.SUCCESS) { 8312 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForA2DP failed:" + status); 8313 return codecConfigList; 8314 } 8315 8316 for (Integer format : formatsList) { 8317 int btSourceCodec = AudioSystem.audioFormatToBluetoothSourceCodec(format); 8318 if (btSourceCodec != BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) { 8319 codecConfigList.add( 8320 new BluetoothCodecConfig.Builder().setCodecType(btSourceCodec).build()); 8321 } 8322 } 8323 return codecConfigList; 8324 } 8325 getHwOffloadFormatsSupportedForLeAudio( @udioSystem.BtOffloadDeviceType int deviceType)8326 private List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio( 8327 @AudioSystem.BtOffloadDeviceType int deviceType) { 8328 ArrayList<Integer> formatsList = new ArrayList<>(); 8329 ArrayList<BluetoothLeAudioCodecConfig> leAudioCodecConfigList = new ArrayList<>(); 8330 8331 int status = AudioSystem.getHwOffloadFormatsSupportedForBluetoothMedia( 8332 deviceType, formatsList); 8333 if (status != AudioManager.SUCCESS) { 8334 Log.e(TAG, "getHwOffloadEncodingFormatsSupportedForLeAudio failed:" + status); 8335 return leAudioCodecConfigList; 8336 } 8337 8338 for (Integer format : formatsList) { 8339 int btLeAudioCodec = AudioSystem.audioFormatToBluetoothLeAudioSourceCodec(format); 8340 if (btLeAudioCodec != BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) { 8341 leAudioCodecConfigList.add(new BluetoothLeAudioCodecConfig.Builder() 8342 .setCodecType(btLeAudioCodec) 8343 .build()); 8344 } 8345 } 8346 return leAudioCodecConfigList; 8347 } 8348 8349 /** 8350 * Returns a list of audio formats that corresponds to encoding formats 8351 * supported on offload path for Le audio playback. 8352 * 8353 * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats 8354 * supported for offload Le Audio playback 8355 * @hide 8356 */ 8357 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 8358 @NonNull getHwOffloadFormatsSupportedForLeAudio()8359 public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeAudio() { 8360 return getHwOffloadFormatsSupportedForLeAudio(AudioSystem.DEVICE_OUT_BLE_HEADSET); 8361 } 8362 8363 /** 8364 * Returns a list of audio formats that corresponds to encoding formats 8365 * supported on offload path for Le Broadcast playback. 8366 * 8367 * @return a list of {@link BluetoothLeAudioCodecConfig} objects containing encoding formats 8368 * supported for offload Le Broadcast playback 8369 * @hide 8370 */ 8371 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 8372 @NonNull getHwOffloadFormatsSupportedForLeBroadcast()8373 public List<BluetoothLeAudioCodecConfig> getHwOffloadFormatsSupportedForLeBroadcast() { 8374 return getHwOffloadFormatsSupportedForLeAudio(AudioSystem.DEVICE_OUT_BLE_BROADCAST); 8375 } 8376 8377 // Since we need to calculate the changes since THE LAST NOTIFICATION, and not since the 8378 // (unpredictable) last time updateAudioPortCache() was called by someone, keep a list 8379 // of the ports that exist at the time of the last notification. 8380 private ArrayList<AudioDevicePort> mPreviousPorts = new ArrayList<AudioDevicePort>(); 8381 8382 /** 8383 * Internal method to compute and generate add/remove messages and then send to any 8384 * registered callbacks. Must be called synchronized on mDeviceCallbacks. 8385 */ broadcastDeviceListChange_sync(Handler handler)8386 private void broadcastDeviceListChange_sync(Handler handler) { 8387 int status; 8388 8389 // Get the new current set of ports 8390 ArrayList<AudioDevicePort> current_ports = new ArrayList<AudioDevicePort>(); 8391 status = AudioManager.listAudioDevicePorts(current_ports); 8392 if (status != AudioManager.SUCCESS) { 8393 return; 8394 } 8395 8396 if (handler != null) { 8397 // This is the callback for the registration, so send the current list 8398 AudioDeviceInfo[] deviceList = 8399 infoListFromPortList(current_ports, GET_DEVICES_ALL); 8400 handler.sendMessage( 8401 Message.obtain(handler, MSG_DEVICES_CALLBACK_REGISTERED, deviceList)); 8402 } else { 8403 AudioDeviceInfo[] added_devices = 8404 calcListDeltas(mPreviousPorts, current_ports, GET_DEVICES_ALL); 8405 AudioDeviceInfo[] removed_devices = 8406 calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL); 8407 if (added_devices.length != 0 || removed_devices.length != 0) { 8408 for (int i = 0; i < mDeviceCallbacks.size(); i++) { 8409 handler = mDeviceCallbacks.valueAt(i).getHandler(); 8410 if (handler != null) { 8411 if (removed_devices.length != 0) { 8412 handler.sendMessage(Message.obtain(handler, 8413 MSG_DEVICES_DEVICES_REMOVED, 8414 removed_devices)); 8415 } 8416 if (added_devices.length != 0) { 8417 handler.sendMessage(Message.obtain(handler, 8418 MSG_DEVICES_DEVICES_ADDED, 8419 added_devices)); 8420 } 8421 } 8422 } 8423 } 8424 } 8425 8426 mPreviousPorts = current_ports; 8427 } 8428 8429 /** 8430 * Handles Port list update notifications from the AudioManager 8431 */ 8432 private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener { 8433 static final String TAG = "OnAmPortUpdateListener"; onAudioPortListUpdate(AudioPort[] portList)8434 public void onAudioPortListUpdate(AudioPort[] portList) { 8435 synchronized (mDeviceCallbacks) { 8436 broadcastDeviceListChange_sync(null); 8437 } 8438 } 8439 8440 /** 8441 * Callback method called upon audio patch list update. 8442 * Note: We don't do anything with Patches at this time, so ignore this notification. 8443 * @param patchList the updated list of audio patches. 8444 */ onAudioPatchListUpdate(AudioPatch[] patchList)8445 public void onAudioPatchListUpdate(AudioPatch[] patchList) {} 8446 8447 /** 8448 * Callback method called when the mediaserver dies 8449 */ onServiceDied()8450 public void onServiceDied() { 8451 // Nothing to do here 8452 } 8453 } 8454 8455 /** 8456 * @hide 8457 * Abstract class to receive event notification about audioserver process state. 8458 */ 8459 @SystemApi 8460 public abstract static class AudioServerStateCallback { onAudioServerDown()8461 public void onAudioServerDown() { } onAudioServerUp()8462 public void onAudioServerUp() { } 8463 } 8464 8465 private Executor mAudioServerStateExec; 8466 private AudioServerStateCallback mAudioServerStateCb; 8467 private final Object mAudioServerStateCbLock = new Object(); 8468 8469 private final IAudioServerStateDispatcher mAudioServerStateDispatcher = 8470 new IAudioServerStateDispatcher.Stub() { 8471 @Override 8472 public void dispatchAudioServerStateChange(boolean state) { 8473 Executor exec; 8474 AudioServerStateCallback cb; 8475 8476 synchronized (mAudioServerStateCbLock) { 8477 exec = mAudioServerStateExec; 8478 cb = mAudioServerStateCb; 8479 } 8480 8481 if ((exec == null) || (cb == null)) { 8482 return; 8483 } 8484 if (state) { 8485 exec.execute(() -> cb.onAudioServerUp()); 8486 } else { 8487 exec.execute(() -> cb.onAudioServerDown()); 8488 } 8489 } 8490 }; 8491 8492 /** 8493 * @hide 8494 * Registers a callback for notification of audio server state changes. 8495 * @param executor {@link Executor} to handle the callbacks. Must be non null. 8496 * @param stateCallback the callback to receive the audio server state changes. 8497 * Must be non null. To remove the callabck, 8498 * call {@link #clearAudioServerStateCallback()} 8499 * @throws IllegalArgumentException If a null argument is specified. 8500 * @throws IllegalStateException If a callback is already registered 8501 * * 8502 */ 8503 @SystemApi setAudioServerStateCallback(@onNull Executor executor, @NonNull AudioServerStateCallback stateCallback)8504 public void setAudioServerStateCallback(@NonNull Executor executor, 8505 @NonNull AudioServerStateCallback stateCallback) { 8506 if (stateCallback == null) { 8507 throw new IllegalArgumentException("Illegal null AudioServerStateCallback"); 8508 } 8509 if (executor == null) { 8510 throw new IllegalArgumentException( 8511 "Illegal null Executor for the AudioServerStateCallback"); 8512 } 8513 8514 synchronized (mAudioServerStateCbLock) { 8515 if (mAudioServerStateCb != null) { 8516 throw new IllegalStateException( 8517 "setAudioServerStateCallback called with already registered callabck"); 8518 } 8519 final IAudioService service = getService(); 8520 try { 8521 service.registerAudioServerStateDispatcher(mAudioServerStateDispatcher); 8522 } catch (RemoteException e) { 8523 throw e.rethrowFromSystemServer(); 8524 } 8525 mAudioServerStateExec = executor; 8526 mAudioServerStateCb = stateCallback; 8527 } 8528 } 8529 8530 /** 8531 * @hide 8532 * Unregisters the callback for notification of audio server state changes. 8533 */ 8534 @SystemApi clearAudioServerStateCallback()8535 public void clearAudioServerStateCallback() { 8536 synchronized (mAudioServerStateCbLock) { 8537 if (mAudioServerStateCb != null) { 8538 final IAudioService service = getService(); 8539 try { 8540 service.unregisterAudioServerStateDispatcher( 8541 mAudioServerStateDispatcher); 8542 } catch (RemoteException e) { 8543 throw e.rethrowFromSystemServer(); 8544 } 8545 } 8546 mAudioServerStateExec = null; 8547 mAudioServerStateCb = null; 8548 } 8549 } 8550 8551 /** 8552 * @hide 8553 * Checks if native audioservice is running or not. 8554 * @return true if native audioservice runs, false otherwise. 8555 */ 8556 @SystemApi isAudioServerRunning()8557 public boolean isAudioServerRunning() { 8558 final IAudioService service = getService(); 8559 try { 8560 return service.isAudioServerRunning(); 8561 } catch (RemoteException e) { 8562 throw e.rethrowFromSystemServer(); 8563 } 8564 } 8565 8566 /** 8567 * Sets the surround sound mode. 8568 * 8569 * @return true if successful, otherwise false 8570 */ 8571 @RequiresPermission(Manifest.permission.WRITE_SETTINGS) setEncodedSurroundMode(@ncodedSurroundOutputMode int mode)8572 public boolean setEncodedSurroundMode(@EncodedSurroundOutputMode int mode) { 8573 try { 8574 return getService().setEncodedSurroundMode(mode); 8575 } catch (RemoteException e) { 8576 throw e.rethrowFromSystemServer(); 8577 } 8578 } 8579 8580 /** 8581 * Gets the surround sound mode. 8582 * 8583 * @return true if successful, otherwise false 8584 */ getEncodedSurroundMode()8585 public @EncodedSurroundOutputMode int getEncodedSurroundMode() { 8586 try { 8587 return getService().getEncodedSurroundMode( 8588 getContext().getApplicationInfo().targetSdkVersion); 8589 } catch (RemoteException e) { 8590 throw e.rethrowFromSystemServer(); 8591 } 8592 } 8593 8594 /** 8595 * @hide 8596 * Returns all surround formats. 8597 * @return a map where the key is a surround format and 8598 * the value indicates the surround format is enabled or not 8599 */ 8600 @TestApi 8601 @NonNull getSurroundFormats()8602 public Map<Integer, Boolean> getSurroundFormats() { 8603 try { 8604 return getService().getSurroundFormats(); 8605 } catch (RemoteException e) { 8606 throw e.rethrowFromSystemServer(); 8607 } 8608 } 8609 8610 /** 8611 * Sets and persists a certain surround format as enabled or not. 8612 * <p> 8613 * This API is called by TvSettings surround sound menu when user enables or disables a 8614 * surround sound format. This setting is persisted as global user setting. 8615 * Applications should revert their changes to surround sound settings unless they intend to 8616 * modify the global user settings across all apps. The framework does not auto-revert an 8617 * application's settings after a lifecycle event. Audio focus is not required to apply these 8618 * settings. 8619 * 8620 * @param enabled the required surround format state, true for enabled, false for disabled 8621 * @return true if successful, otherwise false 8622 */ 8623 @RequiresPermission(Manifest.permission.WRITE_SETTINGS) setSurroundFormatEnabled( @udioFormat.SurroundSoundEncoding int audioFormat, boolean enabled)8624 public boolean setSurroundFormatEnabled( 8625 @AudioFormat.SurroundSoundEncoding int audioFormat, boolean enabled) { 8626 try { 8627 return getService().setSurroundFormatEnabled(audioFormat, enabled); 8628 } catch (RemoteException e) { 8629 throw e.rethrowFromSystemServer(); 8630 } 8631 } 8632 8633 /** 8634 * Gets whether a certain surround format is enabled or not. 8635 * @param audioFormat a surround format 8636 * 8637 * @return whether the required surround format is enabled 8638 */ isSurroundFormatEnabled(@udioFormat.SurroundSoundEncoding int audioFormat)8639 public boolean isSurroundFormatEnabled(@AudioFormat.SurroundSoundEncoding int audioFormat) { 8640 try { 8641 return getService().isSurroundFormatEnabled(audioFormat); 8642 } catch (RemoteException e) { 8643 throw e.rethrowFromSystemServer(); 8644 } 8645 } 8646 8647 /** 8648 * @hide 8649 * Returns all surround formats that are reported by the connected HDMI device. 8650 * The return values are not affected by calling setSurroundFormatEnabled. 8651 * 8652 * @return a list of surround formats 8653 */ 8654 @TestApi 8655 @NonNull getReportedSurroundFormats()8656 public List<Integer> getReportedSurroundFormats() { 8657 try { 8658 return getService().getReportedSurroundFormats(); 8659 } catch (RemoteException e) { 8660 throw e.rethrowFromSystemServer(); 8661 } 8662 } 8663 8664 /** 8665 * Return if audio haptic coupled playback is supported or not. 8666 * 8667 * @return whether audio haptic playback supported. 8668 */ isHapticPlaybackSupported()8669 public static boolean isHapticPlaybackSupported() { 8670 return AudioSystem.isHapticPlaybackSupported(); 8671 } 8672 8673 /** 8674 * @hide 8675 * Indicates whether a platform supports the Ultrasound feature which covers the playback 8676 * and recording of 20kHz~ sounds. If platform supports Ultrasound, then the 8677 * usage will be 8678 * To start the Ultrasound playback: 8679 * - Create an AudioTrack with {@link AudioAttributes.CONTENT_TYPE_ULTRASOUND}. 8680 * To start the Ultrasound capture: 8681 * - Create an AudioRecord with {@link MediaRecorder.AudioSource.ULTRASOUND}. 8682 * 8683 * @return whether the ultrasound feature is supported, true when platform supports both 8684 * Ultrasound playback and capture, false otherwise. 8685 */ 8686 @SystemApi 8687 @RequiresPermission(Manifest.permission.ACCESS_ULTRASOUND) isUltrasoundSupported()8688 public boolean isUltrasoundSupported() { 8689 try { 8690 return getService().isUltrasoundSupported(); 8691 } catch (RemoteException e) { 8692 throw e.rethrowFromSystemServer(); 8693 } 8694 } 8695 8696 /** 8697 * @hide 8698 * Indicates whether the platform supports capturing content from the hotword recognition 8699 * pipeline. To capture content of this type, create an AudioRecord with 8700 * {@link AudioRecord.Builder.setRequestHotwordStream(boolean, boolean)}. 8701 * @param lookbackAudio Query if the hotword stream additionally supports providing buffered 8702 * audio prior to stream open. 8703 * @return True if the platform supports capturing hotword content, and if lookbackAudio 8704 * is true, if it additionally supports capturing buffered hotword content prior to stream 8705 * open. False otherwise. 8706 */ 8707 @SystemApi 8708 @RequiresPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD) isHotwordStreamSupported(boolean lookbackAudio)8709 public boolean isHotwordStreamSupported(boolean lookbackAudio) { 8710 try { 8711 return getService().isHotwordStreamSupported(lookbackAudio); 8712 } catch (RemoteException e) { 8713 return false; 8714 } 8715 } 8716 8717 /** 8718 * @hide 8719 * Introspection API to retrieve audio product strategies. 8720 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of 8721 * audio product strategies, which is indexed by a weakly typed index in order to be extended 8722 * by OEM without any needs of AOSP patches. 8723 * The {Car|Oem}AudioManager can expose API to build {@link AudioAttributes} for a given product 8724 * strategy refered either by its index or human readable string. It will allow clients 8725 * application to start streaming data using these {@link AudioAttributes} on the selected 8726 * device by Audio Policy Engine. 8727 * @return a (possibly zero-length) array of 8728 * {@see android.media.audiopolicy.AudioProductStrategy} objects. 8729 */ 8730 @SystemApi 8731 @NonNull 8732 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) getAudioProductStrategies()8733 public static List<AudioProductStrategy> getAudioProductStrategies() { 8734 final IAudioService service = getService(); 8735 try { 8736 return service.getAudioProductStrategies(); 8737 } catch (RemoteException e) { 8738 throw e.rethrowFromSystemServer(); 8739 } 8740 } 8741 8742 /** 8743 * @hide 8744 * Introspection API to retrieve audio volume groups. 8745 * When implementing {Car|Oem}AudioManager, use this method to retrieve the collection of 8746 * audio volume groups. 8747 * @return a (possibly zero-length) List of 8748 * {@see android.media.audiopolicy.AudioVolumeGroup} objects. 8749 */ 8750 @SystemApi 8751 @NonNull 8752 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) 8753 // TODO also open to MODIFY_AUDIO_SETTINGS_PRIVILEGED b/341780042 getAudioVolumeGroups()8754 public static List<AudioVolumeGroup> getAudioVolumeGroups() { 8755 final IAudioService service = getService(); 8756 try { 8757 return service.getAudioVolumeGroups(); 8758 } catch (RemoteException e) { 8759 throw e.rethrowFromSystemServer(); 8760 } 8761 } 8762 8763 //==================================================================== 8764 // Notification of volume group changes 8765 /** 8766 * Callback to receive updates on volume group changes, register using 8767 * {@link AudioManager#registerVolumeGroupCallback(Executor, AudioVolumeCallback)}. 8768 * 8769 * @hide 8770 */ 8771 @SystemApi 8772 public abstract static class VolumeGroupCallback { 8773 /** 8774 * Callback method called upon audio volume group change. 8775 * @param group the group for which the volume has changed 8776 */ onAudioVolumeGroupChanged(int group, int flags)8777 public void onAudioVolumeGroupChanged(int group, int flags) {} 8778 } 8779 8780 /** 8781 * Register an audio volume group change listener. 8782 * 8783 * @param executor {@link Executor} to handle the callbacks 8784 * @param callback the callback to receive the audio volume group changes 8785 * @throws SecurityException if the caller doesn't have the required permission. 8786 * 8787 * @hide 8788 */ 8789 @SystemApi 8790 @FlaggedApi(FLAG_REGISTER_VOLUME_CALLBACK_API_HARDENING) 8791 @RequiresPermission("Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED") registerVolumeGroupCallback(@onNull Executor executor, @NonNull VolumeGroupCallback callback)8792 public void registerVolumeGroupCallback(@NonNull Executor executor, 8793 @NonNull VolumeGroupCallback callback) { 8794 mVolumeChangedListenerMgr.addListener(executor, callback, "registerVolumeGroupCallback", 8795 () -> new AudioVolumeChangeDispatcherStub()); 8796 } 8797 8798 /** 8799 * Unregister an audio volume group change listener. 8800 * 8801 * @param callback the {@link VolumeGroupCallback} to unregister 8802 * 8803 * @hide 8804 */ 8805 @SystemApi 8806 @FlaggedApi(FLAG_REGISTER_VOLUME_CALLBACK_API_HARDENING) 8807 @RequiresPermission("Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED") unregisterVolumeGroupCallback(@onNull VolumeGroupCallback callback)8808 public void unregisterVolumeGroupCallback(@NonNull VolumeGroupCallback callback) { 8809 mVolumeChangedListenerMgr.removeListener(callback, "unregisterVolumeGroupCallback"); 8810 } 8811 8812 /** 8813 * Manages the VolumeGroupCallback listeners and the AudioVolumeChangeDispatcherStub 8814 */ 8815 private final CallbackUtil.LazyListenerManager<VolumeGroupCallback> mVolumeChangedListenerMgr = 8816 new CallbackUtil.LazyListenerManager(); 8817 8818 final class AudioVolumeChangeDispatcherStub extends IAudioVolumeChangeDispatcher.Stub 8819 implements CallbackUtil.DispatcherStub { 8820 8821 @Override register(boolean register)8822 public void register(boolean register) { 8823 try { 8824 if (register) { 8825 getService().registerAudioVolumeCallback(this); 8826 } else { 8827 getService().unregisterAudioVolumeCallback(this); 8828 } 8829 } catch (RemoteException e) { 8830 e.rethrowFromSystemServer(); 8831 } 8832 } 8833 8834 @Override onAudioVolumeGroupChanged(int group, int flags)8835 public void onAudioVolumeGroupChanged(int group, int flags) { 8836 mVolumeChangedListenerMgr.callListeners((listener) -> 8837 listener.onAudioVolumeGroupChanged(group, flags)); 8838 } 8839 } 8840 8841 //==================================================================== 8842 8843 /** 8844 * Return if an asset contains haptic channels or not. 8845 * 8846 * @param context the {@link Context} to resolve the uri. 8847 * @param uri the {@link Uri} of the asset. 8848 * @return true if the assert contains haptic channels. 8849 * @hide 8850 */ hasHapticChannelsImpl(@onNull Context context, @NonNull Uri uri)8851 public static boolean hasHapticChannelsImpl(@NonNull Context context, @NonNull Uri uri) { 8852 MediaExtractor extractor = new MediaExtractor(); 8853 try { 8854 extractor.setDataSource(context, uri, null); 8855 for (int i = 0; i < extractor.getTrackCount(); i++) { 8856 MediaFormat format = extractor.getTrackFormat(i); 8857 if (format.containsKey(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) 8858 && format.getInteger(MediaFormat.KEY_HAPTIC_CHANNEL_COUNT) > 0) { 8859 return true; 8860 } 8861 } 8862 } catch (IOException e) { 8863 Log.e(TAG, "hasHapticChannels failure:" + e); 8864 } 8865 return false; 8866 } 8867 8868 /** 8869 * Return if an asset contains haptic channels or not. 8870 * 8871 * @param context the {@link Context} to resolve the uri. 8872 * @param uri the {@link Uri} of the asset. 8873 * @return true if the assert contains haptic channels. 8874 * @hide 8875 */ hasHapticChannels(@ullable Context context, @NonNull Uri uri)8876 public static boolean hasHapticChannels(@Nullable Context context, @NonNull Uri uri) { 8877 Objects.requireNonNull(uri); 8878 8879 if (context != null) { 8880 return hasHapticChannelsImpl(context, uri); 8881 } 8882 8883 Context cachedContext = sContext.get(); 8884 if (cachedContext != null) { 8885 if (DEBUG) { 8886 Log.d(TAG, "Try to use static context to query if having haptic channels"); 8887 } 8888 return hasHapticChannelsImpl(cachedContext, uri); 8889 } 8890 8891 // Try with audio service context, this may fail to get correct result. 8892 if (DEBUG) { 8893 Log.d(TAG, "Try to use audio service context to query if having haptic channels"); 8894 } 8895 try { 8896 return getService().hasHapticChannels(uri); 8897 } catch (RemoteException e) { 8898 throw e.rethrowFromSystemServer(); 8899 } 8900 } 8901 8902 /** 8903 * Set whether or not there is an active RTT call. 8904 * This method should be called by Telecom service. 8905 * @hide 8906 * TODO: make this a @SystemApi 8907 */ setRttEnabled(boolean rttEnabled)8908 public static void setRttEnabled(boolean rttEnabled) { 8909 try { 8910 getService().setRttEnabled(rttEnabled); 8911 } catch (RemoteException e) { 8912 throw e.rethrowFromSystemServer(); 8913 } 8914 } 8915 8916 /** 8917 * Adjusts the volume of the most relevant stream, or the given fallback 8918 * stream. 8919 * <p> 8920 * This method should only be used by applications that replace the 8921 * platform-wide management of audio settings or the main telephony 8922 * application. 8923 * <p> 8924 * This method has no effect if the device implements a fixed volume policy 8925 * as indicated by {@link #isVolumeFixed()}. 8926 * <p>This API checks if the caller has the necessary permissions based on the provided 8927 * component name, uid, and pid values. 8928 * See {@link #adjustSuggestedStreamVolume(int, int, int)}. 8929 * 8930 * @param suggestedStreamType The stream type that will be used if there 8931 * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is 8932 * valid here. 8933 * @param direction The direction to adjust the volume. One of 8934 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, 8935 * {@link #ADJUST_SAME}, {@link #ADJUST_MUTE}, 8936 * {@link #ADJUST_UNMUTE}, or {@link #ADJUST_TOGGLE_MUTE}. 8937 * @param flags 8938 * @param packageName the package name of client application 8939 * @param uid the uid of client application 8940 * @param pid the pid of client application 8941 * @param targetSdkVersion the target sdk version of client application 8942 * @see #adjustVolume(int, int) 8943 * @see #adjustStreamVolume(int, int, int) 8944 * @see #setStreamVolume(int, int, int) 8945 * @see #isVolumeFixed() 8946 * 8947 * @hide 8948 */ 8949 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, @SystemVolumeFlags int flags, @NonNull String packageName, int uid, int pid, int targetSdkVersion)8950 public void adjustSuggestedStreamVolumeForUid(int suggestedStreamType, int direction, 8951 @SystemVolumeFlags int flags, 8952 @NonNull String packageName, int uid, int pid, int targetSdkVersion) { 8953 try { 8954 getService().adjustSuggestedStreamVolumeForUid(suggestedStreamType, direction, flags, 8955 packageName, uid, pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion); 8956 } catch (RemoteException e) { 8957 throw e.rethrowFromSystemServer(); 8958 } 8959 } 8960 8961 /** 8962 * Adjusts the volume of a particular stream by one step in a direction. 8963 * <p> 8964 * This method should only be used by applications that replace the platform-wide 8965 * management of audio settings or the main telephony application. 8966 * <p>This method has no effect if the device implements a fixed volume policy 8967 * as indicated by {@link #isVolumeFixed()}. 8968 * <p>From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed 8969 * unless the app has been granted Notification Policy Access. 8970 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}. 8971 * <p>This API checks if the caller has the necessary permissions based on the provided 8972 * component name, uid, and pid values. 8973 * See {@link #adjustStreamVolume(int, int, int)}. 8974 * 8975 * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL}, 8976 * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC}, 8977 * {@link #STREAM_ALARM} or {@link #STREAM_ACCESSIBILITY}. 8978 * @param direction The direction to adjust the volume. One of 8979 * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or 8980 * {@link #ADJUST_SAME}. 8981 * @param flags 8982 * @param packageName the package name of client application 8983 * @param uid the uid of client application 8984 * @param pid the pid of client application 8985 * @param targetSdkVersion the target sdk version of client application 8986 * @see #adjustVolume(int, int) 8987 * @see #setStreamVolume(int, int, int) 8988 * @throws SecurityException if the adjustment triggers a Do Not Disturb change 8989 * and the caller is not granted notification policy access. 8990 * 8991 * @hide 8992 */ 8993 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) adjustStreamVolumeForUid(int streamType, int direction, @SystemVolumeFlags int flags, @NonNull String packageName, int uid, int pid, int targetSdkVersion)8994 public void adjustStreamVolumeForUid(int streamType, int direction, 8995 @SystemVolumeFlags int flags, 8996 @NonNull String packageName, int uid, int pid, int targetSdkVersion) { 8997 try { 8998 getService().adjustStreamVolumeForUid(streamType, direction, flags, packageName, uid, 8999 pid, UserHandle.getUserHandleForUid(uid), targetSdkVersion); 9000 } catch (RemoteException e) { 9001 throw e.rethrowFromSystemServer(); 9002 } 9003 } 9004 9005 /** 9006 * Sets the volume index for a particular stream. 9007 * <p>This method has no effect if the device implements a fixed volume policy 9008 * as indicated by {@link #isVolumeFixed()}. 9009 * <p>From N onward, volume adjustments that would toggle Do Not Disturb are not allowed unless 9010 * the app has been granted Notification Policy Access. 9011 * See {@link NotificationManager#isNotificationPolicyAccessGranted()}. 9012 * <p>This API checks if the caller has the necessary permissions based on the provided 9013 * component name, uid, and pid values. 9014 * See {@link #setStreamVolume(int, int, int)}. 9015 * 9016 * @param streamType The stream whose volume index should be set. 9017 * @param index The volume index to set. See 9018 * {@link #getStreamMaxVolume(int)} for the largest valid value. 9019 * @param flags 9020 * @param packageName the package name of client application 9021 * @param uid the uid of client application 9022 * @param pid the pid of client application 9023 * @param targetSdkVersion the target sdk version of client application 9024 * @see #getStreamMaxVolume(int) 9025 * @see #getStreamVolume(int) 9026 * @see #isVolumeFixed() 9027 * @throws SecurityException if the volume change triggers a Do Not Disturb change 9028 * and the caller is not granted notification policy access. 9029 * 9030 * @hide 9031 */ 9032 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) setStreamVolumeForUid(int streamType, int index, @SystemVolumeFlags int flags, @NonNull String packageName, int uid, int pid, int targetSdkVersion)9033 public void setStreamVolumeForUid(int streamType, int index, 9034 @SystemVolumeFlags int flags, 9035 @NonNull String packageName, int uid, int pid, int targetSdkVersion) { 9036 try { 9037 getService().setStreamVolumeForUid(streamType, index, flags, packageName, uid, pid, 9038 UserHandle.getUserHandleForUid(uid), targetSdkVersion); 9039 } catch (RemoteException e) { 9040 throw e.rethrowFromSystemServer(); 9041 } 9042 } 9043 9044 9045 /** @hide 9046 * TODO: make this a @SystemApi */ 9047 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setMultiAudioFocusEnabled(boolean enabled)9048 public void setMultiAudioFocusEnabled(boolean enabled) { 9049 try { 9050 getService().setMultiAudioFocusEnabled(enabled); 9051 } catch (RemoteException e) { 9052 throw e.rethrowFromSystemServer(); 9053 } 9054 } 9055 9056 9057 /** 9058 * Retrieves the Hardware A/V synchronization ID corresponding to the given audio session ID. 9059 * For more details on Hardware A/V synchronization please refer to 9060 * <a href="https://source.android.com/devices/tv/multimedia-tunneling/"> 9061 * media tunneling documentation</a>. 9062 * @param sessionId the audio session ID for which the HW A/V sync ID is retrieved. 9063 * @return the HW A/V sync ID for this audio session (an integer different from 0). 9064 * @throws UnsupportedOperationException if HW A/V synchronization is not supported. 9065 */ getAudioHwSyncForSession(int sessionId)9066 public int getAudioHwSyncForSession(int sessionId) { 9067 int hwSyncId = AudioSystem.getAudioHwSyncForSession(sessionId); 9068 if (hwSyncId == AudioSystem.AUDIO_HW_SYNC_INVALID) { 9069 throw new UnsupportedOperationException("HW A/V synchronization is not supported."); 9070 } 9071 return hwSyncId; 9072 } 9073 9074 /** 9075 * Selects the audio device that should be used for communication use cases, for instance voice 9076 * or video calls. This method can be used by voice or video chat applications to select a 9077 * different audio device than the one selected by default by the platform. 9078 * <p>The device selection is expressed as an {@link AudioDeviceInfo} among devices returned by 9079 * {@link #getAvailableCommunicationDevices()}. Note that only devices in a sink role 9080 * (AKA output devices, see {@link AudioDeviceInfo#isSink()}) can be specified. The matching 9081 * source device is selected automatically by the platform. 9082 * <p>The selection is active as long as the requesting application process lives, until 9083 * {@link #clearCommunicationDevice} is called or until the device is disconnected. 9084 * It is therefore important for applications to clear the request when a call ends or the 9085 * the requesting activity or service is stopped or destroyed. 9086 * <p>In case of simultaneous requests by multiple applications the priority is given to the 9087 * application currently controlling the audio mode (see {@link #setMode(int)}). This is the 9088 * latest application having selected mode {@link #MODE_IN_COMMUNICATION} or mode 9089 * {@link #MODE_IN_CALL}. Note that <code>MODE_IN_CALL</code> can only be selected by the main 9090 * telephony application with permission 9091 * {@link Manifest.permission#MODIFY_PHONE_STATE}. 9092 * <p> If the requested devices is not currently available, the request will be rejected and 9093 * the method will return false. 9094 * <p>This API replaces the following deprecated APIs: 9095 * <ul> 9096 * <li> {@link #startBluetoothSco()} 9097 * <li> {@link #stopBluetoothSco()} 9098 * <li> {@link #setSpeakerphoneOn(boolean)} 9099 * </ul> 9100 * <h4>Example</h4> 9101 * <p>The example below shows how to enable and disable speakerphone mode. 9102 * <pre class="prettyprint"> 9103 * // Get an AudioManager instance 9104 * AudioManager audioManager = Context.getSystemService(AudioManager.class); 9105 * AudioDeviceInfo speakerDevice = null; 9106 * List<AudioDeviceInfo> devices = audioManager.getAvailableCommunicationDevices(); 9107 * for (AudioDeviceInfo device : devices) { 9108 * if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) { 9109 * speakerDevice = device; 9110 * break; 9111 * } 9112 * } 9113 * if (speakerDevice != null) { 9114 * // Turn speakerphone ON. 9115 * boolean result = audioManager.setCommunicationDevice(speakerDevice); 9116 * if (!result) { 9117 * // Handle error. 9118 * } 9119 * // Turn speakerphone OFF. 9120 * audioManager.clearCommunicationDevice(); 9121 * } 9122 * </pre> 9123 * @param device the requested audio device. 9124 * @return <code>true</code> if the request was accepted, <code>false</code> otherwise. 9125 * @throws IllegalArgumentException If an invalid device is specified. 9126 */ setCommunicationDevice(@onNull AudioDeviceInfo device)9127 public boolean setCommunicationDevice(@NonNull AudioDeviceInfo device) { 9128 Objects.requireNonNull(device); 9129 try { 9130 if (device.getId() == 0) { 9131 Log.w(TAG, "setCommunicationDevice: device not found: " + device); 9132 return false; 9133 } 9134 return getService().setCommunicationDevice(mICallBack, device.getId(), 9135 getAttributionSource()); 9136 } catch (RemoteException e) { 9137 throw e.rethrowFromSystemServer(); 9138 } 9139 } 9140 9141 /** 9142 * Cancels previous communication device selection made with 9143 * {@link #setCommunicationDevice(AudioDeviceInfo)}. 9144 */ clearCommunicationDevice()9145 public void clearCommunicationDevice() { 9146 try { 9147 getService().setCommunicationDevice(mICallBack, 0, getAttributionSource()); 9148 } catch (RemoteException e) { 9149 throw e.rethrowFromSystemServer(); 9150 } 9151 } 9152 9153 /** 9154 * Returns currently selected audio device for communication. 9155 * <p>This API replaces the following deprecated APIs: 9156 * <ul> 9157 * <li> {@link #isBluetoothScoOn()} 9158 * <li> {@link #isSpeakerphoneOn()} 9159 * </ul> 9160 * @return an {@link AudioDeviceInfo} indicating which audio device is 9161 * currently selected for communication use cases. Can be null on platforms 9162 * not supporting {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}. 9163 * is used. 9164 */ 9165 @Nullable getCommunicationDevice()9166 public AudioDeviceInfo getCommunicationDevice() { 9167 try { 9168 return getDeviceForPortId( 9169 getService().getCommunicationDevice(), GET_DEVICES_OUTPUTS); 9170 } catch (RemoteException e) { 9171 throw e.rethrowFromSystemServer(); 9172 } 9173 } 9174 9175 /** 9176 * Returns a list of audio devices that can be selected for communication use cases via 9177 * {@link #setCommunicationDevice(AudioDeviceInfo)}. 9178 * @return a list of {@link AudioDeviceInfo} suitable for use with setCommunicationDevice(). 9179 */ 9180 @NonNull getAvailableCommunicationDevices()9181 public List<AudioDeviceInfo> getAvailableCommunicationDevices() { 9182 try { 9183 ArrayList<AudioDeviceInfo> devices = new ArrayList<>(); 9184 int[] portIds = getService().getAvailableCommunicationDeviceIds(); 9185 for (int portId : portIds) { 9186 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS); 9187 if (device == null) { 9188 continue; 9189 } 9190 devices.add(device); 9191 } 9192 return devices; 9193 } catch (RemoteException e) { 9194 throw e.rethrowFromSystemServer(); 9195 } 9196 } 9197 9198 /** 9199 * Returns a list of direct {@link AudioProfile} that are supported for the specified 9200 * {@link AudioAttributes}. This can be empty in case of an error or if no direct playback 9201 * is possible. 9202 * 9203 * <p>Direct playback means that the audio stream is not resampled or downmixed 9204 * by the framework. Checking for direct support can help the app select the representation 9205 * of audio content that most closely matches the capabilities of the device and peripherals 9206 * (e.g. A/V receiver) connected to it. Note that the provided stream can still be re-encoded 9207 * or mixed with other streams, if needed. 9208 * <p>When using this information to inform your application which audio format to play, 9209 * query again whenever audio output devices change (see {@link AudioDeviceCallback}). 9210 * @param attributes a non-null {@link AudioAttributes} instance. 9211 * @return a list of {@link AudioProfile} 9212 */ 9213 @NonNull getDirectProfilesForAttributes(@onNull AudioAttributes attributes)9214 public List<AudioProfile> getDirectProfilesForAttributes(@NonNull AudioAttributes attributes) { 9215 Objects.requireNonNull(attributes); 9216 ArrayList<AudioProfile> audioProfilesList = new ArrayList<>(); 9217 int status = AudioSystem.getDirectProfilesForAttributes(attributes, audioProfilesList); 9218 if (status != SUCCESS) { 9219 Log.w(TAG, "getDirectProfilesForAttributes failed."); 9220 return new ArrayList<>(); 9221 } 9222 return audioProfilesList; 9223 } 9224 9225 /** 9226 * @hide 9227 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type provided. 9228 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class, 9229 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}. 9230 * The method will return null if no device of the provided type is connected. 9231 * If more than one device of the provided type is connected, an object corresponding to the 9232 * first device encountered in the enumeration list will be returned. 9233 * @param deviceType The device device for which an <code>AudioDeviceInfo</code> 9234 * object is queried. 9235 * @return An AudioDeviceInfo object or null if no device with the requested type is connected. 9236 * @throws IllegalArgumentException If an invalid device type is specified. 9237 */ 9238 @TestApi 9239 @Nullable getDeviceInfoFromType( @udioDeviceInfo.AudioDeviceTypeOut int deviceType)9240 public static AudioDeviceInfo getDeviceInfoFromType( 9241 @AudioDeviceInfo.AudioDeviceTypeOut int deviceType) { 9242 return getDeviceInfoFromTypeAndAddress(deviceType, null); 9243 } 9244 9245 /** 9246 * @hide 9247 * Returns an {@link AudioDeviceInfo} corresponding to a connected device of the type and 9248 * address provided. 9249 * The type must be a valid output type defined in <code>AudioDeviceInfo</code> class, 9250 * for instance {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}. 9251 * If a null address is provided, the matching will happen on the type only. 9252 * The method will return null if no device of the provided type and address is connected. 9253 * If more than one device of the provided type is connected, an object corresponding to the 9254 * first device encountered in the enumeration list will be returned. 9255 * @param type The device device for which an <code>AudioDeviceInfo</code> 9256 * object is queried. 9257 * @param address The device address for which an <code>AudioDeviceInfo</code> 9258 * object is queried or null if requesting match on type only. 9259 * @return An AudioDeviceInfo object or null if no matching device is connected. 9260 * @throws IllegalArgumentException If an invalid device type is specified. 9261 */ 9262 @Nullable getDeviceInfoFromTypeAndAddress( @udioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address)9263 public static AudioDeviceInfo getDeviceInfoFromTypeAndAddress( 9264 @AudioDeviceInfo.AudioDeviceTypeOut int type, @Nullable String address) { 9265 AudioDeviceInfo[] devices = getDevicesStatic(GET_DEVICES_OUTPUTS); 9266 AudioDeviceInfo deviceForType = null; 9267 for (AudioDeviceInfo device : devices) { 9268 if (device.getType() == type) { 9269 deviceForType = device; 9270 if (address == null || address.equals(device.getAddress())) { 9271 return device; 9272 } 9273 } 9274 } 9275 return deviceForType; 9276 } 9277 9278 /** 9279 * Listener registered by client to be notified upon communication audio device change. 9280 * See {@link #setCommunicationDevice(AudioDeviceInfo)}. 9281 */ 9282 public interface OnCommunicationDeviceChangedListener { 9283 /** 9284 * Callback method called upon communication audio device change. 9285 * @param device the audio device requested for communication use cases. 9286 * Can be null on platforms not supporting 9287 * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY}. 9288 */ onCommunicationDeviceChanged(@ullable AudioDeviceInfo device)9289 void onCommunicationDeviceChanged(@Nullable AudioDeviceInfo device); 9290 } 9291 9292 /** 9293 * manages the OnCommunicationDeviceChangedListener listeners and the 9294 * CommunicationDeviceDispatcherStub 9295 */ 9296 private final CallbackUtil.LazyListenerManager<OnCommunicationDeviceChangedListener> 9297 mCommDeviceChangedListenerMgr = new CallbackUtil.LazyListenerManager(); 9298 /** 9299 * Adds a listener for being notified of changes to the communication audio device. 9300 * See {@link #setCommunicationDevice(AudioDeviceInfo)}. 9301 * @param executor 9302 * @param listener 9303 */ addOnCommunicationDeviceChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnCommunicationDeviceChangedListener listener)9304 public void addOnCommunicationDeviceChangedListener( 9305 @NonNull @CallbackExecutor Executor executor, 9306 @NonNull OnCommunicationDeviceChangedListener listener) { 9307 mCommDeviceChangedListenerMgr.addListener( 9308 executor, listener, "addOnCommunicationDeviceChangedListener", 9309 () -> new CommunicationDeviceDispatcherStub()); 9310 } 9311 9312 /** 9313 * Removes a previously added listener of changes to the communication audio device. 9314 * See {@link #setCommunicationDevice(AudioDeviceInfo)}. 9315 * @param listener 9316 */ removeOnCommunicationDeviceChangedListener( @onNull OnCommunicationDeviceChangedListener listener)9317 public void removeOnCommunicationDeviceChangedListener( 9318 @NonNull OnCommunicationDeviceChangedListener listener) { 9319 mCommDeviceChangedListenerMgr.removeListener(listener, 9320 "removeOnCommunicationDeviceChangedListener"); 9321 } 9322 9323 private final class CommunicationDeviceDispatcherStub 9324 extends ICommunicationDeviceDispatcher.Stub implements CallbackUtil.DispatcherStub { 9325 9326 @Override register(boolean register)9327 public void register(boolean register) { 9328 try { 9329 if (register) { 9330 getService().registerCommunicationDeviceDispatcher(this); 9331 } else { 9332 getService().unregisterCommunicationDeviceDispatcher(this); 9333 } 9334 } catch (RemoteException e) { 9335 e.rethrowFromSystemServer(); 9336 } 9337 } 9338 9339 @Override dispatchCommunicationDeviceChanged(int portId)9340 public void dispatchCommunicationDeviceChanged(int portId) { 9341 AudioDeviceInfo device = getDeviceForPortId(portId, GET_DEVICES_OUTPUTS); 9342 mCommDeviceChangedListenerMgr.callListeners( 9343 (listener) -> listener.onCommunicationDeviceChanged(device)); 9344 } 9345 } 9346 9347 9348 /** 9349 * @hide 9350 * Indicates if the platform allows accessing the uplink and downlink audio of an ongoing 9351 * PSTN call. 9352 * When true, {@link getCallUplinkInjectionAudioTrack(AudioFormat)} can be used to obtain 9353 * an AudioTrack for call uplink audio injection and 9354 * {@link getCallDownlinkExtractionAudioRecord(AudioFormat)} can be used to obtain 9355 * an AudioRecord for call downlink audio extraction. 9356 * @return true if PSTN call audio is accessible, false otherwise. 9357 */ 9358 @TestApi 9359 @SystemApi 9360 @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION) isPstnCallAudioInterceptable()9361 public boolean isPstnCallAudioInterceptable() { 9362 final IAudioService service = getService(); 9363 try { 9364 return service.isPstnCallAudioInterceptable(); 9365 } catch (RemoteException e) { 9366 throw e.rethrowFromSystemServer(); 9367 } 9368 } 9369 9370 /** @hide */ 9371 @IntDef(flag = false, prefix = "CALL_REDIRECT_", value = { 9372 CALL_REDIRECT_NONE, 9373 CALL_REDIRECT_PSTN, 9374 CALL_REDIRECT_VOIP } 9375 ) 9376 @Retention(RetentionPolicy.SOURCE) 9377 public @interface CallRedirectionMode {} 9378 9379 /** 9380 * Not used for call redirection 9381 * @hide 9382 */ 9383 public static final int CALL_REDIRECT_NONE = 0; 9384 /** 9385 * Used to redirect PSTN call 9386 * @hide 9387 */ 9388 public static final int CALL_REDIRECT_PSTN = 1; 9389 /** 9390 * Used to redirect VoIP call 9391 * @hide 9392 */ 9393 public static final int CALL_REDIRECT_VOIP = 2; 9394 9395 getCallRedirectMode()9396 private @CallRedirectionMode int getCallRedirectMode() { 9397 int mode = getMode(); 9398 if (mode == MODE_IN_CALL || mode == MODE_CALL_SCREENING 9399 || mode == MODE_CALL_REDIRECT) { 9400 return CALL_REDIRECT_PSTN; 9401 } else if (mode == MODE_IN_COMMUNICATION || mode == MODE_COMMUNICATION_REDIRECT) { 9402 return CALL_REDIRECT_VOIP; 9403 } 9404 return CALL_REDIRECT_NONE; 9405 } 9406 checkCallRedirectionFormat(AudioFormat format, boolean isOutput)9407 private void checkCallRedirectionFormat(AudioFormat format, boolean isOutput) { 9408 if (format.getEncoding() != AudioFormat.ENCODING_PCM_16BIT 9409 && format.getEncoding() != AudioFormat.ENCODING_PCM_FLOAT) { 9410 throw new UnsupportedOperationException(" Unsupported encoding "); 9411 } 9412 if (format.getSampleRate() < 8000 9413 || format.getSampleRate() > 48000) { 9414 throw new UnsupportedOperationException(" Unsupported sample rate "); 9415 } 9416 if (isOutput && format.getChannelMask() != AudioFormat.CHANNEL_OUT_MONO 9417 && format.getChannelMask() != AudioFormat.CHANNEL_OUT_STEREO) { 9418 throw new UnsupportedOperationException(" Unsupported output channel mask "); 9419 } 9420 if (!isOutput && format.getChannelMask() != AudioFormat.CHANNEL_IN_MONO 9421 && format.getChannelMask() != AudioFormat.CHANNEL_IN_STEREO) { 9422 throw new UnsupportedOperationException(" Unsupported input channel mask "); 9423 } 9424 } 9425 9426 class CallIRedirectionClientInfo { 9427 public WeakReference trackOrRecord; 9428 public int redirectMode; 9429 } 9430 9431 private Object mCallRedirectionLock = new Object(); 9432 @GuardedBy("mCallRedirectionLock") 9433 private CallInjectionModeChangedListener mCallRedirectionModeListener; 9434 @GuardedBy("mCallRedirectionLock") 9435 private ArrayList<CallIRedirectionClientInfo> mCallIRedirectionClients; 9436 9437 /** 9438 * @hide 9439 * Returns an AudioTrack that can be used to inject audio to an active call uplink. 9440 * This can be used for functions like call screening or call audio redirection and is reserved 9441 * to system apps with privileged permission. 9442 * @param format the desired audio format for audio playback. 9443 * p>Formats accepted are: 9444 * <ul> 9445 * <li><em>Sampling rate</em> - 8kHz to 48kHz. </li> 9446 * <li><em>Channel mask</em> - Mono or Stereo </li> 9447 * <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li> 9448 * </ul> 9449 * 9450 * @return The AudioTrack used for audio injection 9451 * @throws NullPointerException if AudioFormat argument is null. 9452 * @throws UnsupportedOperationException if on unsupported AudioFormat is specified. 9453 * @throws IllegalArgumentException if an invalid AudioFormat is specified. 9454 * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION is missing . 9455 * @throws IllegalStateException if current audio mode is not MODE_IN_CALL, 9456 * MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT 9457 * or MODE_COMMUNICATION_REDIRECT. 9458 */ 9459 @TestApi 9460 @SystemApi 9461 @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION) getCallUplinkInjectionAudioTrack(@onNull AudioFormat format)9462 public @NonNull AudioTrack getCallUplinkInjectionAudioTrack(@NonNull AudioFormat format) { 9463 Objects.requireNonNull(format); 9464 checkCallRedirectionFormat(format, true /* isOutput */); 9465 9466 AudioTrack track = null; 9467 int redirectMode = getCallRedirectMode(); 9468 if (redirectMode == CALL_REDIRECT_NONE) { 9469 throw new IllegalStateException( 9470 " not available in mode " + AudioSystem.modeToString(getMode())); 9471 } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) { 9472 throw new UnsupportedOperationException(" PSTN Call audio not accessible "); 9473 } 9474 9475 track = new AudioTrack.Builder() 9476 .setAudioAttributes(new AudioAttributes.Builder() 9477 .setSystemUsage(AudioAttributes.USAGE_CALL_ASSISTANT) 9478 .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) 9479 .build()) 9480 .setAudioFormat(format) 9481 .setCallRedirectionMode(redirectMode) 9482 .build(); 9483 9484 if (track != null && track.getState() != AudioTrack.STATE_UNINITIALIZED) { 9485 synchronized (mCallRedirectionLock) { 9486 if (mCallRedirectionModeListener == null) { 9487 mCallRedirectionModeListener = new CallInjectionModeChangedListener(); 9488 try { 9489 addOnModeChangedListener( 9490 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener); 9491 } catch (Exception e) { 9492 Log.e(TAG, "addOnModeChangedListener failed with exception: " + e); 9493 mCallRedirectionModeListener = null; 9494 throw new UnsupportedOperationException(" Cannot register mode listener "); 9495 } 9496 mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>(); 9497 } 9498 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo(); 9499 info.redirectMode = redirectMode; 9500 info.trackOrRecord = new WeakReference<AudioTrack>(track); 9501 mCallIRedirectionClients.add(info); 9502 } 9503 } else { 9504 throw new UnsupportedOperationException(" Cannot create the AudioTrack"); 9505 } 9506 return track; 9507 } 9508 9509 /** 9510 * @hide 9511 * Returns an AudioRecord that can be used to extract audio from an active call downlink. 9512 * This can be used for functions like call screening or call audio redirection and is reserved 9513 * to system apps with privileged permission. 9514 * @param format the desired audio format for audio capture. 9515 *<p>Formats accepted are: 9516 * <ul> 9517 * <li><em>Sampling rate</em> - 8kHz to 48kHz. </li> 9518 * <li><em>Channel mask</em> - Mono or Stereo </li> 9519 * <li><em>Sample format</em> - PCM 16 bit or FLOAT 32 bit </li> 9520 * </ul> 9521 * 9522 * @return The AudioRecord used for audio extraction 9523 * @throws UnsupportedOperationException if on unsupported AudioFormat is specified. 9524 * @throws IllegalArgumentException if an invalid AudioFormat is specified. 9525 * @throws NullPointerException if AudioFormat argument is null. 9526 * @throws SecurityException if permission CALL_AUDIO_INTERCEPTION is missing . 9527 * @throws IllegalStateException if current audio mode is not MODE_IN_CALL, 9528 * MODE_IN_COMMUNICATION, MODE_CALL_SCREENING, MODE_CALL_REDIRECT 9529 * or MODE_COMMUNICATION_REDIRECT. 9530 */ 9531 @TestApi 9532 @SystemApi 9533 @RequiresPermission(Manifest.permission.CALL_AUDIO_INTERCEPTION) getCallDownlinkExtractionAudioRecord(@onNull AudioFormat format)9534 public @NonNull AudioRecord getCallDownlinkExtractionAudioRecord(@NonNull AudioFormat format) { 9535 Objects.requireNonNull(format); 9536 checkCallRedirectionFormat(format, false /* isOutput */); 9537 9538 AudioRecord record = null; 9539 int redirectMode = getCallRedirectMode(); 9540 if (redirectMode == CALL_REDIRECT_NONE) { 9541 throw new IllegalStateException( 9542 " not available in mode " + AudioSystem.modeToString(getMode())); 9543 } else if (redirectMode == CALL_REDIRECT_PSTN && !isPstnCallAudioInterceptable()) { 9544 throw new UnsupportedOperationException(" PSTN Call audio not accessible "); 9545 } 9546 9547 record = new AudioRecord.Builder() 9548 .setAudioAttributes(new AudioAttributes.Builder() 9549 .setInternalCapturePreset(MediaRecorder.AudioSource.VOICE_DOWNLINK) 9550 .build()) 9551 .setAudioFormat(format) 9552 .setCallRedirectionMode(redirectMode) 9553 .build(); 9554 9555 if (record != null && record.getState() != AudioRecord.STATE_UNINITIALIZED) { 9556 synchronized (mCallRedirectionLock) { 9557 if (mCallRedirectionModeListener == null) { 9558 mCallRedirectionModeListener = new CallInjectionModeChangedListener(); 9559 try { 9560 addOnModeChangedListener( 9561 Executors.newSingleThreadExecutor(), mCallRedirectionModeListener); 9562 } catch (Exception e) { 9563 Log.e(TAG, "addOnModeChangedListener failed with exception: " + e); 9564 mCallRedirectionModeListener = null; 9565 throw new UnsupportedOperationException(" Cannot register mode listener "); 9566 } 9567 mCallIRedirectionClients = new ArrayList<CallIRedirectionClientInfo>(); 9568 } 9569 CallIRedirectionClientInfo info = new CallIRedirectionClientInfo(); 9570 info.redirectMode = redirectMode; 9571 info.trackOrRecord = new WeakReference<AudioRecord>(record); 9572 mCallIRedirectionClients.add(info); 9573 } 9574 } else { 9575 throw new UnsupportedOperationException(" Cannot create the AudioRecord"); 9576 } 9577 return record; 9578 } 9579 9580 class CallInjectionModeChangedListener implements OnModeChangedListener { 9581 @Override onModeChanged(@udioMode int mode)9582 public void onModeChanged(@AudioMode int mode) { 9583 synchronized (mCallRedirectionLock) { 9584 final ArrayList<CallIRedirectionClientInfo> clientInfos = 9585 (ArrayList<CallIRedirectionClientInfo>) mCallIRedirectionClients.clone(); 9586 for (CallIRedirectionClientInfo info : clientInfos) { 9587 Object trackOrRecord = info.trackOrRecord.get(); 9588 if (trackOrRecord != null) { 9589 if ((info.redirectMode == CALL_REDIRECT_PSTN 9590 && mode != MODE_IN_CALL && mode != MODE_CALL_SCREENING 9591 && mode != MODE_CALL_REDIRECT) 9592 || (info.redirectMode == CALL_REDIRECT_VOIP 9593 && mode != MODE_IN_COMMUNICATION 9594 && mode != MODE_COMMUNICATION_REDIRECT)) { 9595 if (trackOrRecord instanceof AudioTrack) { 9596 AudioTrack track = (AudioTrack) trackOrRecord; 9597 track.release(); 9598 } else { 9599 AudioRecord record = (AudioRecord) trackOrRecord; 9600 record.release(); 9601 } 9602 mCallIRedirectionClients.remove(info); 9603 } 9604 } 9605 } 9606 if (mCallIRedirectionClients.isEmpty()) { 9607 try { 9608 if (mCallRedirectionModeListener != null) { 9609 removeOnModeChangedListener(mCallRedirectionModeListener); 9610 } 9611 } catch (Exception e) { 9612 Log.e(TAG, "removeOnModeChangedListener failed with exception: " + e); 9613 } finally { 9614 mCallRedirectionModeListener = null; 9615 mCallIRedirectionClients = null; 9616 } 9617 } 9618 } 9619 } 9620 } 9621 9622 //--------------------------------------------------------- 9623 // audio device connection-dependent muting 9624 /** 9625 * @hide 9626 * Mute a set of playback use cases until a given audio device is connected. 9627 * Automatically unmute upon connection of the device, or after the given timeout, whichever 9628 * happens first. 9629 * @param usagesToMute non-empty array of {@link AudioAttributes} usages (for example 9630 * {@link AudioAttributes#USAGE_MEDIA}) to mute until the 9631 * device connects 9632 * @param device the audio device expected to connect within the timeout duration 9633 * @param timeout the maximum amount of time to wait for the device connection 9634 * @param timeUnit the unit for the timeout 9635 * @throws IllegalStateException when trying to issue the command while another is already in 9636 * progress and hasn't been cancelled by 9637 * {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)}. See 9638 * {@link #getMutingExpectedDevice()} to check if a muting command is active. 9639 * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback) 9640 */ 9641 @SystemApi 9642 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) muteAwaitConnection(@onNull int[] usagesToMute, @NonNull AudioDeviceAttributes device, long timeout, @NonNull TimeUnit timeUnit)9643 public void muteAwaitConnection(@NonNull int[] usagesToMute, 9644 @NonNull AudioDeviceAttributes device, 9645 long timeout, @NonNull TimeUnit timeUnit) throws IllegalStateException { 9646 if (timeout <= 0) { 9647 throw new IllegalArgumentException("Timeout must be greater than 0"); 9648 } 9649 Objects.requireNonNull(usagesToMute); 9650 if (usagesToMute.length == 0) { 9651 throw new IllegalArgumentException("Array of usages to mute cannot be empty"); 9652 } 9653 Objects.requireNonNull(device); 9654 Objects.requireNonNull(timeUnit); 9655 try { 9656 getService().muteAwaitConnection(usagesToMute, device, timeUnit.toMillis(timeout)); 9657 } catch (RemoteException e) { 9658 throw e.rethrowFromSystemServer(); 9659 } 9660 } 9661 9662 /** 9663 * @hide 9664 * Query which audio device, if any, is causing some playback use cases to be muted until it 9665 * connects. 9666 * @return the audio device used in 9667 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}, or null 9668 * if there is no active muting command (either because the muting command was not issued 9669 * or because it timed out) 9670 */ 9671 @SystemApi 9672 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) getMutingExpectedDevice()9673 public @Nullable AudioDeviceAttributes getMutingExpectedDevice() { 9674 try { 9675 return getService().getMutingExpectedDevice(); 9676 } catch (RemoteException e) { 9677 throw e.rethrowFromSystemServer(); 9678 } 9679 } 9680 9681 /** 9682 * @hide 9683 * Cancel a {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)} 9684 * command. 9685 * @param device the device whose connection was expected when the {@code muteAwaitConnection} 9686 * command was issued. 9687 * @throws IllegalStateException when trying to issue the command for a device whose connection 9688 * is not anticipated by a previous call to 9689 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)} 9690 */ 9691 @SystemApi 9692 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) cancelMuteAwaitConnection(@onNull AudioDeviceAttributes device)9693 public void cancelMuteAwaitConnection(@NonNull AudioDeviceAttributes device) 9694 throws IllegalStateException { 9695 Objects.requireNonNull(device); 9696 try { 9697 getService().cancelMuteAwaitConnection(device); 9698 } catch (RemoteException e) { 9699 throw e.rethrowFromSystemServer(); 9700 } 9701 } 9702 9703 /** 9704 * @hide 9705 * A callback class to receive events about the muting and unmuting of playback use cases 9706 * conditional on the upcoming connection of an audio device. 9707 * @see #registerMuteAwaitConnectionCallback(Executor, AudioManager.MuteAwaitConnectionCallback) 9708 */ 9709 @SystemApi 9710 public abstract static class MuteAwaitConnectionCallback { 9711 9712 /** 9713 * An event where the expected audio device connected 9714 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[]) 9715 */ 9716 public static final int EVENT_CONNECTION = 1; 9717 /** 9718 * An event where the expected audio device failed connect before the timeout happened 9719 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[]) 9720 */ 9721 public static final int EVENT_TIMEOUT = 2; 9722 /** 9723 * An event where the {@code muteAwaitConnection()} command 9724 * was cancelled with {@link #cancelMuteAwaitConnection(AudioDeviceAttributes)} 9725 * @see MuteAwaitConnectionCallback#onUnmutedEvent(int, AudioDeviceAttributes, int[]) 9726 */ 9727 public static final int EVENT_CANCEL = 3; 9728 9729 /** @hide */ 9730 @IntDef(flag = false, prefix = "EVENT_", value = { 9731 EVENT_CONNECTION, 9732 EVENT_TIMEOUT, 9733 EVENT_CANCEL } 9734 ) 9735 @Retention(RetentionPolicy.SOURCE) 9736 public @interface UnmuteEvent {} 9737 9738 /** 9739 * Called when a number of playback use cases are muted in response to a call to 9740 * {@link #muteAwaitConnection(int[], AudioDeviceAttributes, long, TimeUnit)}. 9741 * @param device the audio device whose connection is expected. Playback use cases are 9742 * unmuted when that device connects 9743 * @param mutedUsages an array of {@link AudioAttributes} usages that describe the affected 9744 * playback use cases. 9745 */ onMutedUntilConnection( @onNull AudioDeviceAttributes device, @NonNull int[] mutedUsages)9746 public void onMutedUntilConnection( 9747 @NonNull AudioDeviceAttributes device, 9748 @NonNull int[] mutedUsages) {} 9749 9750 /** 9751 * Called when an event occurred that caused playback uses cases to be unmuted 9752 * @param unmuteEvent the nature of the event 9753 * @param device the device that was expected to connect 9754 * @param mutedUsages the array of {@link AudioAttributes} usages that were muted until 9755 * the event occurred 9756 */ onUnmutedEvent( @nmuteEvent int unmuteEvent, @NonNull AudioDeviceAttributes device, @NonNull int[] mutedUsages)9757 public void onUnmutedEvent( 9758 @UnmuteEvent int unmuteEvent, 9759 @NonNull AudioDeviceAttributes device, @NonNull int[] mutedUsages) {} 9760 } 9761 9762 9763 /** 9764 * @hide 9765 * Register a callback to receive updates on the playback muting conditional on a specific 9766 * audio device connection. 9767 * @param executor the {@link Executor} handling the callback 9768 * @param callback the callback to register 9769 */ 9770 @SystemApi 9771 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) registerMuteAwaitConnectionCallback( @onNull @allbackExecutor Executor executor, @NonNull MuteAwaitConnectionCallback callback)9772 public void registerMuteAwaitConnectionCallback( 9773 @NonNull @CallbackExecutor Executor executor, 9774 @NonNull MuteAwaitConnectionCallback callback) { 9775 synchronized (mMuteAwaitConnectionListenerLock) { 9776 final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>, 9777 MuteAwaitConnectionDispatcherStub> res = 9778 CallbackUtil.addListener("registerMuteAwaitConnectionCallback", 9779 executor, callback, mMuteAwaitConnectionListeners, 9780 mMuteAwaitConnDispatcherStub, 9781 () -> new MuteAwaitConnectionDispatcherStub(), 9782 stub -> stub.register(true)); 9783 mMuteAwaitConnectionListeners = res.first; 9784 mMuteAwaitConnDispatcherStub = res.second; 9785 } 9786 } 9787 9788 /** 9789 * @hide 9790 * Unregister a previously registered callback for playback muting conditional on device 9791 * connection. 9792 * @param callback the callback to unregister 9793 */ 9794 @SystemApi 9795 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) unregisterMuteAwaitConnectionCallback( @onNull MuteAwaitConnectionCallback callback)9796 public void unregisterMuteAwaitConnectionCallback( 9797 @NonNull MuteAwaitConnectionCallback callback) { 9798 synchronized (mMuteAwaitConnectionListenerLock) { 9799 final Pair<ArrayList<ListenerInfo<MuteAwaitConnectionCallback>>, 9800 MuteAwaitConnectionDispatcherStub> res = 9801 CallbackUtil.removeListener("unregisterMuteAwaitConnectionCallback", 9802 callback, mMuteAwaitConnectionListeners, mMuteAwaitConnDispatcherStub, 9803 stub -> stub.register(false)); 9804 mMuteAwaitConnectionListeners = res.first; 9805 mMuteAwaitConnDispatcherStub = res.second; 9806 } 9807 } 9808 9809 /** 9810 * Add UIDs that can be considered as assistant. 9811 * 9812 * @param assistantUids UIDs of the services that can be considered as assistant. 9813 * 9814 * @hide 9815 */ 9816 @SystemApi 9817 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) addAssistantServicesUids(@onNull int[] assistantUids)9818 public void addAssistantServicesUids(@NonNull int[] assistantUids) { 9819 try { 9820 getService().addAssistantServicesUids(assistantUids); 9821 } catch (RemoteException e) { 9822 throw e.rethrowFromSystemServer(); 9823 } 9824 } 9825 9826 /** 9827 * Remove UIDs that can be considered as assistant. 9828 * 9829 * @param assistantUids UIDs of the services that should be remove. 9830 * 9831 * @hide 9832 */ 9833 @SystemApi 9834 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) removeAssistantServicesUids(@onNull int[] assistantUids)9835 public void removeAssistantServicesUids(@NonNull int[] assistantUids) { 9836 try { 9837 getService().removeAssistantServicesUids(assistantUids); 9838 } catch (RemoteException e) { 9839 throw e.rethrowFromSystemServer(); 9840 } 9841 } 9842 9843 /** 9844 * Get the assistants UIDs that been added with the 9845 * {@link #addAssistantServicesUids(int[])} and not yet removed with 9846 * {@link #removeAssistantServicesUids(int[])} 9847 * 9848 * <p> Note that during native audioserver crash and after boot up the list of assistant 9849 * UIDs will be reset to an empty list (i.e. no UID will be considered as assistant) 9850 * Just after user switch, the list of assistant will also reset to empty. 9851 * In both cases,The component's UID of the assistiant role or assistant setting will be 9852 * automitically added to the list by the audio service. 9853 * 9854 * @return array of assistants UIDs 9855 * 9856 * @hide 9857 */ 9858 @SystemApi 9859 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) getAssistantServicesUids()9860 public @NonNull int[] getAssistantServicesUids() { 9861 try { 9862 int[] uids = getService().getAssistantServicesUids(); 9863 return Arrays.copyOf(uids, uids.length); 9864 } catch (RemoteException e) { 9865 throw e.rethrowFromSystemServer(); 9866 } 9867 } 9868 9869 /** 9870 * Sets UIDs that can be considered as active assistant. Calling the API with a new array will 9871 * overwrite previous UIDs. If the array of UIDs is empty then no UID will be considered active. 9872 * In this manner calling the API with an empty array will remove all UIDs previously set. 9873 * 9874 * @param assistantUids UIDs of the services that can be considered active assistant. Can be 9875 * an empty array, for this no UID will be considered active. 9876 * 9877 * <p> Note that during audio service crash reset and after boot up the list of active assistant 9878 * UIDs will be reset to an empty list (i.e. no UID will be considered as an active assistant). 9879 * Just after user switch the list of active assistant will also reset to empty. 9880 * 9881 * @hide 9882 */ 9883 @SystemApi 9884 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setActiveAssistantServiceUids(@onNull int[] assistantUids)9885 public void setActiveAssistantServiceUids(@NonNull int[] assistantUids) { 9886 try { 9887 getService().setActiveAssistantServiceUids(assistantUids); 9888 } catch (RemoteException e) { 9889 throw e.rethrowFromSystemServer(); 9890 } 9891 } 9892 9893 /** 9894 * Get active assistant UIDs last set with the 9895 * {@link #setActiveAssistantServiceUids(int[])} 9896 * 9897 * @return array of active assistants UIDs 9898 * 9899 * @hide 9900 */ 9901 @SystemApi 9902 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) getActiveAssistantServicesUids()9903 public @NonNull int[] getActiveAssistantServicesUids() { 9904 try { 9905 int[] uids = getService().getActiveAssistantServiceUids(); 9906 return Arrays.copyOf(uids, uids.length); 9907 } catch (RemoteException e) { 9908 throw e.rethrowFromSystemServer(); 9909 } 9910 } 9911 9912 /** 9913 * Returns an {@link AudioHalVersionInfo} indicating the Audio Hal Version. If there is no audio 9914 * HAL found, null will be returned. 9915 * 9916 * @return @see @link #AudioHalVersionInfo The version of Audio HAL. 9917 * @hide 9918 */ 9919 @TestApi getHalVersion()9920 public static @Nullable AudioHalVersionInfo getHalVersion() { 9921 try { 9922 return getService().getHalVersion(); 9923 } catch (RemoteException e) { 9924 Log.e(TAG, "Error querying getHalVersion", e); 9925 throw e.rethrowFromSystemServer(); 9926 } 9927 } 9928 9929 //==================================================================== 9930 // Preferred mixer attributes 9931 9932 /** 9933 * Returns the {@link AudioMixerAttributes} that can be used to set as preferred mixer 9934 * attributes via {@link #setPreferredMixerAttributes( 9935 * AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)}. 9936 * <p>Note that only USB devices are guaranteed to expose configurable mixer attributes. An 9937 * empty list may be returned for all other types of devices as they may not allow dynamic 9938 * configuration. 9939 * 9940 * @param device the device to query 9941 * @return a list of {@link AudioMixerAttributes} that can be used as preferred mixer attributes 9942 * for the given device. 9943 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes) 9944 */ 9945 @NonNull getSupportedMixerAttributes(@onNull AudioDeviceInfo device)9946 public List<AudioMixerAttributes> getSupportedMixerAttributes(@NonNull AudioDeviceInfo device) { 9947 Objects.requireNonNull(device); 9948 List<AudioMixerAttributes> mixerAttrs = new ArrayList<>(); 9949 return (AudioSystem.getSupportedMixerAttributes(device.getId(), mixerAttrs) 9950 == AudioSystem.SUCCESS) ? mixerAttrs : new ArrayList<>(); 9951 } 9952 9953 /** 9954 * Configures the mixer attributes for a particular {@link AudioAttributes} over a given 9955 * {@link AudioDeviceInfo}. 9956 * <p>Call {@link #getSupportedMixerAttributes(AudioDeviceInfo)} to determine which mixer 9957 * attributes can be used with the given device. 9958 * <p>The ownership of preferred mixer attributes is recognized by uid. When a playback from the 9959 * same uid is routed to the given audio device when calling this API, the output mixer/stream 9960 * will be configured with the values previously set via this API. 9961 * <p>Use {@link #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)} 9962 * to cancel setting mixer attributes for this {@link AudioAttributes}. 9963 * 9964 * @param attributes the {@link AudioAttributes} whose mixer attributes should be set. 9965 * Currently, only {@link AudioAttributes#USAGE_MEDIA} is supported. When 9966 * playing audio targeted at the given device, use the same attributes for 9967 * playback. 9968 * @param device the device to be routed. Currently, only USB device will be allowed. 9969 * @param mixerAttributes the preferred mixer attributes. When playing audio targeted at the 9970 * given device, use the same {@link AudioFormat} for both playback 9971 * and the mixer attributes. 9972 * @return true only if the preferred mixer attributes are set successfully. 9973 * @see #getPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo) 9974 * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo) 9975 */ 9976 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS) setPreferredMixerAttributes(@onNull AudioAttributes attributes, @NonNull AudioDeviceInfo device, @NonNull AudioMixerAttributes mixerAttributes)9977 public boolean setPreferredMixerAttributes(@NonNull AudioAttributes attributes, 9978 @NonNull AudioDeviceInfo device, 9979 @NonNull AudioMixerAttributes mixerAttributes) { 9980 Objects.requireNonNull(attributes); 9981 Objects.requireNonNull(device); 9982 Objects.requireNonNull(mixerAttributes); 9983 try { 9984 final int status = getService().setPreferredMixerAttributes( 9985 attributes, device.getId(), mixerAttributes); 9986 return status == AudioSystem.SUCCESS; 9987 } catch (RemoteException e) { 9988 throw e.rethrowFromSystemServer(); 9989 } 9990 } 9991 9992 /** 9993 * Returns current preferred mixer attributes that is set via 9994 * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)} 9995 * 9996 * @param attributes the {@link AudioAttributes} whose mixer attributes should be set. 9997 * @param device the expected routing device 9998 * @return the preferred mixer attributes, which will be null when no preferred mixer attributes 9999 * have been set, or when they have been cleared. 10000 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes) 10001 * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo) 10002 */ 10003 @Nullable getPreferredMixerAttributes( @onNull AudioAttributes attributes, @NonNull AudioDeviceInfo device)10004 public AudioMixerAttributes getPreferredMixerAttributes( 10005 @NonNull AudioAttributes attributes, 10006 @NonNull AudioDeviceInfo device) { 10007 Objects.requireNonNull(attributes); 10008 Objects.requireNonNull(device); 10009 List<AudioMixerAttributes> mixerAttrList = new ArrayList<>(); 10010 int ret = AudioSystem.getPreferredMixerAttributes( 10011 attributes, device.getId(), mixerAttrList); 10012 if (ret == AudioSystem.SUCCESS) { 10013 return mixerAttrList.isEmpty() ? null : mixerAttrList.get(0); 10014 } else { 10015 Log.e(TAG, "Failed calling getPreferredMixerAttributes, ret=" + ret); 10016 return null; 10017 } 10018 } 10019 10020 /** 10021 * Clears the current preferred mixer attributes that were previously set via 10022 * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)} 10023 * 10024 * @param attributes the {@link AudioAttributes} whose mixer attributes should be cleared. 10025 * @param device the expected routing device 10026 * @return true only if the preferred mixer attributes are removed successfully. 10027 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes) 10028 * @see #getPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo) 10029 */ 10030 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS) clearPreferredMixerAttributes( @onNull AudioAttributes attributes, @NonNull AudioDeviceInfo device)10031 public boolean clearPreferredMixerAttributes( 10032 @NonNull AudioAttributes attributes, 10033 @NonNull AudioDeviceInfo device) { 10034 Objects.requireNonNull(attributes); 10035 Objects.requireNonNull(device); 10036 try { 10037 final int status = getService().clearPreferredMixerAttributes( 10038 attributes, device.getId()); 10039 return status == AudioSystem.SUCCESS; 10040 } catch (RemoteException e) { 10041 throw e.rethrowFromSystemServer(); 10042 } 10043 } 10044 10045 /** 10046 * Interface to be notified of changes in the preferred mixer attributes. 10047 * <p>Note that this listener will only be invoked whenever 10048 * {@link #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes)} 10049 * or {@link #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo)} or device 10050 * disconnection causes a change in preferred mixer attributes. 10051 * @see #setPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo, AudioMixerAttributes) 10052 * @see #clearPreferredMixerAttributes(AudioAttributes, AudioDeviceInfo) 10053 */ 10054 public interface OnPreferredMixerAttributesChangedListener { 10055 /** 10056 * Called on the listener to indicate that the preferred mixer attributes for the audio 10057 * attributes over the given device has changed. 10058 * 10059 * @param attributes the audio attributes for playback 10060 * @param device the targeted device 10061 * @param mixerAttributes the {@link AudioMixerAttributes} that contains information for 10062 * preferred mixer attributes or null if preferred mixer attributes 10063 * is cleared 10064 */ onPreferredMixerAttributesChanged( @onNull AudioAttributes attributes, @NonNull AudioDeviceInfo device, @Nullable AudioMixerAttributes mixerAttributes)10065 void onPreferredMixerAttributesChanged( 10066 @NonNull AudioAttributes attributes, 10067 @NonNull AudioDeviceInfo device, 10068 @Nullable AudioMixerAttributes mixerAttributes); 10069 } 10070 10071 /** 10072 * Manage the {@link OnPreferredMixerAttributesChangedListener} listeners and the 10073 * {@link PreferredMixerAttributesDispatcherStub}. 10074 */ 10075 private final CallbackUtil.LazyListenerManager<OnPreferredMixerAttributesChangedListener> 10076 mPrefMixerAttributesListenerMgr = new CallbackUtil.LazyListenerManager(); 10077 10078 /** 10079 * Adds a listener for being notified of changes to the preferred mixer attributes. 10080 * @param executor the executor to execute the callback 10081 * @param listener the listener to be notified of changes in the preferred mixer attributes. 10082 */ addOnPreferredMixerAttributesChangedListener( @onNull @allbackExecutor Executor executor, @NonNull OnPreferredMixerAttributesChangedListener listener)10083 public void addOnPreferredMixerAttributesChangedListener( 10084 @NonNull @CallbackExecutor Executor executor, 10085 @NonNull OnPreferredMixerAttributesChangedListener listener) { 10086 Objects.requireNonNull(executor); 10087 Objects.requireNonNull(listener); 10088 mPrefMixerAttributesListenerMgr.addListener(executor, listener, 10089 "addOnPreferredMixerAttributesChangedListener", 10090 () -> new PreferredMixerAttributesDispatcherStub()); 10091 } 10092 10093 /** 10094 * Removes a previously added listener of changes to the preferred mixer attributes. 10095 * @param listener the listener to be notified of changes in the preferred mixer attributes, 10096 * which were added via {@link #addOnPreferredMixerAttributesChangedListener( 10097 * Executor, OnPreferredMixerAttributesChangedListener)}. 10098 */ removeOnPreferredMixerAttributesChangedListener( @onNull OnPreferredMixerAttributesChangedListener listener)10099 public void removeOnPreferredMixerAttributesChangedListener( 10100 @NonNull OnPreferredMixerAttributesChangedListener listener) { 10101 Objects.requireNonNull(listener); 10102 mPrefMixerAttributesListenerMgr.removeListener(listener, 10103 "removeOnPreferredMixerAttributesChangedListener"); 10104 } 10105 10106 private final class PreferredMixerAttributesDispatcherStub 10107 extends IPreferredMixerAttributesDispatcher.Stub 10108 implements CallbackUtil.DispatcherStub { 10109 10110 @Override register(boolean register)10111 public void register(boolean register) { 10112 try { 10113 if (register) { 10114 getService().registerPreferredMixerAttributesDispatcher(this); 10115 } else { 10116 getService().unregisterPreferredMixerAttributesDispatcher(this); 10117 } 10118 } catch (RemoteException e) { 10119 e.rethrowFromSystemServer(); 10120 } 10121 } 10122 10123 @Override dispatchPrefMixerAttributesChanged(@onNull AudioAttributes attr, int deviceId, @Nullable AudioMixerAttributes mixerAttr)10124 public void dispatchPrefMixerAttributesChanged(@NonNull AudioAttributes attr, 10125 int deviceId, 10126 @Nullable AudioMixerAttributes mixerAttr) { 10127 // TODO: If the device is disconnected, we may not be able to find the device with 10128 // given device id. We need a better to carry the device information via binder. 10129 AudioDeviceInfo device = getDeviceForPortId(deviceId, GET_DEVICES_OUTPUTS); 10130 if (device == null) { 10131 Log.d(TAG, "Drop preferred mixer attributes changed as the device(" 10132 + deviceId + ") is disconnected"); 10133 return; 10134 } 10135 mPrefMixerAttributesListenerMgr.callListeners( 10136 (listener) -> listener.onPreferredMixerAttributesChanged( 10137 attr, device, mixerAttr)); 10138 } 10139 } 10140 10141 /** 10142 * Requests if the implementation supports controlling the latency modes 10143 * over the Bluetooth A2DP or LE Audio links. 10144 * 10145 * @return true if supported, false otherwise 10146 * 10147 * @hide 10148 */ 10149 @SystemApi 10150 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) supportsBluetoothVariableLatency()10151 public boolean supportsBluetoothVariableLatency() { 10152 try { 10153 return getService().supportsBluetoothVariableLatency(); 10154 } catch (RemoteException e) { 10155 throw e.rethrowFromSystemServer(); 10156 } 10157 } 10158 10159 /** 10160 * Enables or disables the variable Bluetooth latency control mechanism in the 10161 * audio framework and the audio HAL. This does not apply to the latency mode control 10162 * on the spatializer output as this is a built-in feature. 10163 * 10164 * @hide 10165 */ 10166 @SystemApi 10167 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) setBluetoothVariableLatencyEnabled(boolean enabled)10168 public void setBluetoothVariableLatencyEnabled(boolean enabled) { 10169 try { 10170 getService().setBluetoothVariableLatencyEnabled(enabled); 10171 } catch (RemoteException e) { 10172 throw e.rethrowFromSystemServer(); 10173 } 10174 } 10175 10176 /** 10177 * Indicates if the variable Bluetooth latency control mechanism is enabled or disabled. 10178 * @hide 10179 */ 10180 @SystemApi 10181 @RequiresPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) isBluetoothVariableLatencyEnabled()10182 public boolean isBluetoothVariableLatencyEnabled() { 10183 try { 10184 return getService().isBluetoothVariableLatencyEnabled(); 10185 } catch (RemoteException e) { 10186 throw e.rethrowFromSystemServer(); 10187 } 10188 } 10189 10190 //==================================================================== 10191 // Stream aliasing changed listener, getter for stream alias or independent streams 10192 10193 /** 10194 * manages the stream aliasing listeners and StreamAliasingDispatcherStub 10195 */ 10196 private final CallbackUtil.LazyListenerManager<Runnable> mStreamAliasingListenerMgr = 10197 new CallbackUtil.LazyListenerManager(); 10198 10199 10200 final class StreamAliasingDispatcherStub extends IStreamAliasingDispatcher.Stub 10201 implements CallbackUtil.DispatcherStub { 10202 10203 @Override register(boolean register)10204 public void register(boolean register) { 10205 try { 10206 getService().registerStreamAliasingDispatcher(this, register); 10207 } catch (RemoteException e) { 10208 e.rethrowFromSystemServer(); 10209 } 10210 } 10211 10212 @Override dispatchStreamAliasingChanged()10213 public void dispatchStreamAliasingChanged() { 10214 mStreamAliasingListenerMgr.callListeners((listener) -> listener.run()); 10215 } 10216 } 10217 10218 /** 10219 * @hide 10220 * Adds a listener to be notified of changes to volume stream type aliasing. 10221 * See {@link #getIndependentStreamTypes()} and {@link #getStreamTypeAlias(int)} 10222 * @param executor the Executor running the listener 10223 * @param onStreamAliasingChangedListener the listener to add for the aliasing changes 10224 */ 10225 @SystemApi 10226 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) addOnStreamAliasingChangedListener( @onNull @allbackExecutor Executor executor, @NonNull Runnable onStreamAliasingChangedListener)10227 public void addOnStreamAliasingChangedListener( 10228 @NonNull @CallbackExecutor Executor executor, 10229 @NonNull Runnable onStreamAliasingChangedListener) { 10230 mStreamAliasingListenerMgr.addListener(executor, onStreamAliasingChangedListener, 10231 "addOnStreamAliasingChangedListener", 10232 () -> new StreamAliasingDispatcherStub()); 10233 } 10234 10235 /** 10236 * @hide 10237 * Removes a previously added listener for changes to stream aliasing. 10238 * See {@link #getIndependentStreamTypes()} and {@link #getStreamTypeAlias(int)} 10239 * @see #addOnStreamAliasingChangedListener(Executor, Runnable) 10240 * @param onStreamAliasingChangedListener the previously added listener of aliasing changes 10241 */ 10242 @SystemApi 10243 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) removeOnStreamAliasingChangedListener( @onNull Runnable onStreamAliasingChangedListener)10244 public void removeOnStreamAliasingChangedListener( 10245 @NonNull Runnable onStreamAliasingChangedListener) { 10246 mStreamAliasingListenerMgr.removeListener(onStreamAliasingChangedListener, 10247 "removeOnStreamAliasingChangedListener"); 10248 } 10249 10250 /** 10251 * @hide 10252 * Test method to temporarily override whether STREAM_NOTIFICATION is aliased to STREAM_RING, 10253 * volumes will be updated in case of a change. 10254 * @param isAliased if true, STREAM_NOTIFICATION is aliased to STREAM_RING 10255 */ 10256 @TestApi 10257 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) setNotifAliasRingForTest(boolean isAliased)10258 public void setNotifAliasRingForTest(boolean isAliased) { 10259 final IAudioService service = getService(); 10260 try { 10261 service.setNotifAliasRingForTest(isAliased); 10262 } catch (RemoteException e) { 10263 throw e.rethrowFromSystemServer(); 10264 } 10265 } 10266 10267 /** 10268 * @hide 10269 * Blocks until permission updates have propagated through the audio system. 10270 * Only useful in tests, where adoptShellPermissions can change the permission state of 10271 * an app without the app being killed. 10272 */ 10273 @TestApi 10274 @SuppressWarnings("UnflaggedApi") // @TestApi without associated feature. permissionUpdateBarrier()10275 public void permissionUpdateBarrier() { 10276 final IAudioService service = getService(); 10277 try { 10278 service.permissionUpdateBarrier(); 10279 } catch (RemoteException e) { 10280 throw e.rethrowFromSystemServer(); 10281 } 10282 } 10283 10284 10285 /** 10286 * @hide 10287 * Return the list of independent stream types for volume control. 10288 * A stream type is considered independent when the volume changes of that type do not 10289 * affect any other independent volume control stream type. 10290 * An independent stream type is its own alias when using {@link #getStreamTypeAlias(int)}. 10291 * @return list of independent stream types, where each value can be one of 10292 * {@link #STREAM_VOICE_CALL}, {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, 10293 * {@link #STREAM_MUSIC}, {@link #STREAM_ALARM}, {@link #STREAM_NOTIFICATION}, 10294 * {@link #STREAM_DTMF} and {@link #STREAM_ACCESSIBILITY}. 10295 */ 10296 @SystemApi 10297 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) getIndependentStreamTypes()10298 public @NonNull List<Integer> getIndependentStreamTypes() { 10299 final IAudioService service = getService(); 10300 try { 10301 return service.getIndependentStreamTypes(); 10302 } catch (RemoteException e) { 10303 throw e.rethrowFromSystemServer(); 10304 } 10305 } 10306 10307 /** 10308 * @hide 10309 * Return the stream type that a given stream is aliased to. 10310 * A stream alias means that any change to the source stream will also be applied to the alias, 10311 * and vice-versa. 10312 * If a stream is independent (i.e. part of the stream types returned by 10313 * {@link #getIndependentStreamTypes()}), its alias is itself. 10314 * @param sourceStreamType the stream type to query for the alias. 10315 * @return the stream type the source type is aliased to. 10316 */ 10317 @SystemApi 10318 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) getStreamTypeAlias(@ublicStreamTypes int sourceStreamType)10319 public @PublicStreamTypes int getStreamTypeAlias(@PublicStreamTypes int sourceStreamType) { 10320 final IAudioService service = getService(); 10321 try { 10322 return service.getStreamTypeAlias(sourceStreamType); 10323 } catch (RemoteException e) { 10324 throw e.rethrowFromSystemServer(); 10325 } 10326 } 10327 10328 /** 10329 * @hide 10330 * Returns whether the system uses {@link AudioVolumeGroup} for volume control 10331 * @return true when volume control is performed through volume groups, false if it uses 10332 * stream types. 10333 */ 10334 @TestApi 10335 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) isVolumeControlUsingVolumeGroups()10336 public boolean isVolumeControlUsingVolumeGroups() { 10337 final IAudioService service = getService(); 10338 try { 10339 return service.isVolumeControlUsingVolumeGroups(); 10340 } catch (RemoteException e) { 10341 throw e.rethrowFromSystemServer(); 10342 } 10343 } 10344 10345 /** 10346 * @hide 10347 * Checks whether a notification sound should be played or not, as reported by the state 10348 * of the audio framework. Querying whether playback should proceed is favored over 10349 * playing and letting the sound be muted or not. 10350 * @param aa the {@link AudioAttributes} of the notification about to maybe play 10351 * @return true if the audio framework state is such that the notification should be played 10352 * because at time of checking, and the notification will be heard, 10353 * false otherwise 10354 */ 10355 @TestApi 10356 @FlaggedApi(FLAG_FOCUS_EXCLUSIVE_WITH_RECORDING) 10357 @RequiresPermission(android.Manifest.permission.QUERY_AUDIO_STATE) shouldNotificationSoundPlay(@onNull final AudioAttributes aa)10358 public boolean shouldNotificationSoundPlay(@NonNull final AudioAttributes aa) { 10359 final IAudioService service = getService(); 10360 try { 10361 return service.shouldNotificationSoundPlay(Objects.requireNonNull(aa)); 10362 } catch (RemoteException e) { 10363 throw e.rethrowFromSystemServer(); 10364 } 10365 } 10366 10367 /** 10368 * Enable strict audio hardening (background) enforcement, regardless of release or temporary 10369 * exemptions for debugging purposes. 10370 * Enforced hardening can be found in the audio dumpsys with the API being restricted and the 10371 * level of restriction which was encountered. 10372 * @hide 10373 */ 10374 @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) setEnableHardening(boolean shouldEnable)10375 public void setEnableHardening(boolean shouldEnable) { 10376 final IAudioService service = getService(); 10377 try { 10378 service.setEnableHardening(shouldEnable); 10379 } catch (RemoteException e) { 10380 throw e.rethrowFromSystemServer(); 10381 } 10382 } 10383 10384 //==================================================================== 10385 // Mute await connection 10386 10387 private final Object mMuteAwaitConnectionListenerLock = new Object(); 10388 10389 @GuardedBy("mMuteAwaitConnectionListenerLock") 10390 private @Nullable ArrayList<ListenerInfo<MuteAwaitConnectionCallback>> 10391 mMuteAwaitConnectionListeners; 10392 10393 @GuardedBy("mMuteAwaitConnectionListenerLock") 10394 private MuteAwaitConnectionDispatcherStub mMuteAwaitConnDispatcherStub; 10395 10396 private final class MuteAwaitConnectionDispatcherStub 10397 extends IMuteAwaitConnectionCallback.Stub { register(boolean register)10398 public void register(boolean register) { 10399 try { 10400 getService().registerMuteAwaitConnectionDispatcher(this, register); 10401 } catch (RemoteException e) { 10402 throw e.rethrowFromSystemServer(); 10403 } 10404 } 10405 10406 @Override 10407 @SuppressLint("GuardedBy") // lock applied inside callListeners method dispatchOnMutedUntilConnection(AudioDeviceAttributes device, int[] mutedUsages)10408 public void dispatchOnMutedUntilConnection(AudioDeviceAttributes device, 10409 int[] mutedUsages) { 10410 CallbackUtil.callListeners(mMuteAwaitConnectionListeners, 10411 mMuteAwaitConnectionListenerLock, 10412 (listener) -> listener.onMutedUntilConnection(device, mutedUsages)); 10413 } 10414 10415 @Override 10416 @SuppressLint("GuardedBy") // lock applied inside callListeners method dispatchOnUnmutedEvent(int event, AudioDeviceAttributes device, int[] mutedUsages)10417 public void dispatchOnUnmutedEvent(int event, AudioDeviceAttributes device, 10418 int[] mutedUsages) { 10419 CallbackUtil.callListeners(mMuteAwaitConnectionListeners, 10420 mMuteAwaitConnectionListenerLock, 10421 (listener) -> listener.onUnmutedEvent(event, device, mutedUsages)); 10422 } 10423 } 10424 10425 //==================================================================== 10426 // Flag related utilities 10427 10428 private boolean mIsAutomotive = false; 10429 initPlatform()10430 private void initPlatform() { 10431 try { 10432 final Context context = getContext(); 10433 if (context != null) { 10434 mIsAutomotive = context.getPackageManager() 10435 .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); 10436 } 10437 } catch (Exception e) { 10438 Log.e(TAG, "Error querying system feature for AUTOMOTIVE", e); 10439 } 10440 } 10441 applyAutoHardening()10442 private boolean applyAutoHardening() { 10443 if (mIsAutomotive && autoPublicVolumeApiHardening()) { 10444 return true; 10445 } 10446 return false; 10447 } 10448 10449 //--------------------------------------------------------- 10450 // Inner classes 10451 //-------------------- 10452 /** 10453 * Helper class to handle the forwarding of native events to the appropriate listener 10454 * (potentially) handled in a different thread. 10455 */ 10456 private class NativeEventHandlerDelegate { 10457 private final Handler mHandler; 10458 NativeEventHandlerDelegate(final AudioDeviceCallback callback, Handler handler)10459 NativeEventHandlerDelegate(final AudioDeviceCallback callback, 10460 Handler handler) { 10461 // find the looper for our new event handler 10462 Looper looper; 10463 if (handler != null) { 10464 looper = handler.getLooper(); 10465 } else { 10466 // no given handler, use the looper the addListener call was called in 10467 looper = Looper.getMainLooper(); 10468 } 10469 10470 // construct the event handler with this looper 10471 if (looper != null) { 10472 // implement the event handler delegate 10473 mHandler = new Handler(looper) { 10474 @Override 10475 public void handleMessage(Message msg) { 10476 switch(msg.what) { 10477 case MSG_DEVICES_CALLBACK_REGISTERED: 10478 case MSG_DEVICES_DEVICES_ADDED: 10479 if (callback != null) { 10480 callback.onAudioDevicesAdded((AudioDeviceInfo[])msg.obj); 10481 } 10482 break; 10483 10484 case MSG_DEVICES_DEVICES_REMOVED: 10485 if (callback != null) { 10486 callback.onAudioDevicesRemoved((AudioDeviceInfo[])msg.obj); 10487 } 10488 break; 10489 10490 default: 10491 Log.e(TAG, "Unknown native event type: " + msg.what); 10492 break; 10493 } 10494 } 10495 }; 10496 } else { 10497 mHandler = null; 10498 } 10499 } 10500 getHandler()10501 Handler getHandler() { 10502 return mHandler; 10503 } 10504 } 10505 } 10506